载入中...
搜索中...
未找到
ClimbingServices.cpp
浏览该文件的文档.
2
3#include "common/Capability.h"
4#include "physics/World3D.h"
5
6namespace eve::climbing {
7namespace {
8
9bool commandMatches(ClimbingCommandRequirement requirement, ClimbingCommand command) {
10 if (requirement == ClimbingCommandRequirement::Any) return true;
11 return (requirement == ClimbingCommandRequirement::Jump && command == ClimbingCommand::Jump) ||
12 (requirement == ClimbingCommandRequirement::Climb && command == ClimbingCommand::Climb) ||
13 (requirement == ClimbingCommandRequirement::Drop && command == ClimbingCommand::Drop) ||
14 (requirement == ClimbingCommandRequirement::Sprint && command == ClimbingCommand::Sprint) ||
16}
17
18} // namespace
19
24 if (subject.isZero())
26 "service subject must be non-zero",
27 "subject", {}, "climbing.services"));
28 if (!ClimbingInputSystem::peek(intent, command, tick))
30 eve::DiagnosticCode::NotFound, "climbing.input.no_match", "intent.commands", {}, "climbing.services"));
31
32 ClimbingPose effectivePose = pose;
33 if (!effectivePose.grounded && command != ClimbingCommand::Drop &&
34 ClimbingInputSystem::coyoteWindowState(tick, lastGroundedTick, runtime.profile_.coyoteTicks) ==
36 effectivePose.grounded = true;
37 auto prepared = runtime.prepareBegin(world, effectivePose, tick);
38 if (!prepared) return eve::Result<ClimbingServiceStart>::failure(prepared.status());
39 if (!commandMatches(prepared.value().action.requiredCommand, command))
41 eve::DiagnosticCode::NotFound, "selected action does not accept the buffered command",
42 "action.requiredCommand", {}, "climbing.services"));
43
44 if (!prepared.value().action.requiredConditionTags.empty()) {
45 IClimbingConditionAuthority* conditions = eve::cap::query<IClimbingConditionAuthority>();
46 if (!conditions)
48 eve::DiagnosticCode::Unsupported, "required climbing condition provider is absent", "conditions", {},
49 "climbing.services"));
50 auto decision = conditions->evaluate(subject, prepared.value().action.requiredConditionTags, tick);
51 if (!decision) return eve::Result<ClimbingServiceStart>::failure(decision.status());
52 if (decision.value() != ClimbingConditionDecision::Allowed)
54 eve::DiagnosticCode::PreconditionViolation, "climbing action conditions were denied", "conditions", {},
55 "climbing.services"));
56 prepared.value().conditionsSatisfied = true;
57 }
58
59 IClimbingStaminaAuthority* stamina = nullptr;
62 if (prepared.value().action.staminaCost > 0.f &&
63 runtime.profile_.staminaPolicy != ClimbingStaminaPolicy::Disabled) {
64 stamina = eve::cap::query<IClimbingStaminaAuthority>();
65 if (!stamina && runtime.profile_.staminaPolicy == ClimbingStaminaPolicy::RequireProvider)
67 eve::Diagnostic::error(eve::DiagnosticCode::Unsupported, "required climbing stamina provider is absent",
68 "stamina", {}, "climbing.services"));
69 if (!stamina) {
71 } else {
72 if (!runtime.profile_.staminaAdapter.empty() &&
73 stamina->adapterId() != runtime.profile_.staminaAdapter)
75 eve::DiagnosticCode::Unsupported, "configured climbing stamina adapter is not available",
76 "staminaAdapter", {}, "climbing.services"));
77 auto reserved = stamina->prepare(subject, prepared.value().action.staminaCost, tick);
78 if (!reserved) return eve::Result<ClimbingServiceStart>::failure(reserved.status());
79 reservation = reserved.value();
80 if (reservation.isZero())
82 eve::DiagnosticCode::InvariantViolation, "stamina provider returned a zero reservation", "stamina",
83 {}, "climbing.services"));
85 }
86 }
87
88 const ClimbingIntent originalIntent = intent;
89 auto consumed = ClimbingInputSystem::consume(intent, command, tick, prepared.value().executionId);
90 if (!consumed || !consumed.value()) {
91 intent = originalIntent;
92 if (stamina) stamina->cancelPrepared(reservation);
95 eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "eligible climbing input changed before commit",
96 "intent.commands", {}, "climbing.services"));
97 }
98 auto committed = runtime.commitBegin(std::move(prepared).takeValue());
99 if (!committed) {
100 intent = originalIntent;
101 if (stamina) stamina->cancelPrepared(reservation);
102 return eve::Result<ClimbingServiceStart>::failure(committed.status());
103 }
104 if (stamina) stamina->commitPrepared(reservation, committed.value().executionId);
105 return eve::Result<ClimbingServiceStart>::success({std::move(committed).takeValue(), staminaState},
107}
108
124
140
141} // namespace eve::climbing
int subject
Definition AnimSmr.cpp:163
eve::EntitySpatialPose pose
Consumer-owned contracts for optional stamina, event, and pose integrations.
World3D * world
std::string_view adapter
Battle::Events events
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
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
static ClimbingCoyoteState coyoteWindowState(eve::SimulationTick currentTick, eve::SimulationTick lastGroundedTick, std::uint64_t coyoteTicks) noexcept
Evaluate a grounded grace window without reading wall clock.
static eve::Result< std::optional< BufferedClimbingCommand > > consume(ClimbingIntent &intent, ClimbingCommand command, eve::SimulationTick currentTick, ClimbingExecutionId executionId)
Atomically mark the oldest eligible command consumed by one committed execution.
static std::optional< BufferedClimbingCommand > peek(const ClimbingIntent &intent, ClimbingCommand command, eve::SimulationTick currentTick) noexcept
Observe the oldest eligible command without consuming or pruning intent.
Owner-thread climbing planner and executor for one character.
Definition Climbing.h:653
static eve::Result< ClimbingServiceStart > tryStart(ClimbingRuntime &runtime, physics::World3D &world, const ClimbingPose &pose, ClimbingIntent &intent, ClimbingCommand command, eve::SimulationTick tick, eve::SimulationTick lastGroundedTick, ClimbingServiceSubject subject)
Start one action and publish any configured stamina debit exactly once.
Consumer-owned authority for project-specific condition tags.
virtual eve::Result< ClimbingConditionDecision > evaluate(ClimbingServiceSubject subject, std::span< const std::string > requiredTags, eve::SimulationTick tick)=0
Evaluate every required tag for one subject at the injected simulation tick.
Optional post-simulation event adapter; it does not own the runtime event queue.
virtual eve::Result< void > publish(ClimbingServiceSubject subject, std::span< const ClimbingEvent > events)=0
Consume an owning event view after all ECS simulation views have closed.
Optional post-physics Animation/IK adapter consuming derived pose constraints only.
Consumer-owned stamina reservation contract.
virtual std::string_view adapterId() const noexcept=0
Stable adapter identity matched against ClimbingProfileDefinition::staminaAdapter.
virtual eve::Result< ClimbingStaminaReservation > prepare(ClimbingServiceSubject subject, float cost, eve::SimulationTick tick)=0
Reserve an exact non-negative cost without publishing the debit.
virtual void cancelPrepared(ClimbingStaminaReservation reservation) noexcept=0
Release an uncommitted reservation; guaranteed infallible and idempotent.
virtual void commitPrepared(ClimbingStaminaReservation reservation, ClimbingExecutionId executionId) noexcept=0
Publish a successfully prepared debit; guaranteed infallible by the provider contract.
constexpr std::uint64_t value() const noexcept
Returns the underlying value at an explicit protocol boundary.
static constexpr StrongUint64 zero() noexcept
Returns the zero value for this strong type.
constexpr bool isZero() const noexcept
Returns whether this value is zero.
Box3D rigid-body world. Script coordinates are meters (Box3D native), unlike 2D World which uses pixe...
Definition World3D.h:63
ClimbingOptionalServiceState
Observable outcome of one optional-service interaction.
ClimbingCommandRequirement
Input edge required by an action definition; Any keeps legacy automatic selection.
Definition Climbing.h:79
ClimbingCommand
Edge and held commands understood by the climbing input phase.
eve::Result< ClimbingPoseResult > applyClimbingPose(animation::AnimSkeleton &skeleton, animation::AnimPose &pose, const ClimbingAdvance &advance, const ClimbingPoseBinding &binding)
Applies contact anchors to an already evaluated animation pose.
eve::Result< ClimbingOptionalServiceState > dispatchClimbingEvents(ClimbingServiceSubject subject, std::span< const ClimbingEvent > events)
Dispatch to the optional event sink, returning ProviderAbsent instead of silently dropping.
Owning output of one execution tick.
Definition Climbing.h:553
Hot authoritative intent component; contains no device or callback pointers.
Input pose used for one deterministic candidate probe.
Definition Climbing.h:275
bool consumed
Definition Graphics.cpp:184