载入中...
搜索中...
未找到
Effects.cpp
浏览该文件的文档.
1#include "effects/Effects.h"
2
4
5#include <simplesquirrel/simplesquirrel.hpp>
6
7#include <cstdint>
8#include <functional>
9#include <utility>
10
11namespace eve::effects {
12
13namespace {
14
16struct ScriptEffectContainer {
17 explicit ScriptEffectContainer(EffectContainerHandleRef value) : reference(value) {}
18 ~ScriptEffectContainer() noexcept {
19 Effects::release(reference).ignore("script effect container proxy destruction");
20 }
22};
23
24eve::Result<EffectDefinition> effectDefinitionFromBinding(const std::string& type, int priority, float duration,
25 const std::string& stackKey,
26 const std::string& policyNameValue) {
27 StackPolicy policy;
28 if (!parsePolicy(policyNameValue, policy))
30 eve::DiagnosticCode::InvalidArgument, "unknown effect stack policy", "policy", {}, "effects.squirrel"));
31
32 EffectDefinition definition;
33 definition.id = type;
34 definition.stackKey = stackKey;
35 definition.priority = priority;
36 definition.duration = duration;
37 switch (policy) {
38 case StackPolicy::Replace: definition.policy.stackMode = StackMode::Replace; break;
39 case StackPolicy::Stack: definition.policy.stackMode = StackMode::NewInstance; break;
40 case StackPolicy::Refresh: definition.policy.stackMode = StackMode::Reuse; break;
41 }
42 auto validation = definition.validate();
43 if (!validation.ok()) return eve::Result<EffectDefinition>::failure(validation.status());
44 return eve::Result<EffectDefinition>::success(std::move(definition));
45}
46
47eve::Value effectUpdateProjection(EffectUpdateSummary summary) {
49 {"expired", eve::Value(static_cast<std::int64_t>(summary.expired))},
50 {"elapsedSeconds", eve::Value(summary.elapsedSeconds)},
51 {"tick", eve::Value(static_cast<std::int64_t>(summary.tick.value()))},
52 });
53}
54
55template <class Ref, class Proxy, class Release>
56ssq::Table makeOwnedProxy(HSQUIRRELVM vm, eve::Result<Ref>&& reference, Release&& release) {
58 const Ref ref = std::move(reference).takeValue();
59 auto object = eve::script::makeOwnedSquirrelInstance<Proxy>(vm, std::make_unique<Proxy>(ref));
60 if (!object) {
61 const eve::Status status = object.status();
62 object.ignore("failed to create owned effects proxy");
63 std::invoke(std::forward<Release>(release), ref).ignore("rollback failed owned effects allocation");
65 }
66 ssq::Object owned = std::move(object).takeValue();
68 result.set("value", owned);
69 result.set("ownership", std::string("owned"));
70 result.set("ownerEpoch", static_cast<std::int64_t>(ref.ownerEpoch));
71 result.set("handle", static_cast<std::int64_t>(ref.packed()));
72 return result;
73}
74
75} // namespace
76
78 Effects* module = Effects::create();
79 return module->containers_.emplace(std::make_unique<EffectContainer>());
80}
81
83 Effects* module = ModuleManager::getInstance<Effects>("Effects");
84 if (!module) return {};
85 return module->containers_.resolve(reference);
86}
87
89 Effects* module = ModuleManager::getInstance<Effects>("Effects");
90 if (!module)
92 "Effects module is no longer loaded", "container", {},
93 "effects.squirrel"));
94 return module->containers_.erase(reference);
95}
96
98 if (!reference.isValid()) return false;
99 Effects* module = ModuleManager::getInstance<Effects>("Effects");
100 return !module || module->containers_.isStale(reference);
101}
102
104
105void Effects::expose(ssq::Table& table) {
106 const HSQUIRRELVM vm = table.getHandle();
107 auto payload = table.addClass<EffectPayload>(
108 "EffectPayload", std::function<EffectPayload*()>([]() -> EffectPayload* { return nullptr; }), false);
109 payload.addFunc("setString", &EffectPayload::setString);
110 payload.addFunc("setNumber", [](EffectPayload* value, const std::string& key, float number) {
111 if (value) value->setNumber(key, number);
112 });
113 payload.addFunc("setBool", &EffectPayload::setBool);
114 payload.addFunc("setNull", &EffectPayload::setNull);
115 payload.addFunc("setJson", [vm](EffectPayload* value, const std::string& key, const std::string& json) {
116 if (!value)
119 "effect payload must not be null", "payload", {},
120 "effects.squirrel")));
121 return eve::script::projectResult(vm, value->setJson(key, json));
122 });
123 payload.addFunc("has", &EffectPayload::has);
124 payload.addFunc("erase", [vm](EffectPayload* value, const std::string& key) {
125 if (!value)
128 "effect payload must not be null", "payload", {},
129 "effects.squirrel")));
130 return eve::script::projectResult(vm, value->erase(key));
131 });
132 payload.addFunc("getJson", &EffectPayload::getJson);
133 payload.addFunc("toJson", &EffectPayload::toJson);
134 payload.addFunc("clear", &EffectPayload::clear);
135
136 auto effect =
137 table.addClass<Effect>("Effect", std::function<Effect*()>([]() -> Effect* { return nullptr; }), false);
138 effect.addFunc("getId", [](Effect* value) { return value ? value->id : std::string{}; });
139 effect.addFunc("getSubject", [](Effect* value) { return value ? value->subject : std::string{}; });
140 effect.addFunc("getType", [](Effect* value) { return value ? value->type : std::string{}; });
141 effect.addFunc("getSource", [](Effect* value) { return value ? value->source : std::string{}; });
142 effect.addFunc("getStackKey", [](Effect* value) { return value ? value->stackKey : std::string{}; });
143 effect.addFunc("getPriority", [](Effect* value) { return value ? value->priority : 0; });
144 effect.addFunc("getDuration", [](Effect* value) { return value ? static_cast<float>(value->duration) : 0.0f; });
145 effect.addFunc("getRemaining", [](Effect* value) { return value ? static_cast<float>(value->remaining) : 0.0f; });
146 effect.addFunc("getMagnitude", [](Effect* value) { return value ? static_cast<float>(value->magnitude) : 0.0f; });
147 effect.addFunc("getStackCount", [](Effect* value) { return value ? static_cast<int>(value->stackCount) : 0; });
148 effect.addFunc("getPayload", [](Effect* value) -> EffectPayload* { return value ? &value->payload : nullptr; });
149 effect.addFunc("addTag", [vm](Effect* value, const std::string& tag) {
150 if (!value)
152 eve::DiagnosticCode::InvalidArgument, "effect must not be null",
153 "effect", {}, "effects.squirrel")));
154 return eve::script::projectResult(vm, value->addTag(tag));
155 });
156 effect.addFunc("removeTag", [vm](Effect* value, const std::string& tag) {
157 if (!value)
159 eve::DiagnosticCode::InvalidArgument, "effect must not be null",
160 "effect", {}, "effects.squirrel")));
161 return eve::script::projectResult(vm, value->removeTag(tag));
162 });
163 effect.addFunc("hasTag", [](Effect* value, const std::string& tag) { return value && value->hasTag(tag); });
164 effect.addFunc("tagCount", &Effect::tagCount);
165 effect.addFunc("tagAt", &Effect::tagAt);
166
167 auto event = table.addClass<EffectEvent>(
168 "EffectEvent", std::function<EffectEvent*()>([]() -> EffectEvent* { return nullptr; }), false);
169 event.addFunc("getSequence", [](EffectEvent* value) {
170 return value ? static_cast<std::int64_t>(value->sequence) : std::int64_t{0};
171 });
172 event.addFunc("getKind", [](EffectEvent* value) { return value ? eventKindName(value->kind) : std::string{}; });
173 event.addFunc("getEffectId", [](EffectEvent* value) { return value ? value->effectId : std::string{}; });
174 event.addFunc("getSubject", [](EffectEvent* value) { return value ? value->subject : std::string{}; });
175 event.addFunc("getType", [](EffectEvent* value) { return value ? value->type : std::string{}; });
176 event.addFunc("getSource", [](EffectEvent* value) { return value ? value->source : std::string{}; });
177 event.addFunc("getReason", [](EffectEvent* value) { return value ? value->reason : std::string{}; });
178
179 auto container = table.addClass<EffectContainer>(
180 "EffectContainer", std::function<EffectContainer*()>([]() -> EffectContainer* { return nullptr; }), false);
181 container.addFunc("apply", [vm](EffectContainer* value, const std::string& subject, const std::string& type,
182 const std::string& source, int priority, float duration,
183 const std::string& stackKey, const std::string& policyNameValue) {
184 if (!value)
186 vm,
188 "effect container must not be null",
189 "container", {}, "effects.squirrel")),
190 [](std::string&& id) { return eve::Value(std::move(id)); });
191 auto definition = effectDefinitionFromBinding(type, priority, duration, stackKey, policyNameValue);
192 if (!definition.ok())
194 vm,
198 definition.status().describe(), "definition", {}, "effects.squirrel")),
199 [](std::string&& id) { return eve::Value(std::move(id)); });
200 EffectDefinition input = std::move(definition).takeValue();
202 [](std::string&& id) { return eve::Value(std::move(id)); });
203 });
204 container.addFunc(
205 "applyCanonical",
206 [vm](EffectContainer* value, const std::string& subject, const std::string& type, const std::string& source,
207 int priority, float duration, const std::string& stackKey, const std::string& policyNameValue) {
208 if (!value)
210 vm,
212 "effect container must not be null",
213 "container", {}, "effects.squirrel")),
214 [](eve::EffectId id) { return eve::Value(id.isNil() ? std::string{} : id.format()); });
215 auto definition = effectDefinitionFromBinding(type, priority, duration, stackKey, policyNameValue);
216 if (!definition.ok())
218 vm,
222 definition.status().describe(), "definition", {}, "effects.squirrel")),
223 [](eve::EffectId id) { return eve::Value(id.isNil() ? std::string{} : id.format()); });
224 EffectDefinition input = std::move(definition).takeValue();
225 return eve::script::projectResult(vm, value->applyCanonical(input, subject, source), [](eve::EffectId id) {
226 return eve::Value(id.isNil() ? std::string{} : id.format());
227 });
228 });
229 container.addFunc("remove", [vm](EffectContainer* value, const std::string& id, const std::string& reason) {
230 if (!value)
233 "effect container must not be null", "container",
234 {}, "effects.squirrel")));
235 return eve::script::projectResult(vm, value->remove(id, reason));
236 });
237 container.addFunc("update", [vm](EffectContainer* value, float dtSeconds) {
238 if (!value)
240 vm,
242 "effect container must not be null",
243 "container", {}, "effects.squirrel")),
244 [](EffectUpdateSummary summary) { return effectUpdateProjection(summary); });
245 return eve::script::projectResult(vm, value->update(dtSeconds),
246 [](EffectUpdateSummary summary) { return effectUpdateProjection(summary); });
247 });
248 container.addFunc("clear", &EffectContainer::clear);
249 container.addFunc("find", [](EffectContainer* value, const std::string& id) -> Effect* {
250 return value ? value->find(id) : nullptr;
251 });
252 container.addFunc("effectCount", &EffectContainer::effectCount);
253 container.addFunc("effectAt", [](EffectContainer* value, int index) -> Effect* {
254 return value ? value->effectAt(index) : nullptr;
255 });
256 container.addFunc("subjectCount", &EffectContainer::subjectCount);
257 container.addFunc("subjectAt", [](EffectContainer* value, const std::string& subject, int index) -> Effect* {
258 return value ? value->subjectAt(subject, index) : nullptr;
259 });
260 container.addFunc("taggedCount", &EffectContainer::taggedCount);
261 container.addFunc("taggedAt",
262 [](EffectContainer* value, const std::string& subject, const std::string& tag,
263 int index) -> Effect* { return value ? value->taggedAt(subject, tag, index) : nullptr; });
264 container.addFunc("eventCount", &EffectContainer::eventCount);
265 container.addFunc("eventAt", [](EffectContainer* value, int index) -> EffectEvent* {
266 return value ? value->eventAt(index) : nullptr;
267 });
268 container.addFunc("clearEvents", &EffectContainer::clearEvents);
269
270 // Canonical script ownership path. The proxy is owned by Squirrel through
271 // a release hook; each operation resolves its RuntimeHandleRef as a
272 // Borrowed observation and therefore detects release/unload staleness.
273 auto ownedContainer = table.addClass<ScriptEffectContainer>(
274 "EffectContainerProxy",
275 std::function<ScriptEffectContainer*()>([]() -> ScriptEffectContainer* { return nullptr; }), false);
276 ownedContainer.addFunc("ownership", [](ScriptEffectContainer*) {
278 });
279 ownedContainer.addFunc(
280 "handle", [](ScriptEffectContainer* value) { return value ? value->reference.packed() : std::uint64_t{0}; });
281 ownedContainer.addFunc("isStale",
282 [](ScriptEffectContainer* value) { return !value || Effects::isStale(value->reference); });
283 ownedContainer.addFunc("release", [vm](ScriptEffectContainer* value) {
284 if (!value)
287 "owned effect container proxy must not be null",
288 "container", {}, "effects.squirrel")));
289 auto result = Effects::release(value->reference);
290 // Retain the coordinates after release so the same script object can
291 // report a stale handle and a second release returns StaleHandle.
292 return eve::script::projectResult(vm, std::move(result));
293 });
294 ownedContainer.addFunc(
295 "apply", [vm](ScriptEffectContainer* value, const std::string& subject, const std::string& type,
296 const std::string& source, int priority, float duration, const std::string& stackKey,
297 const std::string& policyNameValue) {
298 if (!value)
300 vm,
302 eve::DiagnosticCode::InvalidArgument, "owned effect container proxy must not be null",
303 "container", {}, "effects.squirrel")),
304 [](std::string&& id) { return eve::Value(std::move(id)); });
305 auto containerView = Effects::resolve(value->reference);
306 if (!containerView.isBound())
308 vm,
310 "owned effect container handle is stale",
311 "container", {}, "effects.squirrel")),
312 [](std::string&& id) { return eve::Value(std::move(id)); });
313 auto definition = effectDefinitionFromBinding(type, priority, duration, stackKey, policyNameValue);
314 if (!definition)
316 vm,
318 definition.status().describe(),
319 "definition", {}, "effects.squirrel")),
320 [](std::string&& id) { return eve::Value(std::move(id)); });
321 auto input = std::move(definition).takeValue();
322 return eve::script::projectResult(vm, containerView->apply(input, subject, source),
323 [](std::string&& id) { return eve::Value(std::move(id)); });
324 });
325 ownedContainer.addFunc("update", [vm](ScriptEffectContainer* value, float dt) {
326 if (!value)
328 vm,
330 eve::DiagnosticCode::InvalidArgument, "owned effect container proxy must not be null", "container",
331 {}, "effects.squirrel")),
332 [](EffectUpdateSummary summary) { return effectUpdateProjection(summary); });
333 auto containerView = Effects::resolve(value->reference);
334 if (!containerView.isBound())
336 vm,
338 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "owned effect container handle is stale",
339 "container", {}, "effects.squirrel")),
340 [](EffectUpdateSummary summary) { return effectUpdateProjection(summary); });
341 return eve::script::projectResult(vm, containerView->update(dt),
342 [](EffectUpdateSummary summary) { return effectUpdateProjection(summary); });
343 });
344 ownedContainer.addFunc("clear", [](ScriptEffectContainer* value) {
345 if (!value) return;
346 auto containerView = Effects::resolve(value->reference);
347 if (containerView.isBound()) containerView->clear();
348 });
349 ownedContainer.addFunc("find", [](ScriptEffectContainer* value, const std::string& id) -> Effect* {
350 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
351 return containerView.isBound() ? containerView->find(id) : nullptr;
352 });
353 ownedContainer.addFunc("effectCount", [](ScriptEffectContainer* value) {
354 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
355 return containerView.isBound() ? containerView->effectCount() : 0;
356 });
357 ownedContainer.addFunc("effectAt", [](ScriptEffectContainer* value, int index) -> Effect* {
358 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
359 return containerView.isBound() ? containerView->effectAt(index) : nullptr;
360 });
361 ownedContainer.addFunc("subjectCount", [](ScriptEffectContainer* value, const std::string& subject) {
362 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
363 return containerView.isBound() ? containerView->subjectCount(subject) : 0;
364 });
365 ownedContainer.addFunc(
366 "subjectAt", [](ScriptEffectContainer* value, const std::string& subject, int index) -> Effect* {
367 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
368 return containerView.isBound() ? containerView->subjectAt(subject, index) : nullptr;
369 });
370 ownedContainer.addFunc(
371 "taggedCount", [](ScriptEffectContainer* value, const std::string& subject, const std::string& tag) {
372 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
373 return containerView.isBound() ? containerView->taggedCount(subject, tag) : 0;
374 });
375 ownedContainer.addFunc(
376 "taggedAt",
377 [](ScriptEffectContainer* value, const std::string& subject, const std::string& tag, int index) -> Effect* {
378 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
379 return containerView.isBound() ? containerView->taggedAt(subject, tag, index) : nullptr;
380 });
381 ownedContainer.addFunc("eventCount", [](ScriptEffectContainer* value) {
382 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
383 return containerView.isBound() ? containerView->eventCount() : 0;
384 });
385 ownedContainer.addFunc("eventAt", [](ScriptEffectContainer* value, int index) -> EffectEvent* {
386 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
387 return containerView.isBound() ? containerView->eventAt(index) : nullptr;
388 });
389 ownedContainer.addFunc("clearEvents", [](ScriptEffectContainer* value) {
390 auto containerView = value ? Effects::resolve(value->reference) : eve::script::Borrowed<EffectContainer>();
391 if (containerView.isBound()) containerView->clearEvents();
392 });
393 ownedContainer.addFunc(
394 "remove", [vm](ScriptEffectContainer* value, const std::string& id, const std::string& reason) {
395 if (!value)
398 eve::DiagnosticCode::InvalidArgument, "owned effect container proxy must not be null",
399 "container", {}, "effects.squirrel")));
400 auto containerView = Effects::resolve(value->reference);
401 if (!containerView.isBound())
404 "owned effect container handle is stale",
405 "container", {}, "effects.squirrel")));
406 return eve::script::projectResult(vm, containerView->remove(id, reason));
407 });
408 ownedContainer.addFunc(
409 "applyCanonical", [vm](ScriptEffectContainer* value, const std::string& subject, const std::string& type,
410 const std::string& source, int priority, float duration, const std::string& stackKey,
411 const std::string& policyNameValue) {
412 if (!value)
414 vm,
416 eve::DiagnosticCode::InvalidArgument, "owned effect container proxy must not be null",
417 "container", {}, "effects.squirrel")),
418 [](eve::EffectId id) { return eve::Value(id.isNil() ? std::string{} : id.format()); });
419 auto containerView = Effects::resolve(value->reference);
420 if (!containerView.isBound())
422 vm,
424 "owned effect container handle is stale",
425 "container", {}, "effects.squirrel")),
426 [](eve::EffectId id) { return eve::Value(id.isNil() ? std::string{} : id.format()); });
427 auto definition = effectDefinitionFromBinding(type, priority, duration, stackKey, policyNameValue);
428 if (!definition.ok())
430 vm,
432 definition.status().describe(),
433 "definition", {}, "effects.squirrel")),
434 [](eve::EffectId id) { return eve::Value(id.isNil() ? std::string{} : id.format()); });
435 auto input = std::move(definition).takeValue();
437 vm, containerView->applyCanonical(input, subject, source),
438 [](eve::EffectId id) { return eve::Value(id.isNil() ? std::string{} : id.format()); });
439 });
440
441 auto cls = table.addClass(name, Effects::create, false);
442 expose(cls);
443}
444
445void Effects::expose(ssq::Class& cls) {
446 cls.addFunc("getName", &Effects::getName);
447 cls.addFunc("newContainer", [vm = cls.getHandle()](Effects*) -> ssq::Table {
448 return makeOwnedProxy<EffectContainerHandleRef, ScriptEffectContainer>(
449 vm, Effects::newContainer(), [](EffectContainerHandleRef ref) { return Effects::release(ref); });
450 });
451}
452
453} // namespace eve::effects
double value
Value::Object payload
float duration
int subject
Definition AnimSmr.cpp:163
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
Public effects umbrella and script module facade.
EvpackChunkInput input
Definition Evpack.cpp:170
std::uint32_t key
wgpu::PopErrorScopeStatus status
std::string name
const std::string * tag
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::unique_ptr< ParticleEffect > effect
std::string script
Definition PlayHost.cpp:116
std::string id
Definition PlayHost.cpp:108
std::function< eve::Result< void >()> release
Definition Procgen.cpp:86
double number
std::string string
The single Squirrel projection for common Result, Status and Value.
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
void ignore(std::string_view reason={}) const noexcept
Explicitly discard this result after documenting the reason.
Definition Result.h:537
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
std::map< std::string, Value > Object
Definition Value.h:34
Id128 public API.
Definition Identity.h:112
void clearEvents()
Clears retained events without resetting their sequence counter.
int eventCount() const
Returns retained event count.
int taggedCount(const std::string &subject, const std::string &tag) const
Returns active subject instances containing a tag.
int effectCount() const
Returns active instance count in deterministic creation order.
int subjectCount(const std::string &subject) const
Returns active instance count for a subject.
void clear()
Removes all active instances and retained events, resetting id sequences.
Deterministic JSON-compatible payload carried by a definition or instance.
Definition EffectTypes.h:63
std::string toJson() const
Serializes all fields as a deterministic JSON object.
bool has(const std::string &key) const
Returns whether a field exists.
void setBool(const std::string &key, bool value)
Sets a JSON boolean field.
void setString(const std::string &key, const std::string &value)
Sets a JSON string field.
void setNull(const std::string &key)
Sets a JSON null field.
std::string getJson(const std::string &key) const
Serializes a field's typed Value to JSON text, or returns empty when absent/invalid.
void clear()
Removes every field.
Script module factory for generic effect containers.
Definition Effects.h:24
static bool isStale(EffectContainerHandleRef reference) noexcept
Reports whether a container reference is invalid for the current module.
Definition Effects.cpp:97
static eve::Result< void > release(EffectContainerHandleRef reference)
Releases a container owned by the Effects module.
Definition Effects.cpp:88
static eve::Result< EffectContainerHandleRef > newContainer()
Allocates a container and returns its generation-qualified ownership reference.
Definition Effects.cpp:77
static eve::script::Borrowed< EffectContainer > resolve(EffectContainerHandleRef reference) noexcept
Resolves a live container as a non-owning observation.
Definition Effects.cpp:82
Non-owning C++ observation with no implicit lifetime extension.
StackPolicy
Compatibility policy used by the original effects facade.
Definition EffectTypes.h:28
bool parsePolicy(const std::string &name, StackPolicy &policy)
Parses a lowercase legacy stack policy name.
std::string eventKindName(EffectEventKind kind)
Returns the stable lowercase name of an event kind.
eve::script::RuntimeHandleRef< EffectContainerHandleTag > EffectContainerHandleRef
Generation-qualified reference to a module-owned effect container.
Definition Effects.h:21
EffectInstance Effect
Backward-compatible name for the runtime instance type.
std::unordered_map< std::string, SkillDefinition > & table()
Definition Skill.cpp:65
ssq::Table projectStatusResult(HSQUIRRELVM vm, const Status &status)
Project a checked native status that carries no payload.
const char * objectSemanticName(ObjectSemantic semantic) noexcept
Returns the stable name used by diagnostics and documentation.
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::string tagAt(int index) const
Returns a tag by lexical index, or an empty string.
int tagCount() const
Returns the number of tags.
Handle plus owner-lifetime epoch for a non-ECS registry object.