make BuildingSystem stateless: FactoryState becomes a parameter

This commit is contained in:
2026-08-05 06:50:11 +02:00
parent d87d063b10
commit 114a43b205
15 changed files with 401 additions and 395 deletions

View File

@@ -50,6 +50,7 @@ Simulation::Simulation(GameConfig config, unsigned int seed)
{
m_currentEnemyStationEntities[0] = entt::null;
m_currentEnemyStationEntities[1] = entt::null;
m_factoryState = makeFactoryState(m_config);
initializeSubsystems();
@@ -97,7 +98,7 @@ void Simulation::reset(unsigned int seed)
m_pendingSchematicChoices.clear();
m_admin.clear();
m_factoryState = FactoryState{};
m_factoryState = makeFactoryState(m_config);
m_beltSystem = BeltSystem(m_config.world.beltSpeed_tps);
initializeSubsystems();
@@ -109,7 +110,6 @@ void Simulation::initializeSubsystems()
{
m_buildingSystem = std::make_unique<BuildingSystem>(
m_config,
m_factoryState,
m_beltSystem,
[this]() { return allocateBuildingId(); },
[this](int amount) { m_buildingBlocksStock += amount; },
@@ -153,15 +153,15 @@ void Simulation::apply(const Command& command)
const BuildingId id = *placed;
if (c.recipeId.has_value())
{
m_buildingSystem->setRecipe(id, *c.recipeId);
m_buildingSystem->setRecipe(m_factoryState, id, *c.recipeId);
}
if (c.shipLayout.has_value())
{
m_buildingSystem->setShipLayout(id, *c.shipLayout);
m_buildingSystem->setShipLayout(m_factoryState, id, *c.shipLayout);
}
if (c.hasSplitterFilters)
{
m_buildingSystem->setSiteSplitterFilters(id, c.splitterFilterA, c.splitterFilterB);
m_buildingSystem->setSiteSplitterFilters(m_factoryState, id, c.splitterFilterA, c.splitterFilterB);
}
break;
}
@@ -174,26 +174,26 @@ void Simulation::apply(const Command& command)
case CommandKind::RotateInPlace:
{
const RotateInPlaceCommand& c = static_cast<const RotateInPlaceCommand&>(command);
m_buildingSystem->rotateInPlace(*c.id, c.newRotation);
m_buildingSystem->rotateInPlace(m_factoryState, *c.id, c.newRotation);
break;
}
case CommandKind::SetRecipe:
{
const SetRecipeCommand& c = static_cast<const SetRecipeCommand&>(command);
m_buildingSystem->setRecipe(*c.id, c.recipeId);
m_buildingSystem->setRecipe(m_factoryState, *c.id, c.recipeId);
break;
}
case CommandKind::SetShipLayout:
{
const SetShipLayoutCommand& c = static_cast<const SetShipLayoutCommand&>(command);
m_buildingSystem->setShipLayout(*c.id, c.layout);
m_buildingSystem->setShipLayout(m_factoryState, *c.id, c.layout);
break;
}
case CommandKind::SetSiteSplitterFilters:
{
const SetSiteSplitterFiltersCommand& c =
static_cast<const SetSiteSplitterFiltersCommand&>(command);
m_buildingSystem->setSiteSplitterFilters(*c.id, c.filterA, c.filterB);
m_buildingSystem->setSiteSplitterFilters(m_factoryState, *c.id, c.filterA, c.filterB);
break;
}
case CommandKind::SetSplitterFilters:
@@ -243,12 +243,12 @@ void Simulation::tick()
m_waveSystem->tickThreatAccumulation();
// Construction + production pipeline
m_buildingSystem->tickConstruction(m_currentTick);
m_buildingSystem->tickDeconstruction(m_currentTick); // parallel to construction
m_buildingSystem->tickBeltPull(); // step 3
m_buildingSystem->tickProduction(m_currentTick); // step 4
m_buildingSystem->tickShipyardProduction(m_currentTick); // step 4b
m_buildingSystem->tickOutputBelts(); // step 5
m_buildingSystem->tickConstruction(m_factoryState, m_currentTick);
m_buildingSystem->tickDeconstruction(m_factoryState, m_currentTick); // parallel to construction
m_buildingSystem->tickBeltPull(m_factoryState); // step 3
m_buildingSystem->tickProduction(m_factoryState, m_currentTick); // step 4
m_buildingSystem->tickShipyardProduction(m_factoryState, m_currentTick); // step 4b
m_buildingSystem->tickOutputBelts(m_factoryState); // step 5
m_beltSystem.tick(); // step 6
// Step 7: ship behavior systems (movement arbitration via intent priority)
@@ -306,8 +306,7 @@ void Simulation::placeInitialStructures()
(m_config.world.heightTiles - hqParsed.footprint.height()) / 2;
const float hqHp =
static_cast<float>(m_config.stations.hq.hpFormula.evaluate(0.0));
m_hqBuildingId = m_buildingSystem->placeImmediate(
BuildingType::Hq,
m_hqBuildingId = m_buildingSystem->placeImmediate(m_factoryState, BuildingType::Hq,
m_config.stations.hq.surfaceMask,
QPoint(hqAnchorX, hqAnchorY),
Rotation::East);
@@ -356,7 +355,7 @@ void Simulation::placeInitialStructures()
m_admin.addComponent<ModuleOwnerComponent>(wChild,
ModuleOwnerComponent{m_playerStation1Entity});
}
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
m_buildingSystem->registerTileOccupancy(m_factoryState, absCells, allocateBuildingId());
}
{
const QPoint anchor(psAnchorX, ps2Y);
@@ -373,7 +372,7 @@ void Simulation::placeInitialStructures()
m_admin.addComponent<ModuleOwnerComponent>(wChild,
ModuleOwnerComponent{m_playerStation2Entity});
}
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
m_buildingSystem->registerTileOccupancy(m_factoryState, absCells, allocateBuildingId());
}
// Rally point: center of the player defence stations' X column, world vertical midpoint.
@@ -428,7 +427,7 @@ void Simulation::placeEnemyStationSet(int generation)
m_admin.addComponent<ModuleOwnerComponent>(wChild,
ModuleOwnerComponent{m_currentEnemyStationEntities[0]});
}
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
m_buildingSystem->registerTileOccupancy(m_factoryState, absCells, allocateBuildingId());
}
{
const QPoint anchor(anchorX, y2);
@@ -445,7 +444,7 @@ void Simulation::placeEnemyStationSet(int generation)
m_admin.addComponent<ModuleOwnerComponent>(wChild,
ModuleOwnerComponent{m_currentEnemyStationEntities[1]});
}
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
m_buildingSystem->registerTileOccupancy(m_factoryState, absCells, allocateBuildingId());
}
}
@@ -519,7 +518,7 @@ void Simulation::tickDeathsAndLoot()
{
m_debrisSystem->spawn(pos.value, scrap, despawnAt);
}
m_buildingSystem->unregisterTileOccupancy(sb.bodyCells);
m_buildingSystem->unregisterTileOccupancy(m_factoryState, sb.bodyCells);
{
std::vector<entt::entity> stationChildren;
m_admin.forEach<ModuleOwnerComponent>(
@@ -671,7 +670,7 @@ unsigned long long Simulation::computeStateChecksum() const
m_unlockState.appendChecksum(hasher);
// Subsystems contribute their own state.
m_buildingSystem->appendChecksum(hasher);
m_buildingSystem->appendChecksum(m_factoryState, hasher);
m_beltSystem.appendChecksum(hasher);
// ECS component state. View iteration order is a pure function of the
@@ -784,7 +783,7 @@ void Simulation::tryExpandAsteroid()
}
m_buildingBlocksStock -= cost;
++m_expansionsPurchased;
m_buildingSystem->setAsteroidWidth_tiles(getCurrentAsteroidWidth_tiles());
m_buildingSystem->setAsteroidWidth_tiles(m_factoryState, getCurrentAsteroidWidth_tiles());
}
bool Simulation::isGameOver() const
@@ -880,17 +879,17 @@ std::optional<BuildingId> Simulation::tryPlaceBuilding(BuildingType type, QPoint
return std::nullopt;
}
m_buildingBlocksStock -= cost;
return m_buildingSystem->place(type, anchor, rotation, m_currentTick);
return m_buildingSystem->place(m_factoryState, type, anchor, rotation, m_currentTick);
}
void Simulation::deconstruct(BuildingId id)
{
m_buildingBlocksStock += m_buildingSystem->deconstruct(id, m_currentTick);
m_buildingBlocksStock += m_buildingSystem->deconstruct(m_factoryState, id, m_currentTick);
}
void Simulation::cancelDeconstruction(BuildingId id)
{
m_buildingSystem->cancelDeconstruction(id);
m_buildingSystem->cancelDeconstruction(m_factoryState, id);
}
BuildingSystem& Simulation::getBuildingsMutable()