ue-mcp-plugin-voxel-plugin 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -11
- package/dist/tasks/BuildScatterGraph.d.ts +29 -0
- package/dist/tasks/BuildScatterGraph.js +102 -0
- package/dist/tasks/BuildScatterGraph.js.map +1 -0
- package/package.json +2 -2
- package/ue-mcp.plugin.yml +17 -9
package/README.md
CHANGED
|
@@ -2,21 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
[Voxel Plugin](https://voxelplugin.com) actions for [ue-mcp](https://github.com/db-lyon/ue-mcp).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## What ships
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
actions (`voxel_scatter_meshes`, `voxel_spawn_stamps`, `voxel_bake_heightmap`)
|
|
9
|
-
that called ue-mcp tasks with wrong parameter names and passed PCG node-type
|
|
10
|
-
strings that do not exist. They have been removed rather than left as broken
|
|
11
|
-
surface.
|
|
7
|
+
One injected action in v0.2.0, cited to its source:
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
| Category | Action | Wraps |
|
|
10
|
+
|----------|------------------------------|-------|
|
|
11
|
+
| `pcg` | `voxel_build_scatter_graph` | `UPCGVoxelSamplerSettings` (`VoxelPCG/Public/PCGVoxelSampler.h`) feeding `UPCGStaticMeshSpawnerSettings` |
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
More tools are tracked in [`TODO.md`](TODO.md) — each entry cites the header and class it would wrap. The v0.1.0 release shipped three actions that called ue-mcp tasks with wrong parameter names and passed PCG node-type strings that did not exist; v0.1.1 removed them.
|
|
18
14
|
|
|
19
|
-
##
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
ue-mcp plugin install ue-mcp-plugin-voxel-plugin
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The CLI adds an entry under `plugins:` in your `ue-mcp.yml`. Restart ue-mcp; the injected action shows up under `pcg`.
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
pcg(action="voxel_build_scatter_graph",
|
|
27
|
+
assetPath="/Game/PCG/RockScatter",
|
|
28
|
+
meshes=[
|
|
29
|
+
{mesh: "/Game/Foliage/Rock_A.Rock_A", weight: 2},
|
|
30
|
+
{mesh: "/Game/Foliage/Rock_B.Rock_B"}
|
|
31
|
+
],
|
|
32
|
+
pointsPerSquaredMeter=0.05,
|
|
33
|
+
seed=42)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The call creates a `UPCGGraph` at `assetPath`, adds a Voxel Sampler → Static Mesh Spawner pipeline, and populates the weighted mesh table. Attach the resulting graph to a PCG component on or near your `AVoxelWorld`, then:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
pcg(action="execute", actorLabel="MyPCGActor")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Requirements
|
|
20
43
|
|
|
21
44
|
- ue-mcp `>= 1.0.15`
|
|
22
45
|
- Voxel Plugin enabled in your `.uproject` (`Plugins[].Name == "Voxel"`)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseTask, type TaskResult } from "@db-lyon/flowkit";
|
|
2
|
+
interface MeshEntry {
|
|
3
|
+
mesh: string;
|
|
4
|
+
weight?: number;
|
|
5
|
+
}
|
|
6
|
+
interface Options {
|
|
7
|
+
assetPath: string;
|
|
8
|
+
meshes: MeshEntry[];
|
|
9
|
+
pointsPerSquaredMeter?: number;
|
|
10
|
+
seed?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build a PCG graph that scatters weighted static meshes on a voxel terrain.
|
|
14
|
+
*
|
|
15
|
+
* Wraps `UPCGVoxelSamplerSettings` (VoxelPCG/Public/PCGVoxelSampler.h) feeding
|
|
16
|
+
* `UPCGStaticMeshSpawnerSettings`. The output asset is a UPCGGraph that the
|
|
17
|
+
* caller attaches to a PCG component (typically on or near an AVoxelWorld)
|
|
18
|
+
* before calling `pcg.execute`.
|
|
19
|
+
*
|
|
20
|
+
* Layer wiring (FVoxelStackLayer struct) is intentionally not exposed in v1.
|
|
21
|
+
* The sampler defaults to the UE-side default stack/layer, which is what an
|
|
22
|
+
* out-of-the-box voxel world uses.
|
|
23
|
+
*/
|
|
24
|
+
export default class BuildScatterGraph extends BaseTask<Options> {
|
|
25
|
+
get taskName(): string;
|
|
26
|
+
protected validate(): void;
|
|
27
|
+
execute(): Promise<TaskResult>;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { BaseTask } from "@db-lyon/flowkit";
|
|
2
|
+
/**
|
|
3
|
+
* Build a PCG graph that scatters weighted static meshes on a voxel terrain.
|
|
4
|
+
*
|
|
5
|
+
* Wraps `UPCGVoxelSamplerSettings` (VoxelPCG/Public/PCGVoxelSampler.h) feeding
|
|
6
|
+
* `UPCGStaticMeshSpawnerSettings`. The output asset is a UPCGGraph that the
|
|
7
|
+
* caller attaches to a PCG component (typically on or near an AVoxelWorld)
|
|
8
|
+
* before calling `pcg.execute`.
|
|
9
|
+
*
|
|
10
|
+
* Layer wiring (FVoxelStackLayer struct) is intentionally not exposed in v1.
|
|
11
|
+
* The sampler defaults to the UE-side default stack/layer, which is what an
|
|
12
|
+
* out-of-the-box voxel world uses.
|
|
13
|
+
*/
|
|
14
|
+
export default class BuildScatterGraph extends BaseTask {
|
|
15
|
+
get taskName() { return "voxel.build_scatter_graph"; }
|
|
16
|
+
validate() {
|
|
17
|
+
if (!this.options.assetPath)
|
|
18
|
+
throw new Error("assetPath is required");
|
|
19
|
+
if (!Array.isArray(this.options.meshes) || this.options.meshes.length === 0) {
|
|
20
|
+
throw new Error("meshes must be a non-empty array of { mesh, weight? } entries");
|
|
21
|
+
}
|
|
22
|
+
for (const m of this.options.meshes) {
|
|
23
|
+
if (!m?.mesh)
|
|
24
|
+
throw new Error("each meshes[] entry must include a `mesh` asset path");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async execute() {
|
|
28
|
+
const { assetPath, meshes, pointsPerSquaredMeter = 0.1, seed = 1 } = this.options;
|
|
29
|
+
const slash = assetPath.lastIndexOf("/");
|
|
30
|
+
if (slash <= 0) {
|
|
31
|
+
return { success: false, error: new Error(`assetPath must be a content path like /Game/Folder/Name, got: ${assetPath}`) };
|
|
32
|
+
}
|
|
33
|
+
const packagePath = assetPath.slice(0, slash);
|
|
34
|
+
const name = assetPath.slice(slash + 1);
|
|
35
|
+
const create = await this.call("pcg.create_graph", { name, packagePath });
|
|
36
|
+
if (!create.success) {
|
|
37
|
+
// Re-running over an existing graph is a supported workflow; only abort
|
|
38
|
+
// on hard failures, not on the "asset already exists" path.
|
|
39
|
+
const msg = create.error?.message ?? "";
|
|
40
|
+
if (!/exist|already/i.test(msg))
|
|
41
|
+
return create;
|
|
42
|
+
}
|
|
43
|
+
// Bridge's nodeType resolver only falls back to /Script/PCG.* — for
|
|
44
|
+
// VoxelPCG classes we pass the absolute object path so the first
|
|
45
|
+
// FindObject lookup hits.
|
|
46
|
+
const samplerR = await this.call("pcg.add_node", {
|
|
47
|
+
assetPath,
|
|
48
|
+
nodeType: "/Script/VoxelPCG.PCGVoxelSamplerSettings",
|
|
49
|
+
});
|
|
50
|
+
if (!samplerR.success)
|
|
51
|
+
return samplerR;
|
|
52
|
+
const samplerName = samplerR.data?.nodeName;
|
|
53
|
+
if (!samplerName)
|
|
54
|
+
return { success: false, error: new Error("pcg.add_node sampler returned no nodeName") };
|
|
55
|
+
const spawnerR = await this.call("pcg.add_node", {
|
|
56
|
+
assetPath,
|
|
57
|
+
nodeType: "/Script/PCG.PCGStaticMeshSpawnerSettings",
|
|
58
|
+
});
|
|
59
|
+
if (!spawnerR.success)
|
|
60
|
+
return spawnerR;
|
|
61
|
+
const spawnerName = spawnerR.data?.nodeName;
|
|
62
|
+
if (!spawnerName)
|
|
63
|
+
return { success: false, error: new Error("pcg.add_node spawner returned no nodeName") };
|
|
64
|
+
const settingsR = await this.call("pcg.set_node_settings", {
|
|
65
|
+
assetPath,
|
|
66
|
+
nodeName: samplerName,
|
|
67
|
+
settings: {
|
|
68
|
+
PointsPerSquaredMeter: pointsPerSquaredMeter,
|
|
69
|
+
Seed: seed,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
if (!settingsR.success)
|
|
73
|
+
return settingsR;
|
|
74
|
+
const connectR = await this.call("pcg.connect_nodes", {
|
|
75
|
+
assetPath,
|
|
76
|
+
sourceNode: samplerName,
|
|
77
|
+
targetNode: spawnerName,
|
|
78
|
+
});
|
|
79
|
+
if (!connectR.success)
|
|
80
|
+
return connectR;
|
|
81
|
+
const meshesR = await this.call("pcg.set_static_mesh_spawner_meshes", {
|
|
82
|
+
assetPath,
|
|
83
|
+
nodeName: spawnerName,
|
|
84
|
+
entries: meshes,
|
|
85
|
+
replace: true,
|
|
86
|
+
});
|
|
87
|
+
if (!meshesR.success)
|
|
88
|
+
return meshesR;
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
data: {
|
|
92
|
+
assetPath,
|
|
93
|
+
samplerNode: samplerName,
|
|
94
|
+
spawnerNode: spawnerName,
|
|
95
|
+
meshCount: meshes.length,
|
|
96
|
+
pointsPerSquaredMeter,
|
|
97
|
+
seed,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=BuildScatterGraph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BuildScatterGraph.js","sourceRoot":"","sources":["../../src/tasks/BuildScatterGraph.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ue-mcp-plugin-voxel-plugin",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Voxel Plugin actions for ue-mcp.
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Voxel Plugin actions for ue-mcp. One real PCG action in 0.2.0 - rest tracked in TODO.md.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"files": [
|
package/ue-mcp.plugin.yml
CHANGED
|
@@ -2,14 +2,22 @@ actionPrefix: voxel
|
|
|
2
2
|
minServerVersion: 1.0.15
|
|
3
3
|
uePluginDependency: Voxel
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
inject:
|
|
6
|
+
pcg:
|
|
7
|
+
build_scatter_graph:
|
|
8
|
+
task: voxel.build_scatter_graph
|
|
9
|
+
description: "Build a PCG graph that scatters weighted static meshes on a voxel terrain. Wraps UPCGVoxelSamplerSettings (VoxelPCG/Public/PCGVoxelSampler.h) feeding the stock PCGStaticMeshSpawner. After creation, attach the graph to a PCG component (usually near an AVoxelWorld) and call pcg.execute. Params: assetPath (e.g. /Game/PCG/MyScatter), meshes=[{mesh, weight?}], pointsPerSquaredMeter? (default 0.1), seed? (default 1)."
|
|
10
|
+
schema:
|
|
11
|
+
assetPath: { type: string, required: true }
|
|
12
|
+
meshes: { type: array, required: true }
|
|
13
|
+
pointsPerSquaredMeter: { type: number }
|
|
14
|
+
seed: { type: number }
|
|
15
|
+
|
|
13
16
|
knowledge: {}
|
|
14
|
-
|
|
17
|
+
|
|
18
|
+
tasks:
|
|
19
|
+
voxel.build_scatter_graph:
|
|
20
|
+
class_path: tasks/BuildScatterGraph
|
|
21
|
+
description: "Build a Voxel-Sampler-driven PCG mesh scatter graph"
|
|
22
|
+
|
|
15
23
|
flows: {}
|