switch to using own event system

This commit is contained in:
2026-06-13 17:42:16 +02:00
parent ed17664ef1
commit 5317f35198
49 changed files with 611 additions and 300 deletions

View File

@@ -259,9 +259,9 @@ void ArenaSimulation::tick()
m_aiSystem->tickSalvageBehavior(m_admin, *m_scrapSystem, *m_buildingSystem);
// Combat resolution (tick step 8).
std::vector<FireEvent> fireEvents;
m_combatSystem->tick(m_currentTick, m_admin, *m_buildingSystem, fireEvents);
m_fireEvents.insert(m_fireEvents.end(), fireEvents.begin(), fireEvents.end());
std::vector<WeaponFiredEvent> weaponFiredEvents;
m_combatSystem->tick(m_currentTick, m_admin, *m_buildingSystem, weaponFiredEvents);
m_weaponFiredEvents.insert(m_weaponFiredEvents.end(), weaponFiredEvents.begin(), weaponFiredEvents.end());
m_combatSystem->applyPendingDamage(m_currentTick, m_admin);
// Deaths (tick step 9, simplified).
@@ -393,10 +393,10 @@ void ArenaSimulation::tickOnce()
}
}
std::vector<FireEvent> ArenaSimulation::drainFireEvents()
std::vector<WeaponFiredEvent> ArenaSimulation::drainWeaponFiredEvents()
{
std::vector<FireEvent> result;
result.swap(m_fireEvents);
std::vector<WeaponFiredEvent> result;
result.swap(m_weaponFiredEvents);
return result;
}

View File

@@ -13,7 +13,7 @@
#include "BuildingId.h"
#include "entt/entity/entity.hpp"
#include "FireEvent.h"
#include "WeaponFiredEvent.h"
#include "GameConfig.h"
#include "Tick.h"
@@ -58,7 +58,7 @@ public:
void requestStop();
void tickOnce();
std::vector<FireEvent> drainFireEvents();
std::vector<WeaponFiredEvent> drainWeaponFiredEvents();
ArenaStatus status() const;
bool isFinished() const;
@@ -104,7 +104,7 @@ private:
int m_winnerTeam;
std::atomic<bool> m_stopRequested;
std::vector<FireEvent> m_fireEvents;
std::vector<WeaponFiredEvent> m_weaponFiredEvents;
mutable std::mutex m_statusMutex;
ArenaStatus m_status;

View File

