11#include <simplesquirrel/simplesquirrel.hpp>
19eve::Value candidateValue(ClimbingCandidate candidate) {
21 {
"actionId", std::move(candidate.actionId)},
22 {
"definitionGeneration", std::to_string(candidate.definitionGeneration)},
23 {
"world",
static_cast<std::int64_t
>(candidate.world.packed())},
24 {
"obstacleBody",
static_cast<std::int64_t
>(candidate.obstacleBody.packed())},
25 {
"obstacleShape",
static_cast<std::int64_t
>(candidate.obstacleShape.packed())},
26 {
"obstacleBodyId", candidate.obstacleBodyId},
27 {
"obstacleShapeId", candidate.obstacleShapeId},
28 {
"ignoredBodyId", candidate.ignoredBodyId},
29 {
"frontPoint", vecValue(candidate.frontPoint)},
30 {
"topPoint", vecValue(candidate.topPoint)},
31 {
"landingFeet", vecValue(candidate.landingFeet)},
32 {
"surfaceNormal", vecValue(candidate.surfaceNormal)},
33 {
"surfaceTangent", vecValue(candidate.surfaceTangent)},
34 {
"leftHandAnchor", vecValue(candidate.leftHandAnchor)},
35 {
"rightHandAnchor", vecValue(candidate.rightHandAnchor)},
36 {
"bodyLocalTop", vecValue(candidate.bodyLocalTop)},
37 {
"bodyLocalLanding", vecValue(candidate.bodyLocalLanding)},
38 {
"obstacleHeight", candidate.obstacleHeight},
39 {
"obstacleDepth", candidate.obstacleDepth},
40 {
"score", candidate.score},
41 {
"kind",
static_cast<std::int64_t
>(candidate.kind)},
42 {
"support",
static_cast<std::int64_t
>(candidate.support)},
85 metadata.reserve(event.metadata.size());
86 for (std::string&
value : event.metadata) metadata.emplace_back(
std::move(
value));
89 {
"actionId", std::move(event.actionId)},
90 {
"tick", std::to_string(event.tick.value())},
91 {
"executionId", std::to_string(event.executionId.value())},
98 result.reserve(
events.size());
99 for (
auto& event :
events) result.push_back(eventValue(
std::move(event)));
103eve::Value advanceValue(ClimbingAdvance advance) {
106 {
"actionId", std::move(advance.actionId)},
107 {
"feet", vecValue(advance.feet)},
108 {
"desiredDelta", vecValue(advance.desiredDelta)},
109 {
"actualDelta", vecValue(advance.actualDelta)},
110 {
"warpResidual", vecValue(advance.warpResidual)},
111 {
"normalizedTime", advance.normalizedTime},
112 {
"constrained", advance.constrained},
113 {
"grounded", advance.grounded},
114 {
"support",
static_cast<std::int64_t
>(advance.support)},
115 {
"leftHandAnchor", vecValue(advance.leftHandAnchor)},
116 {
"rightHandAnchor", vecValue(advance.rightHandAnchor)},
117 {
"contactWeight", advance.contactWeight},
118 {
"leftHandWeight", advance.leftHandWeight},
119 {
"rightHandWeight", advance.rightHandWeight},
120 {
"leftFootWeight", advance.leftFootWeight},
121 {
"rightFootWeight", advance.rightFootWeight},
122 {
"pelvisWeight", advance.pelvisWeight},
123 {
"compactCollisionRequested", advance.compactCollisionRequested},
124 {
"compactCollisionActive", advance.compactCollisionActive},
125 {
"branchWindowOpen", advance.branchWindowOpen},
126 {
"branchComboTag", std::move(advance.branchComboTag)},
127 {
"executionId", std::to_string(advance.executionId.value())},
128 {
"appliedWarp", vecValue(advance.appliedWarp)},
129 {
"desiredYawDelta", advance.desiredYawDelta},
130 {
"cameraCueProfile", std::move(advance.cameraCueProfile)},
131 {
"cameraCue", std::move(advance.cameraCue)},
132 {
"animationClipId", std::move(advance.animationClipId)},
133 {
"animationGraphNodeId", std::move(advance.animationGraphNodeId)},
134 {
"animationMirrored", advance.animationMirrored},
135 {
"terminalVelocity", vecValue(advance.terminalVelocity)},
136 {
"hasTerminalVelocity", advance.hasTerminalVelocity},
140eve::Value debugValue(ClimbingDebugSnapshot snapshot) {
142 candidates.reserve(snapshot.candidates.size());
143 for (
auto& candidate : snapshot.candidates) candidates.push_back(candidateValue(
std::move(candidate)));
145 queries.reserve(snapshot.queries.size());
146 for (
auto& query : snapshot.queries)
148 {
"code", std::move(
query.code)},
149 {
"start", vecValue(
query.start)},
150 {
"end", vecValue(
query.end)},
151 {
"radius",
query.radius},
152 {
"height",
query.height}}));
154 evidence.reserve(snapshot.evidence.size());
155 for (
auto& item : snapshot.evidence)
156 evidence.push_back(
eve::
Value::
object({{
"actionId", std::move(item.actionId)},
157 {
"code", std::move(item.code)},
158 {
"biasCost", item.biasCost},
159 {
"heightCost", item.heightCost},
160 {
"distanceCost", item.distanceCost},
161 {
"totalCost", item.totalCost}}));
163 motion.reserve(snapshot.motion.size());
164 for (
const auto& item : snapshot.motion)
165 motion.push_back(
eve::
Value::
object({{
"tick", std::to_string(item.tick.value())},
166 {
"plannedFeet", vecValue(item.plannedFeet)},
167 {
"actualFeet", vecValue(item.actualFeet)},
168 {
"residual", vecValue(item.residual)},
169 {
"capsuleHeight", item.capsuleHeight},
170 {
"constrained", item.constrained}}));
173 {
"candidates",
eve::Value(std::move(candidates))},
174 {
"accumulatedWarpResidual", vecValue(snapshot.accumulatedWarpResidual)},
175 {
"broadPhaseQueryCount",
static_cast<std::int64_t
>(snapshot.broadPhaseQueryCount)},
176 {
"broadPhaseHitCount",
static_cast<std::int64_t
>(snapshot.broadPhaseHitCount)},
177 {
"queryCount",
static_cast<std::int64_t
>(snapshot.queryCount)},
178 {
"terminalCode", std::move(snapshot.terminalCode)},
179 {
"executionId",
static_cast<std::int64_t
>(snapshot.executionId.value())},
181 {
"evidence",
eve::Value(std::move(evidence))},
186std::optional<ClimbingActionKind> parseActionKind(std::string_view
value) {
207std::optional<ClimbingAnchorEdgeKind> parseAnchorEdgeKind(std::string_view
value) {
222 {
"graphId", std::move(
reference.graphId)},
224 {
"graphGeneration", std::to_string(
reference.graphGeneration)},
228eve::Value graphReloadValue(ClimbingAnchorGraphReload reload) {
230 invalidated.reserve(reload.invalidatedOccupants.size());
231 for (
const auto& occupant : reload.invalidatedOccupants)
233 {
"agentId", std::to_string(occupant.agentId.value())},
234 {
"executionId", std::to_string(occupant.executionId.value())},
237 {
"oldGeneration", std::to_string(reload.oldGeneration)},
238 {
"newGeneration", std::to_string(reload.newGeneration)},
239 {
"invalidatedOccupants",
eve::Value(std::move(invalidated))},
245eve::Value anchorRouteValue(ClimbingAnchorRoute route) {
247 nodes.reserve(route.nodes.size());
250 steps.reserve(route.steps.size());
253 {
"from", anchorNodeValue(std::move(
step.from))},
254 {
"to", anchorNodeValue(std::move(
step.to))},
255 {
"kind", anchorEdgeKindName(
step.kind)},
258 {
"graphId", std::move(route.graphId)},
259 {
"graphGeneration", std::to_string(route.graphGeneration)},
293eve::Value anchorOverlayValue(ClimbingAnchorAuthoringOverlay overlay) {
295 nodes.reserve(overlay.nodes.size());
298 {
"id", std::move(
node.id)},
299 {
"kind", anchorKindName(
node.kind)},
300 {
"position", vecValue(
node.position)},
301 {
"normal", vecValue(
node.normal)},
302 {
"tangent", vecValue(
node.tangent)},
303 {
"leftHandSocket", vecValue(
node.leftHandSocket)},
304 {
"rightHandSocket", vecValue(
node.rightHandSocket)},
305 {
"feetSocket", vecValue(
node.feetSocket)},
306 {
"occupancySlots",
static_cast<std::int64_t
>(
node.occupancySlots)},
309 edges.reserve(overlay.edges.size());
312 {
"from", std::move(
edge.from)},
313 {
"to", std::move(
edge.to)},
314 {
"kind", anchorEdgeKindName(
edge.kind)},
315 {
"bidirectional",
edge.bidirectional},
318 {
"graphId", std::move(overlay.graphId)},
319 {
"buildSettingsHash", std::move(overlay.buildSettingsHash)},
328 auto json = encoded.value().toJson();
331 {
"graphJson", std::move(json).takeValue()},
332 {
"buildSettingsHash", std::move(result.graph.buildSettingsHash)},
333 {
"ledgeNodeCount",
static_cast<std::int64_t
>(result.ledgeNodeCount)},
334 {
"ladderNodeCount",
static_cast<std::int64_t
>(result.ladderNodeCount)},
354 return {
"contact.left_hand",
"contact.right_hand",
"land"};
364std::optional<ClimbingCancelReason> parseCancelReason(std::string_view
value) {
375template <
class Ref,
class Proxy,
class Release>
378 const Ref ref = std::move(
reference).takeValue();
379 auto object = eve::script::makeOwnedSquirrelInstance<Proxy>(
vm, std::make_unique<Proxy>(ref));
382 object.ignore(
"failed to create owned climbing proxy");
383 std::invoke(std::forward<Release>(
release), ref).ignore(
"rollback failed climbing allocation");
386 ssq::Object
owned = std::move(
object).takeValue();
388 result.set(
"value",
owned);
389 result.set(
"ownership", std::string(
"owned"));
390 result.set(
"ownerEpoch",
static_cast<std::int64_t
>(ref.ownerEpoch));
391 result.set(
"handle",
static_cast<std::int64_t
>(ref.packed()));
396struct ScriptClimbingAnchorGraph {
398 ~ScriptClimbingAnchorGraph() noexcept {
410void Climbing::expose(ssq::Table& table) {
412 auto graph = table.addClass<ScriptClimbingAnchorGraph>(
413 "ClimbingAnchorGraph", std::function<ScriptClimbingAnchorGraph*()>([]() {
return nullptr; }),
false);
414 graph.addFunc(
"ownership", [](ScriptClimbingAnchorGraph*) {
return std::string(
"owned"); });
415 graph.addFunc(
"isStale", [](ScriptClimbingAnchorGraph*
value) {
418 graph.addFunc(
"release", [
vm](ScriptClimbingAnchorGraph*
value) {
422 "climbing anchor graph proxy must not be null",
423 "anchorGraph", {},
"climbing.binding")));
426 graph.addFunc(
"node", [
vm](ScriptClimbingAnchorGraph*
value,
const std::string&
nodeId) {
432 {},
"climbing.binding")),
437 resolved.isBound() ? resolved->nodeRef(
nodeId)
440 "anchorGraph", {},
"climbing.binding")),
443 graph.addFunc(
"reloadJson", [
vm](ScriptClimbingAnchorGraph*
value,
const std::string& json) {
449 {},
"climbing.binding")),
462 resolved.isBound() ? resolved->reload(std::move(definition).takeValue())
465 "anchorGraph", {},
"climbing.binding")),
468 graph.addFunc(
"planRoute", [
vm](ScriptClimbingAnchorGraph*
value,
const std::string& startNodeId,
469 const std::string& goalNodeId,
bool avoidFull, std::int64_t agentId,
470 std::int64_t
executionId, std::int64_t maxVisitedNodes) {
472 maxVisitedNodes <= 0 || maxVisitedNodes > 65536)
476 "graph, paired non-negative owner ids, and route bound are required",
477 "planRoute", {},
"climbing.binding")),
480 if (!resolved.isBound())
485 "anchorGraph", {},
"climbing.binding")),
487 auto start = resolved->nodeRef(startNodeId);
491 auto goal = resolved->nodeRef(goalNodeId);
495 ClimbingAnchorRouteRequest
request;
497 request.goal = std::move(goal).takeValue();
504 request.maxVisitedNodes =
static_cast<std::uint32_t
>(maxVisitedNodes);
507 graph.addFunc(
"generation", [](ScriptClimbingAnchorGraph*
value) -> std::string {
508 if (!
value)
return {};
510 return resolved.isBound() ? std::to_string(resolved->generation()) :
std::
string{};
512 graph.addFunc(
"reservationCount", [](ScriptClimbingAnchorGraph*
value) -> std::int64_t {
513 if (!
value)
return 0;
515 return resolved.isBound() ?
static_cast<std::int64_t
>(resolved->reservationCount()) : 0;
517 auto runtime =
table.addClass<ScriptClimbingRuntime>(
518 "ClimbingRuntime", std::function<ScriptClimbingRuntime*()>([]() {
return nullptr; }),
false);
519 runtime.addFunc(
"ownership", [](ScriptClimbingRuntime*) {
return std::string(
"owned"); });
520 runtime.addFunc(
"isStale",
522 runtime.addFunc(
"release", [
vm](ScriptClimbingRuntime*
value) {
526 "climbing runtime proxy must not be null",
527 "runtime", {},
"climbing.binding")));
530 runtime.addFunc(
"setProfileJson", [
vm](ScriptClimbingRuntime*
value,
const std::string& json) {
534 "climbing runtime proxy must not be null",
535 "runtime", {},
"climbing.binding")));
538 vm, resolved.isBound() ? resolved->setProfileJson(json)
541 "runtime", {},
"climbing.binding")));
543 runtime.addFunc(
"reloadProfileJson", [
vm](ScriptClimbingRuntime*
value,
const std::string& json) {
547 "climbing runtime proxy must not be null",
548 "runtime", {},
"climbing.binding")));
551 vm, resolved.isBound() ? resolved->reloadProfileJson(json)
554 "runtime", {},
"climbing.binding")));
556 runtime.addFunc(
"setProfile", [
vm](ScriptClimbingRuntime*
value,
float radius,
float height,
float skin,
557 float probeDistance,
float obstacleHeight,
float minTopNormalY,
558 float maxWarpResidual,
int maskBits) {
562 "climbing runtime proxy must not be null",
563 "runtime", {},
"climbing.binding")));
565 if (!resolved.isBound())
568 "climbing runtime handle is stale",
"runtime", {},
569 "climbing.binding")));
572 profile.capsuleHeight =
height;
574 profile.maxProbeDistance = probeDistance;
575 profile.maxObstacleHeight = obstacleHeight;
576 profile.minTopNormalY = minTopNormalY;
577 profile.maxWarpResidual = maxWarpResidual;
578 profile.queryFilter.maskBits =
static_cast<std::uint32_t
>(maskBits);
581 runtime.addFunc(
"upsertAction", [
vm](ScriptClimbingRuntime*
value,
const std::string&
id,
float minHeight,
582 float maxHeight,
float minSpeed,
float durationSeconds,
float landingForward,
583 float apexHeight,
int selectionBias) {
587 "climbing runtime proxy must not be null",
588 "runtime", {},
"climbing.binding")));
590 if (!resolved.isBound())
593 "climbing runtime handle is stale",
"runtime", {},
594 "climbing.binding")));
598 vm, resolved->upsertAction({id, minHeight, maxHeight, minSpeed, std::move(duration).takeValue(),
599 landingForward, apexHeight, selectionBias}));
601 runtime.addFunc(
"upsertActionKind", [
vm](ScriptClimbingRuntime*
value,
const std::string&
id,
602 const std::string&
kind,
float minHeight,
float maxHeight,
float minSpeed,
603 float durationSeconds,
float landingForward,
float apexHeight,
604 int selectionBias,
float hangBodyOffset,
float hangFeetBelowLedge,
605 float handSpacing,
float cancelStart,
float cancelEnd) {
609 "climbing runtime proxy must not be null",
610 "runtime", {},
"climbing.binding")));
612 if (!resolved.isBound())
615 "climbing runtime handle is stale",
"runtime", {},
616 "climbing.binding")));
617 const auto parsedKind = parseActionKind(
kind);
621 "unknown climbing action kind",
"kind", {},
"climbing.binding")));
624 ClimbingActionDefinition
action{
625 id, minHeight, maxHeight, minSpeed, std::move(
duration).takeValue(), landingForward,
626 apexHeight, selectionBias};
627 action.kind = *parsedKind;
628 action.hangBodyOffset = hangBodyOffset;
629 action.hangFeetBelowLedge = hangFeetBelowLedge;
630 action.handSpacing = handSpacing;
631 action.cancelWindowStart = cancelStart;
632 action.cancelWindowEnd = cancelEnd;
633 action.requiredNotifies = requiredNotifiesForKind(*parsedKind);
636 runtime.addFunc(
"validateActionClip", [
vm](ScriptClimbingRuntime*
value,
const std::string& actionId,
637 animation::AnimClip*
clip) {
641 "runtime and animation clip are required",
642 "validateActionClip", {},
"climbing.binding")));
645 vm, resolved.isBound() ? resolved->validateAnimationBinding(actionId, *
clip)
648 "runtime", {},
"climbing.binding")));
650 runtime.addFunc(
"probeMode", [
vm](ScriptClimbingRuntime*
value, physics::World3D*
world,
float x,
float y,
float z,
651 float forwardX,
float forwardZ,
float speed,
float verticalSpeed,
bool grounded) {
656 "runtime and world are required",
657 "probeMode", {},
"climbing.binding")),
660 if (!resolved.isBound())
664 "runtime", {},
"climbing.binding")),
667 resolved->probe(*
world, {{
x,
y,
z}, {forwardX, 0.f, forwardZ}, speed, -1, verticalSpeed, grounded});
668 if (!candidates.ok())
671 if (candidates.value().empty())
680 runtime.addFunc(
"tryBegin", [
vm](ScriptClimbingRuntime*
value, physics::World3D*
world,
float x,
float y,
float z,
681 float forwardX,
float forwardZ,
float speed,
int ignoredBodyId,
688 "tryBegin", {},
"climbing.binding")),
691 if (!resolved.isBound())
695 "runtime", {},
"climbing.binding")),
699 resolved->tryBegin(*
world, {{x, y, z}, {forwardX, 0.f, forwardZ}, speed, ignoredBodyId},
703 runtime.addFunc(
"tryBeginMode", [
vm](ScriptClimbingRuntime*
value, physics::World3D*
world,
float x,
float y,
704 float z,
float forwardX,
float forwardZ,
float speed,
int ignoredBodyId,
705 float verticalSpeed,
bool grounded, std::int64_t
tick) {
711 "tryBeginMode", {},
"climbing.binding")),
714 if (!resolved.isBound())
718 "runtime", {},
"climbing.binding")),
722 resolved->tryBegin(*
world,
723 {{x, y, z}, {forwardX, 0.f, forwardZ}, speed, ignoredBodyId, verticalSpeed, grounded},
727 runtime.addFunc(
"tryBeginAnchor", [
vm](ScriptClimbingRuntime*
value, ScriptClimbingAnchorGraph* graphValue,
728 physics::World3D*
world,
const std::string&
nodeId,
729 std::int64_t agentId,
const std::string& actionId,
float x,
float y,
730 float z,
float forwardX,
float forwardZ,
float speed,
int ignoredBodyId,
731 float verticalSpeed,
bool grounded, std::int64_t
tick) {
736 "runtime, graph, world, positive agent id, and tick are required",
737 "tryBeginAnchor", {},
"climbing.binding")),
739 auto runtimeResolved = Climbing::resolve(
value->reference);
740 auto graphResolved = Climbing::resolveAnchorGraph(graphValue->reference);
741 if (!runtimeResolved.isBound() || !graphResolved.isBound())
746 "climbing.binding")),
754 runtimeResolved->tryBeginAnchor(
755 *
world, graphValue->reference,
node.value(),
757 {{
x,
y,
z}, {forwardX, 0.f, forwardZ}, speed, ignoredBodyId, verticalSpeed, grounded},
761 runtime.addFunc(
"transitionAnchor", [
vm](ScriptClimbingRuntime*
value,
762 ScriptClimbingAnchorGraph* graphValue,
763 physics::World3D*
world,
const std::string& targetNodeId,
764 const std::string& edgeKind,
const std::string& actionId,
769 "runtime, graph, world, and non-negative tick are required",
770 "transitionAnchor", {},
"climbing.binding")));
771 const auto parsedEdge = parseAnchorEdgeKind(edgeKind);
775 "unknown climbing anchor edge kind",
"edgeKind",
776 {},
"climbing.binding")));
777 auto runtimeResolved = Climbing::resolve(
value->reference);
778 auto graphResolved = Climbing::resolveAnchorGraph(graphValue->reference);
779 if (!runtimeResolved.isBound() || !graphResolved.isBound())
783 {},
"climbing.binding")));
784 auto node = graphResolved->nodeRef(targetNodeId);
787 vm, runtimeResolved->transitionAnchor(*
world,
node.value(), *parsedEdge, actionId,
790 runtime.addFunc(
"currentAnchor", [
vm](ScriptClimbingRuntime*
value) {
796 "climbing.binding")),
798 auto resolved = Climbing::resolve(
value->reference);
801 resolved.isBound() ? resolved->currentAnchor()
804 {},
"climbing.binding")),
808 runtime.addFunc(
"cancel", [
vm](ScriptClimbingRuntime*
value,
const std::string& reason, std::int64_t
tick) {
812 "runtime and non-negative tick are required",
813 "cancel", {},
"climbing.binding")));
814 auto resolved = Climbing::resolve(
value->reference);
815 if (!resolved.isBound())
818 "climbing runtime handle is stale",
"runtime", {},
819 "climbing.binding")));
820 const auto parsed = parseCancelReason(reason);
824 "unknown climbing cancellation reason",
"reason",
825 {},
"climbing.binding")));
829 runtime.addFunc(
"drainEvents", [
vm](ScriptClimbingRuntime*
value) {
835 "climbing.binding")),
837 auto resolved = Climbing::resolve(
value->reference);
840 resolved.isBound() ? resolved->drainEvents()
843 {},
"climbing.binding")),
846 runtime.addFunc(
"drop", [
vm](ScriptClimbingRuntime*
value, std::int64_t
tick) {
850 "runtime and non-negative tick are required",
851 "drop", {},
"climbing.binding")));
852 auto resolved = Climbing::resolve(
value->reference);
857 "runtime", {},
"climbing.binding")));
859 runtime.addFunc(
"climbUp", [
vm](ScriptClimbingRuntime*
value, std::int64_t
tick) {
863 "runtime and non-negative tick are required",
864 "climbUp", {},
"climbing.binding")));
865 auto resolved = Climbing::resolve(
value->reference);
870 "runtime", {},
"climbing.binding")));
872 runtime.addFunc(
"snapshotJson", [
vm](ScriptClimbingRuntime*
value) {
877 "climbing runtime proxy must not be null",
878 "runtime", {},
"climbing.binding")),
880 auto resolved = Climbing::resolve(
value->reference);
883 resolved.isBound() ? resolved->snapshotJson()
886 {},
"climbing.binding")),
889 runtime.addFunc(
"restoreJson", [
vm](ScriptClimbingRuntime*
value,
const std::string& json,
890 physics::World3D*
world) {
894 "runtime and world are required",
"restoreJson",
895 {},
"climbing.binding")));
896 auto resolved = Climbing::resolve(
value->reference);
898 vm, resolved.isBound() ? resolved->restoreJson(json, *
world)
901 "runtime", {},
"climbing.binding")));
903 runtime.addFunc(
"definitionGeneration", [](ScriptClimbingRuntime*
value) -> std::string {
904 if (!
value)
return {};
905 auto resolved = Climbing::resolve(
value->reference);
906 return resolved.isBound() ? std::to_string(resolved->definitionGeneration()) :
std::
string{};
908 runtime.addFunc(
"setDebugCapture", [
vm](ScriptClimbingRuntime*
value,
bool enabled) {
912 "climbing runtime proxy must not be null",
913 "runtime", {},
"climbing.binding")));
914 auto resolved = Climbing::resolve(
value->reference);
915 if (!resolved.isBound())
918 "climbing runtime handle is stale",
"runtime", {},
919 "climbing.binding")));
923 runtime.addFunc(
"inspect", [
vm](ScriptClimbingRuntime*
value) {
929 "climbing.binding")),
931 auto resolved = Climbing::resolve(
value->reference);
932 if (!resolved.isBound())
936 "runtime", {},
"climbing.binding")),
942 auto module = table.addClass(name, Climbing::create, false);
946void Climbing::expose(ssq::Class&
cls) {
947 cls.addFunc(
"getName", &Climbing::getName);
948 cls.addFunc(
"newRuntime", [
vm =
cls.getHandle()](Climbing*) {
949 return makeOwnedProxy<ClimbingRuntimeHandleRef, ScriptClimbingRuntime>(
950 vm, Climbing::newRuntime(),
951 [](ClimbingRuntimeHandleRef reference) { return Climbing::release(reference); });
953 cls.addFunc(
"newAnchorGraphJson", [
vm =
cls.getHandle()](
Climbing*,
const std::string& json,
954 physics::World3D*
world, physics::Body3D*
body) {
956 return makeOwnedProxy<ClimbingAnchorGraphHandleRef, ScriptClimbingAnchorGraph>(
960 "newAnchorGraphJson", {},
"climbing.binding")),
961 [](ClimbingAnchorGraphHandleRef
reference) {
return Climbing::releaseAnchorGraph(
reference); });
964 return makeOwnedProxy<ClimbingAnchorGraphHandleRef, ScriptClimbingAnchorGraph>(
966 [](ClimbingAnchorGraphHandleRef
reference) { return Climbing::releaseAnchorGraph(reference); });
969 return makeOwnedProxy<ClimbingAnchorGraphHandleRef, ScriptClimbingAnchorGraph>(
971 [](ClimbingAnchorGraphHandleRef
reference) { return Climbing::releaseAnchorGraph(reference); });
972 return makeOwnedProxy<ClimbingAnchorGraphHandleRef, ScriptClimbingAnchorGraph>(
973 vm, Climbing::newAnchorGraph(std::move(definition).takeValue(), *
world,
body->runtimeHandle()),
974 [](ClimbingAnchorGraphHandleRef
reference) { return Climbing::releaseAnchorGraph(reference); });
976 cls.addFunc(
"bakeAnchorGraphJson", [
vm =
cls.getHandle()](
Climbing*,
const std::string& json) {
991 cls.addFunc(
"inspectAnchorGraphJson", [
vm =
cls.getHandle()](
Climbing*,
const std::string& json) {
eve::action::ActionExecutionId executionId
AuthorityStoreHandleRef reference
Deterministic climbing/parkour planning and capsule-constrained execution.
struct SQVM * HSQUIRRELVM
const GltfImportRequest & request
wgpu::PopErrorScopeStatus status
#define Module_IMPL(ModuleName, newExpr)
std::map< std::string, std::vector< std::string > > graph
std::function< eve::Result< void >()> release
The single Squirrel projection for common Result, Status and Value.
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.
static Result< Duration > fromSeconds(double seconds)
Convert finite seconds to the nearest nanosecond.
void ignore(std::string_view reason={}) const noexcept
Explicitly discard this result after documenting the reason.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
Structured status and zero or more diagnostics for an operation.
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
The canonical owning dynamic value used by data-facing protocols.
static Result< Value > fromJson(std::string_view json)
Parse one strict JSON value into an owning Value.
std::vector< Value > Array
static Value object(Object value)
Compatibility factory for an object value.
Script-facing factory and owner for independent climbing runtimes.
static eve::Result< void > release(ClimbingRuntimeHandleRef reference)
Releases a module-owned runtime and invalidates its reference.
static eve::Result< void > releaseAnchorGraph(ClimbingAnchorGraphHandleRef reference)
Releases a module-owned graph instance and all of its reservations.
static bool isStale(ClimbingRuntimeHandleRef reference) noexcept
Reports whether a runtime reference is stale.
static eve::script::Borrowed< ClimbingAnchorGraphInstance > resolveAnchorGraph(ClimbingAnchorGraphHandleRef reference) noexcept
Resolves a live graph instance as a synchronous non-owning observation.
static bool isAnchorGraphStale(ClimbingAnchorGraphHandleRef reference) noexcept
Reports whether a graph instance reference is stale.
static eve::script::Borrowed< ClimbingRuntime > resolve(ClimbingRuntimeHandleRef reference) noexcept
Resolves a live runtime as a non-owning observation.
std::string eventKindName(EventKind kind)
Returns the stable lowercase name of an event kind.
eve::Result< ClimbingAnchorBakeResult > bakeClimbingAnchorGraph(const ClimbingAnchorBakeRequest &request)
Bakes deterministic ledge and ladder topology from owning semantic geometry samples.
eve::detail::StrongUint64< detail::ClimbingExecutionIdTag > ClimbingExecutionId
Stable non-zero identity assigned when a climbing selection transaction commits.
ClimbingAnchorEdgeKind
Allowed authored transition between two explicit anchors.
eve::Result< ClimbingAnchorGraphDefinition > decodeClimbingAnchorGraphDefinition(const eve::Value &value)
Decodes and validates a complete owning graph candidate transactionally.
ClimbingAnchorKind
Authored semantic of one explicit climbing anchor.
ClimbingPhase
Execution lifecycle visible to gameplay and animation adapters.
eve::Result< ClimbingAnchorAuthoringOverlay > inspectClimbingAnchorGraphAuthoring(const ClimbingAnchorGraphDefinition &graph)
Builds a validated owning snapshot for an editor or debug-draw adapter.
void exposeClimbingMotionBindings(ssq::Class &runtime, HSQUIRRELVM vm)
Expose climbing motion bindings.
ClimbingDebugCapture
Runtime policy controlling optional owning diagnostic capture.
eve::script::RuntimeHandleRef< ClimbingAnchorGraphHandleTag > ClimbingAnchorGraphHandleRef
Generation- and module-epoch-qualified anchor graph instance reference.
ClimbingEventKind
Stable semantic event emitted by the authoritative climbing lifecycle.
@ AnchorTransitionStarted
ClimbingActionKind
Data-driven action family; stable action identity remains the definition id.
eve::detail::StrongUint64< detail::ClimbingAnchorAgentIdTag > ClimbingAnchorAgentId
Stable non-zero identity of the character/agent that owns graph occupancy.
eve::Result< ClimbingAnchorBakeRequest > decodeClimbingAnchorBakeRequest(const eve::Value &value)
Decodes all known bake request fields without publishing a graph.
eve::Result< eve::Value > encodeClimbingAnchorGraphDefinition(const ClimbingAnchorGraphDefinition &graph)
Encodes a validated graph to its canonical owning Value representation.
ClimbingProfileDefinition ClimbingProfile
Compatibility-only spelling; ClimbingProfileDefinition is canonical.
eve::Value projectClimbingAdvance(ClimbingAdvance value)
Project climbing advance.
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
eve::Diagnostic Diagnostic
std::unordered_map< std::string, SkillDefinition > & table()
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.
std::string_view phaseName(BattlePhase phase) noexcept
Return the stable protocol spelling of a battle phase.
Build metadata (engine git commit, build time, third-party version).
DiagnosticCode
Stable machine-readable diagnostic codes.
detail::StrongUint64< detail::SimulationTickTag > SimulationTick
Deterministic simulation time step; it is not wall-clock time.
Owning output of one execution tick.