replace combined stateUpdated signal with individual events

This commit is contained in:
2026-06-05 18:10:40 +02:00
parent 9677133c54
commit 4e3e3ac715
18 changed files with 216 additions and 66 deletions

View File

@@ -117,6 +117,12 @@ void EventManager::processEvents()
}
}
void EventManager::clearEvents()
{
std::scoped_lock<std::mutex> lock(m_eventsMutex);
m_events.clear();
}
bool EventManager::hasEvents() const
{
return !m_events.empty();

View File

@@ -28,6 +28,7 @@ public:
void sendEventImmediately(std::shared_ptr<Event> event);
void addEvent(std::shared_ptr<Event> event);
void processEvents();
void clearEvents();
bool hasEvents() const;

View File

@@ -0,0 +1,17 @@
#ifndef BOSS_WAVE_UPDATED_EVENT_H
#define BOSS_WAVE_UPDATED_EVENT_H
#include "Event.h"
#include "Tick.h"
class BossWaveUpdatedEvent : public Event
{
public:
BossWaveUpdatedEvent(int counter, Tick countdownTicks)
: counter(counter), countdownTicks(countdownTicks) {}
const int counter;
const Tick countdownTicks;
};
#endif // BOSS_WAVE_UPDATED_EVENT_H

View File

@@ -0,0 +1,14 @@
#ifndef BUILDING_BLOCKS_CHANGED_EVENT_H
#define BUILDING_BLOCKS_CHANGED_EVENT_H
#include "Event.h"
class BuildingBlocksChangedEvent : public Event
{
public:
explicit BuildingBlocksChangedEvent(int blocks) : blocks(blocks) {}
const int blocks;
};
#endif // BUILDING_BLOCKS_CHANGED_EVENT_H

View File

@@ -1,6 +1,10 @@
SET(HDRS
${HDRS}
${CMAKE_CURRENT_SOURCE_DIR}/TracePrintRequestedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/TickAdvancedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/BuildingBlocksChangedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/GameSpeedChangedEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/BossWaveUpdatedEvent.h
PARENT_SCOPE
)

View File

@@ -0,0 +1,14 @@
#ifndef GAME_SPEED_CHANGED_EVENT_H
#define GAME_SPEED_CHANGED_EVENT_H
#include "Event.h"
class GameSpeedChangedEvent : public Event
{
public:
explicit GameSpeedChangedEvent(double speed) : speed(speed) {}
const double speed;
};
#endif // GAME_SPEED_CHANGED_EVENT_H

View File

@@ -0,0 +1,15 @@
#ifndef TICK_ADVANCED_EVENT_H
#define TICK_ADVANCED_EVENT_H
#include "Event.h"
#include "Tick.h"
class TickAdvancedEvent : public Event
{
public:
explicit TickAdvancedEvent(Tick tick) : tick(tick) {}
const Tick tick;
};
#endif // TICK_ADVANCED_EVENT_H

View File

@@ -93,7 +93,7 @@ void Simulation::reset(GameConfig newConfig, unsigned int seed)
void Simulation::reset(unsigned int seed)
{
EventManager::destroyInstance();
EventManager::getInstance()->clearEvents();
m_rng.seed(seed);
m_currentTick = 0;
m_nextDepartureTick = secondsToTicks(m_config.world.departureIntervalSeconds);

View File

@@ -13,6 +13,7 @@
#include <QVBoxLayout>
#include "BlueprintSerializer.h"
#include "BuildingBlocksChangedEvent.h"
#include "Building.h"
#include "BuildingSystem.h"
@@ -60,6 +61,13 @@ BlueprintPanel::BlueprintPanel(Simulation* sim, const GameConfig* config, QWidge
connect(m_saveBtn, &QPushButton::clicked, this, &BlueprintPanel::onSaveClicked);
connect(m_loadBtn, &QPushButton::clicked, this, &BlueprintPanel::onLoadClicked);
registerForEvent();
}
BlueprintPanel::~BlueprintPanel()
{
unregisterForEvent();
}
void BlueprintPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
@@ -68,9 +76,9 @@ void BlueprintPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
refreshButtonStates();
}
void BlueprintPanel::onStateUpdated(Tick /*tick*/, int blocks, double /*speed*/)
void BlueprintPanel::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
{
m_currentBlocks = blocks;
m_currentBlocks = event->blocks;
refreshButtonStates();
}

View File

@@ -5,7 +5,9 @@
#include <QWidget>
#include "Blueprint.h"
#include "BuildingBlocksChangedEvent.h"
#include "BuildingId.h"
#include "EventHandler.h"
#include "GameConfig.h"
#include "Tick.h"
@@ -14,22 +16,26 @@ class QPushButton;
class QScrollArea;
class QVBoxLayout;
class BlueprintPanel : public QWidget
class BlueprintPanel : public QWidget,
public EventHandler<BuildingBlocksChangedEvent>
{
Q_OBJECT
public:
BlueprintPanel(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr);
~BlueprintPanel() override;
public slots:
void onSelectionChanged(const std::vector<BuildingId>& ids);
void onStateUpdated(Tick tick, int blocks, double speed);
void clearActiveBlueprintButton();
signals:
void blueprintPlacementRequested(Blueprint blueprint);
void exitBlueprintModeRequested();
private:
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
private slots:
void onCreateClicked();
void onDeleteBlueprintClicked(int index);

View File

@@ -34,6 +34,10 @@
#include "SurfaceMask.h"
#include "Tick.h"
#include "TracePrintRequestedEvent.h"
#include "BossWaveUpdatedEvent.h"
#include "BuildingBlocksChangedEvent.h"
#include "GameSpeedChangedEvent.h"
#include "TickAdvancedEvent.h"
namespace
{
@@ -239,12 +243,33 @@ void GameWorldView::onFrame()
clampScroll();
}
// Emit state update for header bar / build grid
emit stateUpdated(m_sim->currentTick(),
m_sim->buildingBlocksStock(),
m_gameSpeedMultiplier,
m_sim->bossWaveCounter(),
m_sim->bossCountdownTicks());
// Fire events for any state that changed since the last frame
{
const Tick newTick = m_sim->currentTick();
const int newBlocks = m_sim->buildingBlocksStock();
const int newBoss = m_sim->bossWaveCounter();
const Tick newCountdown = m_sim->bossCountdownTicks();
if (newTick != m_lastTick)
{
m_lastTick = newTick;
EventManager::getInstance()->sendEventImmediately(
std::make_shared<TickAdvancedEvent>(newTick));
}
if (newBlocks != m_lastBlocks)
{
m_lastBlocks = newBlocks;
EventManager::getInstance()->sendEventImmediately(
std::make_shared<BuildingBlocksChangedEvent>(newBlocks));
}
if (newBoss != m_lastBossCounter || newCountdown != m_lastBossCountdown)
{
m_lastBossCounter = newBoss;
m_lastBossCountdown = newCountdown;
EventManager::getInstance()->sendEventImmediately(
std::make_shared<BossWaveUpdatedEvent>(newBoss, newCountdown));
}
}
// Game over check
if (m_sim->isGameOver() && !m_gameOverShown)
@@ -1403,11 +1428,8 @@ double GameWorldView::gameSpeed() const
void GameWorldView::setGameSpeed(double multiplier)
{
m_gameSpeedMultiplier = multiplier;
emit stateUpdated(m_sim->currentTick(),
m_sim->buildingBlocksStock(),
m_gameSpeedMultiplier,
m_sim->bossWaveCounter(),
m_sim->bossCountdownTicks());
EventManager::getInstance()->sendEventImmediately(
std::make_shared<GameSpeedChangedEvent>(m_gameSpeedMultiplier));
}
void GameWorldView::resetForNewGame()
@@ -1427,8 +1449,12 @@ void GameWorldView::resetForNewGame()
m_scrollLeft = false;
m_scrollRight = false;
m_gameOverShown = false;
m_gameSpeedMultiplier = 1.0;
m_prevNonZeroSpeed = 1.0;
m_lastTick = Tick(-1);
m_lastBlocks = -1;
m_lastBossCounter = -1;
m_lastBossCountdown = Tick(-1);
emit selectionChanged({});
setGameSpeed(1.0);
update();
}

View File

@@ -47,7 +47,6 @@ public:
signals:
void selectionChanged(const std::vector<BuildingId>& ids);
void stateUpdated(Tick tick, int blocks, double speed, int bossCounter, Tick bossCountdownTicks);
void gameOver();
void builderModeExited();
void blueprintModeExited();
@@ -173,4 +172,9 @@ private:
bool m_scrollLeft;
bool m_scrollRight;
bool m_gameOverShown;
Tick m_lastTick = Tick(-1);
int m_lastBlocks = -1;
int m_lastBossCounter = -1;
Tick m_lastBossCountdown = Tick(-1);
};

