载入中...
搜索中...
未找到
RTSBuildingProduction.cpp
浏览该文件的文档.
1#include "rts/RTSSystems.h"
2
3#include <algorithm>
4#include <optional>
5#include <utility>
6#include <vector>
7
8namespace eve::rts {
9
13 if (step.delta.nanoseconds() < 0)
15 DiagnosticCode::InvalidArgument, "RTS production step delta must be non-negative", "step.delta"));
16 std::size_t processed = 0;
17 struct Settlement {
18 ecs::EntityHandle building;
20 };
21 std::vector<Settlement> settlements;
22 std::vector<LifecycleEvent> clearedEvents;
23 {
24 auto view = ecs::View<Building, Building::Identity, Building::Production>();
25 for (auto it = view.begin(); it != view.end(); ++it) {
26 auto [identity, production] = *it;
27 Building* building = identity == nullptr ? nullptr : dynamic_cast<Building*>(ecs::try_get(identity->self));
28 if (building == nullptr || &*building->identity() != identity) continue;
29 auto advanced = production->values.advance(step);
30 if (!advanced) return Result<std::size_t>::failure(advanced.status());
31 advanced.value();
32 ++processed;
33 if (!spawn) continue;
34 std::vector<production::ProductionTask> completed = production->values.readyToSettle("unit");
35 for (int index = 0; index < production->values.taskCount(); ++index) {
36 auto task = production->values.taskAt(index);
37 if (task && task->get().kind == "unit" && task->get().state == production::TaskState::Completed &&
38 !task->get().settlementRequired)
39 completed.push_back(task->get());
40 }
41 if (building->rally()->productionSpawnBlocked &&
42 std::none_of(completed.begin(), completed.end(),
43 [&](const auto& task) { return task.id == building->rally()->blockedProductionTask; })) {
44 building->rally()->productionSpawnBlocked = false;
45 building->rally()->blockedProductionTask.clear();
46 clearedEvents.push_back({LifecycleEventKind::ProductionSpawnCleared, identity->subject, {}, {}, 0.0});
47 }
48 for (const auto& task : completed) {
49 settlements.push_back({identity->self, task});
50 }
51 }
52 }
53 // End the ECS deferred-mutation scope before factories publish stable unit pointers.
54 if (events)
55 for (const auto& event : clearedEvents) events(event, step.tick);
56 for (const auto& settlement : settlements) {
57 auto* building = dynamic_cast<Building*>(ecs::try_get(settlement.building));
58 if (building == nullptr)
60 DiagnosticCode::StaleHandle, "RTS producer disappeared during production settlement", "production"));
61 auto& settled = building->rally()->settledProductionTasks;
62 if (std::find(settled.begin(), settled.end(), settlement.task.id) != settled.end()) {
63 if (settlement.task.settlementRequired) {
65 receipt.settlementId = "rts.unit:" + settlement.task.id;
66 auto committed = building->production()->values.settle(settlement.task.id, std::move(receipt));
67 if (!committed) return Result<std::size_t>::failure(committed.status());
68 }
69 continue;
70 }
71 std::optional<WorldPosition> spawnPosition;
72 if (position) {
73 auto available = position(*building, settlement.task);
74 if (!available) return Result<std::size_t>::failure(available.status());
75 spawnPosition = std::move(available).takeValue();
76 if (!spawnPosition) {
77 const bool newlyBlocked = !building->rally()->productionSpawnBlocked;
78 building->rally()->productionSpawnBlocked = true;
79 building->rally()->blockedProductionTask = settlement.task.id;
80 if (newlyBlocked && events)
82 building->identity()->subject,
83 {},
84 settlement.task.product,
85 0.0},
86 step.tick);
87 continue;
88 }
89 }
90 const WorldPosition requested =
91 spawnPosition.value_or(WorldPosition{building->placement()->worldX, building->placement()->worldY});
92 auto created = spawn(*building, settlement.task, requested);
93 if (!created) return Result<std::size_t>::failure(created.status());
94 const auto outcome = std::move(created).takeValue();
95 if (outcome.state == ProductionSpawnState::Blocked) {
96 if (outcome.unit != nullptr)
98 DiagnosticCode::InvariantViolation, "Blocked production published a unit", "production.spawn"));
99 const bool newlyBlocked = !building->rally()->productionSpawnBlocked;
100 building->rally()->productionSpawnBlocked = true;
101 building->rally()->blockedProductionTask = settlement.task.id;
102 if (newlyBlocked && events)
104 building->identity()->subject,
105 {},
106 settlement.task.product,
107 0.0},
108 step.tick);
109 continue;
110 }
111 Unit* unit = outcome.unit;
112 if (outcome.state != ProductionSpawnState::Created || unit == nullptr)
114 DiagnosticCode::Failed, "RTS production factory returned a null unit", "production.spawn"));
115 const bool wasBlocked = building->rally()->productionSpawnBlocked;
116 building->rally()->productionSpawnBlocked = false;
117 building->rally()->blockedProductionTask.clear();
118 if (wasBlocked && events)
120 unit->identity()->subject, settlement.task.product, 0.0},
121 step.tick);
122 unit->tactics()->combatGroup = building->rally()->combatGroup;
123 building->rally()->reinforcements.push_back(unit->identity()->self);
124
125 bool boarded = false;
126 auto* transport = dynamic_cast<Unit*>(ecs::try_get(building->rally()->transport));
127 if (transport != nullptr && transport->durability()->alive && transport->containment()->capacity > 0 &&
128 transport->containment()->occupants.size() < transport->containment()->capacity &&
129 FactionRelationSystem::isAllied(transport->faction()->link, building->faction()->link)) {
130 auto link = ContainerLink::bind(transport->identity()->self);
131 if (!link) return Result<std::size_t>::failure(link.status());
132 unit->containment()->container = std::move(link).takeValue();
133 transport->containment()->occupants.push_back(unit->identity()->self);
134 boarded = true;
135 }
136 if (!boarded && building->rally()->enabled) {
137 auto queued = unit->orders()->values.replace(building->rally()->command);
138 if (!queued) return Result<std::size_t>::failure(queued.status());
139 std::move(queued).takeValue();
140 }
141 settled.push_back(settlement.task.id);
142 if (settlement.task.settlementRequired) {
144 receipt.settlementId = "rts.unit:" + settlement.task.id;
145 auto committed = building->production()->values.settle(settlement.task.id, std::move(receipt));
146 if (!committed) return Result<std::size_t>::failure(committed.status());
147 }
148 if (events)
149 events({LifecycleEventKind::UnitProduced, building->identity()->subject, unit->identity()->subject,
150 settlement.task.product, 1.0},
151 step.tick);
152 ++processed;
153 }
155}
156
157} // namespace eve::rts
int subject
Definition AnimSmr.cpp:163
std::array< float, 3 > position
size_t queued
Definition OnnxGpgpu.cpp:60
Deterministic phase-one RTS systems and their ECS contracts.
glm::mat4 view
int created
TacticalUnit * unit
Battle::Events events
float step
Definition TreeMesh.cpp:314
uint32_t index
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
static Result< std::size_t > step(const SimulationStep &step, const ProductionSpawn &spawn={}, const ProductionSpawnPosition &position={}, const LifecycleEventSink &events={})
Advance all buildings and settle newly completed unit tasks through the game-owned factory.
RTS building domain root with placement and production composition.
Definition RTSTypes.h:840
static bool isAllied(Faction *left, Faction *right) noexcept
Return true when both live factions are identical or share a team in a common Match.
RTS unit domain root.
Definition RTSTypes.h:495
std::function< void(const LifecycleEvent &, SimulationTick)> LifecycleEventSink
Read-only observer invoked after a non-combat lifecycle transition commits.
Definition RTSSystems.h:127
std::function< Result< ProductionSpawnOutcome >(Building &, const production::ProductionTask &, WorldPosition)> ProductionSpawn
Game-owned factory receiving the requested production exit position. The factory owns final placement...
Definition RTSSystems.h:729
std::function< Result< std::optional< WorldPosition > >(Building &, const production::ProductionTask &)> ProductionSpawnPosition
Game/map-owned deterministic exit probe; empty means every valid exit is currently occupied.
Definition RTSSystems.h:732
One deterministic fixed-step emitted by SimulationClock.
Definition Time.h:158
Owning proof that a domain consumer published one task exactly once.
Definition Production.h:46
A subject-agnostic continuous task retained for audit and save games.
Definition Production.h:158
Two-dimensional deterministic RTS world position.
Definition RTSTypes.h:48