From a783e57731ccb040e6c13d7b72ae19e1a06899f5 Mon Sep 17 00:00:00 2001 From: Malte Langkabel Date: Wed, 19 Aug 2026 17:07:17 +0200 Subject: [PATCH] move the two item visitors to the queries they always were forEachEmergingItem and forEachIncomingItem took a const FactoryState& and touched no member of BuildingSystem: they read the state and the free geometry helpers and nothing else. They are queries wearing a system's uniform, and their one caller -- the renderer -- reached through getBuildings() to call them, passing the state back in as an argument. They move to FactoryQueries beside the rest of the read surface, and the renderer calls them directly. With that, BuildingSystem answers no queries at all: its const accessor on Simulation and on ArenaSimulation had no other user, so both are gone. Nothing outside the command path can now reach the system. No behaviour changes; the bodies move verbatim apart from two arrows in comments that were non-ASCII. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Ne3mejABZoLWKLh8fgpM3x --- src/balancing/ArenaSimulation.cpp | 5 --- src/balancing/ArenaSimulation.h | 1 - src/lib/sim/BuildingSystem.cpp | 53 ------------------------------- src/lib/sim/BuildingSystem.h | 22 +++---------- src/lib/sim/FactoryQueries.cpp | 45 ++++++++++++++++++++++++++ src/lib/sim/FactoryQueries.h | 14 ++++++++ src/lib/sim/Simulation.cpp | 5 --- src/lib/sim/Simulation.h | 3 +- src/ui/WorldRenderer.cpp | 4 +-- 9 files changed, 67 insertions(+), 85 deletions(-) diff --git a/src/balancing/ArenaSimulation.cpp b/src/balancing/ArenaSimulation.cpp index b30bd7a..d31ffba 100644 --- a/src/balancing/ArenaSimulation.cpp +++ b/src/balancing/ArenaSimulation.cpp @@ -494,11 +494,6 @@ const FactoryState& ArenaSimulation::getFactoryState() const return m_factoryState; } -const BuildingSystem& ArenaSimulation::getBuildings() const -{ - return *m_buildingSystem; -} - const ShipSystem& ArenaSimulation::getShips() const { return *m_shipSystem; diff --git a/src/balancing/ArenaSimulation.h b/src/balancing/ArenaSimulation.h index fa23cf8..b6ef73c 100644 --- a/src/balancing/ArenaSimulation.h +++ b/src/balancing/ArenaSimulation.h @@ -85,7 +85,6 @@ public: Tick getCurrentTick() const; const ArenaConfig& getArenaConfig() const; - const BuildingSystem& getBuildings() const; const FactoryState& getFactoryState() const; const ShipSystem& getShips() const; const DebrisSystem& getDebrisSystem() const; diff --git a/src/lib/sim/BuildingSystem.cpp b/src/lib/sim/BuildingSystem.cpp index 63635eb..571e719 100644 --- a/src/lib/sim/BuildingSystem.cpp +++ b/src/lib/sim/BuildingSystem.cpp @@ -774,59 +774,6 @@ void BuildingSystem::tickOutputBelts(FactoryState& state) } } -void BuildingSystem::forEachEmergingItem(const FactoryState& state, - const std::function& visit) const -{ - for (const Building& building : state.buildings) - { - for (std::size_t p = 0; p < building.outputPorts.size(); ++p) - { - const Port& port = building.outputPorts[p]; - const QPoint bodyTile = outputBodyTile(port.tile, port.direction); - const std::vector& lane = building.emergingItems[p]; - - // Render least-progressed first (bottom) → most-progressed last (top), - // matching belt item ordering (REQ-GW-TILE-SIZE). - for (int i = static_cast(lane.size()) - 1; i >= 0; --i) - { - visit(lane[i].item.type, - beltSlotWorldPos(bodyTile, port.direction, lane[i].progress)); - } - } - } -} - -void BuildingSystem::forEachIncomingItem(const FactoryState& state, - const std::function& visit) const -{ - for (const Building& building : state.buildings) - { - for (std::size_t p = 0; p < building.inputPorts.size(); ++p) - { - const Port& port = building.inputPorts[p]; - const QPoint bodyTile = inputBodyTile(port.tile, port.direction); - const std::vector& lane = building.incomingItems[p]; - - // Render least-progressed first (bottom) → most-progressed last (top), - // matching belt item ordering (REQ-GW-TILE-SIZE). - for (int i = static_cast(lane.size()) - 1; i >= 0; --i) - { - visit(lane[i].item.type, - beltSlotWorldPos(bodyTile, port.direction, lane[i].progress)); - } - } - } -} - -// --------------------------------------------------------------------------- -// Queries -// --------------------------------------------------------------------------- - - - - - - void BuildingSystem::rotateInPlace(FactoryState& state, BuildingId id, Rotation newRotation) { // Construction site path — just update rotation; no ports to recompute. diff --git a/src/lib/sim/BuildingSystem.h b/src/lib/sim/BuildingSystem.h index adc32ac..4e851ae 100644 --- a/src/lib/sim/BuildingSystem.h +++ b/src/lib/sim/BuildingSystem.h @@ -108,24 +108,10 @@ public: // (REQ-MAT-OUTPUT-EMERGE). void tickOutputBelts(FactoryState& state); - // -- Queries ------------------------------------------------------------- - // Reading the factory needs no system: those queries are free functions over the - // state (FactoryQueries.h), the placement rules (PlacementRules.h) and the - // production rules (ProductionRules.h). Only the two visitors below are still - // here, and only because their callers reach them through this system. - - // Visits every item currently emerging from a building output port on its - // virtual output belt (REQ-MAT-OUTPUT-EMERGE), passing the item type and its - // world-space centre (in tile units). Least-progressed first (drawn bottom) so - // callers can paint in visit order (REQ-GW-TILE-SIZE ordering). - void forEachEmergingItem(const FactoryState& state, - const std::function& visit) const; - - // Visits every item currently travelling inward on a building input port's - // virtual input belt (REQ-MAT-INPUT-INTAKE), passing the item type and its - // world-space centre (in tile units). Least-progressed first (drawn bottom). - void forEachIncomingItem(const FactoryState& state, - const std::function& visit) const; + // This system answers no queries: reading the factory needs none, the queries being + // free functions over the state (FactoryQueries.h), the placement rules + // (PlacementRules.h) and the production rules (ProductionRules.h). What is left here + // mutates. // Rotate an existing building or construction site to newRotation in place. // For belt-type operational buildings, re-registers with BeltSystem (items diff --git a/src/lib/sim/FactoryQueries.cpp b/src/lib/sim/FactoryQueries.cpp index 5c63000..ed1e45a 100644 --- a/src/lib/sim/FactoryQueries.cpp +++ b/src/lib/sim/FactoryQueries.cpp @@ -3,6 +3,7 @@ #include #include +#include "BeltSlot.h" #include "PortGeometry.h" #include "ProductionRules.h" #include "SelectionBox.h" @@ -234,6 +235,50 @@ TunnelTileMap collectTunnelTiles(const FactoryState& state) return tunnels; } +void forEachEmergingItem(const FactoryState& state, + const std::function& visit) +{ + for (const Building& building : state.buildings) + { + for (std::size_t p = 0; p < building.outputPorts.size(); ++p) + { + const Port& port = building.outputPorts[p]; + const QPoint bodyTile = outputBodyTile(port.tile, port.direction); + const std::vector& lane = building.emergingItems[p]; + + // Render least-progressed first (bottom) -> most-progressed last (top), + // matching belt item ordering (REQ-GW-TILE-SIZE). + for (int i = static_cast(lane.size()) - 1; i >= 0; --i) + { + visit(lane[i].item.type, + beltSlotWorldPos(bodyTile, port.direction, lane[i].progress)); + } + } + } +} + +void forEachIncomingItem(const FactoryState& state, + const std::function& visit) +{ + for (const Building& building : state.buildings) + { + for (std::size_t p = 0; p < building.inputPorts.size(); ++p) + { + const Port& port = building.inputPorts[p]; + const QPoint bodyTile = inputBodyTile(port.tile, port.direction); + const std::vector& lane = building.incomingItems[p]; + + // Render least-progressed first (bottom) -> most-progressed last (top), + // matching belt item ordering (REQ-GW-TILE-SIZE). + for (int i = static_cast(lane.size()) - 1; i >= 0; --i) + { + visit(lane[i].item.type, + beltSlotWorldPos(bodyTile, port.direction, lane[i].progress)); + } + } + } +} + std::vector collectBeltTiles(const FactoryState& state, const std::vector& ids) { diff --git a/src/lib/sim/FactoryQueries.h b/src/lib/sim/FactoryQueries.h index 4d320d2..935cb09 100644 --- a/src/lib/sim/FactoryQueries.h +++ b/src/lib/sim/FactoryQueries.h @@ -1,8 +1,10 @@ #pragma once +#include #include #include +#include #include #include @@ -83,6 +85,18 @@ std::vector buildingsInBox(const FactoryState& state, // single-cell tile. Shared by the placement preview and the selection highlight. TunnelTileMap collectTunnelTiles(const FactoryState& state); +// Visits every item currently emerging from a building output port on its virtual output +// belt (REQ-MAT-OUTPUT-EMERGE), passing the item type and its world-space centre (in tile +// units). Least-progressed first (drawn bottom) so callers can paint in visit order +// (REQ-GW-TILE-SIZE ordering). +void forEachEmergingItem(const FactoryState& state, + const std::function& visit); + +// Visits every item currently travelling inward on a building input port's virtual input +// belt (REQ-MAT-INPUT-INTAKE), in the same form and the same order. +void forEachIncomingItem(const FactoryState& state, + const std::function& visit); + // The tiles of the belt-subsystem buildings among the given ids, in the order the ids // arrive; anything else in the selection is skipped, as are construction sites, whose // tiles the belt subsystem does not know yet (REQ-BLD-SITE-CONFIG). Shared by the panel's diff --git a/src/lib/sim/Simulation.cpp b/src/lib/sim/Simulation.cpp index d735525..7dab1b3 100644 --- a/src/lib/sim/Simulation.cpp +++ b/src/lib/sim/Simulation.cpp @@ -907,11 +907,6 @@ const FactoryState& Simulation::getFactoryState() const return m_factoryState; } -const BuildingSystem& Simulation::getBuildings() const -{ - return *m_buildingSystem; -} - BeltSystem& Simulation::getBeltsMutable() { return m_beltSystem; diff --git a/src/lib/sim/Simulation.h b/src/lib/sim/Simulation.h index ec7f821..218d379 100644 --- a/src/lib/sim/Simulation.h +++ b/src/lib/sim/Simulation.h @@ -120,7 +120,8 @@ public: // private and reachable only through Simulation::apply (the command // chokepoint) or, in tests, SimulationTestAccess — so production code cannot // mutate the factory outside the recorded command path (docs/replay_design.md). - const BuildingSystem& getBuildings() const; + // BuildingSystem has no const accessor: it answers no queries, so nothing outside + // the command path has a reason to reach it (FactoryQueries.h). // The factory's world data, for the free queries in FactoryQueries.h. const FactoryState& getFactoryState() const; diff --git a/src/ui/WorldRenderer.cpp b/src/ui/WorldRenderer.cpp index 50fec8a..6561e49 100644 --- a/src/ui/WorldRenderer.cpp +++ b/src/ui/WorldRenderer.cpp @@ -541,8 +541,8 @@ void WorldRenderer::drawPortItems(QPainter& painter, const WorldCoordinates& coo painter.save(); painter.setClipRegion(clip); - m_sim.getBuildings().forEachEmergingItem(m_sim.getFactoryState(), drawItem); - m_sim.getBuildings().forEachIncomingItem(m_sim.getFactoryState(), drawItem); + forEachEmergingItem(m_sim.getFactoryState(), drawItem); + forEachIncomingItem(m_sim.getFactoryState(), drawItem); painter.restore(); }