载入中...
搜索中...
未找到
ActionModule.cpp
浏览该文件的文档.
2
8#include "tags/GameplayTag.h"
9
10#include <simplesquirrel/simplesquirrel.hpp>
11
12#include <algorithm>
13#include <cstdint>
14#include <functional>
15#include <map>
16#include <memory>
17#include <optional>
18#include <string>
19#include <utility>
20
21namespace eve::action {
22namespace {
23
24class ScriptActionRuntime {
25public:
26 Result<Value> registerAbilityJson(const std::string& abilityJson) {
27 auto decoded = Value::fromJson(abilityJson);
28 if (!decoded) return Result<Value>::failure(decoded.status());
29 auto definition = decodeAbilityAsset(decoded.value());
30 if (!definition) return Result<Value>::failure(definition.status());
31 const std::string definitionId = definition.value().id.format();
32 const LogicalId actionId = definition.value().action.id;
33 auto registered = abilities_.registerDefinition(std::move(definition).takeValue());
34 if (!registered) return Result<Value>::failure(registered.status());
35 abilityActions_[definitionId] = actionId;
36 Value::Object result;
37 result["definitionId"] = definitionId;
38 result["actionId"] = actionId.format();
40 }
41
42 Result<Value> replaceAbilityJson(const std::string& abilityJson) {
43 auto decoded = Value::fromJson(abilityJson);
44 if (!decoded) return Result<Value>::failure(decoded.status());
45 auto definition = decodeAbilityAsset(decoded.value());
46 if (!definition) return Result<Value>::failure(definition.status());
47 const std::string definitionId = definition.value().id.format();
48 const LogicalId actionId = definition.value().action.id;
49 auto replaced = abilities_.replaceDefinition(std::move(definition).takeValue());
50 if (!replaced) return Result<Value>::failure(replaced.status());
51 abilityActions_[definitionId] = actionId;
52 Value::Object result;
53 result["definitionId"] = definitionId;
54 result["actionId"] = actionId.format();
56 }
57
58 Result<Value> registerTimelineAbility(const std::string& definitionText, const std::string& timelineJson,
59 double cooldownSeconds, const std::string& instancingText,
60 const std::string& groupText, const std::string& triggerTag) {
61 return setTimelineAbility(definitionText, timelineJson, cooldownSeconds, instancingText, groupText,
62 triggerTag, false);
63 }
64
65 Result<Value> replaceTimelineAbility(const std::string& definitionText, const std::string& timelineJson,
66 double cooldownSeconds, const std::string& instancingText,
67 const std::string& groupText, const std::string& triggerTag) {
68 return setTimelineAbility(definitionText, timelineJson, cooldownSeconds, instancingText, groupText,
69 triggerTag, true);
70 }
71
72 Result<Value> grantAbility(const std::string& ownerId, const std::string& definitionText) {
73 auto definitionId = LogicalId::parse(definitionText);
74 if (!definitionId)
76 "ability definition id is invalid", "definitionId", {},
77 "action.squirrel"));
78 if (!abilityActions_.contains(definitionText))
80 "ability definition is not registered", definitionText, {},
81 "action.squirrel"));
82 auto granted = abilities_.grant(ownerId, *definitionId);
83 if (!granted) return Result<Value>::failure(granted.status());
84 return abilityGrantValue(granted.value());
85 }
86
87 Result<Value> revokeAbility(std::int64_t grantValue) {
88 auto grant = parseGrant(grantValue);
89 if (!grant) return Result<Value>::failure(grant.status());
90 auto revoked = abilities_.revoke(grant.value());
91 if (!revoked) return Result<Value>::failure(revoked.status());
93 }
94
95 Result<Value> activateAbility(std::int64_t grantValue, std::int64_t tickValue) {
96 auto grant = parseGrant(grantValue);
97 if (!grant) return Result<Value>::failure(grant.status());
98 if (tickValue < 0)
100 DiagnosticCode::InvalidArgument, "ability tick must be non-negative", "tick", {}, "action.squirrel"));
101 auto grantState = abilities_.findGrant(grant.value());
102 if (!grantState) return Result<Value>::failure(grantState.status());
103 const auto action = abilityActions_.find(grantState.value().definitionId.format());
104 if (action == abilityActions_.end())
106 "ability definition action is unavailable", "definitionId",
107 {}, "action.squirrel"));
108 ActionRequest request;
109 request.actionId = action->second;
110 request.requestedTick = SimulationTick(static_cast<std::uint64_t>(tickValue));
111 const auto tick = request.requestedTick;
112 auto activated = abilities_.activate(grant.value(), std::move(request), tick);
113 if (!activated) return Result<Value>::failure(activated.status());
114 return Result<Value>::success(abilityActivationValue(activated.value()),
116 }
117
118 Result<Value> advanceAbilities(std::int64_t tickValue, double seconds) {
119 if (tickValue < 0)
121 DiagnosticCode::InvalidArgument, "ability tick must be non-negative", "tick", {}, "action.squirrel"));
122 auto delta = Duration::fromSeconds(seconds);
123 if (!delta) return Result<Value>::failure(delta.status());
124 Value::Array advances;
125 std::optional<Status> firstFailure;
126 for (const auto& activation : abilities_.activeActivations()) {
127 auto advanced = actions_.advance(activation.executionId,
128 SimulationTick(static_cast<std::uint64_t>(tickValue)), delta.value());
129 if (!advanced) {
130 if (!firstFailure) firstFailure = advanced.status();
131 continue;
132 }
134 value["activationId"] = static_cast<std::int64_t>(activation.id.value());
135 value["executionId"] = static_cast<std::int64_t>(activation.executionId.value());
136 value["phase"] = std::string(actionPhaseName(advanced.value().phase));
137 value["elapsedSeconds"] = advanced.value().totalElapsed.seconds();
138 advances.emplace_back(std::move(value));
139 }
140 auto cooled = abilities_.advanceCooldowns(delta.value());
141 if (!cooled) return Result<Value>::failure(cooled.status());
142 // Always synchronize so terminal (Failed/Cancelled) activations leave the
143 // active list even when one advance returned an error; otherwise the next
144 // call re-hits the same activation and never advances the rest.
145 auto synchronized = abilities_.synchronize();
146 if (!synchronized) return Result<Value>::failure(synchronized.status());
147 if (firstFailure) return Result<Value>::failure(*firstFailure);
148 Value::Object result;
149 result["advances"] = std::move(advances);
150 result["completedCount"] = static_cast<std::int64_t>(synchronized.value());
151 result["activeCount"] = static_cast<std::int64_t>(abilities_.activeActivations().size());
153 }
154
155 Result<Value> cancelAbility(std::int64_t activationValue, std::int64_t tickValue) {
156 if (activationValue <= 0 || tickValue < 0)
158 "ability activation or tick is invalid", "activation", {},
159 "action.squirrel"));
160 const AbilityActivationId activationId(static_cast<std::uint64_t>(activationValue));
161 const auto active = abilities_.activeActivations();
162 const auto found =
163 std::find_if(active.begin(), active.end(), [&](const auto& item) { return item.id == activationId; });
164 if (found == active.end())
166 DiagnosticCode::NotFound, "ability activation was not found", "activationId", {}, "action.squirrel"));
167 auto cancelled =
168 actions_.cancel(found->executionId, SimulationTick(static_cast<std::uint64_t>(tickValue)));
169 if (!cancelled) return Result<Value>::failure(cancelled.status());
170 auto synchronized = abilities_.synchronize();
171 if (!synchronized) return Result<Value>::failure(synchronized.status());
172 Value::Object result;
173 result["activationId"] = activationValue;
174 result["phase"] = std::string("cancelled");
176 }
177
178 Result<Value> abilityGrant(std::int64_t grantValue) const {
179 auto grant = parseGrant(grantValue);
180 if (!grant) return Result<Value>::failure(grant.status());
181 return abilityGrantValue(grant.value());
182 }
183
184 Result<Value> matchingAbilities(const std::string& ownerId, const std::string& eventTag) const {
185 if (!tags::isValidGameplayTagName(eventTag))
187 DiagnosticCode::InvalidArgument, "ability event tag is invalid", "eventTag", {}, "action.squirrel"));
188 Value::Array result;
189 for (const auto grant : abilities_.matchingGrants(ownerId, eventTag))
190 result.emplace_back(static_cast<std::int64_t>(grant.value()));
191 return Result<Value>::success(Value(std::move(result)));
192 }
193
194 Result<Value> submitAction(const std::string& actionIdText, std::int64_t windupNs, std::int64_t activeNs,
195 std::int64_t recoverNs, std::int64_t tickValue) {
196 auto actionId = LogicalId::parse(actionIdText);
197 if (!actionId)
199 "action id is invalid", "actionId", {}, "action.squirrel"));
200 if (tickValue < 0 || windupNs < 0 || activeNs < 0 || recoverNs < 0)
202 "action timing or tick is invalid", "timing", {},
203 "action.squirrel"));
204 ActionDefinition definition;
205 definition.id = *actionId;
206 definition.timing.windup = Duration::fromNanoseconds(static_cast<std::uint64_t>(windupNs));
207 definition.timing.active = Duration::fromNanoseconds(static_cast<std::uint64_t>(activeNs));
208 definition.timing.recover = Duration::fromNanoseconds(static_cast<std::uint64_t>(recoverNs));
209 ActionRequest request;
210 request.actionId = *actionId;
211 request.requestedTick = SimulationTick(static_cast<std::uint64_t>(tickValue));
212 auto submitted = actions_.submit(std::move(definition), std::move(request));
213 if (!submitted) return Result<Value>::failure(submitted.status());
214 Value::Object result;
215 result["executionId"] = static_cast<std::int64_t>(submitted.value().value());
217 }
218
219 Result<Value> advanceAction(std::int64_t executionValue, std::int64_t tickValue, double seconds) {
220 if (executionValue <= 0 || tickValue < 0)
222 "action execution or tick is invalid", "executionId", {},
223 "action.squirrel"));
224 auto delta = Duration::fromSeconds(seconds);
225 if (!delta) return Result<Value>::failure(delta.status());
226 auto advanced =
227 actions_.advance(ActionExecutionId(static_cast<std::uint64_t>(executionValue)),
228 SimulationTick(static_cast<std::uint64_t>(tickValue)), delta.value());
229 if (!advanced) return Result<Value>::failure(advanced.status());
230 Value::Object result;
231 result["executionId"] = executionValue;
232 result["phase"] = std::string(actionPhaseName(advanced.value().phase));
233 result["elapsedSeconds"] = advanced.value().totalElapsed.seconds();
234 Value::Array transitions;
235 for (const auto& transition : advanced.value().transitions) {
236 Value::Object item;
237 item["from"] = std::string(actionPhaseName(transition.from));
238 item["to"] = std::string(actionPhaseName(transition.to));
239 item["tick"] = static_cast<std::int64_t>(transition.tick.value());
240 transitions.emplace_back(std::move(item));
241 }
242 result["transitions"] = std::move(transitions);
244 }
245
246 Result<Value> cancelAction(std::int64_t executionValue, std::int64_t tickValue) {
247 if (executionValue <= 0 || tickValue < 0)
249 "action execution or tick is invalid", "executionId", {},
250 "action.squirrel"));
251 auto cancelled = actions_.cancel(ActionExecutionId(static_cast<std::uint64_t>(executionValue)),
252 SimulationTick(static_cast<std::uint64_t>(tickValue)));
253 if (!cancelled) return Result<Value>::failure(cancelled.status());
254 Value::Object result;
255 result["executionId"] = executionValue;
256 result["phase"] = std::string("cancelled");
258 }
259
260 Result<Value> findAction(std::int64_t executionValue) const {
261 if (executionValue <= 0)
263 "action execution id must be positive", "executionId", {},
264 "action.squirrel"));
265 const auto* execution = actions_.find(ActionExecutionId(static_cast<std::uint64_t>(executionValue)));
266 if (!execution)
268 DiagnosticCode::NotFound, "action execution was not found", "executionId", {}, "action.squirrel"));
269 Value::Object result;
270 result["executionId"] = executionValue;
271 result["definitionId"] = execution->definition().id.format();
272 result["phase"] = std::string(actionPhaseName(execution->phase()));
273 result["elapsedSeconds"] = execution->totalElapsed().seconds();
274 result["phaseSeconds"] = execution->phaseElapsed().seconds();
275 return Result<Value>::success(Value(std::move(result)));
276 }
277
278 std::int64_t executionCount() const { return static_cast<std::int64_t>(actions_.executionCount()); }
279
280private:
281 Result<Value> setTimelineAbility(const std::string& definitionText, const std::string& timelineJson,
282 double cooldownSeconds, const std::string& instancingText,
283 const std::string& groupText, const std::string& triggerTag, bool replace) {
284 auto definitionId = LogicalId::parse(definitionText);
285 if (!definitionId)
287 "ability definition id is invalid", "definitionId", {},
288 "action.squirrel"));
289 auto decoded = Value::fromJson(timelineJson);
290 if (!decoded) return Result<Value>::failure(decoded.status());
291 auto timeline = ActionTimeline::fromValue(decoded.value());
292 if (!timeline) return Result<Value>::failure(timeline.status());
293 auto cooldown = Duration::fromSeconds(cooldownSeconds);
294 if (!cooldown) return Result<Value>::failure(cooldown.status());
295
296 AbilityDefinition definition;
297 definition.id = *definitionId;
298 definition.action.id = timeline.value().actionId;
299 definition.action.timeline = timeline.value();
300 definition.cooldown = cooldown.value();
301 if (instancingText == "non-instanced")
302 definition.instancing = AbilityInstancingPolicy::NonInstanced;
303 else if (instancingText == "per-owner")
304 definition.instancing = AbilityInstancingPolicy::PerOwner;
305 else if (instancingText == "per-execution")
306 definition.instancing = AbilityInstancingPolicy::PerExecution;
307 else
309 "ability instancing policy is invalid", "instancing", {},
310 "action.squirrel"));
311 if (groupText == "independent")
312 definition.activationGroup = AbilityActivationGroup::Independent;
313 else if (groupText == "exclusive-replaceable")
314 definition.activationGroup = AbilityActivationGroup::ExclusiveReplaceable;
315 else if (groupText == "exclusive-blocking")
316 definition.activationGroup = AbilityActivationGroup::ExclusiveBlocking;
317 else
319 "ability activation group is invalid", "activationGroup",
320 {}, "action.squirrel"));
321 if (!triggerTag.empty()) {
322 if (!tags::isValidGameplayTagName(triggerTag))
324 "ability trigger tag is invalid", "triggerTag", {},
325 "action.squirrel"));
326 definition.triggers.push_back({triggerTag, tags::GameplayTagMatch::Exact});
327 }
328
329 const auto& splits = timeline.value().splitTimestamps;
330 if (splits.empty()) {
331 definition.action.timing.active = timeline.value().duration;
332 } else if (splits.size() == 1) {
333 definition.action.timing.windup = splits[0];
334 definition.action.timing.active =
335 Duration::fromNanoseconds(timeline.value().duration.nanoseconds() - splits[0].nanoseconds());
336 } else {
337 definition.action.timing.windup = splits[0];
338 definition.action.timing.active =
339 Duration::fromNanoseconds(splits[1].nanoseconds() - splits[0].nanoseconds());
340 definition.action.timing.recover =
341 Duration::fromNanoseconds(timeline.value().duration.nanoseconds() - splits[1].nanoseconds());
342 }
343 auto changed =
344 replace ? abilities_.replaceDefinition(definition) : abilities_.registerDefinition(definition);
345 if (!changed) return Result<Value>::failure(changed.status());
346 abilityActions_[definitionText] = definition.action.id;
347 Value::Object result;
348 result["definitionId"] = definitionText;
349 result["actionId"] = definition.action.id.format();
350 result["durationSeconds"] = timeline.value().duration.seconds();
351 result["sectionCount"] = static_cast<std::int64_t>(timeline.value().sectionCount());
353 }
354
355 static Result<AbilityGrantId> parseGrant(std::int64_t value) {
356 if (value <= 0)
358 "ability grant id must be positive", "grantId", {},
359 "action.squirrel"));
360 return Result<AbilityGrantId>::success(AbilityGrantId(static_cast<std::uint64_t>(value)));
361 }
362
363 Result<Value> abilityGrantValue(AbilityGrantId grantId) const {
364 auto state = abilities_.findGrant(grantId);
365 if (!state) return Result<Value>::failure(state.status());
366 Value::Object result;
367 result["grantId"] = static_cast<std::int64_t>(state.value().grantId.value());
368 result["ownerId"] = state.value().ownerId;
369 result["definitionId"] = state.value().definitionId.format();
370 result["cooldownSeconds"] = state.value().cooldownRemaining.seconds();
371 return Result<Value>::success(Value(std::move(result)));
372 }
373
374 static Value abilityActivationValue(const AbilityActivation& activation) {
375 Value::Object result;
376 result["activationId"] = static_cast<std::int64_t>(activation.id.value());
377 result["grantId"] = static_cast<std::int64_t>(activation.grantId.value());
378 result["instanceId"] = static_cast<std::int64_t>(activation.instanceId.value());
379 result["executionId"] = static_cast<std::int64_t>(activation.executionId.value());
380 result["ownerId"] = activation.ownerId;
381 return Value(std::move(result));
382 }
383
384 ActionRuntime actions_;
385 AbilityRuntime abilities_{actions_};
386 std::map<std::string, LogicalId, std::less<>> abilityActions_;
387};
388
389ssq::Table project(HSQUIRRELVM vm, Result<Value>&& result) {
390 return script::projectResult(vm, std::move(result), [](Value value) { return value; });
391}
392
393ssq::Table nullRuntime(HSQUIRRELVM vm) {
395 "action runtime must not be null", "runtime", {},
396 "action.squirrel")));
397}
398
399ssq::Table newRuntime(HSQUIRRELVM vm) {
400 auto runtime = std::make_unique<ScriptActionRuntime>();
401 auto object = script::makeOwnedSquirrelInstance<ScriptActionRuntime>(vm, std::move(runtime));
402 if (!object) return script::projectStatusResult(vm, object.status());
404 result.set("value", std::move(object).takeValue());
405 result.set("ownership", std::string("owned"));
406 return result;
407}
408
409} // namespace
410
412
413void Action::expose(ssq::Table& table) {
414 const HSQUIRRELVM vm = table.getHandle();
415 auto runtime = table.addClass<ScriptActionRuntime>(
416 "ActionRuntime", std::function<ScriptActionRuntime*()>([] { return nullptr; }), true);
417 runtime.addFunc("ownership", [](ScriptActionRuntime*) { return std::string("owned"); });
418 runtime.addFunc("registerAbilityJson", [vm](ScriptActionRuntime* self, const std::string& json) {
419 return self ? project(vm, self->registerAbilityJson(json)) : nullRuntime(vm);
420 });
421 runtime.addFunc("replaceAbilityJson", [vm](ScriptActionRuntime* self, const std::string& json) {
422 return self ? project(vm, self->replaceAbilityJson(json)) : nullRuntime(vm);
423 });
424 runtime.addFunc("registerTimelineAbility",
425 [vm](ScriptActionRuntime* self, const std::string& definitionId, const std::string& timelineJson,
426 float cooldownSeconds, const std::string& instancing, const std::string& activationGroup,
427 const std::string& triggerTag) {
428 return self ? project(vm, self->registerTimelineAbility(definitionId, timelineJson,
429 cooldownSeconds, instancing,
430 activationGroup, triggerTag))
431 : nullRuntime(vm);
432 });
433 runtime.addFunc("replaceTimelineAbility",
434 [vm](ScriptActionRuntime* self, const std::string& definitionId, const std::string& timelineJson,
435 float cooldownSeconds, const std::string& instancing, const std::string& activationGroup,
436 const std::string& triggerTag) {
437 return self ? project(vm, self->replaceTimelineAbility(definitionId, timelineJson,
438 cooldownSeconds, instancing,
439 activationGroup, triggerTag))
440 : nullRuntime(vm);
441 });
442 runtime.addFunc("grantAbility",
443 [vm](ScriptActionRuntime* self, const std::string& owner, const std::string& definitionId) {
444 return self ? project(vm, self->grantAbility(owner, definitionId)) : nullRuntime(vm);
445 });
446 runtime.addFunc("revokeAbility", [vm](ScriptActionRuntime* self, std::int64_t grantId) {
447 return self ? project(vm, self->revokeAbility(grantId)) : nullRuntime(vm);
448 });
449 runtime.addFunc("activateAbility", [vm](ScriptActionRuntime* self, std::int64_t grantId, std::int64_t tick) {
450 return self ? project(vm, self->activateAbility(grantId, tick)) : nullRuntime(vm);
451 });
452 runtime.addFunc("advanceAbilities", [vm](ScriptActionRuntime* self, std::int64_t tick, float seconds) {
453 return self ? project(vm, self->advanceAbilities(tick, seconds)) : nullRuntime(vm);
454 });
455 runtime.addFunc("cancelAbility", [vm](ScriptActionRuntime* self, std::int64_t activationId, std::int64_t tick) {
456 return self ? project(vm, self->cancelAbility(activationId, tick)) : nullRuntime(vm);
457 });
458 runtime.addFunc("abilityGrant", [vm](ScriptActionRuntime* self, std::int64_t grantId) {
459 return self ? project(vm, self->abilityGrant(grantId)) : nullRuntime(vm);
460 });
461 runtime.addFunc("matchingAbilities",
462 [vm](ScriptActionRuntime* self, const std::string& owner, const std::string& eventTag) {
463 return self ? project(vm, self->matchingAbilities(owner, eventTag)) : nullRuntime(vm);
464 });
465 runtime.addFunc("submitAction", [vm](ScriptActionRuntime* self, const std::string& actionId, std::int64_t windupNs,
466 std::int64_t activeNs, std::int64_t recoverNs, std::int64_t tick) {
467 return self ? project(vm, self->submitAction(actionId, windupNs, activeNs, recoverNs, tick))
468 : nullRuntime(vm);
469 });
470 runtime.addFunc("advanceAction",
471 [vm](ScriptActionRuntime* self, std::int64_t executionId, std::int64_t tick, float seconds) {
472 return self ? project(vm, self->advanceAction(executionId, tick, seconds)) : nullRuntime(vm);
473 });
474 runtime.addFunc("cancelAction", [vm](ScriptActionRuntime* self, std::int64_t executionId, std::int64_t tick) {
475 return self ? project(vm, self->cancelAction(executionId, tick)) : nullRuntime(vm);
476 });
477 runtime.addFunc("findAction", [vm](ScriptActionRuntime* self, std::int64_t executionId) {
478 return self ? project(vm, self->findAction(executionId)) : nullRuntime(vm);
479 });
480 runtime.addFunc("executionCount",
481 [](ScriptActionRuntime* self) { return self ? self->executionCount() : std::int64_t{0}; });
482
483 auto module = table.addClass(name, Action::create, false);
484 module.addFunc("getName", &Action::getName);
485 module.addFunc("newRuntime", [vm](Action*) { return newRuntime(vm); });
486}
487
488void Action::expose(ssq::Class& cls) {
489 cls.addFunc("getName", &Action::getName);
490 cls.addFunc("newRuntime", [vm = cls.getHandle()](Action*) { return newRuntime(vm); });
491}
492
493} // namespace eve::action
Versioned persistent codec for ability definitions.
Grants, cooldowns, instancing, activation groups and gameplay-event triggers.
Script-facing factory for ActionRuntime + AbilityRuntime.
double value
Versioned, deterministic authoring timeline for gameplay actions.
bool & active
eve::action::ActionExecutionId executionId
struct SQVM * HSQUIRRELVM
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
Stable hierarchical gameplay-tag definitions and registry.
const GltfImportRequest & request
wgpu::PopErrorScopeStatus status
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::string action
Definition PlayHost.cpp:117
bool found
The single Squirrel projection for common Result, Status and Value.
Explicit Value/Owned/Borrowed semantics at the Squirrel boundary.
AbilityInstancingPolicy instancing
SimulationTick tick
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
static constexpr Duration fromNanoseconds(std::int64_t nanoseconds) noexcept
Construct an exact duration from nanoseconds.
Definition Time.h:55
static std::optional< LogicalId > parse(std::string_view text)
Parses a scoped logical name.
Definition Identity.cpp:36
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
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
Definition Value.cpp:57
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
Factory module for script-owned action/ability protocol runtimes.
constexpr std::uint64_t value() const noexcept
Returns the underlying value at an explicit protocol boundary.
const char * actionPhaseName(ActionPhase phase) noexcept
Return the stable lowercase spelling of an action phase.
Definition Action.cpp:42
eve::detail::StrongUint64< AbilityActivationIdTag > AbilityActivationId
Opaque identity of one activation attempt accepted by ActionRuntime.
Result< AbilityDefinition > decodeAbilityAsset(const Value &value)
Decode schema version 2 or migrate version 1 millisecond data to the current definition.
eve::detail::StrongUint64< ActionExecutionIdTag > ActionExecutionId
Definition Action.h:157
eve::detail::StrongUint64< AbilityGrantIdTag > AbilityGrantId
Opaque identity of one owner-to-definition grant.
const ClimbingActionDefinition * findAction(const ClimbingProfile &profile, std::string_view id)
Optional action. @borrowed From profile; lifetime ends when the caller-owned profile changes or is de...
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
ssq::Table project(HSQUIRRELVM vm, const eve::Result< void > &result)
Project a completed editing result that has no payload.
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.
bool isValidGameplayTagName(std::string_view name) noexcept
Returns whether a name is a canonical dot-separated gameplay tag.
detail::StrongUint64< detail::SimulationTickTag > SimulationTick
Deterministic simulation time step; it is not wall-clock time.
Definition Time.h:31
static Result< ActionTimeline > fromValue(const Value &value)
Decode and validate one canonical schema value transactionally.