make BuildingSystem stateless: FactoryState becomes a parameter
This commit is contained in:
@@ -26,7 +26,6 @@ bool inputLaneEntryFree(const std::vector<BeltItemSlot>& lane)
|
||||
} // namespace
|
||||
|
||||
BuildingSystem::BuildingSystem(const GameConfig& config,
|
||||
FactoryState& state,
|
||||
BeltSystem& belts,
|
||||
std::function<BuildingId()> allocateBuildingId,
|
||||
std::function<void(int)> addBuildingBlocks,
|
||||
@@ -35,7 +34,6 @@ BuildingSystem::BuildingSystem(const GameConfig& config,
|
||||
std::function<bool(const std::string&)> isItemUnlocked,
|
||||
std::mt19937& rng)
|
||||
: m_config(config)
|
||||
, m_state(state)
|
||||
, m_belts(belts)
|
||||
, m_allocateBuildingId(std::move(allocateBuildingId))
|
||||
, m_addBuildingBlocks(std::move(addBuildingBlocks))
|
||||
@@ -43,7 +41,6 @@ BuildingSystem::BuildingSystem(const GameConfig& config,
|
||||
, m_isItemUnlocked(std::move(isItemUnlocked))
|
||||
, m_rng(rng)
|
||||
{
|
||||
m_state.asteroidWidth_tiles = config.world.regions.asteroidWidth_tiles;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -213,7 +210,7 @@ std::vector<Item> BuildingSystem::rollReprocessingOutput(const RecipeDef& recipe
|
||||
// Placement
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
std::optional<BuildingId> BuildingSystem::place(BuildingType type, QPoint anchor,
|
||||
std::optional<BuildingId> BuildingSystem::place(FactoryState& state, BuildingType type, QPoint anchor,
|
||||
Rotation rotation, Tick currentTick)
|
||||
{
|
||||
const BuildingDef* def = m_config.buildings.findBuildingDef(type);
|
||||
@@ -221,7 +218,7 @@ std::optional<BuildingId> BuildingSystem::place(BuildingType type, QPoint anchor
|
||||
const ParsedSurfaceMask mask = parseSurfaceMask(def->surfaceMask, rotation);
|
||||
|
||||
// Reject placements that fall outside the world (REQ-BLD-PLACE-VALID).
|
||||
if (!bodyCellsWithinWorldBounds(m_state, m_config, mask.bodyCells, anchor))
|
||||
if (!bodyCellsWithinWorldBounds(state, m_config, mask.bodyCells, anchor))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -232,7 +229,7 @@ std::optional<BuildingId> BuildingSystem::place(BuildingType type, QPoint anchor
|
||||
for (const QPoint& cell : mask.bodyCells)
|
||||
{
|
||||
const QPoint absCell = anchor + cell;
|
||||
m_state.grid.occupy(absCell, id);
|
||||
state.grid.occupy(absCell, id);
|
||||
}
|
||||
|
||||
// Build construction site.
|
||||
@@ -247,13 +244,13 @@ std::optional<BuildingId> BuildingSystem::place(BuildingType type, QPoint anchor
|
||||
site.bodyCells.push_back(anchor + cell);
|
||||
}
|
||||
|
||||
if (m_state.constructionQueue.empty())
|
||||
if (state.constructionQueue.empty())
|
||||
{
|
||||
site.completesAt = currentTick + secondsToTicks(def->constructionTimeSeconds);
|
||||
}
|
||||
// else: completesAt remains 0 (queued, not yet started).
|
||||
|
||||
m_state.constructionQueue.push_back(std::move(site));
|
||||
state.constructionQueue.push_back(std::move(site));
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -261,19 +258,19 @@ std::optional<BuildingId> BuildingSystem::place(BuildingType type, QPoint anchor
|
||||
// Deconstruct
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int BuildingSystem::deconstruct(BuildingId id, Tick currentTick)
|
||||
int BuildingSystem::deconstruct(FactoryState& state, BuildingId id, Tick currentTick)
|
||||
{
|
||||
// Construction site? Removed instantly with the full refund; never queued
|
||||
// for deconstruction (REQ-BLD-DECONSTRUCT).
|
||||
for (std::deque<ConstructionSite>::iterator it = m_state.constructionQueue.begin();
|
||||
it != m_state.constructionQueue.end();
|
||||
for (std::deque<ConstructionSite>::iterator it = state.constructionQueue.begin();
|
||||
it != state.constructionQueue.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id == id)
|
||||
{
|
||||
const BuildingDef* def = m_config.buildings.findBuildingDef(it->type);
|
||||
m_state.grid.release(it->bodyCells);
|
||||
m_state.constructionQueue.erase(it);
|
||||
state.grid.release(it->bodyCells);
|
||||
state.constructionQueue.erase(it);
|
||||
if (def)
|
||||
{
|
||||
return def->cost;
|
||||
@@ -285,7 +282,7 @@ int BuildingSystem::deconstruct(BuildingId id, Tick currentTick)
|
||||
// Operational building? Append it to the deconstruction queue rather than
|
||||
// removing it now; the partial refund is credited on completion in
|
||||
// tickDeconstruction (REQ-BLD-DECON-QUEUE).
|
||||
for (Building& building : m_state.buildings)
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
if (building.id != id) { continue; }
|
||||
if (building.queuedForDeconstruction) { return 0; } // already queued
|
||||
@@ -313,11 +310,11 @@ int BuildingSystem::deconstruct(BuildingId id, Tick currentTick)
|
||||
m_belts.removeTile(building.anchor);
|
||||
}
|
||||
|
||||
const bool wasEmpty = m_state.deconstructionQueue.empty();
|
||||
m_state.deconstructionQueue.push_back(std::move(entry));
|
||||
const bool wasEmpty = state.deconstructionQueue.empty();
|
||||
state.deconstructionQueue.push_back(std::move(entry));
|
||||
if (wasEmpty)
|
||||
{
|
||||
startFrontDeconstruction(currentTick);
|
||||
startFrontDeconstruction(state, currentTick);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -325,10 +322,10 @@ int BuildingSystem::deconstruct(BuildingId id, Tick currentTick)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BuildingSystem::startFrontDeconstruction(Tick currentTick)
|
||||
void BuildingSystem::startFrontDeconstruction(FactoryState& state, Tick currentTick)
|
||||
{
|
||||
if (m_state.deconstructionQueue.empty()) { return; }
|
||||
DeconstructionEntry& front = m_state.deconstructionQueue.front();
|
||||
if (state.deconstructionQueue.empty()) { return; }
|
||||
DeconstructionEntry& front = state.deconstructionQueue.front();
|
||||
if (front.completesAt == 0)
|
||||
{
|
||||
front.completesAt =
|
||||
@@ -340,10 +337,10 @@ void BuildingSystem::startFrontDeconstruction(Tick currentTick)
|
||||
// Set recipe
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId)
|
||||
void BuildingSystem::setRecipe(FactoryState& state, BuildingId id, const std::string& recipeId)
|
||||
{
|
||||
// Construction site: store recipe for when building completes.
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
for (ConstructionSite& site : state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
@@ -366,7 +363,7 @@ void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId)
|
||||
}
|
||||
|
||||
// Operational building: clear buffers and re-init.
|
||||
for (Building& building : m_state.buildings)
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
@@ -416,9 +413,9 @@ void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId)
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::setShipLayout(BuildingId id, const ShipLayoutConfig& layout)
|
||||
void BuildingSystem::setShipLayout(FactoryState& state, BuildingId id, const ShipLayoutConfig& layout)
|
||||
{
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
for (ConstructionSite& site : state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
@@ -427,7 +424,7 @@ void BuildingSystem::setShipLayout(BuildingId id, const ShipLayoutConfig& layout
|
||||
}
|
||||
}
|
||||
|
||||
for (Building& building : m_state.buildings)
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
@@ -451,11 +448,11 @@ void BuildingSystem::setShipLayout(BuildingId id, const ShipLayoutConfig& layout
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::setSiteSplitterFilters(BuildingId id,
|
||||
void BuildingSystem::setSiteSplitterFilters(FactoryState& state, BuildingId id,
|
||||
const std::vector<ItemType>& filterA,
|
||||
const std::vector<ItemType>& filterB)
|
||||
{
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
for (ConstructionSite& site : state.constructionQueue)
|
||||
{
|
||||
if (site.id == id && site.type == BuildingType::Splitter)
|
||||
{
|
||||
@@ -470,15 +467,15 @@ void BuildingSystem::setSiteSplitterFilters(BuildingId id,
|
||||
// Tick hooks
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void BuildingSystem::tickConstruction(Tick currentTick)
|
||||
void BuildingSystem::tickConstruction(FactoryState& state, Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
if (m_state.constructionQueue.empty())
|
||||
if (state.constructionQueue.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConstructionSite& front = m_state.constructionQueue.front();
|
||||
ConstructionSite& front = state.constructionQueue.front();
|
||||
|
||||
// Guard: if somehow the front site was never started, start it now.
|
||||
if (front.completesAt == 0)
|
||||
@@ -556,18 +553,18 @@ void BuildingSystem::tickConstruction(Tick currentTick)
|
||||
// filters configured while under construction carry over (REQ-BLD-SITE-CONFIG).
|
||||
reregisterBeltTile(building, front.splitterFilterA, front.splitterFilterB);
|
||||
|
||||
m_state.buildings.push_back(std::move(building));
|
||||
state.buildings.push_back(std::move(building));
|
||||
|
||||
m_state.constructionQueue.pop_front();
|
||||
state.constructionQueue.pop_front();
|
||||
|
||||
// Start next queued site if present.
|
||||
if (!m_state.constructionQueue.empty() && m_state.constructionQueue.front().completesAt == 0)
|
||||
if (!state.constructionQueue.empty() && state.constructionQueue.front().completesAt == 0)
|
||||
{
|
||||
const BuildingDef* nextDef =
|
||||
m_config.buildings.findBuildingDef(m_state.constructionQueue.front().type);
|
||||
m_config.buildings.findBuildingDef(state.constructionQueue.front().type);
|
||||
if (nextDef)
|
||||
{
|
||||
m_state.constructionQueue.front().completesAt =
|
||||
state.constructionQueue.front().completesAt =
|
||||
currentTick + secondsToTicks(nextDef->constructionTimeSeconds);
|
||||
}
|
||||
}
|
||||
@@ -601,20 +598,20 @@ void BuildingSystem::reregisterBeltTile(const Building& building,
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::tickDeconstruction(Tick currentTick)
|
||||
void BuildingSystem::tickDeconstruction(FactoryState& state, Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
if (m_state.deconstructionQueue.empty())
|
||||
if (state.deconstructionQueue.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DeconstructionEntry& front = m_state.deconstructionQueue.front();
|
||||
DeconstructionEntry& front = state.deconstructionQueue.front();
|
||||
|
||||
// Guard: if the front entry's timer was never started, start it now.
|
||||
if (front.completesAt == 0)
|
||||
{
|
||||
startFrontDeconstruction(currentTick);
|
||||
startFrontDeconstruction(state, currentTick);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -626,15 +623,15 @@ void BuildingSystem::tickDeconstruction(Tick currentTick)
|
||||
// Remove the building from the world and credit its refund (REQ-BLD-DECONSTRUCT).
|
||||
// Belt/tunnel/splitter tiles were already unregistered when the building was
|
||||
// queued (see deconstruct), so only tile occupancy and the record remain.
|
||||
for (std::vector<Building>::iterator it = m_state.buildings.begin();
|
||||
it != m_state.buildings.end();
|
||||
for (std::vector<Building>::iterator it = state.buildings.begin();
|
||||
it != state.buildings.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id != front.id) { continue; }
|
||||
|
||||
const BuildingDef* def = m_config.buildings.findBuildingDef(it->type);
|
||||
m_state.grid.release(it->bodyCells);
|
||||
m_state.buildings.erase(it);
|
||||
state.grid.release(it->bodyCells);
|
||||
state.buildings.erase(it);
|
||||
if (def)
|
||||
{
|
||||
m_addBuildingBlocks(def->cost * m_config.world.refundPercentage / 100);
|
||||
@@ -642,16 +639,16 @@ void BuildingSystem::tickDeconstruction(Tick currentTick)
|
||||
break;
|
||||
}
|
||||
|
||||
m_state.deconstructionQueue.pop_front();
|
||||
state.deconstructionQueue.pop_front();
|
||||
|
||||
// Start the next queued deconstruction, if any.
|
||||
startFrontDeconstruction(currentTick);
|
||||
startFrontDeconstruction(state, currentTick);
|
||||
}
|
||||
|
||||
void BuildingSystem::cancelDeconstruction(BuildingId id)
|
||||
void BuildingSystem::cancelDeconstruction(FactoryState& state, BuildingId id)
|
||||
{
|
||||
for (std::deque<DeconstructionEntry>::iterator it = m_state.deconstructionQueue.begin();
|
||||
it != m_state.deconstructionQueue.end();
|
||||
for (std::deque<DeconstructionEntry>::iterator it = state.deconstructionQueue.begin();
|
||||
it != state.deconstructionQueue.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id != id) { continue; }
|
||||
@@ -659,27 +656,27 @@ void BuildingSystem::cancelDeconstruction(BuildingId id)
|
||||
// Resume operation: clear the flag and re-register belt/tunnel/splitter
|
||||
// tiles that were unregistered at enqueue (which re-pairs tunnels,
|
||||
// REQ-BLD-TUNNEL-PAIR). Deconstruction progress is discarded; no refund.
|
||||
if (Building* building = findBuilding(m_state, id))
|
||||
if (Building* building = findBuilding(state, id))
|
||||
{
|
||||
building->queuedForDeconstruction = false;
|
||||
reregisterBeltTile(*building, it->splitterFilterA, it->splitterFilterB);
|
||||
}
|
||||
|
||||
m_state.deconstructionQueue.erase(it);
|
||||
state.deconstructionQueue.erase(it);
|
||||
// If the running front was removed, the new front (completesAt == 0) has
|
||||
// its timer started by the next tickDeconstruction guard.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::tickBeltPull()
|
||||
void BuildingSystem::tickBeltPull(FactoryState& state)
|
||||
{
|
||||
TRACE();
|
||||
// Same per-tick step as the belts, so items travel inward at belt speed
|
||||
// (REQ-GW-BELT-SPEED, REQ-MAT-INPUT-INTAKE).
|
||||
const double progressPerTick = m_belts.getProgressPerTick_tpt();
|
||||
|
||||
for (Building& building : m_state.buildings)
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -759,17 +756,17 @@ void BuildingSystem::depositToInputBelt(Building& consumer,
|
||||
consumer.incomingItems[inputPortIndex].push_back(BeltItemSlot{item, 0.0});
|
||||
}
|
||||
|
||||
bool BuildingSystem::tryDirectCoupleDeposit(BuildingId producerId,
|
||||
bool BuildingSystem::tryDirectCoupleDeposit(FactoryState& state, BuildingId producerId,
|
||||
const Port& outputPort,
|
||||
const Item& item)
|
||||
{
|
||||
const std::optional<BuildingId> ownerId = m_state.grid.findOwner(outputPort.tile);
|
||||
const std::optional<BuildingId> ownerId = state.grid.findOwner(outputPort.tile);
|
||||
if (!ownerId.has_value() || *ownerId == producerId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Building* consumer = findBuilding(m_state, *ownerId);
|
||||
Building* consumer = findBuilding(state, *ownerId);
|
||||
if (!consumer)
|
||||
{
|
||||
return false; // an unbuilt construction site, or not an operational building
|
||||
@@ -794,10 +791,10 @@ bool BuildingSystem::tryDirectCoupleDeposit(BuildingId producerId,
|
||||
return false;
|
||||
}
|
||||
|
||||
void BuildingSystem::tickProduction(Tick currentTick)
|
||||
void BuildingSystem::tickProduction(FactoryState& state, Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
for (Building& building : m_state.buildings)
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -897,10 +894,10 @@ void BuildingSystem::tickProduction(Tick currentTick)
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::tickShipyardProduction(Tick currentTick)
|
||||
void BuildingSystem::tickShipyardProduction(FactoryState& state, Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
for (Building& building : m_state.buildings)
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -993,14 +990,14 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick)
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::tickOutputBelts()
|
||||
void BuildingSystem::tickOutputBelts(FactoryState& state)
|
||||
{
|
||||
TRACE();
|
||||
// Use BeltSystem's own per-tick step so emerging items travel at exactly the
|
||||
// same speed as real belts (REQ-GW-BELT-SPEED, REQ-MAT-OUTPUT-EMERGE).
|
||||
const double progressPerTick = m_belts.getProgressPerTick_tpt();
|
||||
|
||||
for (Building& building : m_state.buildings)
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -1023,7 +1020,7 @@ void BuildingSystem::tickOutputBelts()
|
||||
{
|
||||
const Item item = lane.front().item;
|
||||
if (m_belts.tryPutItem(port.tile, item, port.direction)
|
||||
|| tryDirectCoupleDeposit(building.id, port, item))
|
||||
|| tryDirectCoupleDeposit(state, building.id, port, item))
|
||||
{
|
||||
lane.erase(lane.begin());
|
||||
}
|
||||
@@ -1043,10 +1040,10 @@ void BuildingSystem::tickOutputBelts()
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::forEachEmergingItem(
|
||||
void BuildingSystem::forEachEmergingItem(const FactoryState& state,
|
||||
const std::function<void(const ItemType&, QPointF)>& visit) const
|
||||
{
|
||||
for (const Building& building : m_state.buildings)
|
||||
for (const Building& building : state.buildings)
|
||||
{
|
||||
for (std::size_t p = 0; p < building.outputPorts.size(); ++p)
|
||||
{
|
||||
@@ -1065,10 +1062,10 @@ void BuildingSystem::forEachEmergingItem(
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::forEachIncomingItem(
|
||||
void BuildingSystem::forEachIncomingItem(const FactoryState& state,
|
||||
const std::function<void(const ItemType&, QPointF)>& visit) const
|
||||
{
|
||||
for (const Building& building : m_state.buildings)
|
||||
for (const Building& building : state.buildings)
|
||||
{
|
||||
for (std::size_t p = 0; p < building.inputPorts.size(); ++p)
|
||||
{
|
||||
@@ -1096,10 +1093,10 @@ void BuildingSystem::forEachIncomingItem(
|
||||
|
||||
|
||||
|
||||
void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
||||
void BuildingSystem::rotateInPlace(FactoryState& state, BuildingId id, Rotation newRotation)
|
||||
{
|
||||
// Construction site path — just update rotation; no ports to recompute.
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
for (ConstructionSite& site : state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
@@ -1109,7 +1106,7 @@ void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
||||
}
|
||||
|
||||
// Operational building path.
|
||||
for (Building& b : m_state.buildings)
|
||||
for (Building& b : state.buildings)
|
||||
{
|
||||
if (b.id != id) { continue; }
|
||||
|
||||
@@ -1161,7 +1158,7 @@ void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
||||
}
|
||||
}
|
||||
|
||||
BuildingId BuildingSystem::placeImmediate(BuildingType type,
|
||||
BuildingId BuildingSystem::placeImmediate(FactoryState& state, BuildingType type,
|
||||
const std::vector<std::string>& surfaceMask,
|
||||
QPoint anchor, Rotation rotation)
|
||||
{
|
||||
@@ -1179,7 +1176,7 @@ BuildingId BuildingSystem::placeImmediate(BuildingType type,
|
||||
{
|
||||
const QPoint absCell = anchor + cell;
|
||||
building.bodyCells.push_back(absCell);
|
||||
m_state.grid.occupy(absCell, id);
|
||||
state.grid.occupy(absCell, id);
|
||||
}
|
||||
for (const Port& port : mask.outputPorts)
|
||||
{
|
||||
@@ -1197,14 +1194,14 @@ BuildingId BuildingSystem::placeImmediate(BuildingType type,
|
||||
initSalvageBayBuffer(building);
|
||||
}
|
||||
|
||||
m_state.buildings.push_back(std::move(building));
|
||||
state.buildings.push_back(std::move(building));
|
||||
return id;
|
||||
}
|
||||
|
||||
bool BuildingSystem::removeBuilding(BuildingId id)
|
||||
bool BuildingSystem::removeBuilding(FactoryState& state, BuildingId id)
|
||||
{
|
||||
for (std::vector<Building>::iterator it = m_state.buildings.begin();
|
||||
it != m_state.buildings.end();
|
||||
for (std::vector<Building>::iterator it = state.buildings.begin();
|
||||
it != state.buildings.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id == id)
|
||||
@@ -1214,31 +1211,31 @@ bool BuildingSystem::removeBuilding(BuildingId id)
|
||||
{
|
||||
m_belts.removeTile(it->anchor);
|
||||
}
|
||||
m_state.grid.release(it->bodyCells);
|
||||
m_state.buildings.erase(it);
|
||||
state.grid.release(it->bodyCells);
|
||||
state.buildings.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BuildingSystem::forEachBuilding(std::function<void(Building&)> fn)
|
||||
void BuildingSystem::forEachBuilding(FactoryState& state, std::function<void(Building&)> fn)
|
||||
{
|
||||
for (Building& b : m_state.buildings)
|
||||
for (Building& b : state.buildings)
|
||||
{
|
||||
fn(b);
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::registerTileOccupancy(const std::vector<QPoint>& cells,
|
||||
void BuildingSystem::registerTileOccupancy(FactoryState& state, const std::vector<QPoint>& cells,
|
||||
BuildingId ownerPlaceholder)
|
||||
{
|
||||
m_state.grid.occupy(cells, ownerPlaceholder);
|
||||
state.grid.occupy(cells, ownerPlaceholder);
|
||||
}
|
||||
|
||||
void BuildingSystem::unregisterTileOccupancy(const std::vector<QPoint>& cells)
|
||||
void BuildingSystem::unregisterTileOccupancy(FactoryState& state, const std::vector<QPoint>& cells)
|
||||
{
|
||||
m_state.grid.release(cells);
|
||||
state.grid.release(cells);
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -1270,12 +1267,12 @@ void appendInputBuffer(Hasher& hasher, const InputBuffer& buffer)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
void BuildingSystem::appendChecksum(const FactoryState& state, Hasher& hasher) const
|
||||
{
|
||||
// m_state.buildings keeps a stable, deterministic order (append on build, swap-free
|
||||
// state.buildings keeps a stable, deterministic order (append on build, swap-free
|
||||
// erase aside — both runs perform identical operations, so order matches).
|
||||
hasher.append(m_state.buildings.size());
|
||||
for (const Building& b : m_state.buildings)
|
||||
hasher.append(state.buildings.size());
|
||||
for (const Building& b : state.buildings)
|
||||
{
|
||||
hasher.append(b.id);
|
||||
hasher.append(b.anchor);
|
||||
@@ -1318,8 +1315,8 @@ void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
hasher.append(b.queuedForDeconstruction);
|
||||
}
|
||||
|
||||
hasher.append(m_state.constructionQueue.size());
|
||||
for (const ConstructionSite& s : m_state.constructionQueue)
|
||||
hasher.append(state.constructionQueue.size());
|
||||
for (const ConstructionSite& s : state.constructionQueue)
|
||||
{
|
||||
hasher.append(s.id);
|
||||
hasher.append(s.anchor);
|
||||
@@ -1336,8 +1333,8 @@ void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
for (const ItemType& type : s.splitterFilterB) { hasher.append(type.id); }
|
||||
}
|
||||
|
||||
hasher.append(m_state.deconstructionQueue.size());
|
||||
for (const DeconstructionEntry& e : m_state.deconstructionQueue)
|
||||
hasher.append(state.deconstructionQueue.size());
|
||||
for (const DeconstructionEntry& e : state.deconstructionQueue)
|
||||
{
|
||||
hasher.append(e.id);
|
||||
hasher.append(e.completesAt);
|
||||
@@ -1347,5 +1344,5 @@ void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
for (const ItemType& type : e.splitterFilterB) { hasher.append(type.id); }
|
||||
}
|
||||
|
||||
m_state.grid.appendChecksum(hasher);
|
||||
state.grid.appendChecksum(hasher);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ class BuildingSystem
|
||||
{
|
||||
public:
|
||||
BuildingSystem(const GameConfig& config,
|
||||
FactoryState& state,
|
||||
BeltSystem& belts,
|
||||
std::function<BuildingId()> allocateBuildingId,
|
||||
std::function<void(int)> addBuildingBlocks,
|
||||
@@ -53,7 +52,7 @@ public:
|
||||
// queue. Terrain type (A vs S) is NOT checked here so that tests can stage
|
||||
// arbitrary layouts; the player-facing entry point
|
||||
// (Simulation::tryPlaceBuilding) enforces the full rule via isPlacementValid.
|
||||
std::optional<BuildingId> place(BuildingType type, QPoint anchor, Rotation rotation,
|
||||
std::optional<BuildingId> place(FactoryState& state, BuildingType type, QPoint anchor, Rotation rotation,
|
||||
Tick currentTick);
|
||||
|
||||
// Returns true if the placement satisfies REQ-BLD-PLACE-VALID terrain and
|
||||
@@ -65,7 +64,8 @@ public:
|
||||
// Sets the current buildable asteroid width in tiles. Grows the left
|
||||
// placement bound as the player unlocks asteroid expansions (REQ-EXP-UNLOCK).
|
||||
// Defaults to world.regions.asteroid_width_tiles at construction.
|
||||
void setAsteroidWidth_tiles(int widthTiles) { m_state.asteroidWidth_tiles = widthTiles; }
|
||||
void setAsteroidWidth_tiles(FactoryState& state, int widthTiles) const
|
||||
{ state.asteroidWidth_tiles = widthTiles; }
|
||||
|
||||
// Mark a building or construction site for demolition (REQ-BLD-DECONSTRUCT).
|
||||
// A construction site is removed instantly and the full cost is returned.
|
||||
@@ -73,23 +73,23 @@ public:
|
||||
// (REQ-BLD-DECON-QUEUE) and stops operating at once; its (partial) refund is
|
||||
// credited later, on completion in tickDeconstruction, so this returns 0 for
|
||||
// it. Returns 0 for unknown ids and for a building already queued.
|
||||
int deconstruct(BuildingId id, Tick currentTick);
|
||||
int deconstruct(FactoryState& state, BuildingId id, Tick currentTick);
|
||||
|
||||
// Take a building back out of the deconstruction queue before it is removed
|
||||
// (REQ-BLD-DECON-QUEUE). Clears its queued flag and resumes operation
|
||||
// (re-registering belt/tunnel/splitter tiles); discards deconstruction
|
||||
// progress and credits no refund. No-op if the id is not queued.
|
||||
void cancelDeconstruction(BuildingId id);
|
||||
void cancelDeconstruction(FactoryState& state, BuildingId id);
|
||||
|
||||
// True if the building is currently in the deconstruction queue.
|
||||
|
||||
// Set the recipe (or schematic id for shipyard) on a building or queued
|
||||
// construction site. Clears both buffers on an operational building.
|
||||
void setRecipe(BuildingId id, const std::string& recipeId);
|
||||
void setRecipe(FactoryState& state, BuildingId id, const std::string& recipeId);
|
||||
|
||||
// Set the module layout for a shipyard. Cancels in-progress production
|
||||
// (materials discarded) and reinitializes input buffers (REQ-BLD-SHIPYARD).
|
||||
void setShipLayout(BuildingId id, const ShipLayoutConfig& layout);
|
||||
void setShipLayout(FactoryState& state, BuildingId id, const ShipLayoutConfig& layout);
|
||||
|
||||
// Splitter filter configuration for a queued/under-construction Splitter
|
||||
// site (REQ-BLD-SITE-CONFIG). Operational splitters are configured through
|
||||
@@ -98,23 +98,23 @@ public:
|
||||
// output directions (derived from its surface mask) and stored filters, or
|
||||
// nullopt if the id is not a Splitter site. The stored filters are applied
|
||||
// to BeltSystem when the splitter finishes building (tickConstruction).
|
||||
void setSiteSplitterFilters(BuildingId id,
|
||||
void setSiteSplitterFilters(FactoryState& state, BuildingId id,
|
||||
const std::vector<ItemType>& filterA,
|
||||
const std::vector<ItemType>& filterB);
|
||||
|
||||
// -- Tick hooks (called from Simulation::tick in the documented order) ---
|
||||
void tickConstruction(Tick currentTick);
|
||||
void tickConstruction(FactoryState& state, Tick currentTick);
|
||||
// Advances the deconstruction queue (REQ-BLD-DECON-QUEUE): one building at a
|
||||
// time, in parallel with tickConstruction. Removes the front building and
|
||||
// credits its refund when its timer elapses.
|
||||
void tickDeconstruction(Tick currentTick);
|
||||
void tickBeltPull();
|
||||
void tickProduction(Tick currentTick);
|
||||
void tickShipyardProduction(Tick currentTick);
|
||||
void tickDeconstruction(FactoryState& state, Tick currentTick);
|
||||
void tickBeltPull(FactoryState& state);
|
||||
void tickProduction(FactoryState& state, Tick currentTick);
|
||||
void tickShipyardProduction(FactoryState& state, Tick currentTick);
|
||||
// Advances each building's virtual output belts, hands finished items off onto
|
||||
// the adjacent real belt, and feeds new buffered items into them
|
||||
// (REQ-MAT-OUTPUT-EMERGE).
|
||||
void tickOutputBelts();
|
||||
void tickOutputBelts(FactoryState& state);
|
||||
|
||||
// -- Queries -------------------------------------------------------------
|
||||
|
||||
@@ -134,19 +134,19 @@ public:
|
||||
// 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(
|
||||
void forEachEmergingItem(const FactoryState& state,
|
||||
const std::function<void(const ItemType&, QPointF)>& 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(
|
||||
void forEachIncomingItem(const FactoryState& state,
|
||||
const std::function<void(const ItemType&, QPointF)>& visit) const;
|
||||
|
||||
// Rotate an existing building or construction site to newRotation in place.
|
||||
// For belt-type operational buildings, re-registers with BeltSystem (items
|
||||
// currently on the tile are discarded by BeltSystem::removeTile).
|
||||
void rotateInPlace(BuildingId id, Rotation newRotation);
|
||||
void rotateInPlace(FactoryState& state, BuildingId id, Rotation newRotation);
|
||||
|
||||
|
||||
// Input-capable adjacent tiles for a building or construction site
|
||||
@@ -155,8 +155,8 @@ public:
|
||||
// the target. Output-port edges are excluded. Empty for an unknown id.
|
||||
|
||||
// Register / unregister tile occupancy for ECS station entities.
|
||||
void registerTileOccupancy(const std::vector<QPoint>& cells, BuildingId ownerPlaceholder);
|
||||
void unregisterTileOccupancy(const std::vector<QPoint>& cells);
|
||||
void registerTileOccupancy(FactoryState& state, const std::vector<QPoint>& cells, BuildingId ownerPlaceholder);
|
||||
void unregisterTileOccupancy(FactoryState& state, const std::vector<QPoint>& cells);
|
||||
|
||||
// Place one "scrap" item into a SalvageBay's output buffer.
|
||||
// Returns false if bay not found, wrong type, or output buffer is full.
|
||||
@@ -164,26 +164,26 @@ public:
|
||||
// Bypass the construction queue and create a fully-operational Building
|
||||
// immediately. Used for pre-placed structures (HQ, defence stations).
|
||||
// surfaceMask comes from the relevant config struct.
|
||||
BuildingId placeImmediate(BuildingType type,
|
||||
BuildingId placeImmediate(FactoryState& state, BuildingType type,
|
||||
const std::vector<std::string>& surfaceMask,
|
||||
QPoint anchor, Rotation rotation);
|
||||
|
||||
// Remove an operational building by id without refund (used for deaths).
|
||||
// Returns true if found and removed.
|
||||
bool removeBuilding(BuildingId id);
|
||||
bool removeBuilding(FactoryState& state, BuildingId id);
|
||||
|
||||
// Mutable iteration over all operational buildings.
|
||||
void forEachBuilding(std::function<void(Building&)> fn);
|
||||
void forEachBuilding(FactoryState& state, std::function<void(Building&)> fn);
|
||||
|
||||
// -- Determinism ---------------------------------------------------------
|
||||
// Folds all building, construction-site, and tile-occupancy state into the
|
||||
// hasher in deterministic order (see docs/replay_design.md).
|
||||
void appendChecksum(Hasher& hasher) const;
|
||||
void appendChecksum(const FactoryState& state, Hasher& hasher) const;
|
||||
|
||||
private:
|
||||
// Starts the front deconstruction-queue entry's timer if not yet started
|
||||
// (mirrors how tickConstruction starts a queued construction site).
|
||||
void startFrontDeconstruction(Tick currentTick);
|
||||
void startFrontDeconstruction(FactoryState& state, Tick currentTick);
|
||||
|
||||
// Registers a belt/splitter/tunnel building's tile with the belt subsystem
|
||||
// (on construction completion, or when un-queuing a deconstruction). No-op for
|
||||
@@ -206,7 +206,7 @@ private:
|
||||
// Attempts to hand an emerging output item straight into a directly adjacent
|
||||
// building whose input edge meets the producer's output port (REQ-MAT-DIRECT-COUPLE).
|
||||
// Returns true if the item was accepted onto the consumer's input belt.
|
||||
bool tryDirectCoupleDeposit(BuildingId producerId,
|
||||
bool tryDirectCoupleDeposit(FactoryState& state, BuildingId producerId,
|
||||
const Port& outputPort,
|
||||
const Item& item);
|
||||
|
||||
@@ -233,9 +233,6 @@ private:
|
||||
|
||||
const GameConfig& m_config;
|
||||
|
||||
// The factory's world data — buildings, queued work, tile ownership. Owned by
|
||||
// Simulation, not by this system (see FactoryState.h).
|
||||
FactoryState& m_state;
|
||||
|
||||
BeltSystem& m_belts;
|
||||
std::function<BuildingId()> m_allocateBuildingId;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Building.h"
|
||||
#include "GameConfig.h"
|
||||
#include "BuildingGrid.h"
|
||||
#include "BuildingId.h"
|
||||
#include "ItemType.h"
|
||||
@@ -52,3 +53,14 @@ struct FactoryState
|
||||
// Seeded from config by BuildingSystem's constructor.
|
||||
int asteroidWidth_tiles = 0;
|
||||
};
|
||||
|
||||
// A fresh factory for a new run: nothing built, and the asteroid bound seeded from
|
||||
// config. Every owner of a FactoryState creates it this way — the bound has no
|
||||
// sensible default without the config, so a default-constructed state would refuse
|
||||
// every placement on the asteroid.
|
||||
inline FactoryState makeFactoryState(const GameConfig& config)
|
||||
{
|
||||
FactoryState state;
|
||||
state.asteroidWidth_tiles = config.world.regions.asteroidWidth_tiles;
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user