View File

@@ -41,41 +41,51 @@ HeaderBar::HeaderBar(QWidget* parent)
connect(btn, &QPushButton::clicked, mapper, qOverload<>(&QSignalMapper::map));
}
connect(mapper, qOverload<int>(&QSignalMapper::mapped), this, &HeaderBar::onSpeedButton);
setFixedHeight(sizeHint().height());
registerForEvents();
}
void HeaderBar::onStateUpdated(Tick tick, int buildingBlocks, double gameSpeed,
int bossCounter, Tick bossCountdownTicks)
HeaderBar::~HeaderBar()
{
const int totalSeconds = static_cast<int>(ticksToSeconds(tick));
const int minutes = totalSeconds / 60;
const int seconds = totalSeconds % 60;
unregisterForEvents();
}
void HeaderBar::handleEvent(std::shared_ptr<const TickAdvancedEvent> event)
{
const int totalSeconds = static_cast<int>(ticksToSeconds(event->tick));
m_timeLabel->setText(
QString("%1:%2")
.arg(minutes, 2, 10, QChar('0'))
.arg(seconds, 2, 10, QChar('0')));
.arg(totalSeconds / 60, 2, 10, QChar('0'))
.arg(totalSeconds % 60, 2, 10, QChar('0')));
}
m_blocksLabel->setText(tr("Blocks: %1").arg(buildingBlocks));
const int bossSeconds = static_cast<int>(ticksToSeconds(
bossCountdownTicks > 0 ? bossCountdownTicks : 0));
const int bossMin = bossSeconds / 60;
const int bossSec = bossSeconds % 60;
m_bossLabel->setText(
tr("Boss Wave #%1 Next boss: %2:%3")
.arg(bossCounter)
.arg(bossMin)
.arg(bossSec, 2, 10, QChar('0')));
void HeaderBar::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
{
m_blocksLabel->setText(tr("Blocks: %1").arg(event->blocks));
}
void HeaderBar::handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event)
{
for (int i = 0; i < kSpeedCount; ++i)
{
const bool active = (std::abs(kSpeeds[i] - gameSpeed) < 0.001);
m_speedButtons[static_cast<std::size_t>(i)]->setChecked(active);
m_speedButtons[static_cast<std::size_t>(i)]->setChecked(
std::abs(kSpeeds[i] - event->speed) < 0.001);
}
}
void HeaderBar::handleEvent(std::shared_ptr<const BossWaveUpdatedEvent> event)
{
const int bossSeconds = static_cast<int>(
ticksToSeconds(event->countdownTicks > 0 ? event->countdownTicks : 0));
m_bossLabel->setText(
tr("Boss Wave #%1 Next boss: %2:%3")
.arg(event->counter)
.arg(bossSeconds / 60)
.arg(bossSeconds % 60, 2, 10, QChar('0')));
}
void HeaderBar::onSpeedButton(int index)
{
if (index >= 0 && index < kSpeedCount)
@@ -83,4 +93,3 @@ void HeaderBar::onSpeedButton(int index)
emit speedChanged(kSpeeds[index]);
}
}

