载入中...
搜索中...
未找到
RTSRestore.cpp
浏览该文件的文档.
1#include <algorithm>
2#include <unordered_set>
3#include "rts/RTS.h"
5
6namespace eve::rts {
9 if ((snapshot.version != 1 && snapshot.version != 2) || snapshot.units.size() != unitCount() ||
10 snapshot.buildings.size() != buildingCount() || snapshot.resourceNodes.size() != resourceNodeCount() ||
11 snapshot.players.size() != playerCount() || snapshot.factions.size() != factionCount() ||
12 snapshot.matches.size() != matchCount())
14 DiagnosticCode::Conflict, "RTS snapshot topology/version does not match this module", "snapshot"));
15
16 auto resolve = [&](SubjectRef subject) -> ecs::Entity* {
17 if (!subject.isValid()) return nullptr;
18 if (auto* value = findUnit(subject)) return value;
19 if (auto* value = findBuilding(subject)) return value;
20 if (auto* value = findResourceNode(subject)) return value;
21 for (const auto& handle : players_)
22 if (subjectOf(handle) == subject) return ecs::try_get(handle);
23 for (const auto& handle : factions_)
24 if (subjectOf(handle) == subject) return ecs::try_get(handle);
25 for (const auto& handle : matches_)
26 if (subjectOf(handle) == subject) return ecs::try_get(handle);
27 return nullptr;
28 };
29 auto findPlayer = [&](SubjectRef subject) -> Player* {
30 for (const auto& value : players_)
31 if (subjectOf(value) == subject) return dynamic_cast<Player*>(ecs::try_get(value));
32 return nullptr;
33 };
34 auto findFaction = [&](SubjectRef subject) -> Faction* {
35 for (const auto& value : factions_)
36 if (subjectOf(value) == subject) return dynamic_cast<Faction*>(ecs::try_get(value));
37 return nullptr;
38 };
39 auto findMatch = [&](SubjectRef subject) -> Match* {
40 for (const auto& value : matches_)
41 if (subjectOf(value) == subject) return dynamic_cast<Match*>(ecs::try_get(value));
42 return nullptr;
43 };
44 std::unordered_set<SubjectRef> seen;
45 auto requireUnique = [&](SubjectRef subject) {
46 return subject.isValid() && resolve(subject) != nullptr && seen.insert(subject).second;
47 };
48 for (const auto& value : snapshot.units)
49 if (!requireUnique(value.subject) || findUnit(value.subject) == nullptr)
51 DiagnosticCode::Conflict, "RTS snapshot contains an unknown/duplicate unit", "units.subject"));
52 for (const auto& value : snapshot.buildings)
53 if (!requireUnique(value.subject) || findBuilding(value.subject) == nullptr)
55 DiagnosticCode::Conflict, "RTS snapshot contains an unknown/duplicate building", "buildings.subject"));
56 for (const auto& value : snapshot.resourceNodes)
57 if (!requireUnique(value.subject) || findResourceNode(value.subject) == nullptr)
59 "RTS snapshot contains an unknown/duplicate resource node",
60 "resourceNodes.subject"));
61 for (const auto& value : snapshot.players)
62 if (!requireUnique(value.subject) || findPlayer(value.subject) == nullptr)
64 DiagnosticCode::Conflict, "RTS snapshot contains an unknown/duplicate player", "players.subject"));
65 for (const auto& value : snapshot.factions)
66 if (!requireUnique(value.subject) || findFaction(value.subject) == nullptr)
68 DiagnosticCode::Conflict, "RTS snapshot contains an unknown/duplicate faction", "factions.subject"));
69 for (const auto& value : snapshot.matches)
70 if (!requireUnique(value.subject) || findMatch(value.subject) == nullptr)
72 DiagnosticCode::Conflict, "RTS snapshot contains an unknown/duplicate match", "matches.subject"));
73
74 auto validType = [&](SubjectRef subject, auto* tag) {
75 using T = std::remove_pointer_t<decltype(tag)>;
76 return !subject.isValid() || dynamic_cast<T*>(resolve(subject)) != nullptr;
77 };
78 auto validUnits = [&](const std::vector<SubjectRef>& subjects) {
79 return std::all_of(subjects.begin(), subjects.end(),
80 [&](SubjectRef subject) { return validType(subject, static_cast<Unit*>(nullptr)); });
81 };
82 for (const auto& value : snapshot.units) {
83 if (!validType(value.faction, static_cast<Faction*>(nullptr)) ||
84 !validType(value.worker.resourceNode, static_cast<ResourceNode*>(nullptr)) ||
85 !validType(value.worker.dropoff, static_cast<Building*>(nullptr)) ||
86 (value.container.isValid() && !validType(value.container, static_cast<Unit*>(nullptr)) &&
87 !validType(value.container, static_cast<Building*>(nullptr))) ||
88 !validUnits(value.occupants) || !validType(value.supplyTarget, static_cast<Unit*>(nullptr)) ||
89 !validType(value.fireSupportRequester, static_cast<Unit*>(nullptr)))
91 DiagnosticCode::Conflict, "RTS unit snapshot contains a relationship of the wrong type",
92 "units.relationships"));
93 }
94 for (const auto& value : snapshot.buildings) {
95 if (!validType(value.faction, static_cast<Faction*>(nullptr)) || !validUnits(value.builders) ||
96 !validType(value.capturingFaction, static_cast<Faction*>(nullptr)) ||
97 (value.rallyCommandTarget.isValid() && resolve(value.rallyCommandTarget) == nullptr) ||
98 !validType(value.rallyTransport, static_cast<Unit*>(nullptr)) || !validUnits(value.reinforcements) ||
99 !validUnits(value.occupants))
101 DiagnosticCode::Conflict, "RTS building snapshot contains a relationship of the wrong type",
102 "buildings.relationships"));
103 }
104 for (const auto& value : snapshot.resourceNodes)
105 if (!validUnits(value.workers))
107 DiagnosticCode::Conflict, "RTS resource snapshot contains a non-unit worker", "resourceNodes.workers"));
108 for (const auto& value : snapshot.players)
109 if (!validUnits(value.units) ||
110 !std::all_of(value.buildings.begin(), value.buildings.end(),
111 [&](SubjectRef id) { return validType(id, static_cast<Building*>(nullptr)); }))
113 DiagnosticCode::Conflict, "RTS player snapshot contains an invalid selection", "players.selection"));
114 for (const auto& value : snapshot.factions)
115 if (!validUnits(value.units) ||
116 !std::all_of(value.buildings.begin(), value.buildings.end(),
117 [&](SubjectRef id) { return validType(id, static_cast<Building*>(nullptr)); }))
119 DiagnosticCode::Conflict, "RTS faction snapshot contains invalid membership", "factions.members"));
120 for (const auto& value : snapshot.matches)
121 if (!std::all_of(value.participants.begin(), value.participants.end(), [&](const auto& participant) {
122 return validType(participant.faction, static_cast<Faction*>(nullptr));
123 }))
125 "RTS match snapshot contains an invalid participant",
126 "matches.participants"));
127
128 RTSProjectileSystem stagedProjectiles;
129 if (!snapshot.projectiles.runtime.slots.empty() || !snapshot.projectiles.payloads.empty()) {
130 auto validProjectiles = stagedProjectiles.restore(snapshot.projectiles, resolve);
131 if (!validProjectiles) return validProjectiles;
132 }
133
134 auto prepareOrders = [&](const OrderComponent::Snapshot& source,
135 const std::map<std::string, SubjectRef>& targets) -> Result<OrderComponent::Snapshot> {
136 auto candidate = source;
137 for (const auto& [id, subject] : targets) {
138 auto found = candidate.extended.find(id);
139 auto* target = resolve(subject);
140 if (found == candidate.extended.end() || target == nullptr)
142 DiagnosticCode::Conflict, "RTS snapshot order target cannot be rebound", "orders.target"));
143 found->second.targetEntity = ecs::handle_of(target);
144 }
145 OrderComponent validator;
146 auto valid = validator.restoreState(candidate);
148 return Result<OrderComponent::Snapshot>::success(std::move(candidate));
149 };
150 std::vector<OrderComponent::Snapshot> unitOrders;
151 std::vector<OrderComponent::Snapshot> buildingOrders;
152 unitOrders.reserve(snapshot.units.size());
153 buildingOrders.reserve(snapshot.buildings.size());
154 for (const auto& value : snapshot.units) {
155 auto prepared = prepareOrders(value.orders, value.orderTargets);
156 if (!prepared) return Result<void>::failure(prepared.status());
157 auto* unit = findUnit(value.subject);
158 auto attributes = value.attributes;
159 attributes.owner = unit->identity()->self;
160 AttributeComponent attributeValidator = unit->attributes()->values;
161 auto currentAttributes = RTSUnitAttributeAdapter::snapshot(*unit);
162 if (!currentAttributes) return Result<void>::failure(currentAttributes.status());
163 auto validAttributes = attributeValidator.restore(attributes, currentAttributes.value().capturedRevision);
164 if (!validAttributes) return validAttributes;
165 TagSet tagValidator;
166 for (const auto& tag : value.tags) {
167 auto validTag = tagValidator.add(tag);
168 if (!validTag) return validTag;
169 }
170 RTSEffectAdapter effectValidator;
171 auto validEffects = effectValidator.restore(value.effects);
172 if (!validEffects) return validEffects;
173 unitOrders.push_back(std::move(prepared).takeValue());
174 }
175 for (const auto& value : snapshot.buildings) {
176 auto prepared = prepareOrders(value.orders, value.orderTargets);
177 if (!prepared) return Result<void>::failure(prepared.status());
178 TagSet tagValidator;
179 for (const auto& tag : value.tags) {
180 auto validTag = tagValidator.add(tag);
181 if (!validTag) return validTag;
182 }
183 RTSEffectAdapter effectValidator;
184 auto validEffects = effectValidator.restore(value.effects);
185 if (!validEffects) return validEffects;
186 ProductionComponent validator;
187 auto valid = validator.restore(value.productionJson);
188 if (!valid) return valid;
189 buildingOrders.push_back(std::move(prepared).takeValue());
190 }
191
192 auto groups = prepareMovementGroups(snapshot);
193 if (!groups) return Result<void>::failure(groups.status());
194 auto handle = [&](SubjectRef subject) {
195 auto* entity = resolve(subject);
196 return entity ? ecs::handle_of(entity) : ecs::EntityHandle{};
197 };
198 for (std::size_t index = 0; index < snapshot.units.size(); ++index) {
199 const auto& value = snapshot.units[index];
200 Unit* unit = findUnit(value.subject);
201 unit->definition()->id = value.definition;
202 unit->identity()->displayName = value.displayName;
203 auto attributes = value.attributes;
204 attributes.owner = unit->identity()->self;
205 auto currentAttributes = RTSUnitAttributeAdapter::snapshot(*unit);
206 if (!currentAttributes) return Result<void>::failure(currentAttributes.status());
207 auto restoredAttributes =
208 RTSUnitAttributeAdapter::restore(*unit, attributes, currentAttributes.value().capturedRevision);
209 if (!restoredAttributes) return restoredAttributes;
210 unit->tags()->values = TagSet{};
211 for (const auto& tag : value.tags) {
212 auto added = unit->tags()->values.add(tag);
213 if (!added) return added;
214 }
215 auto restoredEffects = unit->effects()->values.restore(value.effects);
216 if (!restoredEffects) return restoredEffects;
217 if (value.faction.isValid())
218 unit->faction()->link = FactionLink::bind(handle(value.faction)).value();
219 else
220 unit->faction()->link = {};
221 *unit->motion() = value.motion;
222 *unit->navigation() = value.navigation;
223 unit->navigation()->formationSpeedFactor = 1.f;
224 unit->navigation()->formationTarget.reset();
225 unit->navigation()->trafficRecoveryTarget.reset();
226 *unit->vision() = value.vision;
227 unit->worker()->resourceType = value.worker.resourceType;
228 unit->worker()->cargo = value.worker.cargo;
229 unit->worker()->capacity = value.worker.capacity;
230 unit->worker()->gatherRate = value.worker.gatherRate;
231 unit->worker()->buildRate = value.worker.buildRate;
232 unit->worker()->repairRate = value.worker.repairRate;
233 unit->worker()->autoAssign = value.worker.autoAssign;
234 if (value.worker.resourceNode.isValid())
235 unit->worker()->resourceNode = ResourceNodeLink::bind(handle(value.worker.resourceNode)).value();
236 else
237 unit->worker()->resourceNode = {};
238 if (value.worker.dropoff.isValid())
239 unit->worker()->dropoff = BuildingLink::bind(handle(value.worker.dropoff)).value();
240 else
241 unit->worker()->dropoff = {};
242 *unit->combat() = value.combat;
243 unit->combat()->target = handle(value.combatTarget);
244 *unit->durability() = value.durability;
245 unit->durability()->state.subject = value.subject;
246 *unit->shield() = value.shield;
247 *unit->veterancy() = value.veterancy;
248 *unit->command() = value.command;
249 unit->command()->source = handle(value.commandSource);
250 unit->command()->uplink = handle(value.commandUplink);
251 *unit->abilities() = value.abilities;
252 if (unit->abilities()->channel) unit->abilities()->channel->target = handle(value.abilityTarget);
253 *unit->capture() = value.capture;
254 unit->containment()->capacity = value.containmentCapacity;
255 unit->containment()->occupants.clear();
256 for (auto subject : value.occupants) unit->containment()->occupants.push_back(handle(subject));
257 if (value.container.isValid())
258 unit->containment()->container = ContainerLink::bind(handle(value.container)).value();
259 else
260 unit->containment()->container = {};
261 *unit->supply() = value.supply;
262 unit->supply()->assignedTarget = handle(value.supplyTarget);
263 unit->supply()->convoyLeader = handle(value.convoyLeader);
264 *unit->morale() = value.morale;
265 *unit->artillery() = value.artillery;
266 unit->artillery()->fireSupportRequester = handle(value.fireSupportRequester);
267 unit->artillery()->observedFireSpotter = handle(value.observedFireSpotter);
268 *unit->tactics() = value.tactics;
269 unit->tactics()->escortTarget = handle(value.escortTarget);
270 *unit->technology() = value.technology;
271 auto restored = unit->orders()->values.restoreState(unitOrders[index]);
272 if (!restored) return restored;
273 }
274 for (std::size_t index = 0; index < snapshot.buildings.size(); ++index) {
275 const auto& value = snapshot.buildings[index];
276 Building* building = findBuilding(value.subject);
277 building->definition()->id = value.definition;
278 building->identity()->displayName = value.displayName;
279 building->tags()->values = TagSet{};
280 for (const auto& tag : value.tags) {
281 auto added = building->tags()->values.add(tag);
282 if (!added) return added;
283 }
284 auto restoredEffects = building->effects()->values.restore(value.effects);
285 if (!restoredEffects) return restoredEffects;
286 if (value.faction.isValid())
287 building->faction()->link = FactionLink::bind(handle(value.faction)).value();
288 else
289 building->faction()->link = {};
290 const auto placementLink = building->placement()->link;
291 *building->placement() = value.placement;
292 building->placement()->link = placementLink;
293 *building->construction() = value.construction;
294 building->construction()->builders.clear();
295 for (auto subject : value.builders) building->construction()->builders.push_back(handle(subject));
296 *building->integrity() = value.integrity;
297 building->integrity()->state.subject = value.subject;
298 *building->shield() = value.shield;
299 *building->capture() = value.capture;
300 building->capture()->capturingFaction = handle(value.capturingFaction);
301 *building->dropoff() = value.dropoff;
302 *building->rally() = value.rally;
303 building->rally()->transport = handle(value.rallyTransport);
304 building->rally()->command.targetEntity = handle(value.rallyCommandTarget);
305 building->rally()->reinforcements.clear();
306 for (auto subject : value.reinforcements) building->rally()->reinforcements.push_back(handle(subject));
307 *building->combat() = value.combat;
308 building->combat()->target = handle(value.combatTarget);
309 building->combat()->airDefenseNetworkRoot = handle(value.airDefenseNetworkRoot);
310 *building->garrison() = value.garrison;
311 building->garrison()->occupants.clear();
312 for (auto subject : value.occupants) building->garrison()->occupants.push_back(handle(subject));
313 *building->supply() = value.supply;
314 *building->vision() = value.vision;
315 *building->technology() = value.technology;
316 *building->infrastructure() = value.infrastructure;
317 *building->command() = value.command;
318 *building->indirectFire() = value.indirectFire;
319 auto production = building->production()->values.restore(value.productionJson);
320 if (!production) return production;
321 auto orders = building->orders()->values.restoreState(buildingOrders[index]);
322 if (!orders) return orders;
323 }
324 for (const auto& value : snapshot.resourceNodes) {
325 auto* node = findResourceNode(value.subject);
326 node->identity()->displayName = value.displayName;
327 *node->position() = value.position;
328 *node->stock() = value.stock;
329 node->harvest()->capacity = value.workerCapacity;
330 node->harvest()->workers.clear();
331 for (auto subject : value.workers) node->harvest()->workers.push_back(handle(subject));
332 }
333 for (const auto& value : snapshot.players) {
334 auto* player = findPlayer(value.subject);
335 player->identity()->displayName = value.displayName;
336 player->selection()->units.clear();
337 for (auto subject : value.units) player->selection()->units.push_back(handle(subject));
338 player->selection()->buildings.clear();
339 for (auto subject : value.buildings) player->selection()->buildings.push_back(handle(subject));
340 }
341 for (const auto& value : snapshot.factions) {
342 auto* faction = findFaction(value.subject);
343 faction->identity()->displayName = value.displayName;
344 faction->members()->units.clear();
345 for (auto subject : value.units) faction->members()->units.push_back(handle(subject));
346 faction->members()->buildings.clear();
347 for (auto subject : value.buildings) faction->members()->buildings.push_back(handle(subject));
348 *faction->strategy() = value.strategy;
349 *faction->workforce() = value.workforce;
350 *faction->productionPolicy() = value.productionPolicy;
351 *faction->intel() = value.intel;
352 *faction->technology() = value.technology;
353 }
354 for (const auto& value : snapshot.matches) {
355 auto* match = findMatch(value.subject);
356 *match->rules() = value.rules;
357 *match->state() = value.state;
358 *match->events() = value.events;
359 match->participants()->entries.clear();
360 for (const auto& participant : value.participants) {
362 entry.faction = FactionLink::bind(handle(participant.faction)).value();
363 entry.team = participant.team;
364 entry.eliminated = participant.eliminated;
365 entry.surrendered = participant.surrendered;
366 entry.reason = participant.reason;
367 match->participants()->entries.push_back(std::move(entry));
368 }
369 }
370 movementGroups_ = std::move(groups).takeValue();
371 for (auto& group : movementGroups_)
372 for (std::size_t i = 0; i < group.handles.size(); ++i)
373 group.epochs[i] = static_cast<Unit*>(ecs::try_get(group.handles[i]))->orders()->values.membershipEpoch_;
374 projectiles_ = std::move(stagedProjectiles);
376}
377
379 if (unitCount() != 0 || buildingCount() != 0 || resourceNodeCount() != 0 || playerCount() != 0 ||
380 factionCount() != 0 || matchCount() != 0)
382 DiagnosticCode::Conflict, "RTS snapshot topology can only be rebuilt into an empty module", "snapshot"));
383 if (snapshot.version != 1 && snapshot.version != 2)
385 Diagnostic::error(DiagnosticCode::Conflict, "unsupported RTS snapshot version", "snapshot.version"));
386
387 // A topology rebuild can follow destruction performed while an ECS view was
388 // deferred. Publish those tombstones before allocating replacement roots so
389 // component storage (notably effect timelines) cannot be reused half-staged.
390 ecs::commit();
391
392 std::unordered_set<SubjectRef> subjects;
393 auto reserveSubject = [&](SubjectRef subject) { return subject.isValid() && subjects.insert(subject).second; };
394 for (const auto& value : snapshot.units)
395 if (!reserveSubject(value.subject))
397 Diagnostic::error(DiagnosticCode::Conflict, "invalid/duplicate unit subject", "units.subject"));
398 for (const auto& value : snapshot.buildings)
399 if (!reserveSubject(value.subject))
401 Diagnostic::error(DiagnosticCode::Conflict, "invalid/duplicate building subject", "buildings.subject"));
402 for (const auto& value : snapshot.resourceNodes)
403 if (!reserveSubject(value.subject))
405 DiagnosticCode::Conflict, "invalid/duplicate resource subject", "resourceNodes.subject"));
406 for (const auto& value : snapshot.players)
407 if (!reserveSubject(value.subject))
409 Diagnostic::error(DiagnosticCode::Conflict, "invalid/duplicate player subject", "players.subject"));
410 for (const auto& value : snapshot.factions)
411 if (!reserveSubject(value.subject))
413 Diagnostic::error(DiagnosticCode::Conflict, "invalid/duplicate faction subject", "factions.subject"));
414 for (const auto& value : snapshot.matches)
415 if (!reserveSubject(value.subject))
417 Diagnostic::error(DiagnosticCode::Conflict, "invalid/duplicate match subject", "matches.subject"));
418
419 auto failAndClear = [&](const Status& status) {
420 clearOwnedRoots();
422 };
423 for (const auto& value : snapshot.factions) {
424 auto created = newFaction(value.subject);
425 if (!created) return failAndClear(created.status());
426 }
427 for (const auto& value : snapshot.units) {
428 auto created = newUnit(value.subject, value.definition);
429 if (!created) return failAndClear(created.status());
430 auto materialized = materialize(*created.value());
431 if (!materialized) return failAndClear(materialized.status());
432 }
433 for (const auto& value : snapshot.buildings) {
434 auto created = newBuilding(value.subject, value.definition);
435 if (!created) return failAndClear(created.status());
436 auto materialized = materialize(*created.value());
437 if (!materialized) return failAndClear(materialized.status());
438 }
439 for (const auto& value : snapshot.resourceNodes) {
440 auto created = newResourceNode(value.subject, value.stock.resourceType, value.stock.maximum,
441 {value.position.x, value.position.y}, value.workerCapacity);
442 if (!created) return failAndClear(created.status());
443 }
444 for (const auto& value : snapshot.players) {
445 auto created = newPlayer(value.subject);
446 if (!created) return failAndClear(created.status());
447 }
448 for (const auto& value : snapshot.matches) {
449 auto created = newMatch(value.subject);
450 if (!created) return failAndClear(created.status());
451 }
452 auto restored = restoreState(snapshot);
453 if (!restored) return failAndClear(restored.status());
454 return restored;
455}
456
457} // namespace eve::rts
LogicalId target
double value
int subject
Definition AnimSmr.cpp:163
building::EdgeCurveGroup group
wgpu::PopErrorScopeStatus status
bool valid
const std::string * tag
uint32_t groups
Definition OnnxGpgpu.cpp:39
PrimitiveHandle handle
RTS module owner and phase-one composition profile entry point.
const RoadNode * node
bool found
int created
TacticalUnit * unit
uint32_t index
const UnitySourceAsset & source
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
Structured status and zero or more diagnostics for an operation.
Definition Status.h:68
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
Strong, domain-neutral reference to a runtime subject.
Definition SubjectRef.h:26
Canonical attributes component adapter, backed by attributes::AttributeSet.
Definition RTSTypes.h:323
Result< void > restore(const eve::attributes::AttributeProjectionSnapshot &snapshot, Revision expectedRevision)
Restore selected values after generation and revision checks.
Definition RTSTypes.cpp:338
RTS building domain root with placement and production composition.
Definition RTSTypes.h:840
Faction domain root; membership is a set of typed runtime handles.
Definition RTSTypes.h:1178
Independent match composition root; factions may participate in different matches.
Definition RTSTypes.h:1295
Generic orders component adapter; the queue remains the sole order owner.
Definition RTSTypes.h:385
Result< void > restoreState(const Snapshot &snapshot)
Transactionally restore a complete RTS order projection.
Definition RTSTypes.cpp:501
Player domain root; selection is RTS-local, authority/economy/social are links.
Definition RTSTypes.h:1119
Production adapter whose queue owns all task state.
Definition RTSTypes.h:438
Result< void > restore(std::string_view json)
Transactionally restore the canonical production queue.
Definition RTSTypes.cpp:630
RTS adapter that keeps the common container as the sole instance owner.
Definition RTSEffects.h:77
eve::Result< void > restore(const RTSEffectSnapshot &snapshot)
Restore effects and target state, invalidating prior handles.
RTS impact adapter over the canonical pooled weapon projectile trajectory runtime.
Definition RTSSystems.h:653
Result< void > restore(const RTSProjectileSystemSnapshot &snapshot, const ProjectileSubjectResolver &resolver)
Validate and atomically restore shared trajectories plus RTS payloads.
static eve::Result< void > restore(Unit &unit, const eve::attributes::AttributeProjectionSnapshot &snapshot, eve::Revision expectedRevision)
Restore selected unit combat stats after owner/revision checks.
static eve::Result< eve::attributes::AttributeProjectionSnapshot > snapshot(Unit &unit)
Capture selected unit combat stats with owner generation and revision.
std::size_t factionCount() const noexcept
Return the number of live Faction roots owned by this module.
Definition RTS.cpp:3622
Result< Player * > newPlayer(SubjectRef subject)
Create and own one Player root with a valid subject identity.
Definition RTS.cpp:595
Match * findMatch(SubjectRef subject) const noexcept
Resolve a module-owned match by persistent subject identity.
Definition RTS.cpp:3626
std::size_t matchCount() const noexcept
Return the number of live Match roots owned by this module.
Definition RTS.cpp:3623
Result< Building * > newBuilding(SubjectRef subject, LogicalId definition={})
Create and own one Building root.
Definition RTS.cpp:550
ResourceNode * findResourceNode(SubjectRef subject) const noexcept
Resolve a module-owned resource node by persistent subject identity.
Definition RTS.cpp:893
Result< Match * > newMatch(SubjectRef subject)
Create and own one independent RTS match composition root.
Definition RTS.cpp:798
Building * findBuilding(SubjectRef subject) const noexcept
Resolve a module-owned building by persistent subject identity.
Definition RTS.cpp:891
std::size_t buildingCount() const noexcept
Return the number of live Building roots owned by this module.
Definition RTS.cpp:3619
std::size_t resourceNodeCount() const noexcept
Return the number of live resource nodes owned by this module.
Definition RTS.cpp:3620
Result< Faction * > newFaction(SubjectRef subject)
Create and own one Faction root with a valid subject identity.
Definition RTS.cpp:610
std::size_t playerCount() const noexcept
Return the number of live Player roots owned by this module.
Definition RTS.cpp:3621
Result< ResourceNode * > newResourceNode(SubjectRef subject, std::string resourceType, float amount, WorldPosition position, std::size_t workerCapacity=1)
Create and own one harvestable resource node.
Definition RTS.cpp:571
Unit * findUnit(SubjectRef subject) const noexcept
Resolve a module-owned unit by persistent subject identity.
Definition RTS.cpp:889
Result< void > rebuildState(const RTSStateSnapshot &snapshot)
Materialize a complete snapshot into an empty RTS module.
Result< Unit * > newUnit(SubjectRef subject, LogicalId definition={})
Create and own one Unit root.
Definition RTS.cpp:519
std::size_t unitCount() const noexcept
Return the number of live Unit roots owned by this module.
Definition RTS.cpp:3618
Result< void > restoreState(const RTSStateSnapshot &snapshot)
Validate and atomically restore an exact-topology RTS root snapshot.
Definition RTSRestore.cpp:8
Faction * findFaction(SubjectRef subject) const noexcept
Resolve a module-owned faction by persistent subject identity.
Definition RTS.cpp:3625
Harvestable RTS resource node; deposited balances are owned by an external resource account.
Definition RTSTypes.h:1071
Entity-local sorted tags; this is the RTS entity's tag authority.
Definition RTSTypes.h:153
const std::vector< std::string > & values() const noexcept
Return tags in deterministic order.
Definition RTSTypes.h:162
Result< void > add(std::string_view tag)
Add a tag in deterministic lexical order.
Definition RTSTypes.cpp:233
RTS unit domain root.
Definition RTSTypes.h:495
SubjectRef subjectOf(ecs::Entity *entity)
Complete RTS order projection snapshot; entity handles must be rebound by the owning domain.
Definition RTSTypes.h:388
std::vector< RTSProjectilePayloadSnapshot > payloads
Definition RTSSystems.h:646
weapon::ProjectileRuntimeSnapshot runtime
Definition RTSSystems.h:645
Complete RTS-owned state; v2 adds movement groups, v1 imports with no groups. @cost Linear in saved e...
std::vector< RTSPlayerSnapshot > players
std::vector< RTSResourceNodeSnapshot > resourceNodes
std::vector< RTSUnitSnapshot > units
std::vector< RTSFactionSnapshot > factions
std::vector< RTSMatchSnapshot > matches
std::vector< RTSBuildingSnapshot > buildings
RTSProjectileSystemSnapshot projectiles
std::vector< ProjectileSlotSnapshot > slots