载入中...
搜索中...
未找到
SplinePathBinder.cpp
浏览该文件的文档.
2
3#include "common/SceneQuery.h"
4
5#include <algorithm>
6#include <cmath>
7
8namespace eve::procgen_editing {
9namespace {
10
11const EditorValue* field(const EditorValue& value, const char* key) {
12 const auto* object = value.getIf<EditorValue::Object>();
13 if (!object) return nullptr;
14 const auto found = object->find(key);
15 return found == object->end() ? nullptr : &found->second;
16}
17
18EditorValue bindingValue(const SplinePointBinding& binding) {
19 return EditorValue::Object{{"point", EditorValue(binding.point.value())},
20 {"host", EditorValue(binding.host)},
21 {"object", EditorValue(binding.object)}};
22}
23
24} // namespace
25
27 const std::string& object) const {
28 if (!query_)
29 return eve::editing::failed<SplineBindingPose>(EditorStatus::Unsupported,
30 RuleId("editor.spline.binding-provider-absent"),
31 "Scene transform provider is not available");
33 if (!query_->getNodeIn(host, object, &info))
34 return eve::editing::failed<SplineBindingPose>(EditorStatus::Conflict,
35 RuleId("editor.spline.binding-source-stale"),
36 "Bound scene transform is missing or stale");
37 return eve::editing::applied<SplineBindingPose>({info.x, info.y, info.z});
38}
39
40SplinePathBinder::SplinePathBinder(std::string documentTarget) : documentTarget_(std::move(documentTarget)) {}
41
43 std::string host, std::string object,
45 if (document.targetId().value() != documentTarget_)
46 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.spline.binding-target-mismatch"),
47 "Spline binder targets another document");
48 const auto points = document.points();
49 if (point.empty() ||
50 std::none_of(points.begin(), points.end(), [&](const auto& value) { return value.id == point; }))
51 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.spline.binding-point-missing"),
52 "Bound spline point does not exist");
53 if (host.empty() || object.empty())
54 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.spline.binding-identity-empty"),
55 "Spline binding requires non-empty host and object identities");
56 auto resolved = source.resolve(host, object);
57 if (!resolved.ok())
58 return eve::editing::failed<void>(resolved.code(), RuleId("editor.spline.binding-source-stale"),
59 resolved.status().describe());
60 bindings_[point] = {point, std::move(host), std::move(object)};
61 return eve::editing::applied<void>();
62}
63
65 if (!bindings_.erase(point))
66 return eve::editing::failed<void>(EditorStatus::NotFound, RuleId("editor.spline.binding-not-found"),
67 "Spline point binding was not found");
68 return eve::editing::applied<void>();
69}
70
73 if (document.targetId().value() != documentTarget_)
74 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.spline.binding-target-mismatch"),
75 "Spline binder targets another document");
76 auto candidate = document;
77 const auto points = document.points();
78 for (const auto& [id, binding] : bindings_) {
79 const auto found =
80 std::find_if(points.begin(), points.end(), [&](const auto& value) { return value.id == id; });
81 if (found == points.end())
82 return eve::editing::failed<void>(EditorStatus::Conflict, RuleId("editor.spline.binding-point-stale"),
83 "Bound spline point was removed");
84 auto pose = source.resolve(binding.host, binding.object);
85 if (!pose.ok())
86 return eve::editing::failed<void>(pose.code(), RuleId("editor.spline.binding-source-stale"),
87 pose.status().describe());
88 if (!std::isfinite(pose.value().x) || !std::isfinite(pose.value().y) || !std::isfinite(pose.value().z))
89 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.spline.binding-pose-invalid"),
90 "Bound transform returned non-finite coordinates");
91 auto updated = *found;
92 updated.x = pose.value().x;
93 updated.y = pose.value().y;
94 updated.z = pose.value().z;
95 auto operation = candidate.makeSetPoint(updated);
96 if (!operation.ok())
97 return eve::editing::failed<void>(operation.code(), RuleId("editor.spline.binding-operation-failed"),
98 operation.status().describe());
99 auto applied = candidate.applyDomainOperation(operation.value());
100 if (!applied.ok()) return applied;
101 }
102 return document.commitDomainState(std::make_unique<SplinePathDocument>(std::move(candidate)));
103}
104
105std::vector<SplinePointBinding> SplinePathBinder::bindings() const {
106 std::vector<SplinePointBinding> result;
107 result.reserve(bindings_.size());
108 for (const auto& [unused, binding] : bindings_) {
109 (void)unused;
110 result.push_back(binding);
111 }
112 return result;
113}
114
117 for (const auto& [unused, binding] : bindings_) {
118 (void)unused;
119 bindings.emplace_back(bindingValue(binding));
120 }
121 return EditorValue::Object{{"schema", EditorValue("eve.procgen.splineBinder")},
122 {"version", EditorValue(std::int64_t{1})},
123 {"document", EditorValue(documentTarget_)},
124 {"bindings", EditorValue(std::move(bindings))}};
125}
126
128 const auto* schemaValue = field(snapshot, "schema");
129 const auto* versionValue = field(snapshot, "version");
130 const auto* documentValue = field(snapshot, "document");
131 const auto* bindingsValue = field(snapshot, "bindings");
132 const auto* schema = schemaValue ? schemaValue->getIf<std::string>() : nullptr;
133 const auto* version = versionValue ? versionValue->getIf<std::int64_t>() : nullptr;
134 const auto* document = documentValue ? documentValue->getIf<std::string>() : nullptr;
135 const auto* values = bindingsValue ? bindingsValue->getIf<EditorValue::Array>() : nullptr;
136 if (!schema || *schema != "eve.procgen.splineBinder" || !version || *version != 1)
137 return eve::editing::failed<void>(EditorStatus::Unsupported, RuleId("editor.spline.binding-schema-unsupported"),
138 "Unsupported spline binder snapshot schema");
139 if (!document || *document != documentTarget_ || !values)
140 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.spline.binding-snapshot-invalid"),
141 "Spline binder snapshot targets another document or has invalid bindings");
142 std::map<StableId, SplinePointBinding> candidate;
143 for (const auto& value : *values) {
144 const auto* pointValue = field(value, "point");
145 const auto* hostValue = field(value, "host");
146 const auto* objectValue = field(value, "object");
147 const auto* point = pointValue ? pointValue->getIf<std::string>() : nullptr;
148 const auto* host = hostValue ? hostValue->getIf<std::string>() : nullptr;
149 const auto* object = objectValue ? objectValue->getIf<std::string>() : nullptr;
150 if (!point || point->empty() || !host || host->empty() || !object || object->empty() ||
151 !candidate.emplace(StableId(*point), SplinePointBinding{StableId(*point), *host, *object}).second)
152 return eve::editing::failed<void>(EditorStatus::Rejected, RuleId("editor.spline.binding-snapshot-invalid"),
153 "Spline binder snapshot contains invalid or duplicate links");
154 }
155 bindings_ = std::move(candidate);
156 return eve::editing::applied<void>();
157}
158
159} // namespace eve::procgen_editing
ActionParameterOperation operation
double value
eve::EntitySpatialPose pose
std::map< std::string, Var > values
std::uint32_t key
std::int32_t second
eve::action::ActionVfxBinding binding
std::array< std::uint64_t, kPixelChunkSize *kPixelChunkSize > updated
std::shared_ptr< const std::vector< glm::vec2 > > points
bool found
Json object
UIHostHandle host
const UnitySourceAsset & source
glm::vec3 point
virtual bool getNodeIn(const std::string &host, const std::string &id, SceneNodeInfo *out) const =0
Look up one node in a named host.
Move-only operation result carrying either a value or Status.
Definition Result.h:155
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
const std::string & value() const noexcept
Returns the exact legacy or canonical compatibility spelling.
Definition Identity.h:362
Deterministic owning value tree shared by authoring hosts.
std::vector< Value > Array
std::map< std::string, Value > Object
const T * getIf() const
Return an immediately borrowed typed value.
Consumer-owned transform lookup contract used by spline binding.
Result< SplineBindingPose > resolve(const std::string &host, const std::string &object) const override
Resolve.
Result< void > loadSnapshot(const EditorValue &snapshot)
Atomically restore links for this binder's pinned target.
Result< void > bindResult(const SplinePathDocument &document, const StableId &point, std::string host, std::string object, const ISplineBindingTransformSource &source)
Validate and atomically install or replace one point binding.
EditorValue snapshotValue() const
Capture schema eve.procgen.splineBinder version one.
Result< void > refreshResult(SplinePathDocument &document, const ISplineBindingTransformSource &source) const
Resolve every link, then commit all point positions as one isolated document update.
Result< void > unbindResult(const StableId &point)
Remove one binding without touching its spline point.
std::vector< SplinePointBinding > bindings() const
Return deterministic bindings ordered by stable point id.
SplinePathBinder(std::string documentTarget)
Construct a binder pinned to one spline document target identity.
Owning spline authoring document with transactional operations and schema-versioned snapshots.
TargetId targetId() const override
Target id.
Result< void > commitDomainState(std::unique_ptr< IDomainOperationTarget > candidate) override
Commits domain state.
std::vector< SplinePathControlPoint > points() const
Return points in deterministic order and stable-id tie order.
StrongId< StableIdTag > StableId
Definition EditingIds.h:64
StrongId< RuleIdTag > RuleId
Definition EditingIds.h:60
Result< T > applied(T value, std::vector< Diagnostic > diagnostics={})
Construct an Applied result with an owning payload and optional diagnostics.
const EditorValue * field(const EditorValue &value, const char *name)
Serializable snapshot of one scene node (value type, no scene types).
Definition SceneQuery.h:17
Persistent link from one spline control point to one scene transform identity.
glm::uvec4 info