View File

@@ -4,21 +4,27 @@
#include <QWidget>
#include "BossWaveUpdatedEvent.h"
#include "BuildingBlocksChangedEvent.h"
#include "EventHandler.h"
#include "GameSpeedChangedEvent.h"
#include "Tick.h"
#include "TickAdvancedEvent.h"
class QLabel;
class QPushButton;
class HeaderBar : public QWidget
class HeaderBar : public QWidget,
public CombinedEventHandler<TickAdvancedEvent,
BuildingBlocksChangedEvent,
GameSpeedChangedEvent,
BossWaveUpdatedEvent>
{
Q_OBJECT
public:
explicit HeaderBar(QWidget* parent = nullptr);
public slots:
void onStateUpdated(Tick tick, int buildingBlocks, double gameSpeed,
int bossCounter, Tick bossCountdownTicks);
~HeaderBar() override;
signals:
void speedChanged(double multiplier);
@@ -27,6 +33,11 @@ private slots:
void onSpeedButton(int index);
private:
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
void handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event) override;
void handleEvent(std::shared_ptr<const BossWaveUpdatedEvent> event) override;
QLabel* m_timeLabel;
QLabel* m_blocksLabel;
QLabel* m_bossLabel;

View File

@@ -11,6 +11,7 @@
#include "BlueprintPanel.h"
#include "BuildButtonGrid.h"
#include "BuildingBlocksChangedEvent.h"
#include "BuildingSystem.h"
#include "ConfigLoader.h"
#include "GameWorldView.h"
@@ -52,15 +53,6 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* p
connect(m_gameWorldView, &GameWorldView::selectionChanged,
m_selectedBuildingPanel, &SelectedBuildingPanel::onSelectionChanged);
connect(m_gameWorldView, &GameWorldView::stateUpdated,
m_headerBar, &HeaderBar::onStateUpdated);
connect(m_gameWorldView, &GameWorldView::stateUpdated,
this, &MainWindow::onStateUpdated); // for affordability
connect(m_gameWorldView, &GameWorldView::stateUpdated,
m_selectedBuildingPanel, &SelectedBuildingPanel::onStateUpdated);
connect(m_gameWorldView, &GameWorldView::gameOver,
this, &MainWindow::onGameOver);
@@ -90,9 +82,6 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* p
connect(m_gameWorldView, &GameWorldView::selectionChanged,
m_blueprintPanel, &BlueprintPanel::onSelectionChanged);
connect(m_gameWorldView, &GameWorldView::stateUpdated,
m_blueprintPanel, &BlueprintPanel::onStateUpdated);
connect(m_blueprintPanel, &BlueprintPanel::blueprintPlacementRequested,
m_gameWorldView, &GameWorldView::enterBlueprintMode);
@@ -132,6 +121,13 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir, QWidget* p
m_layoutBlueprints.clear();
}
}
registerForEvent();
}
MainWindow::~MainWindow()
{
unregisterForEvent();
}
void MainWindow::resizeEvent(QResizeEvent* event)
@@ -172,9 +168,9 @@ void MainWindow::layoutPanels()
m_bottomPanel->setGeometry(0, headerH + gameH, totalW, panelH);
}
void MainWindow::onStateUpdated(Tick /*tick*/, int blocks, double /*speed*/)
void MainWindow::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
{
m_buildButtonGrid->updateAffordability(blocks);
m_buildButtonGrid->updateAffordability(event->blocks);
}
void MainWindow::onEscapeMenuRequested()

