载入中...
搜索中...
未找到
ArtifactProvider.cpp
浏览该文件的文档.
2
3#include "common/Capability.h"
4
5#include <algorithm>
6#include <charconv>
7#include <cmath>
8#include <limits>
9#include <memory>
10#include <string_view>
11#include <type_traits>
12#include <unordered_set>
13#include <utility>
14
15namespace eve::scene {
16
21
26
28 return bounds.valid && std::isfinite(bounds.minX) && std::isfinite(bounds.minY) && std::isfinite(bounds.minZ) &&
29 std::isfinite(bounds.maxX) && std::isfinite(bounds.maxY) && std::isfinite(bounds.maxZ) &&
30 bounds.minX <= bounds.maxX && bounds.minY <= bounds.maxY && bounds.minZ <= bounds.maxZ;
31}
32
33const eve::Value* member(const eve::Value::Object& object, const char* name) noexcept {
34 const auto found = object.find(name);
35 return found == object.end() ? nullptr : &found->second;
36}
37
38bool readString(const eve::Value::Object& object, const char* name, std::string& output) {
39 const auto* value = member(object, name);
40 const auto* text = value ? value->getIf<std::string>() : nullptr;
41 if (!text || text->empty()) return false;
42 output = *text;
43 return true;
44}
45
46bool readUint64String(const eve::Value::Object& object, const char* name, std::uint64_t& output) {
47 std::string text;
48 if (!readString(object, name, text)) return false;
49 const auto [end, error] = std::from_chars(text.data(), text.data() + text.size(), output);
50 return error == std::errc{} && end == text.data() + text.size();
51}
52
53bool hasSupportedVersion(const eve::Value::Object& object) noexcept {
54 const auto* encoded = member(object, "version");
55 const auto* version = encoded ? encoded->getIf<std::int64_t>() : nullptr;
56 return version && *version == 1;
57}
58
59bool readFloat(const eve::Value::Object& object, const char* name, float& output) {
60 const auto* value = member(object, name);
61 if (!value) return false;
62 if (const auto* number = value->getIf<double>()) {
63 if (!std::isfinite(*number)) return false;
64 output = static_cast<float>(*number);
65 return std::isfinite(output);
66 }
67 if (const auto* integer = value->getIf<std::int64_t>()) {
68 output = static_cast<float>(*integer);
69 return std::isfinite(output);
70 }
71 return false;
72}
73
75 const auto* encoded = member(object, "bounds");
76 const auto* value = encoded ? encoded->getIf<eve::Value::Object>() : nullptr;
77 return value && readFloat(*value, "minX", bounds.minX) && readFloat(*value, "minY", bounds.minY) &&
78 readFloat(*value, "minZ", bounds.minZ) && readFloat(*value, "maxX", bounds.maxX) &&
79 readFloat(*value, "maxY", bounds.maxY) && readFloat(*value, "maxZ", bounds.maxZ) &&
80 (bounds.valid = true, validBounds(bounds));
81}
82
85 value.emplace("minX", eve::Value(bounds.minX));
86 value.emplace("minY", eve::Value(bounds.minY));
87 value.emplace("minZ", eve::Value(bounds.minZ));
88 value.emplace("maxX", eve::Value(bounds.maxX));
89 value.emplace("maxY", eve::Value(bounds.maxY));
90 value.emplace("maxZ", eve::Value(bounds.maxZ));
91 return eve::Value(std::move(value));
92}
93
95public:
97 : owner_(&owner), record_(std::move(record)) {}
98
99 void commit() noexcept override {
100 if (!owner_) return;
101 owner_->commit(std::move(record_));
102 owner_ = nullptr;
103 }
104
105 void rollback() noexcept override {
106 owner_ = nullptr;
107 record_ = {};
108 }
109
110private:
111 SceneArtifactProvider* owner_ = nullptr;
112 SceneArtifactRecord record_;
113};
114
116 const eve::artifact::PublicationView& publication) {
117 if (failPrepare_)
119 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "scene artifact prepare failure was injected"));
120 if (publication.id.isNil() || publication.buildKey.empty() || publication.parts.empty())
122 eve::DiagnosticCode::InvalidArgument, "scene publication requires identity, build key and parts"));
123 if (find(publication.id) != nullptr)
125 eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "scene artifact identity is already published"));
126 if (nextIndex_ == SceneArtifactHandle::invalidIndex)
128 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "scene artifact handle index exhausted"));
129
130 SceneArtifactRecord record;
131 record.id = publication.id;
132 record.buildKey = std::string(publication.buildKey);
133 record.handle = SceneArtifactHandle(nextIndex_, 1);
134 record.nodes.reserve(publication.parts.size());
135 for (const auto& part : publication.parts) {
136 if (part.id.isNil() || part.role.empty() || !validBounds(part.bounds))
137 return eve::Result<std::unique_ptr<eve::artifact::PreparedPublication>>::failure(eve::Diagnostic::error(
138 eve::DiagnosticCode::InvalidArgument, "scene artifact part has invalid identity, role or bounds"));
139 record.nodes.push_back({std::string(part.role), part.bounds});
140 }
141 try {
142 records_.reserve(records_.size() + 1);
144 std::make_unique<SceneArtifactStage>(*this, std::move(record)));
145 } catch (...) {
147 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "scene artifact prepare allocation failed"));
148 }
149}
150
151void SceneArtifactProvider::commit(SceneArtifactRecord record) noexcept {
152 records_.push_back(std::move(record));
153 ++nextIndex_;
154}
155
157 const auto found =
158 std::find_if(records_.begin(), records_.end(), [id](const auto& record) { return record.id == id; });
159 return found == records_.end() ? nullptr : &*found;
160}
161
163 records_.clear();
164 nextIndex_ = 0;
165 failPrepare_ = false;
166}
167
169 try {
170 eve::Value::Array records;
171 records.reserve(records_.size());
172 for (const auto& record : records_) {
174 nodes.reserve(record.nodes.size());
175 for (const auto& node : record.nodes) {
177 item.emplace("role", eve::Value(node.role));
178 item.emplace("bounds", boundsValue(node.bounds));
179 nodes.emplace_back(std::move(item));
180 }
182 item.emplace("artifactId", eve::Value(record.id.format()));
183 item.emplace("buildKey", eve::Value(record.buildKey));
184 item.emplace("handle", eve::Value(std::to_string(record.handle.packed())));
185 item.emplace("nodes", eve::Value(std::move(nodes)));
186 records.emplace_back(std::move(item));
187 }
189 state.emplace("provider", eve::Value("scene.cpu-registry"));
190 state.emplace("version", eve::Value(std::int64_t(1)));
191 state.emplace("records", eve::Value(std::move(records)));
193 } catch (...) {
194 return failureValue(eve::DiagnosticCode::Failed, "scene artifact snapshot allocation failed");
195 }
196}
197
199 if (!records_.empty())
201 eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "scene artifact restore requires an empty registry"));
202 const auto* object = state.getIf<eve::Value::Object>();
203 const auto* provider = object ? member(*object, "provider") : nullptr;
204 const auto* providerName = provider ? provider->getIf<std::string>() : nullptr;
205 const auto* records = object ? member(*object, "records") : nullptr;
206 const auto* array = records ? records->getIf<eve::Value::Array>() : nullptr;
207 if (!object || !providerName || *providerName != "scene.cpu-registry" || !hasSupportedVersion(*object) || !array)
209 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "invalid scene artifact provider state"));
210
211 std::vector<SceneArtifactRecord> candidate;
212 std::unordered_set<eve::PersistentId> identities;
213 std::uint32_t next = 0;
214 try {
215 candidate.reserve(array->size());
216 for (const eve::Value& encoded : *array) {
217 const auto* item = encoded.getIf<eve::Value::Object>();
218 std::string idText;
219 std::string buildKey;
220 std::uint64_t packed = 0;
221 if (!item || !readString(*item, "artifactId", idText) || !readString(*item, "buildKey", buildKey) ||
222 !readUint64String(*item, "handle", packed))
224 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "invalid scene artifact record"));
225 const auto parsedId = eve::PersistentId::parse(idText);
226 const auto handle = SceneArtifactHandle::fromPacked(packed);
227 const auto* encodedNodes = member(*item, "nodes");
228 const auto* nodes = encodedNodes ? encodedNodes->getIf<eve::Value::Array>() : nullptr;
229 if (!parsedId || parsedId->isNil() || handle.isInvalid() || !nodes ||
230 !identities.emplace(*parsedId).second || handle.index() == SceneArtifactHandle::invalidIndex)
232 "invalid scene artifact identity or handle"));
233 SceneArtifactRecord record{*parsedId, std::move(buildKey), handle, {}};
234 record.nodes.reserve(nodes->size());
235 for (const eve::Value& encodedNode : *nodes) {
236 const auto* node = encodedNode.getIf<eve::Value::Object>();
237 std::string role;
238 const auto* boundsEncoded = node ? member(*node, "bounds") : nullptr;
239 const auto* boundsObject = boundsEncoded ? boundsEncoded->getIf<eve::Value::Object>() : nullptr;
240 if (!node || !readString(*node, "role", role) || !boundsObject)
242 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "invalid scene artifact node"));
244 if (!readBounds(*node, bounds))
246 eve::Diagnostic::error(eve::DiagnosticCode::ParseError, "invalid scene artifact node bounds"));
247 record.nodes.push_back({std::move(role), bounds});
248 }
249 next = std::max(next, handle.index() == std::numeric_limits<std::uint32_t>::max() ? handle.index()
250 : handle.index() + 1u);
251 candidate.push_back(std::move(record));
252 }
253 } catch (...) {
255 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "scene artifact restore allocation failed"));
256 }
257 records_.swap(candidate);
258 nextIndex_ = next;
260}
261
263 static SceneArtifactProvider provider;
264 return provider;
265}
266
268 eve::cap::provide<eve::artifact::ISceneArtifactAdapter>(&sceneArtifactProvider());
269}
270
271} // namespace eve::scene
double value
std::string output
std::string message
DiagnosticCode code
std::string text
std::string name
std::vector< BvhNode > nodes
std::string error
Definition Package.cpp:60
PrimitiveHandle handle
const RoadNode * node
double number
bool found
float(ui::Theme::* member)[4]
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 constexpr RuntimeHandle fromPacked(std::uint64_t value) noexcept
Reconstructs a handle from an explicit packed boundary value.
static constexpr index_type invalidIndex
Reserved index value shared by all invalid handles.
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
std::vector< Value > Array
Definition Value.h:33
Value * find(const std::string &key) noexcept
Return an object member, or nullptr when absent.
Definition Value.cpp:124
A prepared consumer mutation with a non-throwing visibility boundary.
Id128 public API.
Definition Identity.h:112
constexpr bool isNil() const noexcept
Returns whether this value is the all-zero nil ID.
Definition Identity.h:176
static std::optional< Id128 > parse(std::string_view text) noexcept
Parses canonical UUID text.
Definition Identity.h:151
Real scene-module provider for generated artifact publication.
eve::Result< std::unique_ptr< eve::artifact::PreparedPublication > > prepare(const eve::artifact::PublicationView &publication) override
Stage one artifact and copy all data needed after prepare.
const SceneArtifactRecord * find(eve::PersistentId id) const noexcept
Find a committed scene artifact by persistent identity.
eve::Result< void > restoreState(const eve::Value &state) override
Replace the registry from validated backend-neutral state.
void clear() noexcept
Remove all records and reset the local handle allocator.
eve::Result< eve::Value > snapshotState() const override
Export scene identity, build keys, handles and part bounds.
SceneArtifactStage(SceneArtifactProvider &owner, SceneArtifactRecord record)
void rollback() noexcept override
Discard the prepared mutation; idempotent and non-throwing.
void commit() noexcept override
Make the prepared mutation observable; the operation cannot fail.
bool readUint64String(const eve::Value::Object &object, const char *name, std::uint64_t &output)
eve::Result< eve::Value > failureValue(eve::DiagnosticCode code, std::string message)
eve::Value boundsValue(const eve::artifact::Bounds &bounds)
bool validBounds(const eve::artifact::Bounds &bounds) noexcept
bool readBounds(const eve::Value::Object &object, eve::artifact::Bounds &bounds)
void registerSceneArtifactProvider()
Register the scene provider in the common capability registry.
eve::RuntimeHandle< SceneArtifactHandleTag > SceneArtifactHandle
Generation-qualified handle for a scene artifact record.
SceneArtifactProvider & sceneArtifactProvider() noexcept
Return the process-owned scene artifact provider singleton.
bool readFloat(const eve::Value::Object &object, const char *name, float &output)
bool readString(const eve::Value::Object &object, const char *name, std::string &output)
eve::Result< SceneArtifactRecord > failureRecord(eve::DiagnosticCode code, std::string message)
bool hasSupportedVersion(const eve::Value::Object &object) noexcept
DiagnosticCode
Stable machine-readable diagnostic codes.
Definition Diagnostic.h:47
Scene-owned CPU registry provider for generated artifacts.
Backend-neutral axis-aligned bounds copied from a generated part.
Borrowed immutable view of one complete generated publication.
std::span< const PartView > parts
Queryable scene registry record for one published artifact.
std::vector< SceneArtifactNode > nodes
glm::vec4 bounds