@@ -16,6 +16,7 @@
#include "EventManager.h"
#include "FacingComponent.h"
#include "FactionComponent.h"
#include "GameSpeedChangedEvent.h"
#include "HealthComponent.h"
#include "PositionComponent.h"
#include "ScrapSystem.h"
@@ -45,6 +46,13 @@ ArenaView::ArenaView(ArenaSimulation* sim, const VisualsConfig* visuals,
connect(m_renderTimer, &QTimer::timeout, this, &ArenaView::onFrame);
m_renderTimer->start();
m_frameTimer.start();
registerForEvent();
}
ArenaView::~ArenaView()
{
unregisterForEvent();
}
void ArenaView::setGameSpeed(double multiplier)
@@ -54,7 +62,8 @@ void ArenaView::setGameSpeed(double multiplier)
m_prevNonZeroSpeed = multiplier;
}
m_gameSpeedMultiplier = multiplier;
emit speedChanged(multiplier);
EventManager::getInstance()->sendEventImmediately(
std::make_shared<GameSpeedChangedEvent>(multiplier));
}
double ArenaView::gameSpeed() const
@@ -93,34 +102,17 @@ void ArenaView::onFrame()
}
}
// Emit fire events via EventManager
{
const std::vector<FireEvent> fires = m_sim->drainFireEvents();
for (const FireEvent& fe : fires)
const std::vector<WeaponFiredEvent> fires = m_sim->drainWeaponFiredEvents();
for (const WeaponFiredEvent& fe : fires)
{
float maxRadius = 0.125f;
if (m_sim->admin().isValid(fe.target)
&& m_sim->admin().hasAll<StationBodyComponent>(fe.target))
{
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(fe.target);
const int shorter = std::min(sb.footprint.width(),
sb.footprint.height());
maxRadius = shorter / 2.0f;
}
std::uniform_real_distribution<float> angleDist(0.0f, 6.28318530f);
std::uniform_real_distribution<float> radiusDist(0.0f, maxRadius);
const float angle = angleDist(m_rng);
const float radius = radiusDist(m_rng);
ActiveBeam beam;
beam.event = fe;
beam.emittedWallMs = m_wallMs;
beam.targetOffset = QVector2D(radius * std::cos(angle),
radius * std::sin(angle));
m_activeBeams.push_back(beam);
EventManager::getInstance()->sendEventImmediately(
std::make_shared<WeaponFiredEvent>(fe));
}
}
// Expire old beams
{
std::vector<ActiveBeam> live;
for (const ActiveBeam& b : m_activeBeams)
@@ -136,12 +128,36 @@ void ArenaView::onFrame()
if (m_sim->isFinished() && !m_finishedEmitted)
{
m_finishedEmitted = true;
emit finished();
}
update();
}
void ArenaView::handleEvent(std::shared_ptr<const WeaponFiredEvent> event)
{
float maxRadius = 0.125f;
if (m_sim->admin().isValid(event->target)
&& m_sim->admin().hasAll<StationBodyComponent>(event->target))
{
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(event->target);
const int shorter = std::min(sb.footprint.width(),
sb.footprint.height());
maxRadius = shorter / 2.0f;
}
std::uniform_real_distribution<float> angleDist(0.0f, 6.28318530f);
std::uniform_real_distribution<float> radiusDist(0.0f, maxRadius);
const float angle = angleDist(m_rng);
const float radius = radiusDist(m_rng);
ActiveBeam beam;
beam.event = *event;
beam.emittedWallMs = m_wallMs;
beam.targetOffset = QVector2D(radius * std::cos(angle),
radius * std::sin(angle));
m_activeBeams.push_back(beam);
}
void ArenaView::paintGL()
{
QPainter painter(this);
@@ -414,4 +430,3 @@ void ArenaView::drawBeams(QPainter& painter)
worldToWidget(*targetPos + beam.targetOffset));
}
}

View File

