载入中...
搜索中...
未找到
MeshVfxTarget.cpp
浏览该文件的文档.
2
4
5#include <utility>
6
8namespace {
9
10constexpr const char* defaultAsset =
11 R"({"schema":"eve.stylize.mesh-vfx","schemaVersion":1,"layers":[{"style":"rim"}]})";
12
13const EditorValue* field(const EditorValue& value, const char* name) {
14 const auto* object = value.getIf<EditorValue::Object>();
15 if (!object) return nullptr;
16 const auto found = object->find(name);
17 return found == object->end() ? nullptr : &found->second;
18}
19
20PropertySchema assetSchema() {
22 descriptor.path = PropertyPath("asset.json");
23 descriptor.displayNameKey = "editor.stylize.meshVfx.assetJson";
24 descriptor.category = "meshVfx";
27 descriptor.defaultValue = defaultAsset;
28 PropertySchema schema;
29 schema.typeId = "stylize.mesh-vfx";
30 schema.properties.push_back(std::move(descriptor));
31 return schema;
32}
33
34} // namespace
35
36MeshVfxAssetTarget::MeshVfxAssetTarget(std::string id) : id_(std::move(id)) {
37 auto parsed = stylize::MeshVfxAsset::fromJson(defaultAsset);
38 asset_ = std::make_unique<stylize::MeshVfxAsset>(std::move(parsed).expect("default mesh VFX asset"));
39}
40
42
44 : EditableTargetState(other), id_(other.id_), asset_(std::make_unique<stylize::MeshVfxAsset>(*other.asset_)) {}
45
47 if (this == &other) return *this;
48 id_ = other.id_;
51 asset_ = std::make_unique<stylize::MeshVfxAsset>(*other.asset_);
52 return *this;
53}
54
56 return {TargetId(id_),
57 "stylize.mesh-vfx",
59 false,
60 {CapabilityId("eve.editor.target.stylize-mesh-vfx-properties")}};
61}
62
63void* MeshVfxAssetTarget::queryCapability(const CapabilityId& capability) {
64 return capability == CapabilityId("eve.editor.target.stylize-mesh-vfx-properties")
65 ? static_cast<IPropertyProvider*>(this)
66 : nullptr;
67}
68
69bool MeshVfxAssetTarget::matches(const SelectionSnapshot& selection) const {
70 return selection.items.size() == 1 && selection.items.front().target == TargetId(id_);
71}
72
74 if (!matches(selection))
76 eve::DiagnosticCode::InvalidArgument, "Mesh VFX selection mismatch", "editor.stylize.mesh-vfx.selection"));
78}
79
80PropertySchema MeshVfxAssetTarget::schema(const SelectionSnapshot&) const { return assetSchema(); }
81
82std::string MeshVfxAssetTarget::canonicalJson() const {
83 return asset_->toJson().expect("serialize Mesh VFX editor asset");
84}
85
87 if (!matches(selection) || path != PropertyPath("asset.json")) return {};
88 return {editing::PropertyReadState::Value, canonicalJson(), {}};
89}
90
92 const PropertyPath& path, const EditorValue& value,
93 PropertySetMode mode) const {
94 if (!matches(selection) || path != PropertyPath("asset.json") || mode != PropertySetMode::Absolute)
95 return editing::failed<DomainOperation>(editing::Status::Rejected,
96 editing::RuleId("editor.stylize.mesh-vfx.set"),
97 "Mesh VFX requires a matching absolute asset.json edit");
98 const auto* json = value.getIf<std::string>();
99 if (!json)
100 return editing::failed<DomainOperation>(editing::Status::Rejected,
101 editing::RuleId("editor.stylize.mesh-vfx.value"),
102 "Mesh VFX asset.json must be a string");
103 auto parsed = stylize::MeshVfxAsset::fromJson(*json);
104 if (!parsed)
105 return editing::failed<DomainOperation>(
106 editing::Status::Rejected, editing::RuleId("editor.stylize.mesh-vfx.invalid"), parsed.status().describe());
107 auto canonical = parsed.value().toJson();
108 if (!canonical)
109 return editing::failed<DomainOperation>(editing::Status::Rejected,
110 editing::RuleId("editor.stylize.mesh-vfx.serialize"),
111 canonical.status().describe());
113 operation.type = "stylize.mesh-vfx.replace.v1";
114 operation.inverseType = operation.type;
115 operation.target = TargetId(id_);
116 operation.payload = EditorValue::Object{{"assetJson", canonical.value()}};
117 operation.inverse = EditorValue::Object{{"assetJson", canonicalJson()}};
118 operation.hasInverse = true;
119 operation.affectedProperties = {"asset.json"};
120 operation.mergeKey = "stylize.mesh-vfx:" + id_;
121 return editing::applied<DomainOperation>(std::move(operation));
122}
123
125 const PropertyPath& path) const {
126 return makeSet(selection, path, defaultAsset, PropertySetMode::Absolute);
127}
128
130 if (operation.target != TargetId(id_) || operation.type != "stylize.mesh-vfx.replace.v1")
131 return editing::failed<void>(editing::Status::Rejected, editing::RuleId("editor.stylize.mesh-vfx.operation"),
132 "Mesh VFX operation mismatch");
133 const auto* jsonValue = field(operation.payload, "assetJson");
134 const auto* json = jsonValue ? jsonValue->getIf<std::string>() : nullptr;
135 if (!json)
136 return editing::failed<void>(editing::Status::Rejected, editing::RuleId("editor.stylize.mesh-vfx.payload"),
137 "Mesh VFX operation payload is invalid");
138 auto candidate = stylize::MeshVfxAsset::fromJson(*json);
139 if (!candidate)
140 return editing::failed<void>(editing::Status::Rejected, editing::RuleId("editor.stylize.mesh-vfx.invalid"),
141 candidate.status().describe());
142 asset_ = std::make_unique<stylize::MeshVfxAsset>(std::move(candidate).takeValue());
143 bumpRevision();
144 widenDirty(0, 0);
145 return editing::applied<void>();
146}
147
148std::unique_ptr<IDomainOperationTarget> MeshVfxAssetTarget::cloneDomainState() const {
149 return std::make_unique<MeshVfxAssetTarget>(*this);
150}
151
152Result<void> MeshVfxAssetTarget::commitDomainState(std::unique_ptr<IDomainOperationTarget> candidate) {
153 auto* target = dynamic_cast<MeshVfxAssetTarget*>(candidate.get());
154 if (!target || target->id_ != id_)
155 return editing::failed<void>(editing::Status::Conflict, editing::RuleId("editor.stylize.mesh-vfx.candidate"),
156 "Mesh VFX candidate mismatch");
157 *this = *target;
158 return editing::applied<void>();
159}
160
161const stylize::MeshVfxAsset& MeshVfxAssetTarget::asset() const noexcept { return *asset_; }
162
164 return EditorValue::Object{{"schemaVersion", std::int64_t{1}}, {"assetJson", canonicalJson()}};
165}
166
168 const auto* versionValue = field(snapshot, "schemaVersion");
169 const auto* jsonValue = field(snapshot, "assetJson");
170 const auto* version = versionValue ? versionValue->getIf<std::int64_t>() : nullptr;
171 const auto* json = jsonValue ? jsonValue->getIf<std::string>() : nullptr;
172 if (!version || *version != 1 || !json)
173 return editing::failed<void>(editing::Status::Unsupported, editing::RuleId("editor.stylize.mesh-vfx.snapshot"),
174 "Unsupported Mesh VFX editor snapshot");
176 operation.target = TargetId(id_);
177 operation.type = "stylize.mesh-vfx.replace.v1";
178 operation.payload = EditorValue::Object{{"assetJson", *json}};
179 auto result = applyDomainOperation(operation);
180 if (result.ok()) clearDirtyRegion();
181 return result;
182}
183
186
188 auto candidate = stylize::MeshVfxAssetInstance::create(document.asset());
189 if (!candidate)
190 return editing::failed<void>(editing::Status::Rejected, editing::RuleId("editor.stylize.mesh-vfx.preview"),
191 candidate.status().describe());
192 instance_ = std::move(candidate).takeValue();
193 revision_ = Revision(document.revision());
194 return editing::applied<void>();
195}
196
197} // namespace eve::stylize_editing
LogicalId target
ActionParameterOperation operation
double value
std::string descriptor
std::string name
std::string path
Definition PlayHost.cpp:110
std::string id
Definition PlayHost.cpp:108
bool found
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
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
void setRevision(Revision revision)
Adopt a revision observed elsewhere, without advancing it.
void bumpRevision()
Advance the revision without touching the dirty region.
EditRegion dirtyRegion() const override
Return the accumulated dirty region.
void setDirtyRegion(const EditRegion &region)
Replace the dirty region wholesale, without advancing the revision.
Revision revisionValue() const noexcept
Return the revision as the shared protocol revision type.
std::uint64_t revision() const override
Return the current revision.
void widenDirty()
Mark an unknown area dirty without advancing the revision.
eve::OptionalRef< C > capability()
Query a capability through its interface-owned stable identity.
virtual void clearDirtyRegion()=0
Clears dirty region.
UI-independent property access for an immutable selection snapshot.
Dotted property path (layout.size) compared and persisted as text.
Definition EditingIds.h:78
Deterministic owning value tree shared by authoring hosts.
std::map< std::string, Value > Object
const T * getIf() const
Return an immediately borrowed typed value.
static eve::Result< std::unique_ptr< MeshVfxAssetInstance > > create(const MeshVfxAsset &asset)
Build independent runtime state for every asset layer.
Transactional editor target for one canonical MeshVfxAsset document. @ownership Owns the authoritativ...
TargetDescriptor describe() const override
Describe.
PropertySchema schema(const SelectionSnapshot &selection) const override
Schema.
PropertyReadResult read(const SelectionSnapshot &selection, const PropertyPath &path) const override
Reads .
Result< void > applyDomainOperation(const DomainOperation &operation) override
Applies domain operation.
void * queryCapability(const CapabilityId &capability) override
Queries capability.
std::unique_ptr< IDomainOperationTarget > cloneDomainState() const override
Clones domain state.
~MeshVfxAssetTarget()
Mesh vfx asset target.
MeshVfxAssetTarget & operator=(const MeshVfxAssetTarget &other)
Operator =.
Result< DomainOperation > makeSet(const SelectionSnapshot &selection, const PropertyPath &path, const EditorValue &value, PropertySetMode mode) const override
Make set.
const stylize::MeshVfxAsset & asset() const noexcept
Return the authoritative parsed asset.
Result< DomainOperation > makeReset(const SelectionSnapshot &selection, const PropertyPath &path) const override
Make reset.
EditorValue snapshotValue() const
Capture schema-version-one editor persistence data.
Result< void > loadSnapshot(const EditorValue &snapshot)
Atomically load a persisted target snapshot.
Result< void > commitDomainState(std::unique_ptr< IDomainOperationTarget > candidate) override
Commits domain state.
eve::Result< eve::Revision > currentRevision(const SelectionSnapshot &selection) const override
Current revision.
MeshVfxAssetTarget(std::string id)
Construct a target containing a valid one-layer default asset.
~MeshVfxPreviewRuntime()
Mesh vfx preview runtime.
MeshVfxPreviewRuntime()
Mesh vfx preview runtime.
Result< void > publish(const MeshVfxAssetTarget &document)
Build every runtime layer before atomically replacing the active preview.
detail::StrongUint64< detail::RevisionTag > Revision
Monotonic content/state revision used for optimistic-concurrency checks.
Definition Revision.h:13
DomainOperation public API.
PropertyDescriptor public API.
PropertyReadResult public API.
EVENGINE_API_PLATFORM public API.
std::vector< PropertyDescriptor > properties
SelectionSnapshot public API.
std::vector< SelectionItem > items
Stable discovery metadata exposed by every editable target.
Versioned, backend-neutral description of a real-time mesh effect.
static eve::Result< MeshVfxAsset > fromJson(std::string_view json)
Parse, migrate, and validate a JSON asset without mutating live state.