View File

@@ -5,7 +5,9 @@
#include <QWidget>
#include "BuildingBlocksChangedEvent.h"
#include "BuildingId.h"
#include "EventHandler.h"
#include "ShipLayoutBlueprint.h"
#include "Tick.h"
#include "VisualsConfig.h"
@@ -19,26 +21,29 @@ class BlueprintPanel;
class QCloseEvent;
class QResizeEvent;
class MainWindow : public QWidget
class MainWindow : public QWidget,
public EventHandler<BuildingBlocksChangedEvent>
{
Q_OBJECT
public:
MainWindow(Simulation* sim, const std::string& configDir, QWidget* parent = nullptr);
~MainWindow() override;
protected:
void resizeEvent(QResizeEvent* event) override;
void closeEvent(QCloseEvent* event) override;
private:
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
void layoutPanels();
private slots:
void onGameOver();
void onStateUpdated(Tick tick, int blocks, double speed);
void onEscapeMenuRequested();
void onLayoutDialogRequested(BuildingId shipyardId);
private:
void layoutPanels();
std::string m_configDir;
VisualsConfig m_visuals;
Simulation* m_sim;

View File

@@ -13,6 +13,7 @@
#include <QVBoxLayout>
#include "BeltSystem.h"
#include "TickAdvancedEvent.h"
#include "Building.h"
#include "BuildingSystem.h"
#include "BuildingType.h"
@@ -136,6 +137,13 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
this, &SelectedBuildingPanel::onSplitterFilterChanged);
buildEmpty();
registerForEvent();
}
SelectedBuildingPanel::~SelectedBuildingPanel()
{
unregisterForEvent();
}
void SelectedBuildingPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
@@ -488,7 +496,7 @@ const ShipDef* SelectedBuildingPanel::findShipDef(const std::string& id) const
return nullptr;
}
void SelectedBuildingPanel::onStateUpdated(Tick /*tick*/, int /*blocks*/, double /*speed*/)
void SelectedBuildingPanel::handleEvent(std::shared_ptr<const TickAdvancedEvent> /*event*/)
{
if (m_singleBuildingId == kInvalidBuildingId) { return; }
const Building* b = m_sim->buildings().findBuilding(m_singleBuildingId);

View File

@@ -8,11 +8,13 @@
#include "Building.h"
#include "BuildingId.h"
#include "EventHandler.h"
#include "GameConfig.h"
#include "RecipesConfig.h"
#include "ShipLayout.h"
#include "ShipsConfig.h"
#include "Tick.h"
#include "TickAdvancedEvent.h"
class Simulation;
class ShipLayoutPreview;
@@ -22,20 +24,24 @@ class QListWidget;
class QPushButton;
class QVBoxLayout;
class SelectedBuildingPanel : public QWidget
class SelectedBuildingPanel : public QWidget,
public EventHandler<TickAdvancedEvent>
{
Q_OBJECT
public:
SelectedBuildingPanel(Simulation* sim, const GameConfig* config,
QWidget* parent = nullptr);
~SelectedBuildingPanel() override;
signals:
void layoutDialogRequested(BuildingId shipyardId);
public slots:
void onSelectionChanged(const std::vector<BuildingId>& ids);
void onStateUpdated(Tick tick, int blocks, double speed);
private:
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
private slots:
void onRecipeChanged(int comboIndex);