depend on factory data instead of BuildingSystem in the AI path
Ten queries that read nothing but FactoryState become free functions in FactoryQueries.h; the BuildingSystem methods stay as one-line forwards, so no existing caller moves yet. That lets the AI path drop its dependency on the system entirely. AiSystem, SalvagerSystem, DeliverScrapEvaluator and DeliverScrapExecutor took a BuildingSystem& purely to call findBuilding, findNearestBuilding and deliverScrapToSalvageBay — all three are state-pure — so they now take FactoryState& and say what they actually read. Four forward declarations of BuildingSystem go with them. No facade: the queries are plain free functions over the data. A facade was considered to spare the ~180 UI call sites, but the AI needed only the data and would have been given GameConfig it has no use for. isProductionBuildingType moves to BuildingType.h beside isAutoRecipeBuildingType and isBeltSubsystemType rather than being copied into the new file. Verified with a golden-checksum capture before and after — all four sample ticks identical. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
This commit is contained in:
@@ -52,3 +52,18 @@ bool isBeltSubsystemType(BuildingType type)
|
||||
|| type == BuildingType::TunnelEntry
|
||||
|| type == BuildingType::TunnelExit;
|
||||
}
|
||||
|
||||
bool isProductionBuildingType(BuildingType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BuildingType::Miner:
|
||||
case BuildingType::Smelter:
|
||||
case BuildingType::Assembler:
|
||||
case BuildingType::ReprocessingPlant:
|
||||
case BuildingType::Shipyard:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ std::string buildingTypeId(BuildingType type);
|
||||
// they receive, matching against every recipe of their building type.
|
||||
bool isAutoRecipeBuildingType(BuildingType type);
|
||||
|
||||
// Buildings that run a production cycle: Miner, Smelter, Assembler, Reprocessing
|
||||
// Plant and Shipyard (REQ-UI-DEBUG-OVERLAY counts these).
|
||||
bool isProductionBuildingType(BuildingType type);
|
||||
|
||||
// Belts, splitters, and tunnel ends keep their runtime data in the belt subsystem
|
||||
// rather than in the Building instance, so placing/removing them must register or
|
||||
// unregister a tile with BeltSystem.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "AiSystem.h"
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
@@ -42,7 +43,7 @@ AiSystem::AiSystem(const GameConfig& config)
|
||||
{
|
||||
}
|
||||
|
||||
void AiSystem::tick(EntityAdmin& admin, const BuildingSystem& buildings,
|
||||
void AiSystem::tick(EntityAdmin& admin, const FactoryState& state,
|
||||
const DebrisSystem& debris)
|
||||
{
|
||||
TRACE();
|
||||
@@ -55,7 +56,7 @@ void AiSystem::tick(EntityAdmin& admin, const BuildingSystem& buildings,
|
||||
m_attackEvaluator.evaluate(admin);
|
||||
m_repairEvaluator.evaluate(admin);
|
||||
m_salvageScrapEvaluator.evaluate(admin, debris);
|
||||
m_deliverScrapEvaluator.evaluate(admin, buildings);
|
||||
m_deliverScrapEvaluator.evaluate(admin, state);
|
||||
|
||||
// Phase 2: pick the highest-scoring behavior per ship.
|
||||
selectWinningBehaviors(admin);
|
||||
@@ -68,7 +69,7 @@ void AiSystem::tick(EntityAdmin& admin, const BuildingSystem& buildings,
|
||||
m_attackExecutor.execute(admin);
|
||||
m_repairExecutor.execute(admin);
|
||||
m_salvageScrapExecutor.execute(admin);
|
||||
m_deliverScrapExecutor.execute(admin, buildings);
|
||||
m_deliverScrapExecutor.execute(admin, state);
|
||||
}
|
||||
|
||||
void AiSystem::selectWinningBehaviors(EntityAdmin& admin)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
#include "AdvanceEvaluator.h"
|
||||
#include "AdvanceExecutor.h"
|
||||
#include "AttackEvaluator.h"
|
||||
@@ -17,7 +19,6 @@
|
||||
#include "StandbyEvaluator.h"
|
||||
#include "StandbyExecutor.h"
|
||||
|
||||
class BuildingSystem;
|
||||
class EntityAdmin;
|
||||
class DebrisSystem;
|
||||
struct GameConfig;
|
||||
@@ -34,7 +35,7 @@ class AiSystem
|
||||
public:
|
||||
explicit AiSystem(const GameConfig& config);
|
||||
|
||||
void tick(EntityAdmin& admin, const BuildingSystem& buildings, const DebrisSystem& debris);
|
||||
void tick(EntityAdmin& admin, const FactoryState& state, const DebrisSystem& debris);
|
||||
|
||||
private:
|
||||
void selectWinningBehaviors(EntityAdmin& admin);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "SalvagerSystem.h"
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -23,7 +24,7 @@ SalvagerSystem::SalvagerSystem(EntityAdmin& admin)
|
||||
{
|
||||
}
|
||||
|
||||
void SalvagerSystem::tick(Tick currentTick, DebrisSystem& debris, BuildingSystem& buildings,
|
||||
void SalvagerSystem::tick(Tick currentTick, DebrisSystem& debris, FactoryState& state,
|
||||
std::vector<BeamFiredEvent>& outBeamFiredEvents)
|
||||
{
|
||||
TRACE();
|
||||
@@ -89,7 +90,7 @@ void SalvagerSystem::tick(Tick currentTick, DebrisSystem& debris, BuildingSystem
|
||||
[&](entt::entity ship, const DeliverScrapBehavior& deliver, const PositionComponent& pos)
|
||||
{
|
||||
if (!deliver.deliveryBay.has_value()) { return; }
|
||||
const Building* bay = buildings.findBuilding(*deliver.deliveryBay);
|
||||
const Building* bay = findBuilding(state, *deliver.deliveryBay);
|
||||
if (!bay) { return; }
|
||||
|
||||
const QVector2D bayCenter(bay->anchor.x() + bay->footprint.width() / 2.0f,
|
||||
@@ -100,7 +101,7 @@ void SalvagerSystem::tick(Tick currentTick, DebrisSystem& debris, BuildingSystem
|
||||
if (!m_admin.hasAll<CargoComponent>(ship)) { return; }
|
||||
CargoComponent& cargo = m_admin.get<CargoComponent>(ship);
|
||||
if (cargo.current <= 0) { return; }
|
||||
if (buildings.deliverScrapToSalvageBay(*deliver.deliveryBay))
|
||||
if (deliverScrapToSalvageBay(state, *deliver.deliveryBay))
|
||||
{
|
||||
--cargo.current;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "BeamFiredEvent.h"
|
||||
@@ -7,7 +9,6 @@
|
||||
|
||||
#include "entt/entity/entity.hpp"
|
||||
|
||||
class BuildingSystem;
|
||||
class EntityAdmin;
|
||||
class DebrisSystem;
|
||||
|
||||
@@ -21,7 +22,7 @@ class SalvagerSystem
|
||||
public:
|
||||
explicit SalvagerSystem(EntityAdmin& admin);
|
||||
|
||||
void tick(Tick currentTick, DebrisSystem& debris, BuildingSystem& buildings,
|
||||
void tick(Tick currentTick, DebrisSystem& debris, FactoryState& state,
|
||||
std::vector<BeamFiredEvent>& outBeamFiredEvents);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "DeliverScrapEvaluator.h"
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -12,7 +13,7 @@
|
||||
#include "PositionComponent.h"
|
||||
#include "tracing.h"
|
||||
|
||||
void DeliverScrapEvaluator::evaluate(EntityAdmin& admin, const BuildingSystem& buildings)
|
||||
void DeliverScrapEvaluator::evaluate(EntityAdmin& admin, const FactoryState& state)
|
||||
{
|
||||
TRACE();
|
||||
const std::unordered_map<entt::entity, CargoState> cargoByShip = buildCargoByShip(admin);
|
||||
@@ -34,7 +35,7 @@ void DeliverScrapEvaluator::evaluate(EntityAdmin& admin, const BuildingSystem& b
|
||||
if (!deliver.deliveryBay.has_value())
|
||||
{
|
||||
const Building* bay =
|
||||
buildings.findNearestBuilding(pos.value, BuildingType::SalvageBay);
|
||||
findNearestBuilding(state, pos.value, BuildingType::SalvageBay);
|
||||
if (bay) { deliver.deliveryBay = bay->id; }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
class EntityAdmin;
|
||||
class BuildingSystem;
|
||||
|
||||
// Scores high only when the ship's cargo is full, and assigns the nearest
|
||||
// SalvageBay as the delivery destination.
|
||||
class DeliverScrapEvaluator
|
||||
{
|
||||
public:
|
||||
void evaluate(EntityAdmin& admin, const BuildingSystem& buildings);
|
||||
void evaluate(EntityAdmin& admin, const FactoryState& state);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "DeliverScrapExecutor.h"
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
#include <QVector2D>
|
||||
|
||||
@@ -12,7 +13,7 @@
|
||||
#include "SelectedBehaviorComponent.h"
|
||||
#include "tracing.h"
|
||||
|
||||
void DeliverScrapExecutor::execute(EntityAdmin& admin, const BuildingSystem& buildings)
|
||||
void DeliverScrapExecutor::execute(EntityAdmin& admin, const FactoryState& state)
|
||||
{
|
||||
TRACE();
|
||||
admin.forEach<DeliverScrapBehavior, SelectedBehaviorComponent, PositionComponent,
|
||||
@@ -26,7 +27,7 @@ void DeliverScrapExecutor::execute(EntityAdmin& admin, const BuildingSystem& bui
|
||||
QVector2D dest = pos.value;
|
||||
if (deliver.deliveryBay.has_value())
|
||||
{
|
||||
const Building* bay = buildings.findBuilding(*deliver.deliveryBay);
|
||||
const Building* bay = findBuilding(state, *deliver.deliveryBay);
|
||||
if (bay)
|
||||
{
|
||||
dest = QVector2D(bay->anchor.x() + bay->footprint.width() / 2.0f,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
class EntityAdmin;
|
||||
class BuildingSystem;
|
||||
|
||||
// Moves a ship toward its delivery bay when DeliverScrap is the winning
|
||||
// behavior. Never decrements cargo — SalvagerSystem performs the delivery.
|
||||
class DeliverScrapExecutor
|
||||
{
|
||||
public:
|
||||
void execute(EntityAdmin& admin, const BuildingSystem& buildings);
|
||||
void execute(EntityAdmin& admin, const FactoryState& state);
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <random>
|
||||
#include <set>
|
||||
|
||||
#include "FactoryQueries.h"
|
||||
#include "PortGeometry.h"
|
||||
#include "StateChecksum.h"
|
||||
#include "SurfaceMask.h"
|
||||
@@ -1264,87 +1265,37 @@ void BuildingSystem::forEachIncomingItem(
|
||||
|
||||
const Building* BuildingSystem::findBuilding(BuildingId id) const
|
||||
{
|
||||
for (const Building& building : m_state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
return &building;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return ::findBuilding(m_state, id);
|
||||
}
|
||||
|
||||
Building* BuildingSystem::findBuildingMutable(BuildingId id)
|
||||
{
|
||||
for (Building& building : m_state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
return &building;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return ::findBuilding(m_state, id);
|
||||
}
|
||||
|
||||
const ConstructionSite* BuildingSystem::findSite(BuildingId id) const
|
||||
{
|
||||
for (const ConstructionSite& site : m_state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
return &site;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return ::findSite(m_state, id);
|
||||
}
|
||||
|
||||
std::vector<Building> BuildingSystem::getAllBuildings() const
|
||||
{
|
||||
return m_state.buildings;
|
||||
return ::getAllBuildings(m_state);
|
||||
}
|
||||
|
||||
std::vector<ConstructionSite> BuildingSystem::getAllSites() const
|
||||
{
|
||||
return std::vector<ConstructionSite>(m_state.constructionQueue.begin(),
|
||||
m_state.constructionQueue.end());
|
||||
return ::getAllSites(m_state);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool isProductionBuildingType(BuildingType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BuildingType::Miner:
|
||||
case BuildingType::Smelter:
|
||||
case BuildingType::Assembler:
|
||||
case BuildingType::ReprocessingPlant:
|
||||
case BuildingType::Shipyard:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int BuildingSystem::getProductionBuildingCount() const
|
||||
{
|
||||
int count = 0;
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (isProductionBuildingType(b.type)) { ++count; }
|
||||
}
|
||||
return count;
|
||||
return ::getProductionBuildingCount(m_state);
|
||||
}
|
||||
|
||||
int BuildingSystem::getActiveProductionBuildingCount() const
|
||||
{
|
||||
int count = 0;
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (isProductionBuildingType(b.type) && b.production.has_value()) { ++count; }
|
||||
}
|
||||
return count;
|
||||
return ::getActiveProductionBuildingCount(m_state);
|
||||
}
|
||||
|
||||
std::vector<const RecipeDef*>
|
||||
@@ -1522,7 +1473,7 @@ std::vector<BuildingSystem::BeltTileInfo> BuildingSystem::getAllBeltTiles() cons
|
||||
|
||||
bool BuildingSystem::isTileOccupied(QPoint tile) const
|
||||
{
|
||||
return m_state.grid.isOccupied(tile);
|
||||
return ::isTileOccupied(m_state, tile);
|
||||
}
|
||||
|
||||
std::optional<BuildingId> BuildingSystem::findRotateInPlaceTarget(
|
||||
@@ -1643,53 +1594,12 @@ void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
||||
const Building* BuildingSystem::findNearestBuilding(QVector2D worldPos,
|
||||
BuildingType type) const
|
||||
{
|
||||
const Building* best = nullptr;
|
||||
float bestDist = std::numeric_limits<float>::max();
|
||||
for (const Building& b : m_state.buildings)
|
||||
{
|
||||
if (b.type != type)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QVector2D center(b.anchor.x() + b.footprint.width() / 2.0f,
|
||||
b.anchor.y() + b.footprint.height() / 2.0f);
|
||||
float dist = (center - worldPos).length();
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
best = &b;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
return ::findNearestBuilding(m_state, worldPos, type);
|
||||
}
|
||||
|
||||
bool BuildingSystem::deliverScrapToSalvageBay(BuildingId bayId)
|
||||
{
|
||||
Building* bay = nullptr;
|
||||
for (Building& b : m_state.buildings)
|
||||
{
|
||||
if (b.id == bayId)
|
||||
{
|
||||
bay = &b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bay || bay->type != BuildingType::SalvageBay)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (bay->queuedForDeconstruction)
|
||||
{
|
||||
return false; // queued for deconstruction: stopped operating (REQ-BLD-DECON-QUEUE)
|
||||
}
|
||||
// Emerging scrap still counts against the bay's holding capacity
|
||||
// (REQ-MAT-OUTPUT-EMERGE).
|
||||
if (bay->getOutputItemCount() >= bay->outputBuffer.capacity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bay->outputBuffer.items.push_back(Item{ItemType{"scrap"}});
|
||||
return true;
|
||||
return ::deliverScrapToSalvageBay(m_state, bayId);
|
||||
}
|
||||
|
||||
BuildingId BuildingSystem::placeImmediate(BuildingType type,
|
||||
|
||||
@@ -14,6 +14,7 @@ SET(HDRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingConfig.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingGrid.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FactoryState.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FactoryQueries.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingSystem.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/EntityHitTest.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ShipLayout.h
|
||||
@@ -39,6 +40,7 @@ SET(SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BeltSystem.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingConfig.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingGrid.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/FactoryQueries.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingSystem.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/EntityHitTest.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ShipStatsCalculator.cpp
|
||||
|
||||
122
src/lib/sim/FactoryQueries.cpp
Normal file
122
src/lib/sim/FactoryQueries.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "FactoryQueries.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "Item.h"
|
||||
#include "ItemType.h"
|
||||
|
||||
const Building* findBuilding(const FactoryState& state, BuildingId id)
|
||||
{
|
||||
for (const Building& building : state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
return &building;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Building* findBuilding(FactoryState& state, BuildingId id)
|
||||
{
|
||||
for (Building& building : state.buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
return &building;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ConstructionSite* findSite(const FactoryState& state, BuildingId id)
|
||||
{
|
||||
for (const ConstructionSite& site : state.constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
return &site;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Building> getAllBuildings(const FactoryState& state)
|
||||
{
|
||||
return state.buildings;
|
||||
}
|
||||
|
||||
std::vector<ConstructionSite> getAllSites(const FactoryState& state)
|
||||
{
|
||||
return std::vector<ConstructionSite>(state.constructionQueue.begin(),
|
||||
state.constructionQueue.end());
|
||||
}
|
||||
|
||||
int getProductionBuildingCount(const FactoryState& state)
|
||||
{
|
||||
int count = 0;
|
||||
for (const Building& b : state.buildings)
|
||||
{
|
||||
if (isProductionBuildingType(b.type)) { ++count; }
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int getActiveProductionBuildingCount(const FactoryState& state)
|
||||
{
|
||||
int count = 0;
|
||||
for (const Building& b : state.buildings)
|
||||
{
|
||||
if (isProductionBuildingType(b.type) && b.production.has_value()) { ++count; }
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool isTileOccupied(const FactoryState& state, QPoint tile)
|
||||
{
|
||||
return state.grid.isOccupied(tile);
|
||||
}
|
||||
|
||||
const Building* findNearestBuilding(const FactoryState& state, QVector2D worldPos,
|
||||
BuildingType type)
|
||||
{
|
||||
const Building* best = nullptr;
|
||||
float bestDist = std::numeric_limits<float>::max();
|
||||
for (const Building& b : state.buildings)
|
||||
{
|
||||
if (b.type != type)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QVector2D center(b.anchor.x() + b.footprint.width() / 2.0f,
|
||||
b.anchor.y() + b.footprint.height() / 2.0f);
|
||||
float dist = (center - worldPos).length();
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
best = &b;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
bool deliverScrapToSalvageBay(FactoryState& state, BuildingId bayId)
|
||||
{
|
||||
Building* bay = findBuilding(state, bayId);
|
||||
if (!bay || bay->type != BuildingType::SalvageBay)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (bay->queuedForDeconstruction)
|
||||
{
|
||||
return false; // queued for deconstruction: stopped operating (REQ-BLD-DECON-QUEUE)
|
||||
}
|
||||
// Emerging scrap still counts against the bay's holding capacity
|
||||
// (REQ-MAT-OUTPUT-EMERGE).
|
||||
if (bay->getOutputItemCount() >= bay->outputBuffer.capacity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bay->outputBuffer.items.push_back(Item{ItemType{"scrap"}});
|
||||
return true;
|
||||
}
|
||||
51
src/lib/sim/FactoryQueries.h
Normal file
51
src/lib/sim/FactoryQueries.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QPoint>
|
||||
#include <QVector2D>
|
||||
|
||||
#include "Building.h"
|
||||
#include "BuildingId.h"
|
||||
#include "BuildingType.h"
|
||||
#include "FactoryState.h"
|
||||
|
||||
// Queries and operations over the factory's world data that need nothing but that
|
||||
// data — no config, no belts, no RNG. Free functions rather than BuildingSystem
|
||||
// methods so that callers depend on the data they read instead of on the system
|
||||
// that happens to tick it (see FactoryState.h).
|
||||
//
|
||||
// A helper belongs here only if it is a pure function of FactoryState. Anything
|
||||
// needing GameConfig or the asteroid bound stays on BuildingSystem for now.
|
||||
|
||||
// The building with the given id, or nullptr when no building has it. Construction
|
||||
// sites are not buildings yet — use findSite for those.
|
||||
const Building* findBuilding(const FactoryState& state, BuildingId id);
|
||||
Building* findBuilding(FactoryState& state, BuildingId id);
|
||||
|
||||
// The queued construction site with the given id, or nullptr.
|
||||
const ConstructionSite* findSite(const FactoryState& state, BuildingId id);
|
||||
|
||||
std::vector<Building> getAllBuildings(const FactoryState& state);
|
||||
std::vector<ConstructionSite> getAllSites(const FactoryState& state);
|
||||
|
||||
// REQ-UI-DEBUG-OVERLAY "Max Factory Production": count of completed
|
||||
// (operational) Miner/Smelter/Assembler/ReprocessingPlant/Shipyard buildings.
|
||||
int getProductionBuildingCount(const FactoryState& state);
|
||||
|
||||
// REQ-UI-DEBUG-OVERLAY "Current Factory Production": subset of the above that
|
||||
// currently has an active production cycle.
|
||||
int getActiveProductionBuildingCount(const FactoryState& state);
|
||||
|
||||
bool isTileOccupied(const FactoryState& state, QPoint tile);
|
||||
|
||||
// The nearest building of the given type to a world position, or nullptr when
|
||||
// none exists. Distance is measured to the building's footprint centre.
|
||||
const Building* findNearestBuilding(const FactoryState& state, QVector2D worldPos,
|
||||
BuildingType type);
|
||||
|
||||
// Hands one scrap to a Salvage Bay's output buffer (REQ-BLD-SALVAGE-BAY). Fails
|
||||
// if the id is not a Salvage Bay, it is queued for deconstruction
|
||||
// (REQ-BLD-DECON-QUEUE), or its holding capacity is already taken — emerging
|
||||
// scrap counts against that capacity (REQ-MAT-OUTPUT-EMERGE).
|
||||
bool deliverScrapToSalvageBay(FactoryState& state, BuildingId bayId);
|
||||
@@ -260,10 +260,10 @@ void Simulation::tick()
|
||||
m_shipSystem->clearMovementIntents();
|
||||
// Score-based behavior selection: evaluate, select winner, execute (sets
|
||||
// movement intent + preferred module targets only — no world mutation).
|
||||
m_aiSystem->tick(m_admin, *m_buildingSystem, *m_debrisSystem);
|
||||
m_aiSystem->tick(m_admin, m_factoryState, *m_debrisSystem);
|
||||
// Module systems perform the world mutation (collection/delivery, healing).
|
||||
// Each emits its tool beams and applies its own delayed (mid-beam) effects.
|
||||
m_salvagerSystem->tick(m_currentTick, *m_debrisSystem, *m_buildingSystem, m_beamFiredEvents);
|
||||
m_salvagerSystem->tick(m_currentTick, *m_debrisSystem, m_factoryState, m_beamFiredEvents);
|
||||
m_repairSystem->tick(m_currentTick, m_beamFiredEvents);
|
||||
|
||||
// Step 8: combat resolution
|
||||
|
||||
Reference in New Issue
Block a user