载入中...
搜索中...
未找到
ProcgenScriptEditor.cpp
浏览该文件的文档.
2
5#include "procgen/PointSet.h"
6
7#include <algorithm>
8#include <string>
9#include <utility>
10
11namespace eve::procgen_editor {
12namespace {
13
14template <class T = void>
15procgen_editing::Result<T> editorError(procgen_editing::EditorStatus status, std::string rule,
16 std::string message) {
17 return eve::editing::failed<T>(status, eve::editing::RuleId(std::move(rule)), std::move(message));
18}
19
20} // namespace
21
23 : target_(std::move(targetId)), authority_(&target_), transactions_(&authority_) {}
24
26 editor::EditorWorkspace& workspace) const {
27 editor::EditorWorkspace candidate = workspace;
28 struct Panel {
29 const char* id;
30 const char* title;
31 const char* region;
32 const char* context;
33 int order;
34 };
35 constexpr Panel panels[] = {
36 {"procgen.modules", "Modules", "left", "list", 100},
37 {"procgen.preview", "World Preview", "center", "preview", 100},
38 {"procgen.inspector", "Generator Inspector", "right", "inspector", 100},
39 {"procgen.stages", "Debug Stages", "bottom", "stages", 100},
40 };
41 for (const auto& panel : panels) {
42 if (!candidate.registerPanel(panel.id, panel.title, panel.region, panel.order) ||
43 !candidate.setPanelCapability(panel.id, "procgen.script") ||
44 !candidate.setPanelContext(panel.id, panel.context))
45 return editorError(procgen_editing::EditorStatus::Rejected, "editor.procgen.workspace-conflict",
46 "Could not install the procgen script workspace composition");
47 }
48 if (!candidate.activatePanel("procgen.preview"))
49 return editorError(procgen_editing::EditorStatus::Rejected, "editor.procgen.workspace-activate",
50 "Could not activate the procgen preview panel");
51 workspace = std::move(candidate);
52 return eve::editing::applied<void>();
53}
54
55editor::SelectionSnapshot ProcgenScriptEditor::selection() const {
57 snapshot.channel = "procgen";
59 item.domain = editor::SelectionDomain::Asset;
60 item.target = editor::TargetId(target_.targetId());
61 item.item = editor::StableId(target_.moduleId().empty() ? target_.targetId().value() : target_.moduleId());
62 item.type = "procgen-script";
63 snapshot.items.push_back(item);
64 snapshot.primary = item;
65 return snapshot;
66}
67
68procgen_editing::Result<void> ProcgenScriptEditor::commit(
72 spec.id = editor::TransactionId("procgen.script.tx." + std::to_string(++txSequence_));
73 spec.label = std::move(label);
74 spec.target = editor::TargetId(target_.targetId());
75 spec.baseRevision = target_.revision();
76 auto begun = transactions_.begin(std::move(spec));
77 if (!begun.ok())
78 return editorError(begun.code(), "editor.procgen.begin", "Could not begin the generator transaction");
79 auto appended = transactions_.append(std::move(operation).takeValue());
80 if (!appended.ok()) {
81 auto discarded = transactions_.discard();
82 if (!discarded.ok()) discarded.ignore("pending procgen script transaction already inactive");
83 return procgen_editing::Result<void>::failure(appended.status());
84 }
85 auto committed = transactions_.commit();
86 if (!committed.ok()) return procgen_editing::Result<void>::failure(committed.status());
87 dirty_ = true;
88 previewFailureSummary_.clear();
89 return eve::editing::applied<void>();
90}
91
93 return commit(target_.makeLoadModule(std::move(spec)), "Load generator module");
94}
95
97 std::string displayName, std::string kind,
98 const procgen_editing::EditorValue& schema) {
99 auto parsed = procgen_editing::ProcgenScriptDocumentTarget::parseSpec(std::move(uri), std::move(id),
100 std::move(displayName), std::move(kind),
101 schema);
102 if (!parsed.ok()) return procgen_editing::Result<void>::failure(parsed.status());
103 return loadModule(std::move(parsed).takeValue());
104}
105
108 return commit(target_.makeSet(selection(), editing::PropertyPath("param." + key), std::move(value),
110 "Set generator parameter");
111}
112
116
120
124
126 return setParam(std::move(key), procgen_editing::EditorValue(std::move(value)));
127}
128
130 const procgen::PointSet* points) const {
131 if (!points)
132 return editorError<std::vector<PreviewPoint>>(procgen_editing::EditorStatus::Rejected,
133 "editor.procgen.preview", "Preview PointSet must not be null");
134 if (pointBudget_ > 0 && points->getCount() > pointBudget_)
135 return editorError<std::vector<PreviewPoint>>(procgen_editing::EditorStatus::Rejected,
136 "editor.procgen.point-budget",
137 "Preview exceeded the point budget");
138 std::vector<PreviewPoint> next;
139 next.reserve(static_cast<std::size_t>(points->getCount()));
140 for (int i = 0; i < points->getCount(); ++i) {
141 PreviewPoint point;
142 point.x = points->getX(i);
143 point.z = points->getZ(i);
144 point.seed = points->getPointSeed(i);
145 next.push_back(point);
146 }
147 return eve::editing::applied(std::move(next));
148}
149
151 std::string stage,
152 std::uint64_t expectedRevision) {
153 if (expectedRevision != target_.revision())
154 return editorError(procgen_editing::EditorStatus::Conflict, "editor.procgen.stale-preview",
155 "Preview revision does not match the generator document");
156 auto copied = copyPoints(points);
157 if (!copied.ok()) return procgen_editing::Result<void>::failure(copied.status());
158 if (stage.empty()) stage = "output";
159 if (std::find(stageOrder_.begin(), stageOrder_.end(), stage) == stageOrder_.end())
160 stageOrder_.push_back(stage);
161 stages_[stage] = std::move(copied).takeValue();
162 selectedStage_ = stage;
163 previewRevision_ = target_.revision();
164 dirty_ = false;
165 previewFailureSummary_.clear();
166 return eve::editing::applied<void>();
167}
168
170 std::string stage) {
171 if (stage.empty())
172 return editorError(procgen_editing::EditorStatus::Rejected, "editor.procgen.stage",
173 "Debug stage name must not be empty");
174 auto copied = copyPoints(points);
175 if (!copied.ok()) return procgen_editing::Result<void>::failure(copied.status());
176 if (std::find(stageOrder_.begin(), stageOrder_.end(), stage) == stageOrder_.end())
177 stageOrder_.push_back(stage);
178 stages_[stage] = std::move(copied).takeValue();
179 return eve::editing::applied<void>();
180}
181
183 std::uint64_t expectedRevision) {
184 if (expectedRevision != target_.revision())
185 return editorError(procgen_editing::EditorStatus::Conflict, "editor.procgen.stale-preview",
186 "Failed preview revision does not match the generator document");
187 dirty_ = false;
188 previewFailureSummary_ = std::move(message);
189 return eve::editing::applied<void>();
190}
191
193 if (stages_.find(stage) == stages_.end())
194 return editorError(procgen_editing::EditorStatus::NotFound, "editor.procgen.stage",
195 "Debug stage was not found");
196 selectedStage_ = std::move(stage);
197 return eve::editing::applied<void>();
198}
199
201 if (budget < 0)
202 return editorError(procgen_editing::EditorStatus::Rejected, "editor.procgen.point-budget",
203 "Point budget must not be negative");
204 pointBudget_ = budget;
205 return eve::editing::applied<void>();
206}
207
209 continuousRebuild_ = enabled;
210 return eve::editing::applied<void>();
211}
212
214 auto result = transactions_.undo();
215 if (!result.ok()) return result;
216 dirty_ = true;
217 previewFailureSummary_.clear();
218 return result;
219}
220
222 auto result = transactions_.redo();
223 if (!result.ok()) return result;
224 dirty_ = true;
225 previewFailureSummary_.clear();
226 return result;
227}
228
229const procgen::ParamDescriptor* ProcgenScriptEditor::paramAt(int index) const {
230 if (index < 0 || static_cast<std::size_t>(index) >= target_.params().size()) return nullptr;
231 return &target_.params()[static_cast<std::size_t>(index)];
232}
233
234std::string ProcgenScriptEditor::paramKey(int index) const {
235 const auto* param = paramAt(index);
236 return param ? param->key : std::string{};
237}
239 const auto* param = paramAt(index);
240 return param ? (param->displayName.empty() ? param->key : param->displayName) : std::string{};
241}
242std::string ProcgenScriptEditor::paramKind(int index) const {
243 const auto* param = paramAt(index);
244 if (!param) return {};
245 switch (param->kind) {
247 return "int";
249 return "float";
251 return "bool";
253 return "choice";
255 return "string";
256 }
257 return {};
258}
260 const auto* param = paramAt(index);
261 return param ? static_cast<float>(param->minimum) : 0.0f;
262}
264 const auto* param = paramAt(index);
265 return param ? static_cast<float>(param->maximum) : 0.0f;
266}
268 const auto* param = paramAt(index);
269 return param ? static_cast<float>(param->step) : 0.0f;
270}
272 const auto* param = paramAt(index);
273 return param ? static_cast<int>(param->choices.size()) : 0;
274}
275std::string ProcgenScriptEditor::paramChoice(int paramIndex, int choiceIndex) const {
276 const auto* param = paramAt(paramIndex);
277 if (!param || choiceIndex < 0 || static_cast<std::size_t>(choiceIndex) >= param->choices.size()) return {};
278 return param->choices[static_cast<std::size_t>(choiceIndex)];
279}
280
281int ProcgenScriptEditor::getInt(const std::string& key) const {
282 const auto found = target_.values().find(key);
283 if (found == target_.values().end()) return 0;
284 if (const auto* integer = found->second.getIf<std::int64_t>()) return static_cast<int>(*integer);
285 if (const auto* real = found->second.getIf<double>()) return static_cast<int>(*real);
286 return 0;
287}
288float ProcgenScriptEditor::getFloat(const std::string& key) const {
289 const auto found = target_.values().find(key);
290 if (found == target_.values().end()) return 0.0f;
291 if (const auto* real = found->second.getIf<double>()) return static_cast<float>(*real);
292 if (const auto* integer = found->second.getIf<std::int64_t>()) return static_cast<float>(*integer);
293 return 0.0f;
294}
295bool ProcgenScriptEditor::getBool(const std::string& key) const {
296 const auto found = target_.values().find(key);
297 if (found == target_.values().end()) return false;
298 if (const auto* flag = found->second.getIf<bool>()) return *flag;
299 if (const auto* integer = found->second.getIf<std::int64_t>()) return *integer != 0;
300 return false;
301}
302std::string ProcgenScriptEditor::getString(const std::string& key) const {
303 const auto found = target_.values().find(key);
304 if (found == target_.values().end()) return {};
305 if (const auto* text = found->second.getIf<std::string>()) return *text;
306 return {};
307}
308
309const std::vector<ProcgenScriptEditor::PreviewPoint>& ProcgenScriptEditor::displayedPoints() const {
310 static const std::vector<PreviewPoint> empty;
311 const auto found = stages_.find(selectedStage_);
312 return found == stages_.end() ? empty : found->second;
313}
314
315std::string ProcgenScriptEditor::stageName(int index) const {
316 if (index < 0 || static_cast<std::size_t>(index) >= stageOrder_.size()) return {};
317 return stageOrder_[static_cast<std::size_t>(index)];
318}
319
320int ProcgenScriptEditor::pointCount() const { return static_cast<int>(displayedPoints().size()); }
321
323 const auto& points = displayedPoints();
324 if (index < 0 || static_cast<std::size_t>(index) >= points.size()) return 0.0f;
325 return points[static_cast<std::size_t>(index)].x;
326}
328 const auto& points = displayedPoints();
329 if (index < 0 || static_cast<std::size_t>(index) >= points.size()) return 0.0f;
330 return points[static_cast<std::size_t>(index)].z;
331}
332std::uint32_t ProcgenScriptEditor::pointSeed(int index) const {
333 const auto& points = displayedPoints();
334 if (index < 0 || static_cast<std::size_t>(index) >= points.size()) return 0;
335 return points[static_cast<std::size_t>(index)].seed;
336}
337
338} // namespace eve::procgen_editor
ActionParameterOperation operation
double value
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
std::string title
std::string label
std::string message
std::uint32_t key
wgpu::PopErrorScopeStatus status
std::string text
TokenKind kind
std::vector< std::int32_t > order
std::string id
Definition PlayHost.cpp:108
std::uint32_t seed
Definition PointSet.cpp:807
std::string uri
std::uint32_t targetId
std::shared_ptr< const std::vector< glm::vec2 > > points
UI-neutral host for a script generator: schema params, undo, PointSet preview.
bool found
uint32_t index
const VegetationPresetContext & context
glm::vec3 point
void ignore(std::string_view reason={}) const noexcept
Explicitly discard this result after documenting the reason.
Definition Result.h:537
Move-only operation result carrying either a value or Status.
Definition Result.h:155
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
const std::string & value() const noexcept
Returns the exact legacy or canonical compatibility spelling.
Definition Identity.h:362
Dotted property path (layout.size) compared and persisted as text.
Definition EditingIds.h:78
Deterministic owning value tree shared by authoring hosts.
Composition model shared by project-specific developer and runtime editors.
bool setPanelContext(const std::string &id, const std::string &context)
Attach a semantic input context such as scene, graph, or timeline.
Result< WorkspacePanelDescriptor > registerPanel(WorkspacePanelDescriptor descriptor)
Register a checked owning panel descriptor.
Result< WorkspacePanelDescriptor > activatePanel(const StableId &id)
Activate a visible panel with structured not-found/rejected results.
bool setPanelCapability(const std::string &id, const std::string &capability)
Attach a capability requirement used by the host when filtering panels.
Result< TransactionReceipt > commit() override
Preflight and commit all active operations through the authority.
Result< TransactionId > begin(TransactionSpec specification) override
Begin a transaction with a stable id and base revision.
Result< TransactionReceipt > undo() override
Compensate the most recent committed transaction.
Result< void > discard() override
Discard the active, not-yet-committed operation list.
Result< TransactionReceipt > redo() override
Reapply the most recently compensated transaction.
Result< void > append(DomainOperation operation) override
Append an operation to the active transaction without applying it.
Script-friendly collection of attributed 3D samples.
Definition PointSet.h:59
Result< editing::DomainOperation > makeSet(const editing::SelectionSnapshot &, const editing::PropertyPath &, const EditorValue &, editing::PropertySetMode) const override
Make set.
Result< editing::DomainOperation > makeLoadModule(ProcgenScriptModuleSpec spec) const
Replace module identity and schema, remapping values (drop unknown, fill defaults).
const std::string & moduleId() const
Module id.
editing::TargetId targetId() const override
Target id.
std::uint64_t revision() const override
Revision.
const EditorValue::Object & values() const
Values.
const std::vector< procgen::ParamDescriptor > & params() const
Params.
static Result< ProcgenScriptModuleSpec > parseSpec(std::string uri, std::string id, std::string displayName, std::string kind, const EditorValue &schema)
Parse a schema array into a module spec.
float paramStep(int index) const
Param step.
int getInt(const std::string &key) const
Returns the int.
procgen_editing::Result< void > setPointBudget(int budget)
Sets the point budget.
procgen_editing::Result< editor::TransactionReceipt > redo()
std::string getString(const std::string &key) const
Returns the string.
procgen_editing::Result< void > configureWorkspace(editor::EditorWorkspace &workspace) const
Install Modules / Preview / Inspector / Debug Stages panels.
procgen_editing::Result< void > publishStage(const procgen::PointSet *points, std::string stage)
Copy an intermediate debug stage without changing the displayed output unless it is selected.
std::string stageName(int index) const
Stage name.
std::string displayName() const
Display name.
procgen_editing::Result< void > setLive(bool enabled)
Choose whether the presenter should rebuild on every parameter commit.
std::string paramKey(int index) const
Param key.
float paramMaximum(int index) const
Param maximum.
std::string paramChoice(int paramIndex, int choiceIndex) const
Param choice.
procgen_editing::Result< void > setBool(std::string key, bool value)
Sets the bool.
procgen_editing::Result< void > setParam(std::string key, procgen_editing::EditorValue value)
Sets the param.
procgen_editing::Result< void > setString(std::string key, std::string value)
Sets the string.
float getFloat(const std::string &key) const
Returns the float.
procgen_editing::Result< void > setFloat(std::string key, double value)
Sets the float.
procgen_editing::Result< void > setInt(std::string key, int value)
Sets the int.
std::uint32_t pointSeed(int index) const
Point seed.
float paramMinimum(int index) const
Param minimum.
procgen_editing::Result< void > selectStage(std::string stage)
Select stage.
procgen_editing::Result< void > publishPreview(const procgen::PointSet *points, std::string stage, std::uint64_t expectedRevision)
Copy a successful generation into the preview cache.
procgen_editing::Result< void > failPreview(std::string message, std::uint64_t expectedRevision)
procgen_editing::Result< editor::TransactionReceipt > undo()
std::string paramLabel(int index) const
Param label.
bool getBool(const std::string &key) const
Returns the bool.
std::string paramKind(int index) const
Param kind.
ProcgenScriptEditor(std::string targetId)
Construct an empty generator host.
int paramChoiceCount(int index) const
Param choice count.
procgen_editing::Result< void > loadModule(procgen_editing::ProcgenScriptModuleSpec spec)
Result< T > applied(T value, std::vector< Diagnostic > diagnostics={})
Construct an Applied result with an owning payload and optional diagnostics.
eve::editing::StableId StableId
Definition EditorIds.h:36
eve::editing::TargetId TargetId
Definition EditorIds.h:29
eve::editing::TransactionId TransactionId
Definition EditorIds.h:34
bool enabled
SelectionItem public API.
SelectionSnapshot public API.
std::vector< SelectionItem > items
std::optional< SelectionItem > primary
TransactionSpec public API.
UI-independent metadata for one procedural recipe parameter.
Definition ParamSchema.h:14
Authored identity and reflected parameter schema for one script generator.