载入中...
搜索中...
未找到
ProductionBindings.cpp
浏览该文件的文档.
2
4
5#include <simplesquirrel/simplesquirrel.hpp>
6
7#include <functional>
8#include <memory>
9#include <utility>
10
11namespace eve::production {
12namespace {
13
15struct ScriptWorkQueue {
16 explicit ScriptWorkQueue(WorkQueueHandleRef value) : reference(value) {}
18};
19
21struct ScriptWorkTask {
22 ScriptWorkTask(WorkQueueHandleRef queue, std::string id) : reference(queue), taskId(std::move(id)) {}
24 std::string taskId;
25};
26
28struct ScriptWorkEvent {
29 ScriptWorkEvent(WorkQueueHandleRef queue, int eventIndex) : reference(queue), index(eventIndex) {}
31 int index = -1;
32};
33
34template <class T>
35eve::Result<T> productionBindingFailure(eve::DiagnosticCode code, std::string message, std::string path = {}) {
37 eve::Diagnostic::error(code, message, path, {}, "production.squirrel"));
38}
39
40template <class Ref, class Proxy, class Release>
41ssq::Table makeOwnedProxy(HSQUIRRELVM vm, eve::Result<Ref>&& reference, Release&& release, const char* errorPath) {
43 const Ref ref = std::move(reference).takeValue();
44 auto object = eve::script::makeOwnedSquirrelInstance<Proxy>(vm, std::make_unique<Proxy>(ref));
45 if (!object) {
46 const eve::Status status = object.status();
47 object.ignore("failed to create owned production proxy");
48 std::invoke(std::forward<Release>(release), ref).ignore("rollback failed owned production allocation");
50 }
51 ssq::Object owned = std::move(object).takeValue();
53 result.set("ownership", std::string("owned"));
54 result.set("ownerEpoch", static_cast<std::int64_t>(ref.ownerEpoch));
55 result.set("handle", static_cast<std::int64_t>(ref.packed()));
56 (void)errorPath;
57 return result;
58}
59
60ssq::Object projectValueObject(HSQUIRRELVM vm, const eve::Value& value) {
61 if (!vm) return ssq::Object();
62 const SQInteger top = sq_gettop(vm);
63 auto pushed = eve::script::pushValue(vm, value);
64 if (!pushed.ok()) {
65 pushed.ignore("failed to project a work-task Value payload");
66 sq_settop(vm, top);
67 return ssq::Object(vm);
68 }
69 ssq::Object result(vm);
70 if (SQ_SUCCEEDED(sq_getstackobj(vm, -1, &result.getRaw()))) sq_addref(vm, &result.getRaw());
71 sq_settop(vm, top);
72 return result;
73}
74
75} // namespace
76
78 Production* module = Production::create();
79 return module->queues_.emplace(std::make_unique<WorkQueue>());
80}
81
83 Production* module = ModuleManager::getInstance<Production>("Production");
84 if (!module)
85 return productionBindingFailure<std::reference_wrapper<WorkQueue>>(
86 eve::DiagnosticCode::StaleHandle, "Production module is no longer loaded", "queue");
87 auto view = module->queues_.resolve(reference);
88 if (!view.isBound())
89 return productionBindingFailure<std::reference_wrapper<WorkQueue>>(eve::DiagnosticCode::StaleHandle,
90 "work queue handle is stale", "queue");
92}
93
95 Production* module = ModuleManager::getInstance<Production>("Production");
96 if (!module)
97 return productionBindingFailure<void>(eve::DiagnosticCode::StaleHandle, "Production module is no longer loaded",
98 "queue");
99 return module->queues_.erase(reference);
100}
101
103 if (!reference.isValid()) return false;
104 Production* module = ModuleManager::getInstance<Production>("Production");
105 return !module || module->queues_.isStale(reference);
106}
107
109
110void Production::expose(ssq::Table& table) {
111 const HSQUIRRELVM vm = table.getHandle();
112 auto task =
113 table.addClass<ScriptWorkTask>("WorkTask", std::function<ScriptWorkTask*()>([] { return nullptr; }), true);
114 auto resolveTask = [](ScriptWorkTask* proxy) -> eve::OptionalRef<const ProductionTask> {
115 if (!proxy) return {};
116 auto queue = Production::resolve(proxy->reference);
117 if (!queue.ok()) {
118 queue.ignore("stale work queue while reading a task proxy");
119 return {};
120 }
121 return queue.value().get().find(proxy->taskId);
122 };
123 task.addFunc("getId", [resolveTask](ScriptWorkTask* v) {
124 auto value = resolveTask(v);
125 return value ? value->get().id : std::string{};
126 });
127 task.addFunc("getOwner", [resolveTask](ScriptWorkTask* v) {
128 auto value = resolveTask(v);
129 return value ? value->get().owner : std::string{};
130 });
131 task.addFunc("getKind", [resolveTask](ScriptWorkTask* v) {
132 auto value = resolveTask(v);
133 return value ? value->get().kind : std::string{};
134 });
135 task.addFunc("getProduct", [resolveTask](ScriptWorkTask* v) {
136 auto value = resolveTask(v);
137 return value ? value->get().product : std::string{};
138 });
139 task.addFunc("getContext", [vm, resolveTask](ScriptWorkTask* v) {
140 auto value = resolveTask(v);
141 return value ? projectValueObject(vm, value->get().context) : ssq::Object(vm);
142 });
143 task.addFunc("getDuration", [resolveTask](ScriptWorkTask* v) {
144 auto value = resolveTask(v);
145 return value ? float(value->get().duration.seconds()) : 0.0f;
146 });
147 task.addFunc("getProgress", [resolveTask](ScriptWorkTask* v) {
148 auto value = resolveTask(v);
149 return value ? float(value->get().progress.seconds()) : 0.0f;
150 });
151 task.addFunc("getPriority", [resolveTask](ScriptWorkTask* v) {
152 auto value = resolveTask(v);
153 return value ? value->get().priority : 0;
154 });
155 task.addFunc("getState", [resolveTask](ScriptWorkTask* v) {
156 auto value = resolveTask(v);
157 return value ? std::string(taskStateName(value->get().state)) : std::string{};
158 });
159 task.addFunc("getReason", [resolveTask](ScriptWorkTask* v) {
160 auto value = resolveTask(v);
161 return value ? value->get().reason : std::string{};
162 });
163
164 auto event =
165 table.addClass<ScriptWorkEvent>("WorkEvent", std::function<ScriptWorkEvent*()>([] { return nullptr; }), true);
166 auto resolveEvent = [](ScriptWorkEvent* proxy) -> eve::OptionalRef<ProductionEvent> {
167 if (!proxy) return {};
168 auto queue = Production::resolve(proxy->reference);
169 if (!queue.ok()) {
170 queue.ignore("stale work queue while reading an event proxy");
171 return {};
172 }
173 return queue.value().get().eventAt(proxy->index);
174 };
175 event.addFunc("getSequence", [resolveEvent](ScriptWorkEvent* v) {
176 auto value = resolveEvent(v);
177 return value ? int64_t(value->get().sequence) : int64_t{0};
178 });
179 event.addFunc("getTick", [resolveEvent](ScriptWorkEvent* v) {
180 auto value = resolveEvent(v);
181 return value ? int64_t(value->get().tick.value()) : int64_t{0};
182 });
183 event.addFunc("getKind", [resolveEvent](ScriptWorkEvent* v) {
184 auto value = resolveEvent(v);
185 return value ? std::string(eventKindName(value->get().kind)) : std::string{};
186 });
187 event.addFunc("getTaskId", [resolveEvent](ScriptWorkEvent* v) {
188 auto value = resolveEvent(v);
189 return value ? value->get().taskId : std::string{};
190 });
191 event.addFunc("getOwner", [resolveEvent](ScriptWorkEvent* v) {
192 auto value = resolveEvent(v);
193 return value ? value->get().owner : std::string{};
194 });
195 event.addFunc("getTaskKind", [resolveEvent](ScriptWorkEvent* v) {
196 auto value = resolveEvent(v);
197 return value ? value->get().taskKind : std::string{};
198 });
199 event.addFunc("getProduct", [resolveEvent](ScriptWorkEvent* v) {
200 auto value = resolveEvent(v);
201 return value ? value->get().product : std::string{};
202 });
203 event.addFunc("getReason", [resolveEvent](ScriptWorkEvent* v) {
204 auto value = resolveEvent(v);
205 return value ? value->get().reason : std::string{};
206 });
207
208 auto queue =
209 table.addClass<ScriptWorkQueue>("WorkQueue", std::function<ScriptWorkQueue*()>([] { return nullptr; }), true);
210 queue.addFunc("ownership", [](ScriptWorkQueue*) { return std::string("owned"); });
211 queue.addFunc("ownerEpoch", [](ScriptWorkQueue* value) {
212 return value ? static_cast<int64_t>(value->reference.ownerEpoch) : int64_t{0};
213 });
214 queue.addFunc("handle", [](ScriptWorkQueue* value) {
215 return value ? static_cast<int64_t>(value->reference.packed()) : int64_t{0};
216 });
217 queue.addFunc("isStale", [](ScriptWorkQueue* value) { return !value || Production::isStale(value->reference); });
218 queue.addFunc("release", [vm](ScriptWorkQueue* value) {
219 if (!value)
221 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
222 "work queue proxy must not be null", "queue"));
224 });
225 queue.addFunc("enqueue", [vm](ScriptWorkQueue* value, const std::string& owner, const std::string& kind,
226 const std::string& product, const std::string& contextJson, float duration,
227 int priority) {
228 if (!value)
230 vm,
231 productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
232 "work queue proxy must not be null", "queue")
233 .status());
234 auto payload = eve::Value::fromJson(contextJson);
235 if (!payload.ok()) return eve::script::projectStatusResult(vm, payload.status());
236 auto queueView = Production::resolve(value->reference);
237 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
239 vm,
240 queueView.value().get().enqueue(owner, kind, product, std::move(payload).takeValue(), duration, priority),
241 [](std::string id) { return eve::Value(std::move(id)); });
242 });
243 queue.addFunc("pause", [vm](ScriptWorkQueue* value, const std::string& id) {
244 if (!value)
246 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
247 "work queue proxy must not be null", "queue"));
248 auto queueView = Production::resolve(value->reference);
249 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
250 return eve::script::projectResult(vm, queueView.value().get().pause(id));
251 });
252 queue.addFunc("resume", [vm](ScriptWorkQueue* value, const std::string& id) {
253 if (!value)
255 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
256 "work queue proxy must not be null", "queue"));
257 auto queueView = Production::resolve(value->reference);
258 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
259 return eve::script::projectResult(vm, queueView.value().get().resume(id));
260 });
261 queue.addFunc("cancel", [vm](ScriptWorkQueue* value, const std::string& id, const std::string& reason) {
262 if (!value)
264 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
265 "work queue proxy must not be null", "queue"));
266 auto queueView = Production::resolve(value->reference);
267 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
268 return eve::script::projectResult(vm, queueView.value().get().cancel(id, reason));
269 });
270 queue.addFunc("fail", [vm](ScriptWorkQueue* value, const std::string& id, const std::string& reason) {
271 if (!value)
273 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
274 "work queue proxy must not be null", "queue"));
275 auto queueView = Production::resolve(value->reference);
276 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
277 return eve::script::projectResult(vm, queueView.value().get().fail(id, reason));
278 });
279 queue.addFunc("advance", [vm](ScriptWorkQueue* value, std::int64_t tick, float seconds) {
280 if (!value)
282 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
283 "work queue proxy must not be null", "queue"));
284 auto delta = eve::Duration::fromSeconds(seconds);
285 if (!delta.ok()) return eve::script::projectStatusResult(vm, delta.status());
286 auto queueView = Production::resolve(value->reference);
287 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
289 vm, queueView.value().get().advance(
290 {eve::SimulationTick(static_cast<std::uint64_t>(tick)), std::move(delta).takeValue()}));
291 });
292 queue.addFunc("setSlotCount", [vm](ScriptWorkQueue* value, const std::string& owner, int slots) {
293 if (!value)
295 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
296 "work queue proxy must not be null", "queue"));
297 auto queueView = Production::resolve(value->reference);
298 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
299 return eve::script::projectResult(vm, queueView.value().get().setSlotCount(owner, slots));
300 });
301 queue.addFunc("slotCount", [](ScriptWorkQueue* value, const std::string& owner) {
302 auto queueView = value ? Production::resolve(value->reference)
303 : eve::ResultRef<WorkQueue>::failure(eve::Diagnostic::error(
304 eve::DiagnosticCode::InvalidArgument, "work queue proxy must not be null"));
305 if (!queueView.ok()) {
306 queueView.ignore("stale work queue while reading slot count");
307 return 0;
308 }
309 return queueView.value().get().slotCount(owner);
310 });
311 queue.addFunc("runningCount", [](ScriptWorkQueue* value, const std::string& owner) {
312 auto queueView = value ? Production::resolve(value->reference)
313 : eve::ResultRef<WorkQueue>::failure(eve::Diagnostic::error(
314 eve::DiagnosticCode::InvalidArgument, "work queue proxy must not be null"));
315 if (!queueView.ok()) {
316 queueView.ignore("stale work queue while reading running count");
317 return 0;
318 }
319 return queueView.value().get().runningCount(owner);
320 });
321 queue.addFunc("find", [vm](ScriptWorkQueue* value, const std::string& id) {
322 if (!value) return ssq::Object(vm);
323 auto queueView = Production::resolve(value->reference);
324 if (!queueView.ok()) {
325 queueView.ignore("stale work queue while finding a task");
326 return ssq::Object(vm);
327 }
328 if (!queueView.value().get().find(id)) return ssq::Object(vm);
329 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkTask>(
330 vm, std::make_unique<ScriptWorkTask>(value->reference, id));
331 if (!object.ok()) {
332 object.ignore("failed to create work task proxy");
333 return ssq::Object(vm);
334 }
335 return std::move(object).takeValue();
336 });
337 queue.addFunc("taskCount", [](ScriptWorkQueue* value) {
338 auto queueView = value ? Production::resolve(value->reference)
339 : eve::ResultRef<WorkQueue>::failure(eve::Diagnostic::error(
340 eve::DiagnosticCode::InvalidArgument, "work queue proxy must not be null"));
341 if (!queueView.ok()) {
342 queueView.ignore("stale work queue while reading task count");
343 return 0;
344 }
345 return queueView.value().get().taskCount();
346 });
347 queue.addFunc("taskAt", [vm](ScriptWorkQueue* value, int index) {
348 if (!value) return ssq::Object(vm);
349 auto queueView = Production::resolve(value->reference);
350 if (!queueView.ok() || !queueView.value().get().taskAt(index)) {
351 queueView.ignore("work task lookup did not produce a task proxy");
352 return ssq::Object(vm);
353 }
354 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkTask>(
355 vm, std::make_unique<ScriptWorkTask>(value->reference, queueView.value().get().taskAt(index)->get().id));
356 if (!object.ok()) {
357 object.ignore("failed to create work task proxy");
358 return ssq::Object(vm);
359 }
360 return std::move(object).takeValue();
361 });
362 queue.addFunc("ownerTaskCount", [](ScriptWorkQueue* value, const std::string& owner) {
363 auto queueView = value ? Production::resolve(value->reference)
364 : eve::ResultRef<WorkQueue>::failure(eve::Diagnostic::error(
365 eve::DiagnosticCode::InvalidArgument, "work queue proxy must not be null"));
366 if (!queueView.ok()) {
367 queueView.ignore("stale work queue while reading owner task count");
368 return 0;
369 }
370 return queueView.value().get().ownerTaskCount(owner);
371 });
372 queue.addFunc("ownerTaskAt", [vm](ScriptWorkQueue* value, const std::string& owner, int index) {
373 if (!value) return ssq::Object(vm);
374 auto queueView = Production::resolve(value->reference);
375 if (!queueView.ok()) {
376 queueView.ignore("stale work queue while finding an owner task");
377 return ssq::Object(vm);
378 }
379 auto taskRef = queueView.value().get().ownerTaskAt(owner, index);
380 if (!taskRef) return ssq::Object(vm);
381 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkTask>(
382 vm, std::make_unique<ScriptWorkTask>(value->reference, taskRef->get().id));
383 if (!object.ok()) {
384 object.ignore("failed to create work task proxy");
385 return ssq::Object(vm);
386 }
387 return std::move(object).takeValue();
388 });
389 queue.addFunc("eventCount", [](ScriptWorkQueue* value) {
390 auto queueView = value ? Production::resolve(value->reference)
391 : eve::ResultRef<WorkQueue>::failure(eve::Diagnostic::error(
392 eve::DiagnosticCode::InvalidArgument, "work queue proxy must not be null"));
393 if (!queueView.ok()) {
394 queueView.ignore("stale work queue while reading event count");
395 return 0;
396 }
397 return queueView.value().get().eventCount();
398 });
399 queue.addFunc("eventAt", [vm](ScriptWorkQueue* value, int index) {
400 if (!value) return ssq::Object(vm);
401 auto queueView = Production::resolve(value->reference);
402 if (!queueView.ok() || !queueView.value().get().eventAt(index)) {
403 queueView.ignore("work event lookup did not produce an event proxy");
404 return ssq::Object(vm);
405 }
406 auto object = eve::script::makeOwnedSquirrelInstance<ScriptWorkEvent>(
407 vm, std::make_unique<ScriptWorkEvent>(value->reference, index));
408 if (!object.ok()) {
409 object.ignore("failed to create work event proxy");
410 return ssq::Object(vm);
411 }
412 return std::move(object).takeValue();
413 });
414 queue.addFunc("clearEvents", [vm](ScriptWorkQueue* value) {
415 if (!value)
417 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
418 "work queue proxy must not be null", "queue"));
419 auto queueView = Production::resolve(value->reference);
420 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
421 queueView.value().get().clearEvents();
423 });
424 queue.addFunc("snapshot", [vm](ScriptWorkQueue* value) {
425 if (!value)
427 vm,
428 productionBindingFailure<std::string>(eve::DiagnosticCode::InvalidArgument,
429 "work queue proxy must not be null", "queue"),
430 [](std::string text) { return eve::Value(std::move(text)); });
431 auto queueView = Production::resolve(value->reference);
432 if (!queueView.ok())
434 vm,
435 productionBindingFailure<std::string>(queueView.status().code() == eve::StatusCode::NotFound
438 "work queue handle is stale", "queue"),
439 [](std::string text) { return eve::Value(std::move(text)); });
440 return eve::script::projectResult(vm, queueView.value().get().snapshot(),
441 [](std::string text) { return eve::Value(std::move(text)); });
442 });
443 queue.addFunc("restore", [vm](ScriptWorkQueue* value, const std::string& json) {
444 if (!value)
446 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
447 "work queue proxy must not be null", "queue"));
448 auto queueView = Production::resolve(value->reference);
449 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
450 return eve::script::projectResult(vm, queueView.value().get().restore(json));
451 });
452 queue.addFunc("clear", [vm](ScriptWorkQueue* value) {
453 if (!value)
455 vm, productionBindingFailure<void>(eve::DiagnosticCode::InvalidArgument,
456 "work queue proxy must not be null", "queue"));
457 auto queueView = Production::resolve(value->reference);
458 if (!queueView.ok()) return eve::script::projectStatusResult(vm, queueView.status());
459 queueView.value().get().clear();
461 });
462 auto cls = table.addClass(name, Production::create, false);
463 expose(cls);
464}
465
466void Production::expose(ssq::Class& cls) {
467 cls.addFunc("getName", &Production::getName);
468 cls.addFunc("newWorkQueue", [vm = cls.getHandle()](Production*) -> ssq::Table {
469 return makeOwnedProxy<WorkQueueHandleRef, ScriptWorkQueue>(
470 vm, Production::newQueueHandle(), [](WorkQueueHandleRef ref) { return Production::release(ref); }, "queue");
471 });
472}
473
474} // namespace eve::production
double value
Value::Object payload
SQInteger top
float duration
ActiveSource owned
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
int priority
struct SQVM * HSQUIRRELVM
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
std::string message
DiagnosticCode code
wgpu::PopErrorScopeStatus status
float v
std::string text
TokenKind kind
std::string name
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::string error
Definition Package.cpp:60
std::string path
Definition PlayHost.cpp:110
std::function< eve::Result< void >()> release
Definition Procgen.cpp:86
std::string taskId
glm::mat4 view
std::string string
LocalPageCacheEntry slots[ShadowConfig::kLocalSlots]
The single Squirrel projection for common Result, Status and Value.
SimulationTick tick
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
static Result< Duration > fromSeconds(double seconds)
Convert finite seconds to the nearest nanosecond.
Definition Time.cpp:16
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
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Definition Value.cpp:57
Script module factory for generic production queues.
Definition Production.h:387
static eve::Result< WorkQueueHandleRef > newQueueHandle()
Allocates a production queue and returns its ownership reference.
static bool isStale(WorkQueueHandleRef reference) noexcept
Reports whether a queue reference is stale for the current module.
static eve::Result< void > release(WorkQueueHandleRef reference)
Releases a module-owned queue.
static eve::ResultRef< WorkQueue > resolve(WorkQueueHandleRef reference)
Resolves a generation-qualified work-queue identity.
eve::Diagnostic Diagnostic
std::string_view eventKindName(ProductionEventKind kind)
Returns the stable lowercase name of an event kind.
std::string_view taskStateName(TaskState state)
Returns the stable lowercase name of a task state.
eve::script::RuntimeHandleRef< WorkQueueHandleTag > WorkQueueHandleRef
Generation- and module-epoch-qualified production work-queue reference.
Definition Production.h:27
std::unordered_map< std::string, SkillDefinition > & table()
Definition Skill.cpp:65
Result< void > pushValue(HSQUIRRELVM vm, const Value &value, const SquirrelValueOptions &options)
Push a canonical Value into the active Squirrel VM.
ssq::Table projectStatusResult(HSQUIRRELVM vm, const Status &status)
Project a checked native status that carries no payload.
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
Build metadata (engine git commit, build time, third-party version).
Definition Build.cpp:16
DiagnosticCode
Stable machine-readable diagnostic codes.
Definition Diagnostic.h:47
std::optional< std::reference_wrapper< T > > OptionalRef
Optional borrowed reference; it does not extend T's lifetime.
Definition BorrowedRef.h:24
Result< std::reference_wrapper< T > > ResultRef
Checked borrowed reference carried by Result; it does not own T.
Definition BorrowedRef.h:31
EVEngine ECS 集成层:底层实现使用 sunxfancy/ECS.hpp https://github.com/sunxfancy/ECS.hpp
Definition ECS.h:14
Handle plus owner-lifetime epoch for a non-ECS registry object.