载入中...
搜索中...
未找到
ActionCollisionIgnoreState.cpp
浏览该文件的文档.
2
3#include "common/Capability.h"
4#include "physics/Body3D.h"
5#include "physics/World3D.h"
6
7#include <utility>
8
10namespace {
11
12} // namespace
13
15 : world_(&world), worldLifetime_(world.queryLifetime_), worldHandle_(world.runtimeHandle()),
16 resolver_(std::move(resolver)) {}
17
19 cap::removeListener<eve::action::IActionStateWindowSink>(this);
20 releaseAll();
21}
22
24 for (std::size_t index = 0; index < cap::listenerCount<eve::action::IActionStateWindowSink>(); ++index)
25 if (cap::listenerAt<eve::action::IActionStateWindowSink>(index) == this) return true;
26 return false;
27}
28
30 const bool current = enabled();
31 if (value && !current)
32 cap::addListener<eve::action::IActionStateWindowSink>(this);
33 else if (!value && current)
34 cap::removeListener<eve::action::IActionStateWindowSink>(this);
35}
36
40
41World3D* ActionCollisionIgnoreState::liveWorld() const noexcept {
42 auto lifetime = worldLifetime_.lock();
43 if (!lifetime || !world_ || !world_->isValid() || world_->runtimeHandle() != worldHandle_) return nullptr;
44 return world_;
45}
46
47Result<ActionCollisionIgnoreState::PairKey> ActionCollisionIgnoreState::resolvePair(
48 ecs::EntityHandle subject, std::string_view channel) const {
49 World3D* world = liveWorld();
50 if (!world)
52 Diagnostic::error(DiagnosticCode::StaleHandle, "collision world is no longer live", "world"));
53 if (!resolver_)
55 Diagnostic::error(DiagnosticCode::NotFound, "collision pair resolver is unavailable", "resolver"));
56 auto pair = resolver_(subject, channel);
57 if (!pair) return Result<PairKey>::failure(pair.status());
58 if (!pair.value().first.isValid() || !pair.value().second.isValid() ||
59 pair.value().first.world != worldHandle_ || pair.value().second.world != worldHandle_)
61 DiagnosticCode::InvalidArgument, "collision pair must contain two links owned by this world", "pair"));
62 PairKey key{pair.value().first.body, pair.value().second.body};
63 if (key.first == key.second)
65 Diagnostic::error(DiagnosticCode::InvalidArgument, "collision pair bodies must be distinct", "pair"));
66 if (key.second < key.first) std::swap(key.first, key.second);
67 if (!world->findBody(key.first) || !world->findBody(key.second))
69 Diagnostic::error(DiagnosticCode::StaleHandle, "collision pair contains a stale body", "pair"));
71}
72
76 if (!supports(binding.kind))
78 Diagnostic::error(DiagnosticCode::Unsupported, "physics adapter does not own this window kind", "kind"));
79 std::optional<ecs::EntityHandle> subject;
80 if (binding.targetIndex) {
81 if (*binding.targetIndex >= context.targets.size())
83 Diagnostic::error(DiagnosticCode::NotFound, "collision target index is unavailable", "targetIndex"));
84 subject = context.targets[*binding.targetIndex];
85 } else {
86 subject = context.source;
87 }
88 if (!subject)
90 Diagnostic::error(DiagnosticCode::NotFound, "collision window has no source or target", "subject"));
91 auto pair = resolvePair(*subject, binding.resource);
92 if (!pair) return Result<void>::failure(pair.status());
93
94 const ActiveKey activeKey{context.executionId, event.itemId.format()};
95 const auto activeFound = active_.find(activeKey);
96 if (activeFound != active_.end()) {
97 if (activeFound->second == pair.value())
100 DiagnosticCode::Conflict, "collision-window key resolves to a different body pair", "itemId"));
101 }
102
103 World3D* world = liveWorld();
104 Body3D* first = world ? world->findBody(pair.value().first) : nullptr;
105 Body3D* second = world ? world->findBody(pair.value().second) : nullptr;
106 if (!world || !first || !second)
108 Diagnostic::error(DiagnosticCode::StaleHandle, "collision pair became stale during enter", "pair"));
109 auto pairFound = pairs_.find(pair.value());
110 if (pairFound == pairs_.end()) {
111 const bool restoreEnabled = world->isBodyPairCollisionEnabled(first, second);
112 pairFound = pairs_.emplace(pair.value(), PairState{restoreEnabled, 0}).first;
113 world->setBodyPairCollisionEnabled(first, second, false);
114 }
115 ++pairFound->second.owners;
116 active_.emplace(activeKey, pair.value());
118}
119
123 if (!supports(binding.kind))
125 Diagnostic::error(DiagnosticCode::Unsupported, "physics adapter does not own this window kind", "kind"));
126 const ActiveKey activeKey{context.executionId, event.itemId.format()};
127 const auto activeFound = active_.find(activeKey);
128 if (activeFound == active_.end()) return Result<void>::success(Status::success(StatusCode::NoOp));
129 const PairKey pairKey = activeFound->second;
130 active_.erase(activeFound);
131 const auto pairFound = pairs_.find(pairKey);
132 if (pairFound == pairs_.end()) return Result<void>::success(Status::success(StatusCode::NoOp));
133 if (pairFound->second.owners > 1) {
134 --pairFound->second.owners;
135 } else {
136 restorePair(pairFound->first, pairFound->second);
137 pairs_.erase(pairFound);
138 }
140}
141
142void ActionCollisionIgnoreState::restorePair(const PairKey& key, const PairState& state) noexcept {
143 World3D* world = liveWorld();
144 Body3D* first = world ? world->findBody(key.first) : nullptr;
145 Body3D* second = world ? world->findBody(key.second) : nullptr;
146 if (world && first && second) world->setBodyPairCollisionEnabled(first, second, state.restoreEnabled);
147}
148
149void ActionCollisionIgnoreState::releaseAll() noexcept {
150 for (const auto& [key, state] : pairs_) restorePair(key, state);
151 active_.clear();
152 pairs_.clear();
153}
154
156 setEnabled(false);
157 const bool changed = !active_.empty() || !pairs_.empty();
158 releaseAll();
160}
161
162} // namespace eve::physics::action_adapter
Action adapter for temporary 3D body-pair collision ignores.
double value
int subject
Definition AnimSmr.cpp:163
std::uint32_t key
std::int32_t second
std::int32_t first
TokenKind kind
eve::action::ActionVfxBinding binding
World3D * world
std::weak_ptr< const void > lifetime
double current
uint32_t index
const VegetationPresetContext & context
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
3D rigid body (Box3D) in meter-space coordinates (+Y up by convention). Owned by a World3D; create pr...
Definition Body3D.h:24
Box3D rigid-body world. Script coordinates are meters (Box3D native), unlike 2D World which uses pixe...
Definition World3D.h:63
PhysicsWorldHandle runtimeHandle() const noexcept
Process-local identity used by PhysicsLink; invalid after destruction.
Definition World3D.h:141
bool isValid() const
True while the underlying Box3D world is alive.
Definition World3D.cpp:430
ActionCollisionIgnoreState(World3D &world, ActionCollisionPairResolver resolver)
Construct an adapter for one borrowed 3D world.
Result< void > shutdown()
Unregister and restore every still-live pair to its pre-window state.
~ActionCollisionIgnoreState() override
Action collision ignore state.
Result< void > enter(const eve::action::ActionStateWindowBinding &binding, const eve::action::ActionTimelineEvent &event, const eve::action::ActionNotifyContext &context) override
Enter one validated window or idempotently observe the same active key.
bool enabled() const
Return whether this exact adapter is registered.
void setEnabled(bool enabled)
Opt this adapter into or out of Action state-window dispatch.
Result< void > exit(const eve::action::ActionStateWindowBinding &binding, const eve::action::ActionTimelineEvent &event, const eve::action::ActionNotifyContext &context) override
Exit one previously entered window by execution and item identity.
bool supports(eve::action::ActionStateWindowKind kind) const noexcept override
Whether this sink owns the supplied semantic window kind.
ActionStateWindowKind
Stable semantic kind for one built-in state window.
std::function< Result< ActionCollisionPair >(ecs::EntityHandle, std::string_view channel)> ActionCollisionPairResolver
Resolves an action entity and semantic channel to two physics links.
Context linking a routed event to its action execution.
Owning validated state-window request authored on an action timeline.
Owning event projection returned by the runtime sampler.