载入中...
搜索中...
未找到
ArtifactPublish.cpp
浏览该文件的文档.
2
3#include "common/Capability.h"
5
6#include <exception>
7#include <string>
8#include <type_traits>
9#include <utility>
10#include <vector>
11
12namespace eve::procgen {
13namespace {
14
15struct PublicationBuffer {
16 std::vector<eve::artifact::PartView> parts;
17 std::vector<std::vector<eve::artifact::Point>> pointBuffers;
19};
20
22 switch (type) {
28 case ArtifactType::Composite: break;
29 }
31}
32
33eve::artifact::Bounds boundsView(const Bounds& bounds) {
34 return {bounds.minX, bounds.minY, bounds.minZ, bounds.maxX, bounds.maxY, bounds.maxZ, bounds.valid};
35}
36
37void appendPartView(const ArtifactPart& source, PublicationBuffer& buffer) {
40 view.role = source.role;
41 view.kind = partKind(source.type);
42 view.schemaVersion = source.schemaVersion.value();
43 view.buildKey = source.buildKey.format();
44 view.bounds = boundsView(source.bounds);
45 std::visit(
46 [&view, &buffer](const auto& payload) {
47 using T = std::decay_t<decltype(payload)>;
48 if constexpr (std::is_same_v<T, MeshData>) {
49 view.positions = payload.positions();
50 view.normals = payload.normals();
51 view.uvs = payload.uvs();
52 view.indices = payload.indices();
53 } else if constexpr (std::is_same_v<T, Collider>) {
54 view.positions = payload.vertices;
55 view.indices = payload.indices;
56 } else if constexpr (std::is_same_v<T, Grid2D>) {
57 view.width = payload.getWidth();
58 view.height = payload.getHeight();
59 view.cells = payload.cells();
60 } else if constexpr (std::is_same_v<T, PointSet>) {
61 buffer.pointBuffers.emplace_back();
62 auto& points = buffer.pointBuffers.back();
63 points.reserve(payload.points().size());
64 for (const auto& point : payload.points()) points.push_back({point.x, point.y, point.z});
65 view.points = points;
66 }
67 },
68 source.payload);
69 buffer.parts.emplace_back(view);
70}
71
72void appendLeafView(const GeneratedArtifact& source, PublicationBuffer& buffer) {
75 view.role = artifactTypeName(source.type);
76 view.kind = partKind(source.type);
77 view.schemaVersion = source.schemaVersion.value();
78 view.buildKey = source.buildKey.format();
79 view.bounds = boundsView(source.bounds);
80 std::visit(
81 [&view, &buffer](const auto& payload) {
82 using T = std::decay_t<decltype(payload)>;
83 if constexpr (std::is_same_v<T, MeshData>) {
84 view.positions = payload.positions();
85 view.normals = payload.normals();
86 view.uvs = payload.uvs();
87 view.indices = payload.indices();
88 } else if constexpr (std::is_same_v<T, Collider>) {
89 view.positions = payload.vertices;
90 view.indices = payload.indices;
91 } else if constexpr (std::is_same_v<T, Grid2D>) {
92 view.width = payload.getWidth();
93 view.height = payload.getHeight();
94 view.cells = payload.cells();
95 } else if constexpr (std::is_same_v<T, PointSet>) {
96 buffer.pointBuffers.emplace_back();
97 auto& points = buffer.pointBuffers.back();
98 points.reserve(payload.points().size());
99 for (const auto& point : payload.points()) points.push_back({point.x, point.y, point.z});
100 view.points = points;
101 }
102 },
103 source.payload);
104 buffer.parts.emplace_back(view);
105}
106
107PublicationBuffer makePublicationBuffer(const GeneratedArtifact& artifact) {
108 PublicationBuffer buffer;
109 if (artifact.type == ArtifactType::Composite) {
110 const auto& composite = std::get<CompositeArtifact>(artifact.payload);
111 buffer.parts.reserve(composite.children.size());
112 buffer.pointBuffers.reserve(composite.children.size());
113 for (const auto& part : composite.children) appendPartView(part, buffer);
114 } else {
115 buffer.parts.reserve(1);
116 buffer.pointBuffers.reserve(1);
117 appendLeafView(artifact, buffer);
118 }
119 buffer.view.id = eve::PersistentId::fromUuid(artifact.id);
120 buffer.view.schemaVersion = artifact.schemaVersion.value();
121 buffer.view.buildKey = artifact.buildKey.format();
122 buffer.view.bounds = boundsView(artifact.bounds);
123 buffer.view.parts = std::span<const eve::artifact::PartView>(buffer.parts.data(), buffer.parts.size());
124 return buffer;
125}
126
128class ProviderParticipant final : public eve::transaction::ITransactionParticipant {
129public:
130 ProviderParticipant(std::string name, eve::artifact::ProviderContract& provider,
132 : name_(std::move(name)), provider_(&provider), view_(view) {}
133
134 ~ProviderParticipant() override {
135 if (stage_) stage_->rollback();
136 }
137
138 std::string_view name() const noexcept override { return name_; }
139
140 [[nodiscard]] eve::Result<void> prepare(const eve::transaction::TransactionContext&) override {
141 if (phase_ != Phase::Idle)
142 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact provider participant is not idle", name_ + ".prepare"));
143 // Do not initialize a placeholder Result and then move-assign over it:
144 // in assertion builds move assignment intentionally rejects overwriting
145 // an unobserved Result. Returning from this lambda constructs the one
146 // authoritative Result directly while still converting provider throws
147 // into the publication diagnostic.
148 auto prepared = [&]() -> eve::Result<std::unique_ptr<eve::artifact::PreparedPublication>> {
149 try {
150 return provider_->prepare(view_);
151 } catch (const std::exception& error) {
153 eve::DiagnosticCode::Failed, std::string("artifact provider prepare threw: ") + error.what(),
154 name_ + ".prepare"));
155 } catch (...) {
157 eve::DiagnosticCode::Failed, "artifact provider prepare threw", name_ + ".prepare"));
158 }
159 }();
160 if (!prepared.ok()) return eve::Result<void>::failure(prepared.status());
161 stage_ = std::move(prepared).takeValue();
162 if (!stage_)
163 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::InvariantViolation, "artifact provider returned a null prepared stage", name_ + ".prepare"));
164 phase_ = Phase::Prepared;
166 }
167
168 [[nodiscard]] eve::Result<void> commit(const eve::transaction::TransactionContext&) override {
169 if (phase_ != Phase::Prepared || !stage_)
170 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact provider participant is not prepared", name_ + ".commit"));
171 stage_->commit();
172 stage_.reset();
173 phase_ = Phase::Committed;
175 }
176
177 [[nodiscard]] eve::Result<void> rollback(const eve::transaction::TransactionContext&) override {
178 if (phase_ != Phase::Prepared)
179 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact provider participant is not prepared", name_ + ".rollback"));
180 stage_->rollback();
181 stage_.reset();
182 phase_ = Phase::RolledBack;
184 }
185
186 [[nodiscard]] eve::Result<void> compensate(const eve::transaction::TransactionContext&) override {
187 if (phase_ != Phase::Committed)
188 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact provider participant is not committed", name_ + ".compensate"));
189 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Unsupported, "artifact provider publication has no inverse compensation", name_ + ".compensate"));
190 }
191
192private:
193 enum class Phase { Idle, Prepared, Committed, RolledBack };
194
195 std::string name_;
196 eve::artifact::ProviderContract* provider_ = nullptr;
198 std::unique_ptr<eve::artifact::PreparedPublication> stage_;
199 Phase phase_ = Phase::Idle;
200};
201
203class StoreParticipant final : public eve::transaction::ITransactionParticipant {
204public:
205 StoreParticipant(ArtifactStore& store, GeneratedArtifact artifact)
206 : store_(&store), artifact_(std::move(artifact)) {}
207
208 ~StoreParticipant() override {
209 if (stage_) stage_->rollback();
210 }
211
212 std::string_view name() const noexcept override { return "procgen.artifact-store"; }
213
214 [[nodiscard]] eve::Result<void> prepare(const eve::transaction::TransactionContext&) override {
215 if (phase_ != Phase::Idle)
216 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store participant is not idle", "procgen.artifact-store.prepare"));
217 auto staged = store_->stagePublish(std::move(artifact_));
218 if (!staged.ok()) return eve::Result<void>::failure(staged.status());
219 stage_ = std::move(staged).takeValue();
220 if (!stage_)
221 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::InvariantViolation, "artifact store returned a null prepared stage", "procgen.artifact-store.prepare"));
222 phase_ = Phase::Prepared;
224 }
225
226 [[nodiscard]] eve::Result<void> commit(const eve::transaction::TransactionContext&) override {
227 if (phase_ != Phase::Prepared || !stage_)
228 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store participant is not prepared", "procgen.artifact-store.commit"));
229 stage_->commit();
230 stage_.reset();
231 phase_ = Phase::Committed;
233 }
234
235 [[nodiscard]] eve::Result<void> rollback(const eve::transaction::TransactionContext&) override {
236 if (phase_ != Phase::Prepared)
237 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store participant is not prepared", "procgen.artifact-store.rollback"));
238 stage_->rollback();
239 stage_.reset();
240 phase_ = Phase::RolledBack;
242 }
243
244 [[nodiscard]] eve::Result<void> compensate(const eve::transaction::TransactionContext&) override {
245 if (phase_ != Phase::Committed)
246 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store participant is not committed", "procgen.artifact-store.compensate"));
247 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Unsupported, "artifact store publication has no inverse compensation", "procgen.artifact-store.compensate"));
248 }
249
250private:
251 enum class Phase { Idle, Prepared, Committed, RolledBack };
252
253 ArtifactStore* store_ = nullptr;
254 GeneratedArtifact artifact_;
255 std::unique_ptr<eve::artifact::PreparedPublication> stage_;
256 Phase phase_ = Phase::Idle;
257};
258
260class ProviderRestoreParticipant final : public eve::transaction::ITransactionParticipant {
261public:
262 ProviderRestoreParticipant(std::string name, eve::artifact::ProviderContract& provider, const eve::Value& state)
263 : name_(std::move(name)), provider_(&provider), state_(&state) {}
264
265 std::string_view name() const noexcept override { return name_; }
266
267 [[nodiscard]] eve::Result<void> prepare(const eve::transaction::TransactionContext&) override {
268 if (phase_ != Phase::Idle)
269 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact restore participant is not idle", name_ + ".prepare"));
270 phase_ = Phase::Prepared;
272 }
273
274 [[nodiscard]] eve::Result<void> commit(const eve::transaction::TransactionContext&) override {
275 if (phase_ != Phase::Prepared)
276 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact restore participant is not prepared", name_ + ".commit"));
277 auto restored = provider_->restoreState(*state_);
278 if (!restored.ok()) return eve::Result<void>::failure(restored.status());
279 phase_ = Phase::Committed;
281 }
282
283 [[nodiscard]] eve::Result<void> rollback(const eve::transaction::TransactionContext&) override {
284 if (phase_ != Phase::Prepared)
285 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact restore participant is not prepared", name_ + ".rollback"));
286 phase_ = Phase::RolledBack;
288 }
289
290 [[nodiscard]] eve::Result<void> compensate(const eve::transaction::TransactionContext&) override {
291 if (phase_ != Phase::Committed)
292 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact restore participant is not committed", name_ + ".compensate"));
293 provider_->clearState();
294 phase_ = Phase::Compensated;
296 }
297
298private:
299 enum class Phase { Idle, Prepared, Committed, RolledBack, Compensated };
300
301 std::string name_;
302 eve::artifact::ProviderContract* provider_ = nullptr;
303 const eve::Value* state_ = nullptr;
304 Phase phase_ = Phase::Idle;
305};
306
308class StoreRestoreParticipant final : public eve::transaction::ITransactionParticipant {
309public:
310 StoreRestoreParticipant(ArtifactStore& store, const eve::Value& state) : store_(&store), state_(&state) {}
311
312 std::string_view name() const noexcept override { return "procgen.artifact-store.restore"; }
313
314 [[nodiscard]] eve::Result<void> prepare(const eve::transaction::TransactionContext&) override {
315 if (phase_ != Phase::Idle)
316 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store restore participant is not idle", "procgen.artifact-store.restore.prepare"));
317 phase_ = Phase::Prepared;
319 }
320
321 [[nodiscard]] eve::Result<void> commit(const eve::transaction::TransactionContext&) override {
322 if (phase_ != Phase::Prepared)
323 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store restore participant is not prepared", "procgen.artifact-store.restore.commit"));
324 auto restored = store_->restoreState(*state_);
325 if (!restored.ok()) return eve::Result<void>::failure(restored.status());
326 phase_ = Phase::Committed;
328 }
329
330 [[nodiscard]] eve::Result<void> rollback(const eve::transaction::TransactionContext&) override {
331 if (phase_ != Phase::Prepared)
332 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store restore participant is not prepared", "procgen.artifact-store.restore.rollback"));
333 phase_ = Phase::RolledBack;
335 }
336
337 [[nodiscard]] eve::Result<void> compensate(const eve::transaction::TransactionContext&) override {
338 if (phase_ != Phase::Committed)
339 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::PreconditionViolation, "artifact store restore participant is not committed", "procgen.artifact-store.restore.compensate"));
340 store_->clear();
341 phase_ = Phase::Compensated;
343 }
344
345private:
346 enum class Phase { Idle, Prepared, Committed, RolledBack, Compensated };
347
348 ArtifactStore* store_ = nullptr;
349 const eve::Value* state_ = nullptr;
350 Phase phase_ = Phase::Idle;
351};
352
353template <class Adapter>
354eve::Result<void> addProviderParticipant(
355 bool required, const char* name, const eve::artifact::PublicationView& publication,
356 std::vector<std::unique_ptr<eve::transaction::ITransactionParticipant>>& owners,
357 std::vector<eve::transaction::ITransactionParticipant*>& participants) {
359 Adapter* adapter = eve::cap::query<Adapter>();
360 if (!adapter)
361 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Unsupported, std::string("required artifact adapter is unavailable: ") + name, std::string("artifact.adapters.") + name));
362 try {
363 owners.emplace_back(std::make_unique<ProviderParticipant>(name, *adapter, publication));
364 participants.push_back(owners.back().get());
365 } catch (...) {
366 return eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::Failed, std::string("failed to allocate artifact participant: ") + name, std::string("artifact.adapters.") + name));
367 }
369}
370
371const eve::Value* objectMember(const eve::Value::Object& object, const char* name) noexcept {
372 const auto found = object.find(name);
373 return found == object.end() ? nullptr : &found->second;
374}
375
376eve::transaction::TransactionContext publicationContext(const eve::PersistentId& id, std::string_view operation) {
378 return eve::transaction::TransactionContext(std::string(operation) + ".invalid-identity");
379}
380
381} // namespace
382
385 PublicationBuffer publication;
386 try {
387 publication = makePublicationBuffer(artifact);
388 } catch (const std::exception& error) {
391 std::string("failed to materialize artifact publication view: ") + error.what()));
392 } catch (...) {
394 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "failed to materialize artifact publication view"));
395 }
396
397 std::vector<std::unique_ptr<eve::transaction::ITransactionParticipant>> owners;
398 std::vector<eve::transaction::ITransactionParticipant*> participants;
399 owners.reserve(5);
400 participants.reserve(5);
401 auto scene =
402 addProviderParticipant<ISceneArtifactAdapter>(options.scene, "scene", publication.view, owners, participants);
403 if (!scene.ok()) return eve::Result<ArtifactPublishReceipt>::failure(scene.status());
404 auto map = addProviderParticipant<IMapArtifactAdapter>(options.map, "map", publication.view, owners, participants);
405 if (!map.ok()) return eve::Result<ArtifactPublishReceipt>::failure(map.status());
406 auto graphics = addProviderParticipant<IGraphicsArtifactAdapter>(options.graphics, "graphics", publication.view,
407 owners, participants);
408 if (!graphics.ok()) return eve::Result<ArtifactPublishReceipt>::failure(graphics.status());
409 auto physics = addProviderParticipant<IPhysicsArtifactAdapter>(options.physics, "physics", publication.view, owners,
410 participants);
411 if (!physics.ok()) return eve::Result<ArtifactPublishReceipt>::failure(physics.status());
412
413 try {
414 owners.emplace_back(std::make_unique<StoreParticipant>(store_, std::move(artifact)));
415 participants.push_back(owners.back().get());
416 } catch (...) {
418 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "failed to allocate artifact store participant"));
419 }
420
421 const auto context = publicationContext(publication.view.id, "artifact.publish");
423 auto coordinated = coordinator.execute(context, participants);
424 if (!coordinated.ok()) return eve::Result<ArtifactPublishReceipt>::failure(coordinated.status());
425 auto transactionReceipt = std::move(coordinated).takeValue();
426 if (transactionReceipt.state != eve::transaction::CoordinatorState::Committed)
429 "artifact publication coordinator returned a non-committed receipt"));
430
432 receipt.id = ArtifactId::fromUuid(publication.view.id);
433 receipt.scenePublished = options.scene;
434 receipt.graphicsPublished = options.graphics;
435 receipt.physicsPublished = options.physics;
436 receipt.mapPublished = options.map;
437 return eve::Result<ArtifactPublishReceipt>::success(std::move(receipt));
438}
439
441 if (!context.hashProvider)
443 eve::DiagnosticCode::Unsupported, "artifact snapshot requires an injected hash provider"));
444 const auto schema = eve::LogicalId::fromParts("eve", "artifact-publication");
445 if (!schema)
447 eve::Diagnostic::error(eve::DiagnosticCode::InvariantViolation, "artifact snapshot schema id is invalid"));
448
449 auto store = store_.snapshotState();
450 if (!store.ok()) return eve::Result<eve::SnapshotEnvelope>::failure(store.status());
451 eve::Value::Object providers;
452 const auto appendProvider = [&providers](const char* name,
454 if (!provider) return eve::Result<void>::success();
455 auto state = provider->snapshotState();
456 if (!state.ok()) return eve::Result<void>::failure(state.status());
457 providers.emplace(name, std::move(state).takeValue());
459 };
460 auto scene = appendProvider("scene", eve::cap::query<eve::artifact::ISceneArtifactAdapter>());
461 if (!scene.ok()) return eve::Result<eve::SnapshotEnvelope>::failure(scene.status());
462 auto map = appendProvider("map", eve::cap::query<eve::artifact::IMapArtifactAdapter>());
463 if (!map.ok()) return eve::Result<eve::SnapshotEnvelope>::failure(map.status());
464 auto graphics = appendProvider("graphics", eve::cap::query<eve::artifact::IGraphicsArtifactAdapter>());
465 if (!graphics.ok()) return eve::Result<eve::SnapshotEnvelope>::failure(graphics.status());
466 auto physics = appendProvider("physics", eve::cap::query<eve::artifact::IPhysicsArtifactAdapter>());
467 if (!physics.ok()) return eve::Result<eve::SnapshotEnvelope>::failure(physics.status());
468
470 payload.emplace("store", std::move(store).takeValue());
471 payload.emplace("providers", eve::Value(std::move(providers)));
472 return eve::makeSnapshotEnvelope("eve.artifact.publication", *schema, eve::SchemaVersion(1), context.instanceId,
473 context.revision, context.tick, eve::Value(std::move(payload)),
474 context.hashProvider);
475}
476
478 const eve::SnapshotHashProvider& hashProvider) {
479 auto verified = eve::verifySnapshotEnvelope(snapshot, hashProvider);
480 if (!verified.ok()) return verified;
481 const auto schema = eve::LogicalId::fromParts("eve", "artifact-publication");
482 if (!schema || snapshot.type != "eve.artifact.publication" || snapshot.schema != *schema ||
483 snapshot.schemaVersion.value() != 1)
485 eve::Diagnostic::error(eve::DiagnosticCode::UnknownVersion, "unsupported artifact publication snapshot"));
486 if (store_.size() != 0)
488 eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "artifact snapshot restore requires an empty store"));
489
490 const auto* payload = snapshot.payload.getIf<eve::Value::Object>();
491 const auto* storeState = payload ? objectMember(*payload, "store") : nullptr;
492 const auto* providerStateValue = payload ? objectMember(*payload, "providers") : nullptr;
493 const auto* providerStates = providerStateValue ? providerStateValue->getIf<eve::Value::Object>() : nullptr;
494 if (!payload || !storeState || !providerStates)
496 eve::DiagnosticCode::ParseError, "artifact publication snapshot payload is incomplete"));
497
498 eve::artifact::ISceneArtifactAdapter* scene = eve::cap::query<eve::artifact::ISceneArtifactAdapter>();
499 eve::artifact::IMapArtifactAdapter* map = eve::cap::query<eve::artifact::IMapArtifactAdapter>();
500 eve::artifact::IGraphicsArtifactAdapter* graphics = eve::cap::query<eve::artifact::IGraphicsArtifactAdapter>();
501 eve::artifact::IPhysicsArtifactAdapter* physics = eve::cap::query<eve::artifact::IPhysicsArtifactAdapter>();
502 if ((scene && !scene->emptyState()) || (map && !map->emptyState()) || (graphics && !graphics->emptyState()) ||
503 (physics && !physics->emptyState()))
505 "artifact snapshot restore requires empty providers"));
506
507 const auto lookupProvider = [providerStates](const char* name) -> const eve::Value* {
508 const auto found = providerStates->find(name);
509 return found == providerStates->end() ? nullptr : &found->second;
510 };
511 for (const auto& entry : *providerStates) {
512 if (entry.first != "scene" && entry.first != "map" && entry.first != "graphics" && entry.first != "physics")
514 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "unknown artifact publication provider state"));
515 }
516 if ((lookupProvider("scene") && !scene) || (lookupProvider("map") && !map) ||
517 (lookupProvider("graphics") && !graphics) || (lookupProvider("physics") && !physics))
519 eve::DiagnosticCode::Unsupported, "snapshot contains state for an unavailable provider"));
520
521 std::vector<std::unique_ptr<eve::transaction::ITransactionParticipant>> owners;
522 std::vector<eve::transaction::ITransactionParticipant*> participants;
523 owners.reserve(5);
524 participants.reserve(5);
525 try {
526 owners.emplace_back(std::make_unique<StoreRestoreParticipant>(store_, *storeState));
527 participants.push_back(owners.back().get());
528 const auto addRestore = [&owners, &participants](const char* name, eve::artifact::ProviderContract* provider,
529 const eve::Value* state) {
530 if (!provider || !state) return;
531 owners.emplace_back(std::make_unique<ProviderRestoreParticipant>(name, *provider, *state));
532 participants.push_back(owners.back().get());
533 };
534 addRestore("scene", scene, lookupProvider("scene"));
535 addRestore("map", map, lookupProvider("map"));
536 addRestore("graphics", graphics, lookupProvider("graphics"));
537 addRestore("physics", physics, lookupProvider("physics"));
538 } catch (...) {
540 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "failed to allocate artifact restore participants"));
541 }
542
543 const auto context = publicationContext(snapshot.instanceId, "artifact.restore");
545 auto coordinated = coordinator.execute(context, participants);
546 if (!coordinated.ok()) return eve::Result<void>::failure(coordinated.status());
547 auto transactionReceipt = std::move(coordinated).takeValue();
548 if (transactionReceipt.state != eve::transaction::CoordinatorState::Committed)
550 eve::DiagnosticCode::InvariantViolation, "artifact restore coordinator returned a non-committed receipt"));
552}
553
554} // namespace eve::procgen
ActionParameterOperation operation
Value::Object payload
std::vector< eve::artifact::PartView > parts
std::vector< std::vector< eve::artifact::Point > > pointBuffers
Capability-driven, transactional publication of generated artifacts.
bool required
std::string name
std::unique_ptr< gpgpu::GpuBuffer > buffer
Definition OnnxGpgpu.cpp:26
std::string error
Definition Package.cpp:60
std::shared_ptr< const std::vector< glm::vec2 > > points
std::weak_ptr< PrimitiveScene > scene
glm::mat4 view
bool found
const SquirrelValueOptions & options
std::string_view adapter
int children
Definition TreeMesh.cpp:295
const UnitySourceAsset & source
const VegetationPresetContext & context
glm::vec3 point
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
static std::optional< LogicalId > fromParts(std::string_view namespaceName, std::string_view name)
Builds a logical ID from separate namespace and name components.
Definition Identity.cpp:48
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
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
Value * find(const std::string &key) noexcept
Return an object member, or nullptr when absent.
Definition Value.cpp:124
Graphics resource publication capability, implemented by graphics.
Tile/map publication capability, implemented by the map module.
Collider publication capability, implemented by physics.
Scene graph publication capability, implemented by the scene module.
Base contract for a consumer-owned artifact provider.
virtual void clearState() noexcept
Clear provider state during aggregate-restore failure cleanup.
virtual eve::Result< std::unique_ptr< PreparedPublication > > prepare(const PublicationView &publication)=0
Prepare a provider-local mutation from a borrowed publication view.
virtual bool emptyState() const noexcept
Return whether this provider has no committed observable state.
virtual eve::Result< void > restoreState(const eve::Value &state)
Transactionally restore backend-neutral observable provider state.
Id128 public API.
Definition Identity.h:112
static constexpr Id128 fromUuid(const Id128< OtherTag > &value) noexcept
Re-tags an existing UUID at an explicit domain boundary.
Definition Identity.h:136
eve::Result< eve::SnapshotEnvelope > snapshot(const ArtifactSnapshotContext &context) const
Capture store and registered provider state in a sealed snapshot.
eve::Result< ArtifactPublishReceipt > publish(GeneratedArtifact artifact, ArtifactPublishOptions options)
Publish through required capabilities and then atomically into the store.
eve::Result< void > restore(const eve::SnapshotEnvelope &snapshot, const eve::SnapshotHashProvider &hashProvider)
Restore store and provider state transactionally from a sealed snapshot.
std::size_t size() const noexcept
Return the number of published top-level artifacts.
eve::Result< eve::Value > snapshotState() const
Export identity, build-key and complete typed dense payload state.
Coordinates participant lifecycles with deterministic ordering.
Result< TransactionReceipt > execute(const TransactionContext &context, std::span< ITransactionParticipant * > participants) const
Atomically execute borrowed participants for one context.
Synchronous participant contract for one coordinator transaction.
Immutable context shared by every participant of one transaction.
Definition Transaction.h:30
PartKind
The leaf kinds understood by consumer-owned artifact providers.
const char * artifactTypeName(ArtifactType type) noexcept
Return the stable textual spelling of an artifact kind.
ArtifactType
Runtime payload kind; it is checked against the variant on publish.
Result< SnapshotEnvelope > makeSnapshotEnvelope(std::string type, LogicalId schema, SchemaVersion schemaVersion, PersistentId instanceId, Revision revision, SimulationTick tick, Value payload, const SnapshotHashProvider &hashProvider)
Construct and seal a snapshot envelope.
Definition Snapshot.cpp:103
Result< void > verifySnapshotEnvelope(const SnapshotEnvelope &snapshot, const SnapshotHashProvider &hashProvider)
Verify an envelope's content hash without modifying it.
Definition Snapshot.cpp:63
std::function< Result< ContentId >(std::string_view canonicalInput)> SnapshotHashProvider
Injected content-digest implementation used by snapshots.
Definition Snapshot.h:36
Stable outer format shared by persistence and cross-process snapshots.
Definition Snapshot.h:46
Backend-neutral axis-aligned bounds copied from a generated part.
Borrowed immutable view of one generated leaf.
Borrowed immutable view of one complete generated publication.
Required provider set for one artifact publication transaction.
Compatibility receipt retaining procgen ArtifactId at this boundary.
Snapshot context supplied by the caller; time and hashing are injected.
Complete immutable-once-published artifact record.
glm::vec4 bounds