Compare commits
2 Commits
71d0dad3f2
...
2522a8c974
| Author | SHA1 | Date | |
|---|---|---|---|
| 2522a8c974 | |||
| e39b81eb22 |
@@ -48,6 +48,7 @@ ArenaSimulation::ArenaSimulation(const GameConfig& gameConfig,
|
||||
{
|
||||
m_buildingSystem = std::make_unique<BuildingSystem>(
|
||||
m_gameConfig,
|
||||
m_factoryState,
|
||||
m_beltSystem,
|
||||
[this]() { return allocateBuildingId(); },
|
||||
[](int) {},
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "BalancingConfig.h"
|
||||
#include "BeltSystem.h"
|
||||
#include "FactoryState.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "BuildingId.h"
|
||||
|
||||
@@ -107,6 +108,7 @@ private:
|
||||
BuildingId m_nextBuildingId;
|
||||
|
||||
EntityAdmin m_admin;
|
||||
FactoryState m_factoryState;
|
||||
BeltSystem m_beltSystem;
|
||||
std::unique_ptr<BuildingSystem> m_buildingSystem;
|
||||
std::unique_ptr<ShipSystem> m_shipSystem;
|
||||
|
||||
@@ -23,6 +23,7 @@ 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,
|
||||
@@ -31,6 +32,7 @@ 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))
|
||||
@@ -308,7 +310,7 @@ std::optional<BuildingId> BuildingSystem::place(BuildingType type, QPoint anchor
|
||||
for (const QPoint& cell : mask.bodyCells)
|
||||
{
|
||||
const QPoint absCell = anchor + cell;
|
||||
m_grid.occupy(absCell, id);
|
||||
m_state.grid.occupy(absCell, id);
|
||||
}
|
||||
|
||||
// Build construction site.
|
||||
@@ -323,13 +325,13 @@ std::optional<BuildingId> BuildingSystem::place(BuildingType type, QPoint anchor
|
||||
site.bodyCells.push_back(anchor + cell);
|
||||
}
|
||||
|
||||
if (m_constructionQueue.empty())
|
||||
if (m_state.constructionQueue.empty())
|
||||
{
|
||||
site.completesAt = currentTick + secondsToTicks(def->constructionTimeSeconds);
|
||||
}
|
||||
// else: completesAt remains 0 (queued, not yet started).
|
||||
|
||||
m_constructionQueue.push_back(std::move(site));
|
||||
m_state.constructionQueue.push_back(std::move(site));
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -405,15 +407,15 @@ int BuildingSystem::deconstruct(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_constructionQueue.begin();
|
||||
it != m_constructionQueue.end();
|
||||
for (std::deque<ConstructionSite>::iterator it = m_state.constructionQueue.begin();
|
||||
it != m_state.constructionQueue.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id == id)
|
||||
{
|
||||
const BuildingDef* def = m_config.buildings.findBuildingDef(it->type);
|
||||
m_grid.release(it->bodyCells);
|
||||
m_constructionQueue.erase(it);
|
||||
m_state.grid.release(it->bodyCells);
|
||||
m_state.constructionQueue.erase(it);
|
||||
if (def)
|
||||
{
|
||||
return def->cost;
|
||||
@@ -425,7 +427,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_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
if (building.id != id) { continue; }
|
||||
if (building.queuedForDeconstruction) { return 0; } // already queued
|
||||
@@ -453,8 +455,8 @@ int BuildingSystem::deconstruct(BuildingId id, Tick currentTick)
|
||||
m_belts.removeTile(building.anchor);
|
||||
}
|
||||
|
||||
const bool wasEmpty = m_deconstructionQueue.empty();
|
||||
m_deconstructionQueue.push_back(std::move(entry));
|
||||
const bool wasEmpty = m_state.deconstructionQueue.empty();
|
||||
m_state.deconstructionQueue.push_back(std::move(entry));
|
||||
if (wasEmpty)
|
||||
{
|
||||
startFrontDeconstruction(currentTick);
|
||||
@@ -467,8 +469,8 @@ int BuildingSystem::deconstruct(BuildingId id, Tick currentTick)
|
||||
|
||||
void BuildingSystem::startFrontDeconstruction(Tick currentTick)
|
||||
{
|
||||
if (m_deconstructionQueue.empty()) { return; }
|
||||
DeconstructionEntry& front = m_deconstructionQueue.front();
|
||||
if (m_state.deconstructionQueue.empty()) { return; }
|
||||
DeconstructionEntry& front = m_state.deconstructionQueue.front();
|
||||
if (front.completesAt == 0)
|
||||
{
|
||||
front.completesAt =
|
||||
@@ -483,7 +485,7 @@ void BuildingSystem::startFrontDeconstruction(Tick currentTick)
|
||||
void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId)
|
||||
{
|
||||
// Construction site: store recipe for when building completes.
|
||||
for (ConstructionSite& site : m_constructionQueue)
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
@@ -506,7 +508,7 @@ void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId)
|
||||
}
|
||||
|
||||
// Operational building: clear buffers and re-init.
|
||||
for (Building& building : m_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
@@ -558,7 +560,7 @@ void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId)
|
||||
|
||||
void BuildingSystem::setShipLayout(BuildingId id, const ShipLayoutConfig& layout)
|
||||
{
|
||||
for (ConstructionSite& site : m_constructionQueue)
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
@@ -567,7 +569,7 @@ void BuildingSystem::setShipLayout(BuildingId id, const ShipLayoutConfig& layout
|
||||
}
|
||||
}
|
||||
|
||||
for (Building& building : m_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
@@ -594,7 +596,7 @@ void BuildingSystem::setShipLayout(BuildingId id, const ShipLayoutConfig& layout
|
||||
std::optional<BeltSystem::SplitterInfo>
|
||||
BuildingSystem::getSiteSplitterInfo(BuildingId id) const
|
||||
{
|
||||
for (const ConstructionSite& site : m_constructionQueue)
|
||||
for (const ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id != id) { continue; }
|
||||
if (site.type != BuildingType::Splitter) { return std::nullopt; }
|
||||
@@ -618,7 +620,7 @@ void BuildingSystem::setSiteSplitterFilters(BuildingId id,
|
||||
const std::vector<ItemType>& filterA,
|
||||
const std::vector<ItemType>& filterB)
|
||||
{
|
||||
for (ConstructionSite& site : m_constructionQueue)
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id == id && site.type == BuildingType::Splitter)
|
||||
{
|
||||
@@ -636,12 +638,12 @@ void BuildingSystem::setSiteSplitterFilters(BuildingId id,
|
||||
void BuildingSystem::tickConstruction(Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
if (m_constructionQueue.empty())
|
||||
if (m_state.constructionQueue.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConstructionSite& front = m_constructionQueue.front();
|
||||
ConstructionSite& front = m_state.constructionQueue.front();
|
||||
|
||||
// Guard: if somehow the front site was never started, start it now.
|
||||
if (front.completesAt == 0)
|
||||
@@ -719,18 +721,18 @@ void BuildingSystem::tickConstruction(Tick currentTick)
|
||||
// filters configured while under construction carry over (REQ-BLD-SITE-CONFIG).
|
||||
reregisterBeltTile(building, front.splitterFilterA, front.splitterFilterB);
|
||||
|
||||
m_buildings.push_back(std::move(building));
|
||||
m_state.buildings.push_back(std::move(building));
|
||||
|
||||
m_constructionQueue.pop_front();
|
||||
m_state.constructionQueue.pop_front();
|
||||
|
||||
// Start next queued site if present.
|
||||
if (!m_constructionQueue.empty() && m_constructionQueue.front().completesAt == 0)
|
||||
if (!m_state.constructionQueue.empty() && m_state.constructionQueue.front().completesAt == 0)
|
||||
{
|
||||
const BuildingDef* nextDef =
|
||||
m_config.buildings.findBuildingDef(m_constructionQueue.front().type);
|
||||
m_config.buildings.findBuildingDef(m_state.constructionQueue.front().type);
|
||||
if (nextDef)
|
||||
{
|
||||
m_constructionQueue.front().completesAt =
|
||||
m_state.constructionQueue.front().completesAt =
|
||||
currentTick + secondsToTicks(nextDef->constructionTimeSeconds);
|
||||
}
|
||||
}
|
||||
@@ -767,12 +769,12 @@ void BuildingSystem::reregisterBeltTile(const Building& building,
|
||||
void BuildingSystem::tickDeconstruction(Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
if (m_deconstructionQueue.empty())
|
||||
if (m_state.deconstructionQueue.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DeconstructionEntry& front = m_deconstructionQueue.front();
|
||||
DeconstructionEntry& front = m_state.deconstructionQueue.front();
|
||||
|
||||
// Guard: if the front entry's timer was never started, start it now.
|
||||
if (front.completesAt == 0)
|
||||
@@ -789,15 +791,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_buildings.begin();
|
||||
it != m_buildings.end();
|
||||
for (std::vector<Building>::iterator it = m_state.buildings.begin();
|
||||
it != m_state.buildings.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id != front.id) { continue; }
|
||||
|
||||
const BuildingDef* def = m_config.buildings.findBuildingDef(it->type);
|
||||
m_grid.release(it->bodyCells);
|
||||
m_buildings.erase(it);
|
||||
m_state.grid.release(it->bodyCells);
|
||||
m_state.buildings.erase(it);
|
||||
if (def)
|
||||
{
|
||||
m_addBuildingBlocks(def->cost * m_config.world.refundPercentage / 100);
|
||||
@@ -805,7 +807,7 @@ void BuildingSystem::tickDeconstruction(Tick currentTick)
|
||||
break;
|
||||
}
|
||||
|
||||
m_deconstructionQueue.pop_front();
|
||||
m_state.deconstructionQueue.pop_front();
|
||||
|
||||
// Start the next queued deconstruction, if any.
|
||||
startFrontDeconstruction(currentTick);
|
||||
@@ -813,8 +815,8 @@ void BuildingSystem::tickDeconstruction(Tick currentTick)
|
||||
|
||||
void BuildingSystem::cancelDeconstruction(BuildingId id)
|
||||
{
|
||||
for (std::deque<DeconstructionEntry>::iterator it = m_deconstructionQueue.begin();
|
||||
it != m_deconstructionQueue.end();
|
||||
for (std::deque<DeconstructionEntry>::iterator it = m_state.deconstructionQueue.begin();
|
||||
it != m_state.deconstructionQueue.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id != id) { continue; }
|
||||
@@ -828,7 +830,7 @@ void BuildingSystem::cancelDeconstruction(BuildingId id)
|
||||
reregisterBeltTile(*building, it->splitterFilterA, it->splitterFilterB);
|
||||
}
|
||||
|
||||
m_deconstructionQueue.erase(it);
|
||||
m_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;
|
||||
@@ -848,7 +850,7 @@ void BuildingSystem::tickBeltPull()
|
||||
// (REQ-GW-BELT-SPEED, REQ-MAT-INPUT-INTAKE).
|
||||
const double progressPerTick = m_belts.getProgressPerTick_tpt();
|
||||
|
||||
for (Building& building : m_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -932,7 +934,7 @@ bool BuildingSystem::tryDirectCoupleDeposit(BuildingId producerId,
|
||||
const Port& outputPort,
|
||||
const Item& item)
|
||||
{
|
||||
const std::optional<BuildingId> ownerId = m_grid.findOwner(outputPort.tile);
|
||||
const std::optional<BuildingId> ownerId = m_state.grid.findOwner(outputPort.tile);
|
||||
if (!ownerId.has_value() || *ownerId == producerId)
|
||||
{
|
||||
return false;
|
||||
@@ -966,7 +968,7 @@ bool BuildingSystem::tryDirectCoupleDeposit(BuildingId producerId,
|
||||
void BuildingSystem::tickProduction(Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
for (Building& building : m_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -1069,7 +1071,7 @@ void BuildingSystem::tickProduction(Tick currentTick)
|
||||
void BuildingSystem::tickShipyardProduction(Tick currentTick)
|
||||
{
|
||||
TRACE();
|
||||
for (Building& building : m_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -1169,7 +1171,7 @@ void BuildingSystem::tickOutputBelts()
|
||||
// same speed as real belts (REQ-GW-BELT-SPEED, REQ-MAT-OUTPUT-EMERGE).
|
||||
const double progressPerTick = m_belts.getProgressPerTick_tpt();
|
||||
|
||||
for (Building& building : m_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
// A building queued for deconstruction stops operating (REQ-BLD-DECON-QUEUE).
|
||||
if (building.queuedForDeconstruction) { continue; }
|
||||
@@ -1215,7 +1217,7 @@ void BuildingSystem::tickOutputBelts()
|
||||
void BuildingSystem::forEachEmergingItem(
|
||||
const std::function<void(const ItemType&, QPointF)>& visit) const
|
||||
{
|
||||
for (const Building& building : m_buildings)
|
||||
for (const Building& building : m_state.buildings)
|
||||
{
|
||||
for (std::size_t p = 0; p < building.outputPorts.size(); ++p)
|
||||
{
|
||||
@@ -1237,7 +1239,7 @@ void BuildingSystem::forEachEmergingItem(
|
||||
void BuildingSystem::forEachIncomingItem(
|
||||
const std::function<void(const ItemType&, QPointF)>& visit) const
|
||||
{
|
||||
for (const Building& building : m_buildings)
|
||||
for (const Building& building : m_state.buildings)
|
||||
{
|
||||
for (std::size_t p = 0; p < building.inputPorts.size(); ++p)
|
||||
{
|
||||
@@ -1262,7 +1264,7 @@ void BuildingSystem::forEachIncomingItem(
|
||||
|
||||
const Building* BuildingSystem::findBuilding(BuildingId id) const
|
||||
{
|
||||
for (const Building& building : m_buildings)
|
||||
for (const Building& building : m_state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
@@ -1274,7 +1276,7 @@ const Building* BuildingSystem::findBuilding(BuildingId id) const
|
||||
|
||||
Building* BuildingSystem::findBuildingMutable(BuildingId id)
|
||||
{
|
||||
for (Building& building : m_buildings)
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
@@ -1286,7 +1288,7 @@ Building* BuildingSystem::findBuildingMutable(BuildingId id)
|
||||
|
||||
const ConstructionSite* BuildingSystem::findSite(BuildingId id) const
|
||||
{
|
||||
for (const ConstructionSite& site : m_constructionQueue)
|
||||
for (const ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
@@ -1298,13 +1300,13 @@ const ConstructionSite* BuildingSystem::findSite(BuildingId id) const
|
||||
|
||||
std::vector<Building> BuildingSystem::getAllBuildings() const
|
||||
{
|
||||
return m_buildings;
|
||||
return m_state.buildings;
|
||||
}
|
||||
|
||||
std::vector<ConstructionSite> BuildingSystem::getAllSites() const
|
||||
{
|
||||
return std::vector<ConstructionSite>(m_constructionQueue.begin(),
|
||||
m_constructionQueue.end());
|
||||
return std::vector<ConstructionSite>(m_state.constructionQueue.begin(),
|
||||
m_state.constructionQueue.end());
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -1328,7 +1330,7 @@ bool isProductionBuildingType(BuildingType type)
|
||||
int BuildingSystem::getProductionBuildingCount() const
|
||||
{
|
||||
int count = 0;
|
||||
for (const Building& b : m_buildings)
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (isProductionBuildingType(b.type)) { ++count; }
|
||||
}
|
||||
@@ -1338,7 +1340,7 @@ int BuildingSystem::getProductionBuildingCount() const
|
||||
int BuildingSystem::getActiveProductionBuildingCount() const
|
||||
{
|
||||
int count = 0;
|
||||
for (const Building& b : m_buildings)
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (isProductionBuildingType(b.type) && b.production.has_value()) { ++count; }
|
||||
}
|
||||
@@ -1489,7 +1491,7 @@ BuildingSystem::getProductionStatus(const Building& building) const
|
||||
std::vector<BuildingSystem::BeltTileInfo> BuildingSystem::getAllBeltTiles() const
|
||||
{
|
||||
std::vector<BeltTileInfo> result;
|
||||
for (const Building& b : m_buildings)
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (b.type != BuildingType::Belt && b.type != BuildingType::Splitter)
|
||||
{
|
||||
@@ -1520,7 +1522,7 @@ std::vector<BuildingSystem::BeltTileInfo> BuildingSystem::getAllBeltTiles() cons
|
||||
|
||||
bool BuildingSystem::isTileOccupied(QPoint tile) const
|
||||
{
|
||||
return m_grid.isOccupied(tile);
|
||||
return m_state.grid.isOccupied(tile);
|
||||
}
|
||||
|
||||
std::optional<BuildingId> BuildingSystem::findRotateInPlaceTarget(
|
||||
@@ -1541,13 +1543,13 @@ std::optional<BuildingId> BuildingSystem::findRotateInPlaceTarget(
|
||||
|
||||
// All body cells must be occupied by the same entity.
|
||||
const QPoint firstAbs = anchor + mask.bodyCells[0];
|
||||
const std::optional<BuildingId> firstOwner = m_grid.findOwner(firstAbs);
|
||||
const std::optional<BuildingId> firstOwner = m_state.grid.findOwner(firstAbs);
|
||||
if (!firstOwner.has_value()) { return std::nullopt; }
|
||||
const BuildingId candidateId = *firstOwner;
|
||||
|
||||
for (const QPoint& rel : mask.bodyCells)
|
||||
{
|
||||
const std::optional<BuildingId> owner = m_grid.findOwner(anchor + rel);
|
||||
const std::optional<BuildingId> owner = m_state.grid.findOwner(anchor + rel);
|
||||
if (!owner.has_value() || *owner != candidateId)
|
||||
{
|
||||
return std::nullopt;
|
||||
@@ -1555,14 +1557,14 @@ std::optional<BuildingId> BuildingSystem::findRotateInPlaceTarget(
|
||||
}
|
||||
|
||||
// Verify the candidate is the same building type with the same cell count.
|
||||
for (const ConstructionSite& site : m_constructionQueue)
|
||||
for (const ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id != candidateId) { continue; }
|
||||
if (site.type != type) { return std::nullopt; }
|
||||
if (site.bodyCells.size() != mask.bodyCells.size()) { return std::nullopt; }
|
||||
return candidateId;
|
||||
}
|
||||
for (const Building& b : m_buildings)
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (b.id != candidateId) { continue; }
|
||||
if (b.type != type) { return std::nullopt; }
|
||||
@@ -1576,7 +1578,7 @@ std::optional<BuildingId> BuildingSystem::findRotateInPlaceTarget(
|
||||
void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
||||
{
|
||||
// Construction site path — just update rotation; no ports to recompute.
|
||||
for (ConstructionSite& site : m_constructionQueue)
|
||||
for (ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
@@ -1586,7 +1588,7 @@ void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
||||
}
|
||||
|
||||
// Operational building path.
|
||||
for (Building& b : m_buildings)
|
||||
for (Building& b : m_state.buildings)
|
||||
{
|
||||
if (b.id != id) { continue; }
|
||||
|
||||
@@ -1643,7 +1645,7 @@ const Building* BuildingSystem::findNearestBuilding(QVector2D worldPos,
|
||||
{
|
||||
const Building* best = nullptr;
|
||||
float bestDist = std::numeric_limits<float>::max();
|
||||
for (const Building& b : m_buildings)
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (b.type != type)
|
||||
{
|
||||
@@ -1664,7 +1666,7 @@ const Building* BuildingSystem::findNearestBuilding(QVector2D worldPos,
|
||||
bool BuildingSystem::deliverScrapToSalvageBay(BuildingId bayId)
|
||||
{
|
||||
Building* bay = nullptr;
|
||||
for (Building& b : m_buildings)
|
||||
for (Building& b : m_state.buildings)
|
||||
{
|
||||
if (b.id == bayId)
|
||||
{
|
||||
@@ -1708,7 +1710,7 @@ BuildingId BuildingSystem::placeImmediate(BuildingType type,
|
||||
{
|
||||
const QPoint absCell = anchor + cell;
|
||||
building.bodyCells.push_back(absCell);
|
||||
m_grid.occupy(absCell, id);
|
||||
m_state.grid.occupy(absCell, id);
|
||||
}
|
||||
for (const Port& port : mask.outputPorts)
|
||||
{
|
||||
@@ -1726,14 +1728,14 @@ BuildingId BuildingSystem::placeImmediate(BuildingType type,
|
||||
initSalvageBayBuffer(building);
|
||||
}
|
||||
|
||||
m_buildings.push_back(std::move(building));
|
||||
m_state.buildings.push_back(std::move(building));
|
||||
return id;
|
||||
}
|
||||
|
||||
bool BuildingSystem::removeBuilding(BuildingId id)
|
||||
{
|
||||
for (std::vector<Building>::iterator it = m_buildings.begin();
|
||||
it != m_buildings.end();
|
||||
for (std::vector<Building>::iterator it = m_state.buildings.begin();
|
||||
it != m_state.buildings.end();
|
||||
++it)
|
||||
{
|
||||
if (it->id == id)
|
||||
@@ -1743,8 +1745,8 @@ bool BuildingSystem::removeBuilding(BuildingId id)
|
||||
{
|
||||
m_belts.removeTile(it->anchor);
|
||||
}
|
||||
m_grid.release(it->bodyCells);
|
||||
m_buildings.erase(it);
|
||||
m_state.grid.release(it->bodyCells);
|
||||
m_state.buildings.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1753,7 +1755,7 @@ bool BuildingSystem::removeBuilding(BuildingId id)
|
||||
|
||||
void BuildingSystem::forEachBuilding(std::function<void(Building&)> fn)
|
||||
{
|
||||
for (Building& b : m_buildings)
|
||||
for (Building& b : m_state.buildings)
|
||||
{
|
||||
fn(b);
|
||||
}
|
||||
@@ -1762,12 +1764,12 @@ void BuildingSystem::forEachBuilding(std::function<void(Building&)> fn)
|
||||
void BuildingSystem::registerTileOccupancy(const std::vector<QPoint>& cells,
|
||||
BuildingId ownerPlaceholder)
|
||||
{
|
||||
m_grid.occupy(cells, ownerPlaceholder);
|
||||
m_state.grid.occupy(cells, ownerPlaceholder);
|
||||
}
|
||||
|
||||
void BuildingSystem::unregisterTileOccupancy(const std::vector<QPoint>& cells)
|
||||
{
|
||||
m_grid.release(cells);
|
||||
m_state.grid.release(cells);
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -1801,10 +1803,10 @@ void appendInputBuffer(Hasher& hasher, const InputBuffer& buffer)
|
||||
|
||||
void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
{
|
||||
// m_buildings keeps a stable, deterministic order (append on build, swap-free
|
||||
// m_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_buildings.size());
|
||||
for (const Building& b : m_buildings)
|
||||
hasher.append(m_state.buildings.size());
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
hasher.append(b.id);
|
||||
hasher.append(b.anchor);
|
||||
@@ -1847,8 +1849,8 @@ void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
hasher.append(b.queuedForDeconstruction);
|
||||
}
|
||||
|
||||
hasher.append(m_constructionQueue.size());
|
||||
for (const ConstructionSite& s : m_constructionQueue)
|
||||
hasher.append(m_state.constructionQueue.size());
|
||||
for (const ConstructionSite& s : m_state.constructionQueue)
|
||||
{
|
||||
hasher.append(s.id);
|
||||
hasher.append(s.anchor);
|
||||
@@ -1865,8 +1867,8 @@ void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
for (const ItemType& type : s.splitterFilterB) { hasher.append(type.id); }
|
||||
}
|
||||
|
||||
hasher.append(m_deconstructionQueue.size());
|
||||
for (const DeconstructionEntry& e : m_deconstructionQueue)
|
||||
hasher.append(m_state.deconstructionQueue.size());
|
||||
for (const DeconstructionEntry& e : m_state.deconstructionQueue)
|
||||
{
|
||||
hasher.append(e.id);
|
||||
hasher.append(e.completesAt);
|
||||
@@ -1876,5 +1878,5 @@ void BuildingSystem::appendChecksum(Hasher& hasher) const
|
||||
for (const ItemType& type : e.splitterFilterB) { hasher.append(type.id); }
|
||||
}
|
||||
|
||||
m_grid.appendChecksum(hasher);
|
||||
m_state.grid.appendChecksum(hasher);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingGrid.h"
|
||||
#include "FactoryState.h"
|
||||
#include "BuildingType.h"
|
||||
#include "BuildingId.h"
|
||||
#include "GameConfig.h"
|
||||
@@ -47,6 +47,7 @@ class BuildingSystem
|
||||
{
|
||||
public:
|
||||
BuildingSystem(const GameConfig& config,
|
||||
FactoryState& state,
|
||||
BeltSystem& belts,
|
||||
std::function<BuildingId()> allocateBuildingId,
|
||||
std::function<void(int)> addBuildingBlocks,
|
||||
@@ -285,6 +286,11 @@ private:
|
||||
QPoint anchor) const;
|
||||
|
||||
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;
|
||||
std::function<void(int)> m_addBuildingBlocks;
|
||||
@@ -293,24 +299,4 @@ private:
|
||||
std::function<bool(const std::string&)> m_isItemUnlocked;
|
||||
std::mt19937& m_rng;
|
||||
int m_asteroidWidth_tiles;
|
||||
|
||||
std::vector<Building> m_buildings;
|
||||
std::deque<ConstructionSite> m_constructionQueue;
|
||||
|
||||
// One pending demolition of a fully-built building (REQ-BLD-DECON-QUEUE).
|
||||
// completesAt == 0 means "queued but its timer has not started yet"
|
||||
// (mirrors ConstructionSite). For a Splitter, the filters it had are captured
|
||||
// here so cancelDeconstruction can restore them on re-registration.
|
||||
struct DeconstructionEntry
|
||||
{
|
||||
BuildingId id = kInvalidBuildingId;
|
||||
Tick completesAt = 0;
|
||||
std::vector<ItemType> splitterFilterA;
|
||||
std::vector<ItemType> splitterFilterB;
|
||||
};
|
||||
std::deque<DeconstructionEntry> m_deconstructionQueue;
|
||||
|
||||
// The authority on which building owns which tile; every placement and removal
|
||||
// path claims and releases its body cells here.
|
||||
BuildingGrid m_grid;
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ SET(HDRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Building.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingConfig.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingGrid.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FactoryState.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingSystem.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/EntityHitTest.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ShipLayout.h
|
||||
|
||||
48
src/lib/sim/FactoryState.h
Normal file
48
src/lib/sim/FactoryState.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "Building.h"
|
||||
#include "BuildingGrid.h"
|
||||
#include "BuildingId.h"
|
||||
#include "ItemType.h"
|
||||
#include "Tick.h"
|
||||
|
||||
// One pending demolition of a fully-built building (REQ-BLD-DECON-QUEUE).
|
||||
// completesAt == 0 means "queued but its timer has not started yet"
|
||||
// (mirrors ConstructionSite). For a Splitter, the filters it had are captured
|
||||
// here so cancelDeconstruction can restore them on re-registration.
|
||||
struct DeconstructionEntry
|
||||
{
|
||||
BuildingId id = kInvalidBuildingId;
|
||||
Tick completesAt = 0;
|
||||
std::vector<ItemType> splitterFilterA;
|
||||
std::vector<ItemType> splitterFilterB;
|
||||
};
|
||||
|
||||
// The factory's world data: every building, the work queued on them, and the
|
||||
// tile ownership index. This is the buildings-side counterpart to EntityAdmin —
|
||||
// data with no behaviour of its own beyond what BuildingGrid encapsulates.
|
||||
//
|
||||
// Buildings deliberately stay a plain vector rather than becoming EnTT entities
|
||||
// (see docs/architecture.md). Separating this data from the systems that operate
|
||||
// on it is not a step toward putting them in the entity model; it is the same
|
||||
// data/behaviour split the ecs/system/ classes already follow, where world data
|
||||
// arrives as a tick argument instead of being owned by the system.
|
||||
//
|
||||
// Owned by Simulation (and by ArenaSimulation in the balancing tool), not by the
|
||||
// systems that operate on it. BuildingSystem holds a reference. The remaining step
|
||||
// is to pass this into the tick methods instead, so the systems become stateless
|
||||
// over it — that one is gated on the query surface, which today reaches the data
|
||||
// through BuildingSystem's ~180 const call sites.
|
||||
struct FactoryState
|
||||
{
|
||||
std::vector<Building> buildings;
|
||||
std::deque<ConstructionSite> constructionQueue;
|
||||
std::deque<DeconstructionEntry> deconstructionQueue;
|
||||
|
||||
// The authority on which building owns which tile; every placement and removal
|
||||
// path claims and releases its body cells here.
|
||||
BuildingGrid grid;
|
||||
};
|
||||
@@ -94,6 +94,7 @@ void Simulation::reset(unsigned int seed)
|
||||
m_pendingSchematicChoices.clear();
|
||||
|
||||
m_admin.clear();
|
||||
m_factoryState = FactoryState{};
|
||||
m_beltSystem = BeltSystem(m_config.world.beltSpeed_tps);
|
||||
initializeSubsystems();
|
||||
|
||||
@@ -105,6 +106,7 @@ void Simulation::initializeSubsystems()
|
||||
{
|
||||
m_buildingSystem = std::make_unique<BuildingSystem>(
|
||||
m_config,
|
||||
m_factoryState,
|
||||
m_beltSystem,
|
||||
[this]() { return allocateBuildingId(); },
|
||||
[this](int amount) { m_buildingBlocksStock += amount; },
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <QPoint>
|
||||
|
||||
#include "BeltSystem.h"
|
||||
#include "FactoryState.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "entt/entity/entity.hpp"
|
||||
#include "SchematicChoiceOption.h"
|
||||
@@ -209,6 +210,9 @@ private:
|
||||
UnlockState m_unlockState;
|
||||
|
||||
EntityAdmin m_admin;
|
||||
// The factory's world data. Owned here, not by BuildingSystem, so the systems
|
||||
// that operate on it can be handed the same state (see FactoryState.h).
|
||||
FactoryState m_factoryState;
|
||||
BeltSystem m_beltSystem;
|
||||
std::unique_ptr<BuildingSystem> m_buildingSystem;
|
||||
std::unique_ptr<ShipSystem> m_shipSystem;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "FactoryState.h"
|
||||
#include "BuildingType.h"
|
||||
#include "ConfigLoader.h"
|
||||
#include "DeliverScrapBehavior.h"
|
||||
@@ -54,6 +55,7 @@
|
||||
struct Fixture
|
||||
{
|
||||
GameConfig cfg;
|
||||
FactoryState state;
|
||||
BeltSystem belts;
|
||||
BuildingId nextBuildingId;
|
||||
int stock;
|
||||
@@ -76,7 +78,7 @@ struct Fixture
|
||||
, nextBuildingId(1)
|
||||
, stock(0)
|
||||
, rng(42)
|
||||
, buildings(cfg, belts,
|
||||
, buildings(cfg, state, belts,
|
||||
[this]() { return nextBuildingId++; },
|
||||
[this](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "FactoryState.h"
|
||||
#include "BuildingType.h"
|
||||
#include "ConfigLoader.h"
|
||||
#include "Item.h"
|
||||
@@ -83,6 +84,7 @@ static std::vector<Item> outputSideItems(const Building& b)
|
||||
struct PlacementFixture
|
||||
{
|
||||
GameConfig cfg = loadTestConfig();
|
||||
FactoryState state;
|
||||
BeltSystem belts{cfg.world.beltSpeed_tps};
|
||||
int stock = 0;
|
||||
std::mt19937 rng{0};
|
||||
@@ -90,7 +92,7 @@ struct PlacementFixture
|
||||
BuildingSystem bs;
|
||||
|
||||
PlacementFixture()
|
||||
: bs(cfg, belts,
|
||||
: bs(cfg, state, belts,
|
||||
[this]() { return nextBuildingId++; },
|
||||
[this](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -111,7 +113,8 @@ TEST_CASE("BuildingSystem: place miner occupies expected body tiles", "[building
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -219,7 +222,8 @@ TEST_CASE("BuildingSystem: placing a belt registers it with BeltSystem after con
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -248,7 +252,8 @@ TEST_CASE("BuildingSystem: placed building enters construction queue", "[buildin
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -290,7 +295,8 @@ TEST_CASE("BuildingSystem: first queued building starts construction immediately
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -308,7 +314,8 @@ TEST_CASE("BuildingSystem: second queued building waits (completesAt == 0)", "[b
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -330,7 +337,8 @@ TEST_CASE("BuildingSystem: construction completes after configured duration", "[
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -496,7 +504,8 @@ TEST_CASE("BuildingSystem: second building starts after first completes", "[buil
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -526,7 +535,8 @@ TEST_CASE("BuildingSystem: miner produces iron_ore after recipe duration", "[bui
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -559,7 +569,8 @@ TEST_CASE("BuildingSystem: miner output buffer stalls when full", "[building]")
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -599,7 +610,8 @@ TEST_CASE("BuildingSystem: productionBuildingCount excludes construction sites",
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -639,7 +651,8 @@ TEST_CASE("BuildingSystem: activeProductionBuildingCount tracks production cycle
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -681,7 +694,8 @@ TEST_CASE("BuildingSystem: smelter input buffer fills from adjacent west-flowing
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -723,7 +737,8 @@ TEST_CASE("BuildingSystem: accepted input travels inward before entering the buf
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -764,7 +779,8 @@ TEST_CASE("BuildingSystem: input reservation caps buffered plus in-transit at th
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -806,7 +822,8 @@ TEST_CASE("BuildingSystem: smelter auto-smelts ore without a recipe selection",
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -852,7 +869,8 @@ TEST_CASE("BuildingSystem: smelter runs a satisfiable recipe while an incomplete
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -906,7 +924,8 @@ TEST_CASE("BuildingSystem: miner output buffer drains onto adjacent belt", "[bui
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -945,7 +964,8 @@ TEST_CASE("BuildingSystem: output port couples directly into an adjacent input p
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -985,7 +1005,8 @@ TEST_CASE("BuildingSystem: direct coupling to a non-consumer leaves the item stu
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1024,7 +1045,8 @@ TEST_CASE("BuildingSystem: setRecipe clears output buffer and active production"
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1067,7 +1089,8 @@ TEST_CASE("BuildingSystem: reprocessing plant output buffer capacity equals max
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1099,7 +1122,8 @@ TEST_CASE("BuildingSystem: reprocessing plant produces one cycle output then sta
|
||||
// Seed chosen so first roll produces 2-item output (iron_ingot), filling buffer.
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1157,7 +1181,8 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns nullopt when tile is
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1176,7 +1201,8 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns the site id for a que
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1199,7 +1225,8 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns the building id for a
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1226,7 +1253,8 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns nullopt when building
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1248,7 +1276,8 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget never rotates a tunnel in pla
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1274,7 +1303,8 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns nullopt when footprin
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1298,7 +1328,8 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget works for a symmetric multi-t
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1327,7 +1358,8 @@ TEST_CASE("BuildingSystem: rotateInPlace updates the rotation field of a constru
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1350,7 +1382,8 @@ TEST_CASE("BuildingSystem: rotateInPlace preserves the construction progress of
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1374,7 +1407,8 @@ TEST_CASE("BuildingSystem: rotateInPlace updates rotation and output port direct
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
@@ -1405,7 +1439,8 @@ TEST_CASE("BuildingSystem: rotateInPlace re-registers a belt tile with BeltSyste
|
||||
int stock = 0;
|
||||
std::mt19937 rng(0);
|
||||
BuildingId nextBuildingId = 1;
|
||||
BuildingSystem bs(cfg, belts,
|
||||
FactoryState state_bs;
|
||||
BuildingSystem bs(cfg, state_bs, belts,
|
||||
[&nextBuildingId]() { return nextBuildingId++; },
|
||||
[&stock](int n) { stock += n; },
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "FactoryState.h"
|
||||
#include "BuildingType.h"
|
||||
#include "CombatSystem.h"
|
||||
#include "ConfigLoader.h"
|
||||
@@ -51,6 +52,7 @@ static entt::entity findWeaponChild(EntityAdmin& admin, entt::entity ship)
|
||||
struct CombatFixture
|
||||
{
|
||||
GameConfig cfg;
|
||||
FactoryState state;
|
||||
std::mt19937 rng;
|
||||
EntityAdmin admin;
|
||||
BuildingId nextBuildingId;
|
||||
@@ -65,7 +67,7 @@ struct CombatFixture
|
||||
, nextBuildingId(1)
|
||||
, belts(cfg.world.beltSpeed_tps)
|
||||
, ships(cfg, admin)
|
||||
, buildings(cfg, belts,
|
||||
, buildings(cfg, state, belts,
|
||||
[this]() { return nextBuildingId++; },
|
||||
[](int){},
|
||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||
|
||||
Reference in New Issue
Block a user