@@ -9,7 +9,8 @@
#include <QTimer>
#include <QVector2D>
#include "FireEvent.h"
#include "EventHandler.h"
#include "WeaponFiredEvent.h"
#include "entt/entity/entity.hpp"
#include "EntitySelectedEvent.h"
@@ -20,23 +21,21 @@
class ArenaSimulation;
class QPainter;
class ArenaView : public QOpenGLWidget
class ArenaView : public QOpenGLWidget,
public EventHandler<WeaponFiredEvent>
{
Q_OBJECT
public:
ArenaView(ArenaSimulation* sim, const VisualsConfig* visuals,
QWidget* parent = nullptr);
~ArenaView() override;
void setGameSpeed(double multiplier);
double gameSpeed() const;
void togglePause();
void stopRendering();
signals:
void speedChanged(double multiplier);
void finished();
protected:
void paintGL() override;
void mousePressEvent(QMouseEvent* event) override;
@@ -45,6 +44,8 @@ private slots:
void onFrame();
private:
void handleEvent(std::shared_ptr<const WeaponFiredEvent> event) override;
void drawTiles(QPainter& painter);
void drawBuildings(QPainter& painter);
void drawStations(QPainter& painter);
@@ -62,7 +63,7 @@ private:
struct ActiveBeam
{
FireEvent event;
WeaponFiredEvent event;
qint64 emittedWallMs;
QVector2D targetOffset;
};

View File

@@ -3,8 +3,13 @@
#include <QHBoxLayout>
#include <QVBoxLayout>
ArenaWidget::ArenaWidget(const std::string& arenaName, QWidget* parent)
#include "ArenaInspectRequestedEvent.h"
#include "ArenaStartRequestedEvent.h"
#include "EventManager.h"
ArenaWidget::ArenaWidget(int arenaIndex, const std::string& arenaName, QWidget* parent)
: QFrame(parent)
, m_arenaIndex(arenaIndex)
, m_running(false)
, m_wasFinished(false)
{
@@ -31,11 +36,17 @@ void ArenaWidget::buildLayout(const std::string& arenaName)
titleRow->addStretch();
m_inspectButton = new QPushButton(tr("Inspect"), this);
connect(m_inspectButton, &QPushButton::clicked, this, &ArenaWidget::inspectRequested);
connect(m_inspectButton, &QPushButton::clicked, this, [this]() {
EventManager::getInstance()->sendEventImmediately(
std::make_shared<ArenaInspectRequestedEvent>(m_arenaIndex));
});
titleRow->addWidget(m_inspectButton);
m_startButton = new QPushButton(tr("Start"), this);
connect(m_startButton, &QPushButton::clicked, this, &ArenaWidget::startRequested);
connect(m_startButton, &QPushButton::clicked, this, [this]() {
EventManager::getInstance()->sendEventImmediately(
std::make_shared<ArenaStartRequestedEvent>(m_arenaIndex));
});
titleRow->addWidget(m_startButton);
outerLayout->addLayout(titleRow);

View File

@@ -14,19 +14,16 @@ class ArenaWidget : public QFrame
Q_OBJECT
public:
explicit ArenaWidget(const std::string& arenaName, QWidget* parent = nullptr);
ArenaWidget(int arenaIndex, const std::string& arenaName, QWidget* parent = nullptr);
void updateStatus(const ArenaStatus& status);
void startSimulation();
void resetToGrey();
signals:
void startRequested();
void inspectRequested();
private:
void buildLayout(const std::string& arenaName);
int m_arenaIndex;
QLabel* m_titleLabel;
QLabel* m_team1Header;
QLabel* m_team2Header;

View File

@@ -48,14 +48,17 @@ BalancingWindow::BalancingWindow(const BalancingConfig& balancingConfig,
m_pollTimer = new QTimer(this);
connect(m_pollTimer, &QTimer::timeout, this, &BalancingWindow::pollStatuses);
m_pollTimer->start(100);
registerForEvents();
}
BalancingWindow::~BalancingWindow()
{
unregisterForEvents();
m_pollTimer->stop();
if (m_inspectWindow)
{
m_inspectWindow->disconnect(this);
delete m_inspectWindow;
m_inspectWindow = nullptr;
}
@@ -81,16 +84,11 @@ void BalancingWindow::populateArenas(const BalancingConfig& balancingConfig)
entry.config = arenaConfig;
entry.simulation = std::make_unique<ArenaSimulation>(
m_gameConfig, arenaConfig, m_nextSeed++);
entry.widget = new ArenaWidget(arenaConfig.name, scrollContent);
entry.widget = new ArenaWidget(index, arenaConfig.name, scrollContent);
contentLayout->addWidget(entry.widget);
entry.widget->updateStatus(entry.simulation->status());
connect(entry.widget, &ArenaWidget::startRequested,
this, [this, index]() { startArena(index); });
connect(entry.widget, &ArenaWidget::inspectRequested,
this, [this, index]() { inspectArena(index); });
m_arenas.push_back(std::move(entry));
}
@@ -158,6 +156,21 @@ void BalancingWindow::startAll()
}
}
void BalancingWindow::handleEvent(std::shared_ptr<const ArenaStartRequestedEvent> event)
{
startArena(event->arenaIndex);
}
void BalancingWindow::handleEvent(std::shared_ptr<const ArenaInspectRequestedEvent> event)
{
inspectArena(event->arenaIndex);
}
void BalancingWindow::handleEvent(std::shared_ptr<const InspectWindowClosedEvent> /*event*/)
{
closeInspectWindow();
}
void BalancingWindow::startArena(int index)
{
ArenaEntry& entry = m_arenas[index];
@@ -179,7 +192,6 @@ void BalancingWindow::inspectArena(int index)
{
if (m_inspectWindow)
{
m_inspectWindow->disconnect(this);
delete m_inspectWindow;
m_inspectWindow = nullptr;
@@ -210,8 +222,6 @@ void BalancingWindow::inspectArena(int index)
m_inspectWindow = new InspectWindow(
m_inspectedSim.get(), &m_gameConfig, &m_visuals, entry.config.name, nullptr);
connect(m_inspectWindow, &InspectWindow::closed,
this, &BalancingWindow::closeInspectWindow);
setMainControlsEnabled(false);
m_inspectWindow->show();
@@ -224,7 +234,6 @@ void BalancingWindow::closeInspectWindow()
return;
}
m_inspectWindow->disconnect(this);
m_inspectWindow->deleteLater();
m_inspectWindow = nullptr;

View File

@@ -10,15 +10,22 @@
#include <QTimer>
#include <QWidget>
#include "ArenaInspectRequestedEvent.h"
#include "ArenaStartRequestedEvent.h"
#include "ArenaWidget.h"
#include "ArenaSimulation.h"
#include "BalancingConfig.h"
#include "EventHandler.h"
#include "GameConfig.h"
#include "InspectWindowClosedEvent.h"
#include "VisualsConfig.h"
class InspectWindow;
class BalancingWindow : public QWidget
class BalancingWindow : public QWidget,
public CombinedEventHandler<ArenaStartRequestedEvent,
ArenaInspectRequestedEvent,
InspectWindowClosedEvent>
{
Q_OBJECT
@@ -30,15 +37,20 @@ public:
QWidget* parent = nullptr);
~BalancingWindow() override;
private:
void handleEvent(std::shared_ptr<const ArenaStartRequestedEvent> event) override;
void handleEvent(std::shared_ptr<const ArenaInspectRequestedEvent> event) override;
void handleEvent(std::shared_ptr<const InspectWindowClosedEvent> event) override;
private slots:
void pollStatuses();
void reloadConfig();
void startAll();
private:
void startArena(int index);
void inspectArena(int index);
void closeInspectWindow();
private:
void populateArenas(const BalancingConfig& balancingConfig);
void stopAllArenas();
void updateButtons();

View File

@@ -10,7 +10,9 @@
#include "ArenaView.h"
#include "EntityAdmin.h"
#include "EventManager.h"
#include "HealthComponent.h"
#include "InspectWindowClosedEvent.h"
#include "ModuleOwnerComponent.h"
#include "ShipIdentityComponent.h"
#include "ShipStatsCalculator.h"
@@ -76,9 +78,6 @@ InspectWindow::InspectWindow(ArenaSimulation* sim, const GameConfig* config,
m_arenaView = new ArenaView(sim, visuals, this);
mainLayout->addWidget(m_arenaView, 1);
connect(m_arenaView, &ArenaView::speedChanged,
this, &InspectWindow::onSpeedChanged);
// Info panel (bottom)
{
QWidget* infoPanel = new QWidget(this);
@@ -140,19 +139,20 @@ InspectWindow::InspectWindow(ArenaSimulation* sim, const GameConfig* config,
setFocusPolicy(Qt::StrongFocus);
registerForEvent();
registerForEvents();
}
InspectWindow::~InspectWindow()
{
unregisterForEvent();
unregisterForEvents();
}
void InspectWindow::closeEvent(QCloseEvent* event)
{
m_arenaView->stopRendering();
m_pollTimer->stop();
emit closed();
EventManager::getInstance()->sendEventImmediately(
std::make_shared<InspectWindowClosedEvent>());
event->accept();
}
@@ -176,11 +176,11 @@ void InspectWindow::onSpeedButton(int index)
}
}
void InspectWindow::onSpeedChanged(double multiplier)
void InspectWindow::handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event)
{
for (int i = 0; i < kSpeedCount; ++i)
{
const bool active = (std::abs(kSpeeds[i] - multiplier) < 0.001);
const bool active = (std::abs(kSpeeds[i] - event->speed) < 0.001);
m_speedButtons[static_cast<std::size_t>(i)]->setChecked(active);
}
}

View File

@@ -15,13 +15,15 @@
#include "EntitySelectedEvent.h"
#include "EventHandler.h"
#include "GameConfig.h"
#include "GameSpeedChangedEvent.h"
#include "VisualsConfig.h"
class ArenaView;
class ShipStatsPanel;
class InspectWindow : public QWidget,
public EventHandler<EntitySelectedEvent>
public CombinedEventHandler<EntitySelectedEvent,
GameSpeedChangedEvent>
{
Q_OBJECT
@@ -31,19 +33,16 @@ public:
const std::string& arenaName, QWidget* parent = nullptr);
~InspectWindow() override;
signals:
void closed();
protected:
void closeEvent(QCloseEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
private:
void handleEvent(std::shared_ptr<const EntitySelectedEvent> event) override;
void handleEvent(std::shared_ptr<const GameSpeedChangedEvent> event) override;
private slots:
void onSpeedButton(int index);
void onSpeedChanged(double multiplier);
void pollStatus();
private: