From 4c166bf47f59a6e72912145ce6be8ab9ed6dfc69 Mon Sep 17 00:00:00 2001 From: mlangkabel Date: Wed, 5 Aug 2026 07:25:59 +0200 Subject: [PATCH] depend on the registry instead of DebrisSystem in the AI path --- src/balancing/ArenaSimulation.cpp | 4 ++-- src/balancing/ArenaView.cpp | 2 +- src/lib/ecs/system/AiSystem.cpp | 5 ++--- src/lib/ecs/system/AiSystem.h | 3 +-- src/lib/ecs/system/DebrisSystem.cpp | 16 ++++++++-------- src/lib/ecs/system/DebrisSystem.h | 12 ++++++++++-- src/lib/ecs/system/SalvagerSystem.cpp | 10 +++++----- src/lib/ecs/system/SalvagerSystem.h | 5 ++--- src/lib/ecs/system/ai/SalvageScrapEvaluator.cpp | 4 ++-- src/lib/ecs/system/ai/SalvageScrapEvaluator.h | 3 +-- src/lib/sim/Simulation.cpp | 4 ++-- src/test/BehaviorSystemTest.cpp | 6 +++--- src/test/CombatSystemTest.cpp | 2 +- src/test/DebrisTest.cpp | 12 ++++++------ src/ui/FieldSelectionPanel.cpp | 2 +- src/ui/GameWorldView.cpp | 6 +++--- 16 files changed, 50 insertions(+), 46 deletions(-) diff --git a/src/balancing/ArenaSimulation.cpp b/src/balancing/ArenaSimulation.cpp index bf944b5..b30bd7a 100644 --- a/src/balancing/ArenaSimulation.cpp +++ b/src/balancing/ArenaSimulation.cpp @@ -324,9 +324,9 @@ void ArenaSimulation::tick() // Ship behavior systems (tick step 7): evaluate, select winner, execute. // Module + combat systems emit their tool beams into a shared buffer. m_shipSystem->clearMovementIntents(); - m_aiSystem->tick(m_admin, m_factoryState, *m_debrisSystem); + m_aiSystem->tick(m_admin, m_factoryState); std::vector beamFiredEvents; - m_salvagerSystem->tick(m_currentTick, *m_debrisSystem, m_factoryState, beamFiredEvents); + m_salvagerSystem->tick(m_currentTick, m_factoryState, beamFiredEvents); m_repairSystem->tick(m_currentTick, beamFiredEvents); // Combat resolution (tick step 8). diff --git a/src/balancing/ArenaView.cpp b/src/balancing/ArenaView.cpp index e9c453d..ffdf88d 100644 --- a/src/balancing/ArenaView.cpp +++ b/src/balancing/ArenaView.cpp @@ -340,7 +340,7 @@ void ArenaView::drawBuildings(QPainter& painter) void ArenaView::drawDebris(QPainter& painter) { const float r = getTilePx() * 0.2f; - for (const DebrisInfo& debris : m_sim->getDebrisSystem().getAllDebrisInfo()) + for (const DebrisInfo& debris : getAllDebrisInfo(m_sim->getAdmin())) { const QPointF center = worldToWidget(debris.position); painter.setBrush(QColor(128, 110, 90)); diff --git a/src/lib/ecs/system/AiSystem.cpp b/src/lib/ecs/system/AiSystem.cpp index fbaf86f..3b28a37 100644 --- a/src/lib/ecs/system/AiSystem.cpp +++ b/src/lib/ecs/system/AiSystem.cpp @@ -43,8 +43,7 @@ AiSystem::AiSystem(const GameConfig& config) { } -void AiSystem::tick(EntityAdmin& admin, const FactoryState& state, - const DebrisSystem& debris) +void AiSystem::tick(EntityAdmin& admin, const FactoryState& state) { TRACE(); @@ -55,7 +54,7 @@ void AiSystem::tick(EntityAdmin& admin, const FactoryState& state, m_retreatEvaluator.evaluate(admin); m_attackEvaluator.evaluate(admin); m_repairEvaluator.evaluate(admin); - m_salvageScrapEvaluator.evaluate(admin, debris); + m_salvageScrapEvaluator.evaluate(admin); m_deliverScrapEvaluator.evaluate(admin, state); // Phase 2: pick the highest-scoring behavior per ship. diff --git a/src/lib/ecs/system/AiSystem.h b/src/lib/ecs/system/AiSystem.h index a020f7b..fd9bb03 100644 --- a/src/lib/ecs/system/AiSystem.h +++ b/src/lib/ecs/system/AiSystem.h @@ -20,7 +20,6 @@ #include "StandbyExecutor.h" class EntityAdmin; -class DebrisSystem; struct GameConfig; // Orchestrates ship-behavior decision-making in three batched phases: @@ -35,7 +34,7 @@ class AiSystem public: explicit AiSystem(const GameConfig& config); - void tick(EntityAdmin& admin, const FactoryState& state, const DebrisSystem& debris); + void tick(EntityAdmin& admin, const FactoryState& state); private: void selectWinningBehaviors(EntityAdmin& admin); diff --git a/src/lib/ecs/system/DebrisSystem.cpp b/src/lib/ecs/system/DebrisSystem.cpp index 0a6936b..12d23f5 100644 --- a/src/lib/ecs/system/DebrisSystem.cpp +++ b/src/lib/ecs/system/DebrisSystem.cpp @@ -46,13 +46,13 @@ std::optional DebrisSystem::consume(entt::entity entity) return amount; } -bool DebrisSystem::collectOne(entt::entity entity) +bool collectOne(EntityAdmin& admin, entt::entity entity) { - if (!m_admin.isValid(entity) || !m_admin.hasAll(entity)) + if (!admin.isValid(entity) || !admin.hasAll(entity)) { return false; } - DebrisComponent& data = m_admin.get(entity); + DebrisComponent& data = admin.get(entity); if (data.amount <= 0) { return false; @@ -60,18 +60,18 @@ bool DebrisSystem::collectOne(entt::entity entity) --data.amount; if (data.amount <= 0) { - m_admin.destroy(entity); + admin.destroy(entity); } return true; } -std::vector DebrisSystem::getAllDebrisInfo() const +std::vector getAllDebrisInfo(const EntityAdmin& admin) { std::vector result; - m_admin.forEach( - [&result, this](entt::entity e, const DebrisComponent& sd) + admin.forEach( + [&result, &admin](entt::entity e, const DebrisComponent& sd) { - result.push_back(DebrisInfo{e, m_admin.get(e).value, sd.amount}); + result.push_back(DebrisInfo{e, admin.get(e).value, sd.amount}); }); return result; } diff --git a/src/lib/ecs/system/DebrisSystem.h b/src/lib/ecs/system/DebrisSystem.h index 2b41ff1..9a3b352 100644 --- a/src/lib/ecs/system/DebrisSystem.h +++ b/src/lib/ecs/system/DebrisSystem.h @@ -38,9 +38,17 @@ public: // false if the entity is invalid or already empty (REQ-SHP-SALVAGE). bool collectOne(entt::entity entity); - // Lightweight snapshot for callers that need to iterate all debris. - std::vector getAllDebrisInfo() const; private: EntityAdmin& m_admin; }; + +// Debris state read and changed straight off the registry — no system needed. + +// Lightweight snapshot for callers that need to iterate all debris. +std::vector getAllDebrisInfo(const EntityAdmin& admin); + +// Collects a single scrap unit from the debris: decrements its amount by one, +// destroying the entity once depleted. Returns true if a scrap was collected, +// false if the entity is invalid or already empty (REQ-SHP-SALVAGE). +bool collectOne(EntityAdmin& admin, entt::entity entity); diff --git a/src/lib/ecs/system/SalvagerSystem.cpp b/src/lib/ecs/system/SalvagerSystem.cpp index 5574b39..7efa23d 100644 --- a/src/lib/ecs/system/SalvagerSystem.cpp +++ b/src/lib/ecs/system/SalvagerSystem.cpp @@ -24,14 +24,14 @@ SalvagerSystem::SalvagerSystem(EntityAdmin& admin) { } -void SalvagerSystem::tick(Tick currentTick, DebrisSystem& debris, FactoryState& state, +void SalvagerSystem::tick(Tick currentTick, FactoryState& state, std::vector& outBeamFiredEvents) { TRACE(); // Apply collections whose mid-beam delay has elapsed (cycles started earlier). - applyPendingCollections(currentTick, debris); + applyPendingCollections(currentTick); - const std::vector allDebris = debris.getAllDebrisInfo(); + const std::vector allDebris = getAllDebrisInfo(m_admin); // Tick down per-module collection cooldowns. m_admin.forEach( @@ -108,7 +108,7 @@ void SalvagerSystem::tick(Tick currentTick, DebrisSystem& debris, FactoryState& }); } -void SalvagerSystem::applyPendingCollections(Tick currentTick, DebrisSystem& debris) +void SalvagerSystem::applyPendingCollections(Tick currentTick) { std::vector::iterator it = m_pendingCollections.begin(); while (it != m_pendingCollections.end()) @@ -118,7 +118,7 @@ void SalvagerSystem::applyPendingCollections(Tick currentTick, DebrisSystem& deb if (m_admin.isValid(it->ship) && m_admin.hasAll(it->ship)) { CargoComponent& cargo = m_admin.get(it->ship); - if (cargo.current < cargo.maxCapacity && debris.collectOne(it->debris)) + if (cargo.current < cargo.maxCapacity && collectOne(m_admin, it->debris)) { ++cargo.current; } diff --git a/src/lib/ecs/system/SalvagerSystem.h b/src/lib/ecs/system/SalvagerSystem.h index 97a5526..752f274 100644 --- a/src/lib/ecs/system/SalvagerSystem.h +++ b/src/lib/ecs/system/SalvagerSystem.h @@ -10,7 +10,6 @@ #include "entt/entity/entity.hpp" class EntityAdmin; -class DebrisSystem; // World-mutation system for salvage modules: each module runs a collection cycle // on its own cooldown. When a cycle starts it emits a salvage beam toward an @@ -22,7 +21,7 @@ class SalvagerSystem public: explicit SalvagerSystem(EntityAdmin& admin); - void tick(Tick currentTick, DebrisSystem& debris, FactoryState& state, + void tick(Tick currentTick, FactoryState& state, std::vector& outBeamFiredEvents); private: @@ -33,7 +32,7 @@ private: Tick appliesAt; }; - void applyPendingCollections(Tick currentTick, DebrisSystem& debris); + void applyPendingCollections(Tick currentTick); EntityAdmin& m_admin; std::vector m_pendingCollections; diff --git a/src/lib/ecs/system/ai/SalvageScrapEvaluator.cpp b/src/lib/ecs/system/ai/SalvageScrapEvaluator.cpp index 4b78060..b7da572 100644 --- a/src/lib/ecs/system/ai/SalvageScrapEvaluator.cpp +++ b/src/lib/ecs/system/ai/SalvageScrapEvaluator.cpp @@ -15,11 +15,11 @@ #include "SensorRangeComponent.h" #include "tracing.h" -void SalvageScrapEvaluator::evaluate(EntityAdmin& admin, const DebrisSystem& debris) +void SalvageScrapEvaluator::evaluate(EntityAdmin& admin) { TRACE(); const std::unordered_map cargoByShip = buildCargoByShip(admin); - const std::vector allDebris = debris.getAllDebrisInfo(); + const std::vector allDebris = getAllDebrisInfo(admin); admin.forEach( [&](entt::entity e, SalvageScrapBehavior& salvage, const PositionComponent& pos, diff --git a/src/lib/ecs/system/ai/SalvageScrapEvaluator.h b/src/lib/ecs/system/ai/SalvageScrapEvaluator.h index ef33f47..f0fd03b 100644 --- a/src/lib/ecs/system/ai/SalvageScrapEvaluator.h +++ b/src/lib/ecs/system/ai/SalvageScrapEvaluator.h @@ -1,7 +1,6 @@ #pragma once class EntityAdmin; -class DebrisSystem; // When cargo is not full, finds the nearest debris within sensor range and sets // it as the target, scoring high. Scores inactive when cargo is full or no debris @@ -9,5 +8,5 @@ class DebrisSystem; class SalvageScrapEvaluator { public: - void evaluate(EntityAdmin& admin, const DebrisSystem& debris); + void evaluate(EntityAdmin& admin); }; diff --git a/src/lib/sim/Simulation.cpp b/src/lib/sim/Simulation.cpp index 50b479a..d735525 100644 --- a/src/lib/sim/Simulation.cpp +++ b/src/lib/sim/Simulation.cpp @@ -268,10 +268,10 @@ void Simulation::tick() m_shipSystem->clearMovementIntents(); // Score-based behavior selection: evaluate, select winner, execute (sets // movement intent + preferred module targets only — no world mutation). - m_aiSystem->tick(m_admin, m_factoryState, *m_debrisSystem); + m_aiSystem->tick(m_admin, m_factoryState); // Module systems perform the world mutation (collection/delivery, healing). // Each emits its tool beams and applies its own delayed (mid-beam) effects. - m_salvagerSystem->tick(m_currentTick, *m_debrisSystem, m_factoryState, m_beamFiredEvents); + m_salvagerSystem->tick(m_currentTick, m_factoryState, m_beamFiredEvents); m_repairSystem->tick(m_currentTick, m_beamFiredEvents); // Step 8: combat resolution diff --git a/src/test/BehaviorSystemTest.cpp b/src/test/BehaviorSystemTest.cpp index dc99699..b2ee724 100644 --- a/src/test/BehaviorSystemTest.cpp +++ b/src/test/BehaviorSystemTest.cpp @@ -101,14 +101,14 @@ struct Fixture void decide() { ships.clearMovementIntents(); - ai.tick(admin, state, scraps); + ai.tick(admin, state); } // World mutation: collection/delivery and healing. void runModules() { beamEvents.clear(); - salvager.tick(tick, scraps, state, beamEvents); + salvager.tick(tick, state, beamEvents); repair.tick(tick, beamEvents); } @@ -141,7 +141,7 @@ struct Fixture void salvageTick() { beamEvents.clear(); - salvager.tick(tick, scraps, state, beamEvents); + salvager.tick(tick, state, beamEvents); ++tick; } diff --git a/src/test/CombatSystemTest.cpp b/src/test/CombatSystemTest.cpp index eced6c0..1c13192 100644 --- a/src/test/CombatSystemTest.cpp +++ b/src/test/CombatSystemTest.cpp @@ -415,7 +415,7 @@ TEST_CASE("CombatSystem: scrap is spawned on ship death", "[combat]") sim.tick(); - const std::vector scraps = sim.getDebrisSystem().getAllDebrisInfo(); + const std::vector scraps = getAllDebrisInfo(sim.getAdmin()); REQUIRE(scraps.size() == 1); CHECK(sim.getAdmin().get(scraps[0].entity).amount == 59); } diff --git a/src/test/DebrisTest.cpp b/src/test/DebrisTest.cpp index fd3acea..990cce1 100644 --- a/src/test/DebrisTest.cpp +++ b/src/test/DebrisTest.cpp @@ -116,16 +116,16 @@ TEST_CASE("DebrisSystem: collectOne depletes one scrap and keeps the debris unti const entt::entity e = ss.spawn(QVector2D(0.0f, 0.0f), 3, 100); - REQUIRE(ss.collectOne(e)); + REQUIRE(collectOne(admin, e)); REQUIRE(admin.isValid(e)); REQUIRE(admin.get(e).amount == 2); - REQUIRE(ss.collectOne(e)); + REQUIRE(collectOne(admin, e)); REQUIRE(admin.isValid(e)); REQUIRE(admin.get(e).amount == 1); // Final unit collected: the debris is removed once depleted. - REQUIRE(ss.collectOne(e)); + REQUIRE(collectOne(admin, e)); REQUIRE_FALSE(admin.isValid(e)); } @@ -134,7 +134,7 @@ TEST_CASE("DebrisSystem: collectOne returns false for an invalid entity", "[debr EntityAdmin admin; DebrisSystem ss(admin); - REQUIRE_FALSE(ss.collectOne(entt::null)); + REQUIRE_FALSE(collectOne(admin, entt::null)); } // --------------------------------------------------------------------------- @@ -149,7 +149,7 @@ TEST_CASE("DebrisSystem: getAllDebrisInfo returns all spawned debris", "[debris] ss.spawn(QVector2D(1.0f, 2.0f), 3, 100); ss.spawn(QVector2D(4.0f, 5.0f), 6, 200); - const std::vector info = ss.getAllDebrisInfo(); + const std::vector info = getAllDebrisInfo(admin); REQUIRE(info.size() == 2); } @@ -161,7 +161,7 @@ TEST_CASE("DebrisSystem: getAllDebrisInfo reports each debris entry.s remaining const entt::entity a = ss.spawn(QVector2D(1.0f, 2.0f), 3, 100); const entt::entity b = ss.spawn(QVector2D(4.0f, 5.0f), 6, 200); - const std::vector info = ss.getAllDebrisInfo(); + const std::vector info = getAllDebrisInfo(admin); REQUIRE(info.size() == 2); for (const DebrisInfo& i : info) { diff --git a/src/ui/FieldSelectionPanel.cpp b/src/ui/FieldSelectionPanel.cpp index 679381d..160b8cc 100644 --- a/src/ui/FieldSelectionPanel.cpp +++ b/src/ui/FieldSelectionPanel.cpp @@ -367,7 +367,7 @@ int FieldSelectionPanel::selectedDebrisScrapTotal() const { // Sum the remaining scrap across the still-living selected debris (REQ-UI-DEBRIS-PANEL). int total = 0; - for (const DebrisInfo& info : m_sim->getDebrisSystem().getAllDebrisInfo()) + for (const DebrisInfo& info : getAllDebrisInfo(m_sim->getAdmin())) { if (std::find(m_selectedDebris.begin(), m_selectedDebris.end(), info.entity) != m_selectedDebris.end()) diff --git a/src/ui/GameWorldView.cpp b/src/ui/GameWorldView.cpp index 4a643b1..ace7188 100644 --- a/src/ui/GameWorldView.cpp +++ b/src/ui/GameWorldView.cpp @@ -777,7 +777,7 @@ void GameWorldView::pruneDespawnedDebris() if (m_selectedDebris.empty()) { return; } std::vector live; - for (const DebrisInfo& info : m_sim->getDebrisSystem().getAllDebrisInfo()) + for (const DebrisInfo& info : getAllDebrisInfo(m_sim->getAdmin())) { if (std::find(m_selectedDebris.begin(), m_selectedDebris.end(), info.entity) != m_selectedDebris.end()) @@ -1510,7 +1510,7 @@ void GameWorldView::drawSelectionHighlights(QPainter& painter) if (!m_selectedDebris.empty()) { const qreal outlineRadius = static_cast(getTilePx() * 0.2f) + 3.0; - for (const DebrisInfo& debris : m_sim->getDebrisSystem().getAllDebrisInfo()) + for (const DebrisInfo& debris : getAllDebrisInfo(m_sim->getAdmin())) { if (std::find(m_selectedDebris.begin(), m_selectedDebris.end(), debris.entity) == m_selectedDebris.end()) { continue; } @@ -1654,7 +1654,7 @@ void GameWorldView::drawBeltItems(QPainter& painter) void GameWorldView::drawDebris(QPainter& painter) { const float r = getTilePx() * 0.2f; - for (const DebrisInfo& debris : m_sim->getDebrisSystem().getAllDebrisInfo()) + for (const DebrisInfo& debris : getAllDebrisInfo(m_sim->getAdmin())) { const QPointF center = worldToWidget(debris.position); painter.setBrush(QColor(128, 110, 90));