载入中...
搜索中...
未找到
CrowdDocument.cpp
浏览该文件的文档.
32 if (!id || id->empty() || !x || !y || !radius || !wait || !std::isfinite(*x) || !std::isfinite(*y) ||
55 return eve::editing::failed<CrowdPathRecord>(EditorStatus::Rejected, RuleId("editor.crowd.invalid-path"),
68 return eve::editing::failed<CrowdPathRecord>(EditorStatus::Rejected, RuleId("editor.crowd.loop-point-count"),
74 return EditorValue::Object{{"id", agent.id.value()}, {"archetype", agent.archetype}, {"x", agent.x},
76 {"maximumSpeed", agent.maximumSpeed}, {"behavior", agent.behavior}, {"path", agent.path.value()}};
80 const auto string = [&](const char* key) -> const std::string* { const auto* v = field(value, key); return v ? v->getIf<std::string>() : nullptr; };
81 const auto number = [&](const char* key) -> const double* { const auto* v = field(value, key); return v ? v->getIf<double>() : nullptr; };
82 const auto* id = string("id"); const auto* archetype = string("archetype"); const auto* behavior = string("behavior");
84 const auto* heading = number("heading"); const auto* radius = number("radius"); const auto* speed = number("maximumSpeed");
86 if (!id || id->empty() || !archetype || !behavior || !behaviors.contains(*behavior) || !path || !x || !y ||
97 return eve::editing::failed<CrowdAgentRecord>(EditorStatus::Rejected, RuleId("editor.crowd.missing-agent-path"),
113 const auto* weightEntry = field(value, "weight"); const auto* enabledEntry = field(value, "enabled");
121 if (!id || id->empty() || !name || name->empty() || !kind || !kinds.contains(*kind) || !points ||
144 result.payload = std::move(payload); result.inverse = std::move(inverse); result.hasInverse = true;
175 if (type == "crowd.agent.set.v1") { auto value = parseAgent(payload); if (!value.ok()) return Result<void>::failure(value.status()); agents_.insert_or_assign(value.value().id, value.value()); }
176 else if (type == "crowd.zone.set.v1") { auto value = parseZone(payload); if (!value.ok()) return Result<void>::failure(value.status()); zones_.insert_or_assign(value.value().id, value.value()); }
177 else if (type == "crowd.path.set.v1") { auto value = parsePath(payload); if (!value.ok()) return Result<void>::failure(value.status()); paths_.insert_or_assign(value.value().id, value.value()); }
178 else if (type == "crowd.agent.delete.v1" || type == "crowd.zone.delete.v1" || type == "crowd.path.delete.v1") {
181 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.invalid-delete"),
183 const StableId stable(*id); std::size_t erased = type[6] == 'a' ? agents_.erase(stable) : (type[6] == 'z' ? zones_.erase(stable) : paths_.erase(stable));
185 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.crowd.object-not-found"),
188 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.unsupported-operation"),
197std::unique_ptr<IDomainOperationTarget> CrowdDocumentTarget::cloneDomainState() const { return std::make_unique<CrowdDocumentTarget>(*this); }
198Result<void> CrowdDocumentTarget::commitDomainState(std::unique_ptr<IDomainOperationTarget> candidate) {
201 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.invalid-staging-state"),
210Result<DomainOperation> CrowdDocumentTarget::makeSetAgent(const CrowdAgentRecord& record) const {
213 return eve::editing::failed<DomainOperation>(parsed.code(), RuleId("editor.crowd.invalid-agent"),
215 const auto found = agents_.find(record.id); return eve::editing::applied<DomainOperation>(operation("crowd.agent.set.v1", found == agents_.end() ? "crowd.agent.delete.v1" : "crowd.agent.set.v1", id_, agentValue(record), found == agents_.end() ? EditorValue(record.id.value()) : agentValue(found->second), record.id));
220 return eve::editing::failed<DomainOperation>(EditorStatus::NotFound, RuleId("editor.crowd.agent-not-found"),
228 return eve::editing::failed<DomainOperation>(parsed.code(), RuleId("editor.crowd.invalid-zone"),
232 operation("crowd.zone.set.v1", found == zones_.end() ? "crowd.zone.delete.v1" : "crowd.zone.set.v1", id_,
233 zoneValue(record), found == zones_.end() ? EditorValue(record.id.value()) : zoneValue(found->second),
239 return eve::editing::failed<DomainOperation>(EditorStatus::NotFound, RuleId("editor.crowd.zone-not-found"),
247 return eve::editing::failed<DomainOperation>(parsed.code(), RuleId("editor.crowd.invalid-path"),
251 operation("crowd.path.set.v1", found == paths_.end() ? "crowd.path.delete.v1" : "crowd.path.set.v1", id_,
252 pathValue(record), found == paths_.end() ? EditorValue(record.id.value()) : pathValue(found->second),
258 return eve::editing::failed<DomainOperation>(EditorStatus::NotFound, RuleId("editor.crowd.path-not-found"),
263 return eve::editing::failed<DomainOperation>(EditorStatus::Conflict, RuleId("editor.crowd.path-in-use"),
272 for (const auto& [id, agent] : agents_) if (!agent.path.empty() && !paths_.contains(agent.path)) result.push_back(eve::editing::ruleDiagnostic(eve::DiagnosticCode::NotFound, RuleId("editor.crowd.dangling-path"), DiagnosticSeverity::Error, "Agent " + id.value() + " references a missing path"));
273 for (const auto& [id, path] : paths_) for (std::size_t i=1;i<path.points.size();++i) if(path.points[i-1].x==path.points[i].x && path.points[i-1].y==path.points[i].y) result.push_back(eve::editing::ruleDiagnostic(eve::DiagnosticCode::PreconditionViolation, RuleId("editor.crowd.zero-path-segment"),DiagnosticSeverity::Warning,"Path " + id.value() + " contains a zero-length segment"));
281 if (budget <= 0) { result.status=EditorStatus::Rejected; result.diagnostics.push_back(eve::editing::ruleDiagnostic(eve::DiagnosticCode::InvalidArgument, RuleId("editor.crowd.invalid-overlay-budget"),DiagnosticSeverity::Error,"Overlay primitive budget must be positive")); return result; }
282 auto add=[&](CrowdOverlayPrimitive primitive){ if(static_cast<int>(result.primitives.size())>=budget) return false; result.primitives.push_back(std::move(primitive)); return true; };
283 for(const auto& [id,path]:paths_) for(std::size_t i=1;i<path.points.size();++i) if(!add({"line",id,{path.points[i-1].x,path.points[i-1].y,path.points[i].x,path.points[i].y},path.name})) goto exhausted;
284 for(const auto& [id,zone]:zones_) { for(std::size_t i=0;i<zone.points.size();++i) { const auto& a=zone.points[i]; const auto& b=zone.points[(i+1)%zone.points.size()]; if(!add({"line",id,{a[0],a[1],b[0],b[1]},zone.kind})) goto exhausted; } }
285 for(const auto& [id,agent]:agents_) if(!add({"circle",id,{agent.x,agent.y,agent.radius,agent.heading},agent.behavior})) goto exhausted;
288 result.status=EditorStatus::Rejected; result.diagnostics.push_back(eve::editing::ruleDiagnostic(eve::DiagnosticCode::PreconditionViolation, RuleId("editor.crowd.overlay-budget"),DiagnosticSeverity::Error,"Crowd overlay exceeds the primitive budget")); return result;
292 EditorValue::Array agents, zones, paths; for(const auto& [id,value]:agents_){(void)id;agents.push_back(agentValue(value));} for(const auto& [id,value]:zones_){(void)id;zones.push_back(zoneValue(value));} for(const auto& [id,value]:paths_){(void)id;paths.push_back(pathValue(value));}
293 return EditorValue::Object{{"schemaVersion",int64_t{1}},{"agents",std::move(agents)},{"zones",std::move(zones)},{"paths",std::move(paths)}};
297 const auto* versionEntry=field(snapshot,"schemaVersion"); const auto* agentsEntry=field(snapshot,"agents"); const auto* zonesEntry=field(snapshot,"zones"); const auto* pathsEntry=field(snapshot,"paths");
298 const auto* version=versionEntry?versionEntry->getIf<int64_t>():nullptr; const auto* agents=agentsEntry?agentsEntry->getIf<EditorValue::Array>():nullptr; const auto* zones=zonesEntry?zonesEntry->getIf<EditorValue::Array>():nullptr; const auto* paths=pathsEntry?pathsEntry->getIf<EditorValue::Array>():nullptr;
300 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.invalid-snapshot"),
309 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.duplicate-path"),
318 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.duplicate-zone"),
327 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.duplicate-agent"),
332 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.crowd.invalid-snapshot-reference"),
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
const std::string & value() const noexcept
Returns the exact legacy or canonical compatibility spelling.
Definition Identity.h:362
UI-neutral agent/zone/path document with reversible domain operations.
Definition CrowdDocument.h:83
Result< void > commitDomainState(std::unique_ptr< IDomainOperationTarget > candidate) override
Commits domain state.
Definition CrowdDocument.cpp:198
std::unique_ptr< IDomainOperationTarget > cloneDomainState() const override
Clones domain state.
Definition CrowdDocument.cpp:197
std::vector< EditorDiagnostic > validate() const
Validate geometry, numeric limits and cross references.
Definition CrowdDocument.cpp:270
Result< DomainOperation > makeDeletePath(const StableId &id) const
Plan reversible path deletion when no agent references it.
Definition CrowdDocument.cpp:255
std::vector< CrowdPathRecord > paths() const
Enumerate paths in stable-id order.
Definition CrowdDocument.cpp:208
EditorValue snapshotValue() const
Capture deterministic schema-version-one authoring data.
Definition CrowdDocument.cpp:291
std::vector< CrowdZoneRecord > zones() const
Enumerate zones in stable-id order.
Definition CrowdDocument.cpp:207
Result< DomainOperation > makeDeleteZone(const StableId &id) const
Plan reversible zone deletion.
Definition CrowdDocument.cpp:236
CrowdOverlayResult overlay(int primitiveBudget=100000) const
Produce deterministic path, zone and agent overlay primitives.
Definition CrowdDocument.cpp:277
Result< DomainOperation > makeDeleteAgent(const StableId &id) const
Plan reversible agent deletion.
Definition CrowdDocument.cpp:217
Result< void > loadSnapshot(const EditorValue &snapshot)
Atomically load validated authoring data.
Definition CrowdDocument.cpp:296
Result< DomainOperation > makeSetPath(const CrowdPathRecord &record) const
Plan reversible path creation or replacement.
Definition CrowdDocument.cpp:244
Result< DomainOperation > makeSetAgent(const CrowdAgentRecord &record) const
Plan reversible agent creation or replacement.
Definition CrowdDocument.cpp:210
std::vector< CrowdAgentRecord > agents() const
Enumerate agents in stable-id order.
Definition CrowdDocument.cpp:206
Result< void > applyDomainOperation(const DomainOperation &operation) override
Applies domain operation.
Definition CrowdDocument.cpp:170
static CapabilityId editorCapabilityId()
Stable capability id for crowd agent, zone and path editing.
Definition CrowdDocument.h:86
Result< DomainOperation > makeSetZone(const CrowdZoneRecord &record) const
Plan reversible zone creation or replacement.
Definition CrowdDocument.cpp:225
void * queryCapability(const CapabilityId &capability) override
Query an optional target capability.
Definition CrowdDocument.cpp:166
void bumpRevision()
Advance the revision without touching the dirty region.
Definition EditableTarget.h:179
Revision revisionValue() const noexcept
Return the revision as the shared protocol revision type.
Definition EditableTarget.h:169
void widenDirty()
Mark an unknown area dirty without advancing the revision.
Definition EditableTarget.h:177
eve::OptionalRef< C > capability()
Query a capability through its interface-owned stable identity.
Definition EditableTarget.h:82
Deterministic owning value tree shared by authoring hosts.
Definition EditingValue.h:19
Definition CrowdDocument.cpp:8
Diagnostic ruleDiagnostic(eve::DiagnosticCode code, RuleId rule, DiagnosticSeverity severity, std::string message)
Build a common diagnostic carrying an open editing rule identity.
Definition EditingResult.h:25
@ InvalidArgument
@ NotFound
@ PreconditionViolation
Definition Container.h:602
Stable authoring record for one crowd agent.
Definition CrowdDocument.h:26
Renderer-neutral line, circle and label primitives for AI overlays.
Definition CrowdDocument.h:64
Revision-tagged deterministic viewport overlay.
Definition CrowdDocument.h:72
std::vector< CrowdOverlayPrimitive > primitives
Definition CrowdDocument.h:75
std::vector< EditorDiagnostic > diagnostics
Definition CrowdDocument.h:76
Stable ordered path shared by multiple agents.
Definition CrowdDocument.h:56
Stable waypoint used by a crowd path.
Definition CrowdDocument.h:48
Stable polygonal sensing, avoidance or gameplay zone.
Definition CrowdDocument.h:38
std::vector< std::array< double, 2 > > points
Definition CrowdDocument.h:42
std::vector< ObjectRefValue > affectedObjects
Definition EditingProtocol.h:51
Stable discovery metadata exposed by every editable target.
Definition EditableTarget.h:39
std::vector< CapabilityId > capabilities
Definition EditableTarget.h:44