载入中...
搜索中...
未找到
VoxelEditingCommands.cpp
浏览该文件的文档.
2
4
5#include <cstdint>
6#include <string>
7
8namespace eve::voxel_editing {
9namespace {
10
11const editing::Value* field(const editing::Value& value, const char* key) {
12 const auto* object = value.getIf<editing::Value::Object>();
13 if (!object) return nullptr;
14 const auto found = object->find(key);
15 return found == object->end() ? nullptr : &found->second;
16}
17
18const std::string* stringField(const editing::Value& value, const char* key) {
19 const editing::Value* entry = field(value, key);
20 return entry ? entry->getIf<std::string>() : nullptr;
21}
22
23bool readInt(const editing::Value& value, const char* key, int& output, bool required) {
24 const editing::Value* entry = field(value, key);
25 if (!entry) return !required;
26 if (const auto* integer = entry->getIf<int64_t>()) {
27 output = static_cast<int>(*integer);
28 return true;
29 }
30 if (const auto* real = entry->getIf<double>()) {
31 output = static_cast<int>(*real);
32 return true;
33 }
34 return false;
35}
36
37bool readBool(const editing::Value& value, const char* key, bool& output, bool required) {
38 const editing::Value* entry = field(value, key);
39 if (!entry) return !required;
40 const auto* flag = entry->getIf<bool>();
41 if (!flag) return false;
42 output = *flag;
43 return true;
44}
45
46editing::Result<void> addCommand(editing::IEditingCommandRegistry& registry, const char* id, const char* displayName,
48 editing::EditingCommandDescriptor descriptor;
50 descriptor.ownerModule = "voxel_editing";
51 descriptor.displayName = displayName;
52 descriptor.category = "Voxel";
53 descriptor.automationAllowed = true;
54 return registry.registerPlannedCommand(std::move(descriptor), std::move(planner));
55}
56
57VoxelCatalogTarget* asCatalog(editing::IEditableTarget& target) {
58 return dynamic_cast<VoxelCatalogTarget*>(&target);
59}
60
61editing::SelectionSnapshot selectionFor(const VoxelCatalogTarget& target, const std::string& item) {
62 editing::SelectionSnapshot selection;
63 selection.channel = "voxel-catalog";
64 editing::SelectionItem row;
66 row.target = editing::TargetId(target.targetId());
67 row.item = editing::StableId(item);
68 row.type = "voxel.model";
69 selection.items.push_back(row);
70 selection.primary = row;
71 return selection;
72}
73
74editing::Result<editing::CommandPlan> planFrom(editing::Result<editing::DomainOperation> operation,
75 editing::Value summary) {
76 if (!operation.ok())
77 return eve::editing::failed<editing::CommandPlan>(operation.code(), editing::RuleId("voxel.editing.operation"),
78 "Voxel catalog rejected the planned edit");
79 editing::CommandPlan plan;
80 plan.operations.push_back(std::move(operation).takeValue());
81 plan.summary = std::move(summary);
82 return eve::editing::applied<editing::CommandPlan>(std::move(plan));
83}
84
85} // namespace
86
88 auto registered = addCommand(
89 registry, "voxel.model.create.v1", "Create voxel model",
91 auto* catalog = asCatalog(target);
92 const std::string* id = stringField(request.payload, "id");
93 if (!catalog || !id || id->empty())
94 return eve::editing::failed<editing::CommandPlan>(editing::Status::Rejected,
95 editing::RuleId("voxel.editing.model-payload"),
96 "Voxel model create requires id");
97 const std::string* name = stringField(request.payload, "name");
100 model.name = name && !name->empty() ? *name : *id;
101 if (!readInt(request.payload, "sizeX", model.sizeX, false) ||
102 !readInt(request.payload, "sizeY", model.sizeY, false) ||
103 !readInt(request.payload, "sizeZ", model.sizeZ, false))
104 return eve::editing::failed<editing::CommandPlan>(editing::Status::Rejected,
105 editing::RuleId("voxel.editing.size"),
106 "Voxel model size must be integers");
107 return planFrom(catalog->makeCreateModel(model), editing::Value::Object{{"id", *id}});
108 });
109 if (!registered.ok()) return registered;
110
111 registered = addCommand(
112 registry, "voxel.model.delete.v1", "Delete voxel model",
114 auto* catalog = asCatalog(target);
115 const std::string* id = stringField(request.payload, "id");
116 if (!catalog || !id || id->empty())
117 return eve::editing::failed<editing::CommandPlan>(editing::Status::Rejected,
118 editing::RuleId("voxel.editing.model-payload"),
119 "Voxel model delete requires id");
120 return planFrom(catalog->makeDeleteModel(editing::ObjectId(*id)), editing::Value::Object{{"id", *id}});
121 });
122 if (!registered.ok()) return registered;
123
124 registered = addCommand(
125 registry, "voxel.model.voxel.set.v1", "Set voxel occupancy",
126 [](editing::IEditableTarget& target, const editing::CommandRequest& request) {
127 auto* catalog = asCatalog(target);
128 const std::string* item = stringField(request.payload, "item");
129 int x = 0, y = 0, z = 0;
130 bool occupied = true;
131 if (!catalog || !item || item->empty() || !readInt(request.payload, "x", x, true) ||
132 !readInt(request.payload, "y", y, true) || !readInt(request.payload, "z", z, true) ||
133 !readBool(request.payload, "occupied", occupied, true))
134 return eve::editing::failed<editing::CommandPlan>(
135 editing::Status::Rejected, editing::RuleId("voxel.editing.voxel-payload"),
136 "Voxel occupancy requires item, x, y, z and occupied");
137 return planFrom(catalog->makeSetVoxel(editing::ObjectId(*item), x, y, z, occupied),
138 editing::Value::Object{{"item", *item}});
139 });
140 if (!registered.ok()) return registered;
141
142 return addCommand(
143 registry, "voxel.property.set.v1", "Set voxel catalog property",
144 [](editing::IEditableTarget& target, const editing::CommandRequest& request) {
145 auto* catalog = asCatalog(target);
146 auto* properties = static_cast<editing::IPropertyProvider*>(
147 target.queryCapability(VoxelCatalogTarget::propertyCapabilityId()));
148 const std::string* item = stringField(request.payload, "item");
149 const std::string* path = stringField(request.payload, "path");
150 const editing::Value* value = field(request.payload, "value");
151 if (!catalog || !properties || !item || item->empty() || !path || !value)
152 return eve::editing::failed<editing::CommandPlan>(editing::Status::Rejected,
153 editing::RuleId("voxel.editing.property-payload"),
154 "Voxel property requires item, path and value");
155 return planFrom(properties->makeSet(selectionFor(*catalog, *item), editing::PropertyPath(*path), *value,
156 editing::PropertySetMode::Absolute),
157 editing::Value::Object{{"item", *item}, {"path", *path}});
158 });
159}
160
161} // namespace eve::voxel_editing
LogicalId target
ActionParameterOperation operation
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
std::string output
std::string descriptor
const GltfImportRequest & request
std::uint32_t key
std::map< std::string, PropertyRule > properties
bool required
std::string name
std::string path
Definition PlayHost.cpp:110
std::string id
Definition PlayHost.cpp:108
glm::mat4 model
bool found
bool occupied
MagicaVoxel-style sculpted models: bounded occupancy grids and hull sockets.
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
IEditableTarget public API.
Lower-layer registration boundary implemented by an editor or runtime editing host.
std::map< std::string, Value > Object
const T * getIf() const
Return an immediately borrowed typed value.
StrongId< TargetIdTag > TargetId
Definition EditingIds.h:57
StrongId< ObjectIdTag > ObjectId
Definition EditingIds.h:65
std::function< Result< CommandPlan >(IEditableTarget &, const CommandRequest &)> EditingCommandPlanner
Side-effect-free planner invoked with the resolved target.
StrongId< StableIdTag > StableId
Definition EditingIds.h:64
StrongId< RuleIdTag > RuleId
Definition EditingIds.h:60
StrongId< CommandIdTag > CommandId
Definition EditingIds.h:58
const EditorValue * field(const EditorValue &value, const char *name)
WidgetDesc row(std::vector< WidgetDesc > children, std::string id)
Horizontal elastic layout row.
Definition Widget.cpp:679
editing::Result< void > registerEditingCommands(editing::IEditingCommandRegistry &registry)
Register voxel-catalog planned commands with a generic editing host.
CommandRequest public API.
NodeType type
Definition Widget.h:16
One MagicaVoxel-style object: a bounded occupancy grid.