ue-mcp-plugin-voxel-plugin 0.2.0 → 0.3.1
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 -8
- package/dist/tasks/EnsureWaitForWorld.d.ts +32 -0
- package/dist/tasks/EnsureWaitForWorld.js +91 -0
- package/dist/tasks/EnsureWaitForWorld.js.map +1 -0
- package/dist/tasks/GetWorldStatus.d.ts +27 -0
- package/dist/tasks/GetWorldStatus.js +57 -0
- package/dist/tasks/GetWorldStatus.js.map +1 -0
- package/dist/tasks/SpawnWorld.d.ts +37 -0
- package/dist/tasks/SpawnWorld.js +72 -0
- package/dist/tasks/SpawnWorld.js.map +1 -0
- package/docs/Modules.md +107 -0
- package/docs/README.md +47 -0
- package/docs/Tests.md +280 -0
- package/docs/Voxel.md +450 -0
- package/docs/VoxelBlueprint.md +167 -0
- package/docs/VoxelCore.md +128 -0
- package/docs/VoxelGraph.md +386 -0
- package/docs/VoxelPCG.md +288 -0
- package/package.json +3 -2
- package/ue-mcp.plugin.yml +34 -0
package/README.md
CHANGED
|
@@ -4,13 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
## What ships
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Each action is cited to the C++ header it wraps. Full API reference under [`docs/`](docs/).
|
|
8
8
|
|
|
9
|
-
| Category | Action
|
|
10
|
-
|
|
11
|
-
| `
|
|
9
|
+
| Category | Action | Wraps |
|
|
10
|
+
|----------|---------------------------------|-------|
|
|
11
|
+
| `level` | `voxel_spawn_voxel_world` | `level.place_actor` for `AVoxelWorld` (`Voxel/Public/VoxelWorld.h`) + property defaults so the world renders |
|
|
12
|
+
| `level` | `voxel_get_voxel_world_status` | 5 zero-arg lifecycle UFUNCTIONs on `AVoxelWorld` (`Voxel/Public/VoxelWorld.h`) |
|
|
13
|
+
| `pcg` | `voxel_build_scatter_graph` | `UPCGVoxelSamplerSettings` (`VoxelPCG/Public/PCGVoxelSampler.h`) feeding `UPCGStaticMeshSpawnerSettings` |
|
|
14
|
+
| `pcg` | `voxel_ensure_wait_for_world` | Splices `UPCGWaitForVoxelWorldSettings` (`VoxelPCG/Public/PCGWaitForVoxelWorld.h`) into an existing graph |
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
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.
|
|
14
17
|
|
|
15
18
|
## Install
|
|
16
19
|
|
|
@@ -20,9 +23,24 @@ ue-mcp plugin install ue-mcp-plugin-voxel-plugin
|
|
|
20
23
|
|
|
21
24
|
The CLI adds an entry under `plugins:` in your `ue-mcp.yml`. Restart ue-mcp; the injected action shows up under `pcg`.
|
|
22
25
|
|
|
23
|
-
##
|
|
26
|
+
## 0-to-1 workflow
|
|
24
27
|
|
|
25
28
|
```text
|
|
29
|
+
# 1. drop a voxel world into the level
|
|
30
|
+
level(action="voxel_spawn_voxel_world", label="MyVoxelWorld")
|
|
31
|
+
|
|
32
|
+
# 2. poll until the runtime finishes its first generation pass
|
|
33
|
+
level(action="voxel_get_voxel_world_status", actorLabel="MyVoxelWorld")
|
|
34
|
+
# => { isRuntimeCreated, isVoxelWorldReady, isProcessingNewState, progress, numPendingTasks }
|
|
35
|
+
# wait for isVoxelWorldReady && !isProcessingNewState before doing anything else.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That's the hello-world. `spawn_voxel_world` defaults `LayerStack` to the plugin-bundled `/Voxel/Default/DefaultStack.DefaultStack` so the actor renders without further setup.
|
|
39
|
+
|
|
40
|
+
## PCG actions (once a world is live)
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
# Build a scatter graph that drops weighted meshes on the voxel surface.
|
|
26
44
|
pcg(action="voxel_build_scatter_graph",
|
|
27
45
|
assetPath="/Game/PCG/RockScatter",
|
|
28
46
|
meshes=[
|
|
@@ -31,14 +49,22 @@ pcg(action="voxel_build_scatter_graph",
|
|
|
31
49
|
],
|
|
32
50
|
pointsPerSquaredMeter=0.05,
|
|
33
51
|
seed=42)
|
|
52
|
+
|
|
53
|
+
# Attach the graph to a PCG component, then materialize:
|
|
54
|
+
pcg(action="execute", actorLabel="MyPCGActor")
|
|
34
55
|
```
|
|
35
56
|
|
|
36
|
-
|
|
57
|
+
If a PCG graph scatters before the voxel runtime finishes generating, you get empty / stale output. The gate is a `WaitForVoxelWorld` node — splice one into any graph idempotently:
|
|
37
58
|
|
|
38
59
|
```text
|
|
39
|
-
pcg(action="
|
|
60
|
+
pcg(action="voxel_ensure_wait_for_world",
|
|
61
|
+
assetPath="/Game/PCG/RockScatter",
|
|
62
|
+
beforeNode="PCGStaticMeshSpawner")
|
|
63
|
+
# => { waitNode, inserted: true, rewiredEdges: N } # or inserted:false if already gated
|
|
40
64
|
```
|
|
41
65
|
|
|
66
|
+
`beforeNode` is whichever node you want to gate — almost always your spawner.
|
|
67
|
+
|
|
42
68
|
## Requirements
|
|
43
69
|
|
|
44
70
|
- ue-mcp `>= 1.0.15`
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BaseTask, type TaskResult } from "@db-lyon/flowkit";
|
|
2
|
+
interface Options {
|
|
3
|
+
assetPath: string;
|
|
4
|
+
/**
|
|
5
|
+
* The PCG node you want to gate on the voxel world being ready —
|
|
6
|
+
* almost always the spawner that materializes the final result
|
|
7
|
+
* (PCGStaticMeshSpawner, PCGVoxelStampSpawner, etc.). Whichever
|
|
8
|
+
* nodes currently feed `beforeNode` get rerouted through a new
|
|
9
|
+
* `WaitForVoxelWorld` node.
|
|
10
|
+
*/
|
|
11
|
+
beforeNode: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Insert a `WaitForVoxelWorld` node immediately upstream of `beforeNode`
|
|
15
|
+
* in an existing PCG graph. Idempotent: if any node already feeding
|
|
16
|
+
* `beforeNode` is a Wait node, returns `inserted: false` and changes
|
|
17
|
+
* nothing.
|
|
18
|
+
*
|
|
19
|
+
* Header: `VoxelPCG/Public/PCGWaitForVoxelWorld.h`
|
|
20
|
+
* (`UPCGWaitForVoxelWorldSettings`, control-flow node, no settings).
|
|
21
|
+
*
|
|
22
|
+
* Fixes the most common PCG-on-voxel footgun documented in
|
|
23
|
+
* `docs/VoxelPCG.md`: pipelines that scatter / stamp before the voxel
|
|
24
|
+
* runtime finishes generating produce empty or stale output. The Wait
|
|
25
|
+
* node blocks downstream execution until the voxel world is ready.
|
|
26
|
+
*/
|
|
27
|
+
export default class EnsureWaitForWorld extends BaseTask<Options> {
|
|
28
|
+
get taskName(): string;
|
|
29
|
+
protected validate(): void;
|
|
30
|
+
execute(): Promise<TaskResult>;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { BaseTask } from "@db-lyon/flowkit";
|
|
2
|
+
const WAIT_NODE_TITLE = "Wait For Voxel World";
|
|
3
|
+
const WAIT_NODE_TYPE = "/Script/VoxelPCG.PCGWaitForVoxelWorldSettings";
|
|
4
|
+
/**
|
|
5
|
+
* Insert a `WaitForVoxelWorld` node immediately upstream of `beforeNode`
|
|
6
|
+
* in an existing PCG graph. Idempotent: if any node already feeding
|
|
7
|
+
* `beforeNode` is a Wait node, returns `inserted: false` and changes
|
|
8
|
+
* nothing.
|
|
9
|
+
*
|
|
10
|
+
* Header: `VoxelPCG/Public/PCGWaitForVoxelWorld.h`
|
|
11
|
+
* (`UPCGWaitForVoxelWorldSettings`, control-flow node, no settings).
|
|
12
|
+
*
|
|
13
|
+
* Fixes the most common PCG-on-voxel footgun documented in
|
|
14
|
+
* `docs/VoxelPCG.md`: pipelines that scatter / stamp before the voxel
|
|
15
|
+
* runtime finishes generating produce empty or stale output. The Wait
|
|
16
|
+
* node blocks downstream execution until the voxel world is ready.
|
|
17
|
+
*/
|
|
18
|
+
export default class EnsureWaitForWorld extends BaseTask {
|
|
19
|
+
get taskName() { return "voxel.ensure_wait_for_world"; }
|
|
20
|
+
validate() {
|
|
21
|
+
if (!this.options.assetPath)
|
|
22
|
+
throw new Error("assetPath is required");
|
|
23
|
+
if (!this.options.beforeNode)
|
|
24
|
+
throw new Error("beforeNode is required");
|
|
25
|
+
}
|
|
26
|
+
async execute() {
|
|
27
|
+
const { assetPath, beforeNode } = this.options;
|
|
28
|
+
const graphR = await this.call("pcg.read_graph", { assetPath });
|
|
29
|
+
if (!graphR.success)
|
|
30
|
+
return graphR;
|
|
31
|
+
const graph = (graphR.data ?? {});
|
|
32
|
+
const nodes = graph.nodes ?? [];
|
|
33
|
+
const edges = graph.edges ?? [];
|
|
34
|
+
if (!nodes.some(n => n.name === beforeNode)) {
|
|
35
|
+
return { success: false, error: new Error(`node '${beforeNode}' not found in ${assetPath}`) };
|
|
36
|
+
}
|
|
37
|
+
const inbound = edges.filter(e => e.to === beforeNode);
|
|
38
|
+
if (inbound.length === 0) {
|
|
39
|
+
return { success: false, error: new Error(`no edges flow into '${beforeNode}' in ${assetPath} — nothing to gate`) };
|
|
40
|
+
}
|
|
41
|
+
const nodesByName = new Map(nodes.map(n => [n.name, n]));
|
|
42
|
+
const alreadyGated = inbound
|
|
43
|
+
.map(e => nodesByName.get(e.from))
|
|
44
|
+
.find(n => n?.title === WAIT_NODE_TITLE);
|
|
45
|
+
if (alreadyGated) {
|
|
46
|
+
return {
|
|
47
|
+
success: true,
|
|
48
|
+
data: { assetPath, beforeNode, waitNode: alreadyGated.name, inserted: false, rewiredEdges: 0 },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const waitR = await this.call("pcg.add_node", { assetPath, nodeType: WAIT_NODE_TYPE });
|
|
52
|
+
if (!waitR.success)
|
|
53
|
+
return waitR;
|
|
54
|
+
const waitName = waitR.data?.nodeName;
|
|
55
|
+
if (!waitName) {
|
|
56
|
+
return { success: false, error: new Error("pcg.add_node WaitForVoxelWorld returned no nodeName") };
|
|
57
|
+
}
|
|
58
|
+
for (const e of inbound) {
|
|
59
|
+
const dis = await this.call("pcg.disconnect_nodes", {
|
|
60
|
+
assetPath,
|
|
61
|
+
sourceNode: e.from,
|
|
62
|
+
sourcePin: e.fromPin,
|
|
63
|
+
targetNode: e.to,
|
|
64
|
+
targetPin: e.toPin,
|
|
65
|
+
});
|
|
66
|
+
if (!dis.success)
|
|
67
|
+
return dis;
|
|
68
|
+
const c1 = await this.call("pcg.connect_nodes", {
|
|
69
|
+
assetPath,
|
|
70
|
+
sourceNode: e.from,
|
|
71
|
+
sourcePin: e.fromPin,
|
|
72
|
+
targetNode: waitName,
|
|
73
|
+
});
|
|
74
|
+
if (!c1.success)
|
|
75
|
+
return c1;
|
|
76
|
+
const c2 = await this.call("pcg.connect_nodes", {
|
|
77
|
+
assetPath,
|
|
78
|
+
sourceNode: waitName,
|
|
79
|
+
targetNode: beforeNode,
|
|
80
|
+
targetPin: e.toPin,
|
|
81
|
+
});
|
|
82
|
+
if (!c2.success)
|
|
83
|
+
return c2;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
data: { assetPath, beforeNode, waitNode: waitName, inserted: true, rewiredEdges: inbound.length },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=EnsureWaitForWorld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EnsureWaitForWorld.js","sourceRoot":"","sources":["../../src/tasks/EnsureWaitForWorld.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BaseTask, type TaskResult } from "@db-lyon/flowkit";
|
|
2
|
+
interface Options {
|
|
3
|
+
actorLabel: string;
|
|
4
|
+
world?: "editor" | "pie";
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* One-call snapshot of an `AVoxelWorld`'s lifecycle state.
|
|
8
|
+
*
|
|
9
|
+
* Composes 5x `editor.invoke_function` against the zero-arg lifecycle
|
|
10
|
+
* UFUNCTIONs on `AVoxelWorld` (`Voxel/Public/VoxelWorld.h`):
|
|
11
|
+
*
|
|
12
|
+
* bool IsRuntimeCreated()
|
|
13
|
+
* bool IsVoxelWorldReady()
|
|
14
|
+
* bool IsProcessingNewState()
|
|
15
|
+
* float GetProgress()
|
|
16
|
+
* int32 GetNumPendingTasks()
|
|
17
|
+
*
|
|
18
|
+
* Use it before any operation that requires the voxel runtime to be live —
|
|
19
|
+
* scattering meshes / placing stamps into a half-built world produces empty
|
|
20
|
+
* or stale output. The five calls fan out in parallel.
|
|
21
|
+
*/
|
|
22
|
+
export default class GetWorldStatus extends BaseTask<Options> {
|
|
23
|
+
get taskName(): string;
|
|
24
|
+
protected validate(): void;
|
|
25
|
+
execute(): Promise<TaskResult>;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BaseTask } from "@db-lyon/flowkit";
|
|
2
|
+
/**
|
|
3
|
+
* One-call snapshot of an `AVoxelWorld`'s lifecycle state.
|
|
4
|
+
*
|
|
5
|
+
* Composes 5x `editor.invoke_function` against the zero-arg lifecycle
|
|
6
|
+
* UFUNCTIONs on `AVoxelWorld` (`Voxel/Public/VoxelWorld.h`):
|
|
7
|
+
*
|
|
8
|
+
* bool IsRuntimeCreated()
|
|
9
|
+
* bool IsVoxelWorldReady()
|
|
10
|
+
* bool IsProcessingNewState()
|
|
11
|
+
* float GetProgress()
|
|
12
|
+
* int32 GetNumPendingTasks()
|
|
13
|
+
*
|
|
14
|
+
* Use it before any operation that requires the voxel runtime to be live —
|
|
15
|
+
* scattering meshes / placing stamps into a half-built world produces empty
|
|
16
|
+
* or stale output. The five calls fan out in parallel.
|
|
17
|
+
*/
|
|
18
|
+
export default class GetWorldStatus extends BaseTask {
|
|
19
|
+
get taskName() { return "voxel.get_world_status"; }
|
|
20
|
+
validate() {
|
|
21
|
+
if (!this.options.actorLabel)
|
|
22
|
+
throw new Error("actorLabel is required");
|
|
23
|
+
}
|
|
24
|
+
async execute() {
|
|
25
|
+
const { actorLabel, world } = this.options;
|
|
26
|
+
const baseParams = { actorLabel };
|
|
27
|
+
if (world)
|
|
28
|
+
baseParams.world = world;
|
|
29
|
+
const fns = [
|
|
30
|
+
"IsRuntimeCreated",
|
|
31
|
+
"IsVoxelWorldReady",
|
|
32
|
+
"IsProcessingNewState",
|
|
33
|
+
"GetProgress",
|
|
34
|
+
"GetNumPendingTasks",
|
|
35
|
+
];
|
|
36
|
+
const results = await Promise.all(fns.map(functionName => this.call("editor.invoke_function", { ...baseParams, functionName })));
|
|
37
|
+
for (let i = 0; i < results.length; i++) {
|
|
38
|
+
if (!results[i].success)
|
|
39
|
+
return results[i];
|
|
40
|
+
}
|
|
41
|
+
const ret = (r) => r.data?.returnValues?.ReturnValue;
|
|
42
|
+
const asBool = (s) => s === "true" || s === "True";
|
|
43
|
+
const asNum = (s) => (s == null ? NaN : Number(s));
|
|
44
|
+
return {
|
|
45
|
+
success: true,
|
|
46
|
+
data: {
|
|
47
|
+
actorLabel,
|
|
48
|
+
isRuntimeCreated: asBool(ret(results[0])),
|
|
49
|
+
isVoxelWorldReady: asBool(ret(results[1])),
|
|
50
|
+
isProcessingNewState: asBool(ret(results[2])),
|
|
51
|
+
progress: asNum(ret(results[3])),
|
|
52
|
+
numPendingTasks: asNum(ret(results[4])),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=GetWorldStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GetWorldStatus.js","sourceRoot":"","sources":["../../src/tasks/GetWorldStatus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAW7D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,QAAiB;IAC3D,IAAI,QAAQ,KAAa,OAAO,wBAAwB,CAAC,CAAC,CAAC;IAEjD,QAAQ;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAC3C,MAAM,UAAU,GAA4B,EAAE,UAAU,EAAE,CAAC;QAC3D,IAAI,KAAK;YAAE,UAAU,CAAC,KAAK,GAAG,KAAK,CAAC;QAEpC,MAAM,GAAG,GAAG;YACV,kBAAkB;YAClB,mBAAmB;YACnB,sBAAsB;YACtB,aAAa;YACb,oBAAoB;SACZ,CAAC;QAEX,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CACrB,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,EAAE,GAAG,UAAU,EAAE,YAAY,EAAE,CAAC,CACrE,CACF,CAAC;QAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,GAAG,GAAG,CAAC,CAAa,EAAsB,EAAE,CAC/C,CAAC,CAAC,IAA+B,EAAE,YAAY,EAAE,WAAW,CAAC;QAChE,MAAM,MAAM,GAAG,CAAC,CAAqB,EAAW,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,CAAC;QAChF,MAAM,KAAK,GAAG,CAAC,CAAqB,EAAU,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE/E,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ,UAAU;gBACV,gBAAgB,EAAM,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7C,iBAAiB,EAAK,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7C,oBAAoB,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7C,QAAQ,EAAc,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5C,eAAe,EAAO,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;aAC7C;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BaseTask, type TaskResult } from "@db-lyon/flowkit";
|
|
2
|
+
interface Vec3 {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
z: number;
|
|
6
|
+
}
|
|
7
|
+
interface Options {
|
|
8
|
+
label?: string;
|
|
9
|
+
location?: Vec3;
|
|
10
|
+
voxelSize?: number;
|
|
11
|
+
/**
|
|
12
|
+
* Asset path of a UVoxelLayerStack. Defaults to the plugin-bundled
|
|
13
|
+
* `/Voxel/Default/DefaultStack.DefaultStack`. Pass an empty string to
|
|
14
|
+
* leave the property unset (the world will load but render nothing
|
|
15
|
+
* until you assign a stack yourself).
|
|
16
|
+
*/
|
|
17
|
+
layerStack?: string;
|
|
18
|
+
/** Optional UVoxelMegaMaterial asset path. */
|
|
19
|
+
megaMaterial?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Drop an `AVoxelWorld` actor into the active level — the first thing
|
|
23
|
+
* any Voxel-Plugin workflow needs. Wraps `level.place_actor` with the
|
|
24
|
+
* Voxel-Plugin class path, then applies `voxelSize` / `LayerStack` /
|
|
25
|
+
* `MegaMaterial` via `level.set_actor_property` so the resulting actor
|
|
26
|
+
* is renderable out of the box.
|
|
27
|
+
*
|
|
28
|
+
* Header: `Voxel/Public/VoxelWorld.h` (`AVoxelWorld`).
|
|
29
|
+
*
|
|
30
|
+
* Pair with `level.voxel_get_voxel_world_status` to poll the runtime
|
|
31
|
+
* until `isVoxelWorldReady` flips true before scattering / stamping.
|
|
32
|
+
*/
|
|
33
|
+
export default class SpawnWorld extends BaseTask<Options> {
|
|
34
|
+
get taskName(): string;
|
|
35
|
+
execute(): Promise<TaskResult>;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { BaseTask } from "@db-lyon/flowkit";
|
|
2
|
+
const DEFAULT_LAYER_STACK = "/Voxel/Default/DefaultStack.DefaultStack";
|
|
3
|
+
/**
|
|
4
|
+
* Drop an `AVoxelWorld` actor into the active level — the first thing
|
|
5
|
+
* any Voxel-Plugin workflow needs. Wraps `level.place_actor` with the
|
|
6
|
+
* Voxel-Plugin class path, then applies `voxelSize` / `LayerStack` /
|
|
7
|
+
* `MegaMaterial` via `level.set_actor_property` so the resulting actor
|
|
8
|
+
* is renderable out of the box.
|
|
9
|
+
*
|
|
10
|
+
* Header: `Voxel/Public/VoxelWorld.h` (`AVoxelWorld`).
|
|
11
|
+
*
|
|
12
|
+
* Pair with `level.voxel_get_voxel_world_status` to poll the runtime
|
|
13
|
+
* until `isVoxelWorldReady` flips true before scattering / stamping.
|
|
14
|
+
*/
|
|
15
|
+
export default class SpawnWorld extends BaseTask {
|
|
16
|
+
get taskName() { return "voxel.spawn_world"; }
|
|
17
|
+
async execute() {
|
|
18
|
+
const { label, location, voxelSize, layerStack, megaMaterial } = this.options;
|
|
19
|
+
const placeParams = {
|
|
20
|
+
actorClass: "/Script/Voxel.VoxelWorld",
|
|
21
|
+
};
|
|
22
|
+
if (label)
|
|
23
|
+
placeParams.label = label;
|
|
24
|
+
if (location)
|
|
25
|
+
placeParams.location = location;
|
|
26
|
+
const placed = await this.call("level.place_actor", placeParams);
|
|
27
|
+
if (!placed.success)
|
|
28
|
+
return placed;
|
|
29
|
+
const actorLabel = placed.data?.actorLabel
|
|
30
|
+
?? placed.data?.label
|
|
31
|
+
?? label;
|
|
32
|
+
if (!actorLabel) {
|
|
33
|
+
return { success: false, error: new Error("level.place_actor did not return an actorLabel") };
|
|
34
|
+
}
|
|
35
|
+
const applied = {};
|
|
36
|
+
// Default the LayerStack so a bare AVoxelWorld actually renders.
|
|
37
|
+
// Explicit empty string opts out.
|
|
38
|
+
const resolvedLayerStack = layerStack === "" ? undefined
|
|
39
|
+
: (layerStack ?? DEFAULT_LAYER_STACK);
|
|
40
|
+
const setProp = async (propertyName, value) => {
|
|
41
|
+
const r = await this.call("level.set_actor_property", { actorLabel, propertyName, value });
|
|
42
|
+
if (!r.success)
|
|
43
|
+
return r;
|
|
44
|
+
applied[propertyName] = value;
|
|
45
|
+
return r;
|
|
46
|
+
};
|
|
47
|
+
if (typeof voxelSize === "number") {
|
|
48
|
+
const r = await setProp("VoxelSize", voxelSize);
|
|
49
|
+
if (!r.success)
|
|
50
|
+
return r;
|
|
51
|
+
}
|
|
52
|
+
if (resolvedLayerStack) {
|
|
53
|
+
const r = await setProp("LayerStack", resolvedLayerStack);
|
|
54
|
+
if (!r.success)
|
|
55
|
+
return r;
|
|
56
|
+
}
|
|
57
|
+
if (megaMaterial) {
|
|
58
|
+
const r = await setProp("MegaMaterial", megaMaterial);
|
|
59
|
+
if (!r.success)
|
|
60
|
+
return r;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
success: true,
|
|
64
|
+
data: {
|
|
65
|
+
actorLabel,
|
|
66
|
+
actorClass: "/Script/Voxel.VoxelWorld",
|
|
67
|
+
applied,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=SpawnWorld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnWorld.js","sourceRoot":"","sources":["../../src/tasks/SpawnWorld.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAmB7D,MAAM,mBAAmB,GAAG,0CAA0C,CAAC;AAEvE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,QAAiB;IACvD,IAAI,QAAQ,KAAa,OAAO,mBAAmB,CAAC,CAAC,CAAC;IAEtD,KAAK,CAAC,OAAO;QACX,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAE9E,MAAM,WAAW,GAA4B;YAC3C,UAAU,EAAE,0BAA0B;SACvC,CAAC;QACF,IAAI,KAAK;YAAE,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC;QACrC,IAAI,QAAQ;YAAE,WAAW,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAE9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;QACjE,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC;QAEnC,MAAM,UAAU,GAAI,MAAM,CAAC,IAA4D,EAAE,UAAU;eAC/E,MAAM,CAAC,IAAuC,EAAE,KAAK;eACtD,KAAK,CAAC;QACzB,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,gDAAgD,CAAC,EAAE,CAAC;QAChG,CAAC;QAED,MAAM,OAAO,GAA4B,EAAE,CAAC;QAE5C,iEAAiE;QACjE,kCAAkC;QAClC,MAAM,kBAAkB,GAAG,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS;YAC/B,CAAC,CAAC,CAAC,UAAU,IAAI,mBAAmB,CAAC,CAAC;QAE/D,MAAM,OAAO,GAAG,KAAK,EAAE,YAAoB,EAAE,KAAc,EAAE,EAAE;YAC7D,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3F,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC;YACzB,OAAO,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC;YAC9B,OAAO,CAAC,CAAC;QACX,CAAC,CAAC;QAEF,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YAChD,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,kBAAkB,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;YAC1D,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;YACtD,IAAI,CAAC,CAAC,CAAC,OAAO;gBAAE,OAAO,CAAC,CAAC;QAC3B,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ,UAAU;gBACV,UAAU,EAAE,0BAA0B;gBACtC,OAAO;aACR;SACF,CAAC;IACJ,CAAC;CACF"}
|
package/docs/Modules.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Voxel Plugin — Module Map
|
|
2
|
+
|
|
3
|
+
The plugin ships **twelve modules** plus a UHT (UnrealHeaderTool) extension. Every module funnels through a single `VoxelGlobalMethods.SetupVoxelModule` shim defined in `VoxelCore/VoxelCore.Build.cs`, which standardizes C++20, IWYU=None, unity builds, the shared PCH (`VoxelPCH.h` for runtime, `VoxelCoreEditorPCH.h` for editor), and `FPSemanticsMode.Precise` (so PCG point output is identical on client and server).
|
|
4
|
+
|
|
5
|
+
## Module list
|
|
6
|
+
|
|
7
|
+
| Module | Type | Loading phase | Public headers? | Role |
|
|
8
|
+
|---|---|---|---|---|
|
|
9
|
+
| `VoxelCore` | Runtime | `PostConfigInit` | yes | Foundational containers, math, threading, messaging, ISPC bridge, dependency tracking. No voxel concepts. |
|
|
10
|
+
| `VoxelCoreEditor` | Editor | `Default` | yes | Slate widgets, detail customizations, asset wizards used by every other editor module. |
|
|
11
|
+
| `VoxelGraph` | Runtime | `Default` | yes | Visual-graph asset, compilation pipeline, typed buffers, function-library nodes. |
|
|
12
|
+
| `VoxelGraphEditor` | Editor | `Default` | yes | Graph editor UI, node panels, preview viewport, message log. |
|
|
13
|
+
| `Voxel` | Runtime | `PostConfigInit` | yes | The gameplay-facing module: `AVoxelWorld`, stamps, layers, mega-material, render/collision/navigation, sculpt/spline/shape/scatter. |
|
|
14
|
+
| `VoxelEditor` | Editor | `Default` | yes | World/stamp/layer detail panels, interactive sculpt tools, placement mode integration. |
|
|
15
|
+
| `VoxelBlueprint` | UncookedOnly | `PostConfigInit` | yes | Kismet (BP) K2 nodes that expose voxel-graph parameters and the make/break pin-value flow. Editor-time only. |
|
|
16
|
+
| `VoxelBlueprintEditor` | Editor | `Default` | no (private only) | Slate pieces specific to the BP K2 nodes. |
|
|
17
|
+
| `VoxelPCG` | Runtime | `Default` | yes | Bridge to Epic's PCG framework. PCG nodes that read/write voxel state plus voxel-graph nodes that operate on point sets. |
|
|
18
|
+
| `VoxelPCGEditor` | Editor | `Default` | no (private only) | PCG node UI/customizations. |
|
|
19
|
+
| `VoxelTests` | Runtime | `Default` | no | Automation tests; include-correctness checks when `VoxelDevWorkflow.txt` is present. |
|
|
20
|
+
| `VoxelUHT` | UBT plugin | n/a | n/a | Custom UnrealHeaderTool exporter (`*.generated.voxel.cpp`) that codegens function-library wrappers around `UVoxelFunctionLibrary` and `FVoxelRuntimePinValue`. |
|
|
21
|
+
|
|
22
|
+
`UncookedOnly` means `VoxelBlueprint` is built into editor/uncooked targets only — it ships nothing in packaged builds, because BP K2 node classes only exist to extend the Kismet compiler.
|
|
23
|
+
|
|
24
|
+
## Loading phases
|
|
25
|
+
|
|
26
|
+
Two modules load at `PostConfigInit` (very early, before most engine systems):
|
|
27
|
+
|
|
28
|
+
- `VoxelCore` — needed early so `FVoxelMessageManager`, the `FVoxelDeveloperSettings` CDO, and the ISPC runtime are available before subsystems initialize.
|
|
29
|
+
- `Voxel` — needs early load so `AVoxelWorld` subsystems can register themselves before the world begins streaming.
|
|
30
|
+
|
|
31
|
+
`VoxelBlueprint` also loads `PostConfigInit` (but as `UncookedOnly`) so its K2 node factories are registered before the Blueprint editor opens any assets.
|
|
32
|
+
|
|
33
|
+
Everything else loads at the `Default` phase.
|
|
34
|
+
|
|
35
|
+
## Dependency graph
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
VoxelCore ←─────────────────────────┐
|
|
39
|
+
▲ │
|
|
40
|
+
┌───────────────┼───────────────┐ │
|
|
41
|
+
│ │ │ │
|
|
42
|
+
VoxelGraph Voxel VoxelPCG ───→ Voxel + VoxelGraph
|
|
43
|
+
▲ ▲ ▲ │
|
|
44
|
+
│ │ │ │
|
|
45
|
+
│ │ │ │
|
|
46
|
+
VoxelGraphEditor VoxelEditor VoxelPCGEditor │
|
|
47
|
+
▲ │
|
|
48
|
+
│ │
|
|
49
|
+
VoxelBlueprint ──→ Voxel + VoxelGraph + VoxelEditor + VoxelGraphEditor + VoxelCoreEditor
|
|
50
|
+
▲
|
|
51
|
+
│
|
|
52
|
+
VoxelBlueprintEditor
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
(Arrow direction: A → B means A depends on B.)
|
|
56
|
+
|
|
57
|
+
Concrete declarations from the `*.Build.cs` files:
|
|
58
|
+
|
|
59
|
+
- `VoxelCore` adds engine deps `Chaos`, `Renderer`, `Projects`, `ApplicationCore`, `TraceLog`. Private deps include `zlib`, `UElibPNG`, `Json`, `HTTP`, `Landscape`, `EventLoop`, `MoviePlayer`. Editor builds pull in `MaterialEditor`, `UATHelper`, `GraphEditor`, `DesktopPlatform`.
|
|
60
|
+
- `Voxel` depends on `VoxelGraph`, plus `Chaos`, `Renderer`, `PhysicsCore`, `Landscape`, `NavigationSystem`, `PCG`, `MeshDescription`, `StaticMeshDescription`.
|
|
61
|
+
- `VoxelGraph` depends only on the standard set plus `TraceLog`, `Chaos`, `PhysicsCore`, `Json` (and `MessageLog` in editor).
|
|
62
|
+
- `VoxelPCG` depends on `Voxel`, `VoxelGraph`, `PCG`.
|
|
63
|
+
- `VoxelBlueprint` depends on `VoxelCoreEditor`, `Voxel`, `VoxelEditor`, `VoxelGraph`, `VoxelGraphEditor`, plus `BlueprintGraph` and `KismetCompiler` for K2 node integration.
|
|
64
|
+
- `VoxelEditor` is the heaviest editor module — it depends on `Voxel`, `VoxelPCG`, `VoxelGraph`, `VoxelGraphEditor`, plus the full editor surface (`LevelEditor`, `AssetTools`, `PlacementMode`, `InteractiveToolsFramework`, `SceneOutliner`, `DetailCustomizations`, etc.).
|
|
65
|
+
- `VoxelTests` depends only on `Json` and `NavigationSystem`.
|
|
66
|
+
|
|
67
|
+
## ISPC and the build script
|
|
68
|
+
|
|
69
|
+
`VoxelCore.Build.cs` defines `VoxelISPCCompiler`, which scans every module's `Source/<Module>/**.ispc` and `**.isph` files and generates a per-platform build script (`Intermediate/ISPC/<Platform>/<Arch>/<Editor>/<Config>/Build.ps1` or `Build.sh`). On Windows it downloads the same ISPC binary Unreal uses (`UnrealEngine-28863921/...`) if the engine copy is missing. ISPC is built into per-module static libraries (`libVoxel.a`, `libVoxelCore.a`, etc.) linked via `PublicAdditionalLibraries`.
|
|
70
|
+
|
|
71
|
+
The cross-platform target matrix is hard-coded to:
|
|
72
|
+
|
|
73
|
+
- `Win64` / `Linux` / `Mac (x64)` / `Android (x64)`: `avx512skx-i32x8`, `avx2`, `avx`, `sse4`
|
|
74
|
+
- `LinuxArm64` / `Mac (arm64)` / `Android (arm64)` / `iOS` / `VisionOS`: `neon`
|
|
75
|
+
|
|
76
|
+
## Build toggles
|
|
77
|
+
|
|
78
|
+
Two opt-in flags live as marker files in the plugin's parent `Plugins/` directory:
|
|
79
|
+
|
|
80
|
+
- `VoxelDevWorkflow.txt` — disables unity builds for `Win64` and `Mac` and switches off forced code optimization so iteration with a debugger is bearable. Also installs the IDE-friendly include-path that lets ReSharper/Rider see ISPC generated headers.
|
|
81
|
+
- `VoxelDebug.txt` — forces the `VOXEL_DEBUG=1` define regardless of build configuration. Equivalently, building `Debug` (or `DebugGame` with dev workflow on) flips this on automatically.
|
|
82
|
+
|
|
83
|
+
There's also `CheckPackaging.txt`: if present, all optimization is disabled (build-only sanity pass).
|
|
84
|
+
|
|
85
|
+
## UHT extension
|
|
86
|
+
|
|
87
|
+
`VoxelUHT/Program.cs` defines a single `[UhtExporter]` named `"VoxelGraph"` that:
|
|
88
|
+
|
|
89
|
+
1. Locates `UVoxelFunctionLibrary` and `FVoxelRuntimePinValue` in the parsed metadata.
|
|
90
|
+
2. Walks every header in the `VoxelGraph` module.
|
|
91
|
+
3. For every class deriving from `UVoxelFunctionLibrary`, emits a `*.generated.voxel.cpp` file with the C++ glue that turns `UFUNCTION`-tagged static methods into compute-graph nodes.
|
|
92
|
+
|
|
93
|
+
This is why writing a new voxel-graph function library node only requires a `UFUNCTION` declaration — the boilerplate that wires it into the graph system is generated by this UHT plugin at build time.
|
|
94
|
+
|
|
95
|
+
## What's in each module's `Public/`
|
|
96
|
+
|
|
97
|
+
| Module | Subfolders under `Public/` |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `VoxelCore` | `VoxelMinimal/`, `VoxelMinimal/Containers/`, `VoxelMinimal/Utilities/`, root |
|
|
100
|
+
| `Voxel` | `Collision/`, `Graphs/`, `Heightmap/`, `MegaMaterial/`, `Nanite/`, `Navigation/`, `Render/`, `Scatter/`, `Sculpt/`, `Shape/`, `Spline/`, `StaticMesh/`, `Surface/`, `Texture/`, root |
|
|
101
|
+
| `VoxelGraph` | `Buffer/`, `FunctionLibrary/`, `Nodes/`, `Preview/`, `Utilities/`, root |
|
|
102
|
+
| `VoxelPCG` | flat (no subfolders) |
|
|
103
|
+
| `VoxelBlueprint` | flat (five K2 node headers) |
|
|
104
|
+
| `VoxelCoreEditor`, `VoxelEditor`, `VoxelGraphEditor` | each has a `Public/`, but most concrete UI lives in `Private/` |
|
|
105
|
+
| `VoxelBlueprintEditor`, `VoxelPCGEditor`, `VoxelTests` | private-only, no `Public/` |
|
|
106
|
+
|
|
107
|
+
For per-module API detail see [VoxelCore](VoxelCore.md), [Voxel](Voxel.md), [VoxelGraph](VoxelGraph.md), [VoxelPCG](VoxelPCG.md), [VoxelBlueprint](VoxelBlueprint.md).
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Voxel Plugin — Reference Docs
|
|
2
|
+
|
|
3
|
+
Reference docs for the [Voxel Plugin](https://voxelplugin.com) (Phyronnaz) — module map, public C++ surface per module, how the pieces fit together. They live in this repo because this is the ue-mcp wrapper for the Voxel Plugin, and the same reference material that helps wrapper-action authors also helps anyone building against the plugin from C++ or Blueprint.
|
|
4
|
+
|
|
5
|
+
These docs are **API-level reference** — what's in each module, what the public types do, how the pieces relate. They complement, not replace, the official knowledgebase at <https://docs.voxelplugin.com/knowledgebase>, which covers task-oriented "how do I do X" workflows.
|
|
6
|
+
|
|
7
|
+
## When to read what
|
|
8
|
+
|
|
9
|
+
| You want… | Go here |
|
|
10
|
+
|---|---|
|
|
11
|
+
| "How do I author a stamp / use the graph editor / set up PCG?" | [Official KB](https://docs.voxelplugin.com/knowledgebase) — those pages exist and are decent. |
|
|
12
|
+
| "What modules does this plugin actually ship, and how do they depend on each other?" | [Modules.md](Modules.md) |
|
|
13
|
+
| "What's in the foundation module — containers, math, threading, ISPC?" | [VoxelCore.md](VoxelCore.md) |
|
|
14
|
+
| "What's `AVoxelWorld`? What are stamps, layers, the runtime, sampling?" | [Voxel.md](Voxel.md) |
|
|
15
|
+
| "How does the graph compile pipeline work? What's a buffer? What nodes ship?" | [VoxelGraph.md](VoxelGraph.md) |
|
|
16
|
+
| "How do PCG and Voxel talk to each other?" | [VoxelPCG.md](VoxelPCG.md) |
|
|
17
|
+
| "What K2 nodes does the plugin add to Blueprint?" | [VoxelBlueprint.md](VoxelBlueprint.md) |
|
|
18
|
+
| "Is the test suite worth borrowing patterns from?" | [Tests.md](Tests.md) |
|
|
19
|
+
|
|
20
|
+
## Doc scope
|
|
21
|
+
|
|
22
|
+
These docs cover the **runtime + Blueprint** public API. Editor modules (`VoxelCoreEditor`, `VoxelEditor`, `VoxelGraphEditor`, `VoxelBlueprintEditor`, `VoxelPCGEditor`) are mentioned in [Modules.md](Modules.md) but not given their own reference pages — most of their public surface is detail customizations and Slate widgets that aren't useful to call from game code.
|
|
23
|
+
|
|
24
|
+
The plugin's `Tests/` content and `VoxelTests` module are covered as a *pattern-mining* exercise in [Tests.md](Tests.md), not as exhaustive reference.
|
|
25
|
+
|
|
26
|
+
## Conventions
|
|
27
|
+
|
|
28
|
+
- File paths are written relative to the plugin source root (`Plugins/Voxel/Source/...`) unless they're inside a code block.
|
|
29
|
+
- C++ type names use their actual prefixes (`F`, `U`, `A`, `T`, `S`, `I`) — `AVoxelWorld`, `UVoxelGraph`, `FVoxelBox`, `TVoxelArray<T>`.
|
|
30
|
+
- Where the official KB has a corresponding page, the module doc links out to it.
|
|
31
|
+
- Cross-doc links between these pages use relative paths so they work on disk and on a wiki host.
|
|
32
|
+
|
|
33
|
+
## Plugin metadata
|
|
34
|
+
|
|
35
|
+
- Source: <https://voxelplugin.com>
|
|
36
|
+
- Docs (official, task-focused): <https://docs.voxelplugin.com/knowledgebase>
|
|
37
|
+
- Discord (support): <https://discord.voxelplugin.com>
|
|
38
|
+
- License: see `Plugins/Voxel/LICENSES.txt` in the plugin itself. Note in particular the Transvoxel attribution requirement called out in [VoxelCore.md](VoxelCore.md#transvoxel-data).
|
|
39
|
+
- Loaded by default (`EnabledByDefault: true` in `Voxel.uplugin`).
|
|
40
|
+
|
|
41
|
+
## Doc maintenance
|
|
42
|
+
|
|
43
|
+
When the upstream plugin is bumped to a new version, this is what to refresh:
|
|
44
|
+
|
|
45
|
+
1. [Modules.md](Modules.md) — re-read every `*.Build.cs`; phases and module-name changes happen at major version bumps.
|
|
46
|
+
2. Per-module docs — `Glob` `Public/**/*.h` and reconcile against the listings here. New top-level types deserve a row; deleted ones should be removed.
|
|
47
|
+
3. [Tests.md](Tests.md) — re-run the include-test count and check `VoxelTests.Build.cs` for new infrastructure files.
|