载入中...
搜索中...
未找到
ActionSpatialBlock.cpp
浏览该文件的文档.
2
3#include <cmath>
4#include <limits>
5#include <utility>
6
7namespace eve::action {
8namespace {
9
10Result<double> number(const Value& value, std::string path) {
11 double result = 0.0;
12 if (const auto* integer = value.getIf<std::int64_t>())
13 result = static_cast<double>(*integer);
14 else if (const auto* decimal = value.getIf<double>())
15 result = *decimal;
16 else
18 Diagnostic::error(DiagnosticCode::InvalidArgument, "spatial component must be numeric", path));
19 if (!std::isfinite(result))
21 Diagnostic::error(DiagnosticCode::InvalidArgument, "spatial component must be finite", path));
22 return Result<double>::success(result);
23}
24
25Result<ActionSpatialVector3> vector(const Value::Object& payload, std::string_view key,
26 ActionSpatialVector3 fallback) {
27 const auto found = payload.find(std::string(key));
28 if (found == payload.end()) return Result<ActionSpatialVector3>::success(fallback);
29 const auto* values = found->second.getIf<Value::Array>();
30 if (!values || values->size() != 3)
32 DiagnosticCode::InvalidArgument, "spatial vector must contain exactly three numbers", std::string(key)));
33 ActionSpatialVector3 result;
34 double* components[] = {&result.x, &result.y, &result.z};
35 for (std::size_t index = 0; index < 3; ++index) {
36 auto parsed = number((*values)[index], std::string(key) + "[" + std::to_string(index) + "]");
37 if (!parsed) return Result<ActionSpatialVector3>::failure(parsed.status());
38 *components[index] = std::move(parsed).takeValue();
39 }
41}
42
43Result<std::string> text(const Value::Object& payload, std::string_view key, std::string fallback) {
44 const auto found = payload.find(std::string(key));
45 if (found == payload.end()) return Result<std::string>::success(std::move(fallback));
46 const auto* value = found->second.getIf<std::string>();
47 if (!value)
49 Diagnostic::error(DiagnosticCode::InvalidArgument, "spatial field must be text", std::string(key)));
51}
52
53} // namespace
54
56 switch (mode) {
57 case ActionSpatialAttachmentMode::FollowTarget: return "follow_target";
58 case ActionSpatialAttachmentMode::FollowPositionOnly: return "follow_position_only";
59 case ActionSpatialAttachmentMode::WorldTransformAtStart: return "world_transform_at_start";
60 }
61 return "follow_target";
62}
63
65 ActionSpatialBinding candidate;
66 auto mode = text(payload, "attachment", "follow_target");
67 if (!mode) return Result<ActionSpatialBinding>::failure(mode.status());
68 if (mode.value() == "follow_target")
70 else if (mode.value() == "follow_position_only")
72 else if (mode.value() == "world_transform_at_start")
74 else
76 Diagnostic::error(DiagnosticCode::InvalidArgument, "unknown spatial attachment mode", "attachment"));
77
78 auto target = text(payload, "spatialTarget", "source");
80 if (target.value() == "source")
82 else if (target.value() == "target")
84 else
86 Diagnostic::error(DiagnosticCode::InvalidArgument, "unknown spatial target", "spatialTarget"));
87
88 if (const auto found = payload.find("targetIndex"); found != payload.end()) {
89 const auto* index = found->second.getIf<std::int64_t>();
90 if (!index || *index < 0 || static_cast<std::uint64_t>(*index) > std::numeric_limits<std::size_t>::max())
92 DiagnosticCode::InvalidArgument, "target index must be a non-negative integer", "targetIndex"));
93 candidate.targetIndex = static_cast<std::size_t>(*index);
94 }
95 auto bone = text(payload, "bone", {});
96 if (!bone) return Result<ActionSpatialBinding>::failure(bone.status());
97 candidate.bone = std::move(bone).takeValue();
98
99 auto position = vector(payload, "positionOffset", {});
101 candidate.positionOffset = std::move(position).takeValue();
102 auto rotation = vector(payload, "rotationOffsetDegrees", {});
104 candidate.rotationOffsetDegrees = std::move(rotation).takeValue();
105 auto scale = vector(payload, "scale", {1.0, 1.0, 1.0});
107 candidate.scale = std::move(scale).takeValue();
108 if (candidate.scale.x <= 0.0 || candidate.scale.y <= 0.0 || candidate.scale.z <= 0.0)
110 Diagnostic::error(DiagnosticCode::InvalidArgument, "spatial scale components must be positive", "scale"));
111 return Result<ActionSpatialBinding>::success(std::move(candidate));
112}
113
114} // namespace eve::action
double value
Typed spatial payload shared by presentation action blocks.
Value::Object payload
std::map< std::string, Var > values
std::uint32_t key
std::string text
std::array< float, 4 > rotation
std::array< float, 3 > position
std::string path
Definition PlayHost.cpp:110
double number
bool found
uint32_t index
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
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
std::string_view actionSpatialAttachmentModeName(ActionSpatialAttachmentMode mode) noexcept
Return the stable payload spelling for an attachment mode.
ActionSpatialAttachmentMode
How a spawned presentation object follows its resolved anchor.
@ FollowTarget
Re-evaluate position and rotation from the anchor every update.
@ WorldTransformAtStart
Capture the complete world transform once on Enter.
@ FollowPositionOnly
Re-evaluate position only and retain the spawn rotation.
Validated spatial settings decoded from a notify payload.
ActionSpatialAttachmentMode mode
static Result< ActionSpatialBinding > fromPayload(const Value::Object &payload)
Decode and validate the common spatial fields in an owning payload.
ActionSpatialVector3 rotationOffsetDegrees