ue-mcp-plugin-voxel-plugin 0.2.0 → 0.3.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 CHANGED
@@ -4,13 +4,14 @@
4
4
 
5
5
  ## What ships
6
6
 
7
- One injected action in v0.2.0, cited to its source:
7
+ Each action is cited to the C++ header it wraps. Full API reference under [`docs/`](docs/).
8
8
 
9
- | Category | Action | Wraps |
10
- |----------|------------------------------|-------|
11
- | `pcg` | `voxel_build_scatter_graph` | `UPCGVoxelSamplerSettings` (`VoxelPCG/Public/PCGVoxelSampler.h`) feeding `UPCGStaticMeshSpawnerSettings` |
9
+ | Category | Action | Wraps |
10
+ |----------|---------------------------------|-------|
11
+ | `pcg` | `voxel_build_scatter_graph` | `UPCGVoxelSamplerSettings` (`VoxelPCG/Public/PCGVoxelSampler.h`) feeding `UPCGStaticMeshSpawnerSettings` |
12
+ | `level` | `voxel_get_voxel_world_status` | 5 zero-arg lifecycle UFUNCTIONs on `AVoxelWorld` (`Voxel/Public/VoxelWorld.h`) |
12
13
 
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.
14
+ 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
15
 
15
16
  ## Install
16
17
 
@@ -39,6 +40,14 @@ The call creates a `UPCGGraph` at `assetPath`, adds a Voxel Sampler → Static M
39
40
  pcg(action="execute", actorLabel="MyPCGActor")
40
41
  ```
41
42
 
43
+ Check the voxel world is actually live before scattering / stamping into it:
44
+
45
+ ```text
46
+ level(action="voxel_get_voxel_world_status", actorLabel="MyVoxelWorld")
47
+ ```
48
+
49
+ Returns `{ isRuntimeCreated, isVoxelWorldReady, isProcessingNewState, progress, numPendingTasks }`. The runtime can be mid-regeneration even after `IsRuntimeCreated` flips true — wait for `isVoxelWorldReady && !isProcessingNewState` before pipelines that depend on stable terrain.
50
+
42
51
  ## Requirements
43
52
 
44
53
  - ue-mcp `>= 1.0.15`
@@ -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,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.
package/docs/Tests.md ADDED
@@ -0,0 +1,280 @@
1
+ # VoxelTests — What's in It, What It's Worth Borrowing
2
+
3
+ > Audience: a senior UE5 engineer evaluating whether the plugin's testing approach is worth borrowing for their own project.
4
+
5
+ ## Overview
6
+
7
+ Phyronnaz's `VoxelTests` module is split into two surfaces:
8
+
9
+ - a **content-driven integration layer** — 23 test maps and 127 supporting assets under `Plugins/Voxel/Tests/`
10
+ - a **header include-safety harness** — 96 source files under `Plugins/Voxel/Source/VoxelTests/Private/`
11
+
12
+ The framework is lightweight and **eschews UE Automation** (`IMPLEMENT_SIMPLE_AUTOMATION_TEST`) entirely. Instead, it implements a custom **Blueprint-callable test harness** that loads maps in sequence, tracks pass/fail state, captures screenshots, and emits a JSON report suitable for CI. A separate startup hook auto-generates one `.cpp` per public header to verify every header compiles in isolation.
13
+
14
+ ## Layout
15
+
16
+ ### `Plugins/Voxel/Tests/` — content integration tests
17
+
18
+ - 23 `.umap` test maps covering gameplay, rendering, stamping, navigation
19
+ - 127 supporting assets (materials, graphs, meshes)
20
+ - Total: 150 files
21
+ - Folders: `Assets/`, `BasicGameplay/`, `BasicSplines/`, `CurveNode/`, `DistanceFields/`, `GradientTest/`, `Lumen/`, `MaterialRendering/{CurveMaterial,Gravel,MuddyLeaves}/`, `Metadata/`, `MetadataQueries/`, `Navigation/`, `OverrideGraphs/`, `PCGWorld/`, `Queries/`, `RVT/`, `Sculpting/`, `SmoothBlendsAndSmartSurfaces/`, `TangentNormals/`, `Velocity/`, `WPO/`
22
+
23
+ ### `Plugins/Voxel/Source/VoxelTests/` — native infrastructure
24
+
25
+ - 96 source files (90 `.cpp` + 6 headers)
26
+ - 85 auto-generated include-test stubs in `VoxelCoreIncludeTest/` — one `.cpp` per `VoxelMinimal/` header
27
+ - 6 manual infrastructure files:
28
+ - `VoxelTestsModule.cpp` — module entry, CLI flag handling (`-VoxelTests`, `-RunVoxelTests`)
29
+ - `VoxelTestManager.h/.cpp` — singleton: map sequencing, JSON serialization
30
+ - `VoxelTestLibrary.h/.cpp` — Blueprint-exposed test API
31
+ - `VoxelTestPCH.h` — lightweight include guard for `VoxelCoreMinimal.h`
32
+ - `VoxelCoreIncludeTestGenerator.cpp` — startup hook that creates the stubs
33
+
34
+ The `Build.cs` is intentionally tiny:
35
+
36
+ ```csharp
37
+ public VoxelTests(ReadOnlyTargetRules Target) : base(Target)
38
+ {
39
+ if (new VoxelConfig(this).DevWorkflow)
40
+ {
41
+ // Needed by include testing
42
+ PrivatePCHHeaderFile = "Private/VoxelTestPCH.h";
43
+ }
44
+
45
+ PublicDependencyModuleNames.AddRange(new string[] { "Json" });
46
+ PrivateDependencyModuleNames.AddRange(new string[] { "NavigationSystem" });
47
+ }
48
+ ```
49
+
50
+ ## Framework
51
+
52
+ ### Custom Blueprint-driven, not UE Automation
53
+
54
+ There are **no `IMPLEMENT_SIMPLE_AUTOMATION_TEST` macros**. Instead:
55
+
56
+ 1. **Blueprint layer:** call `UVoxelTestLibrary::StartTest(Name)` → returns `FVoxelTestHandle`.
57
+ 2. **State machine:** each test transitions `Started → Succeeded | Failed`.
58
+ 3. **Manager orchestration** (`FVoxelTestManager` singleton):
59
+ - Sequentially loads test maps from `/Game/VoxelTests/`.
60
+ - Collects pass/fail results, warnings, errors, screenshot GUIDs.
61
+ - Writes JSON to `Saved/VoxelTests/VoxelTests.json`.
62
+ - Captures high-res screenshots on demand.
63
+
64
+ Activation: console command `voxel.tests.Start` or CLI flag `-RunVoxelTests` (non-editor mode only).
65
+
66
+ ### Naming
67
+
68
+ | Surface | Convention |
69
+ |---|---|
70
+ | Test maps | `TEST_<Feature>.umap` (`TEST_BasicGameplay.umap`, `TEST_Gradient.umap`) |
71
+ | Assets | `TEST_<Type>_<Name>.uasset` (`TEST_VHG_Gradient.uasset`, `TEST_MI_Gravel_Red.uasset`) |
72
+ | Include-test stubs | `VoxelCoreIncludeTest_<Category>_<HeaderName>.cpp` |
73
+
74
+ ### Custom assertion macros: none
75
+
76
+ No `VOXEL_TEST_*` macros. The Blueprint-callable surface is the API:
77
+
78
+ ```cpp
79
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
80
+ static FVoxelTestHandle StartTest(const FString& Name);
81
+
82
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
83
+ static void PassTest(const FVoxelTestHandle& Handle);
84
+
85
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
86
+ static void FailTest(const FVoxelTestHandle& Handle, const FString& Reason);
87
+
88
+ UFUNCTION(BlueprintCallable, Category = "Voxel|Tests")
89
+ static void TakeScreenshot(const FGuid& Guid);
90
+ ```
91
+
92
+ Tests call these from Blueprint event graphs (typically on a timer or completion callback). Standard `check()` / `ensure()` are intercepted by `FVoxelTestsOutputDevice` for logging.
93
+
94
+ ### No BDD / spec layer
95
+
96
+ Purely imperative, map-and-actor-driven: an actor in the map handles setup/teardown on `BeginPlay`, the BP graph waits for a completion condition, then calls `FailTest` or `PassTest`.
97
+
98
+ ## Fixture and runtime setup
99
+
100
+ ### Minimal `VoxelRuntime` bootstrapping
101
+
102
+ Tests do **not** spawn an in-memory `AVoxelWorld` CDO. Instead:
103
+
104
+ 1. **Editor-mounted content:** the module registers `Plugins/Voxel/Tests/` as a game path at startup:
105
+ ```cpp
106
+ FPackageName::RegisterMountPoint("/Game/VoxelTests/", DiskPath);
107
+ ```
108
+ 2. **Per-map setup:** each test map ships a custom test actor (e.g. `TEST_BasicGameplayActor.uasset`) that:
109
+ - executes on `BeginPlay`,
110
+ - configures nav generation (`SetNavMeshGeneration(bRuntime)`),
111
+ - spawns the runtime objects under test (VoxelWorld refs, stamps, AI pawns),
112
+ - calls `StartTest` and monitors for completion.
113
+ 3. **World lifespan:** entire map persists for the test; teardown destroys all actors after reporting.
114
+
115
+ ### Asset loading
116
+
117
+ - No transient CDOs — all test assets are pre-authored, disk-resident under `Plugins/Voxel/Tests/Assets/`.
118
+ - Graphs are pre-built `UVoxelHeightGraph` / `UVoxelVolumeGraph` `.uasset`s.
119
+ - Meshes & materials are standard UE5 content.
120
+
121
+ ### No explicit mocking
122
+
123
+ - GPU / render targets: used as-is.
124
+ - Navigation: gated via `SetNavMeshGeneration(bool bRuntime)` which flips `ERuntimeGenerationType` and triggers a rebuild.
125
+ - Threading / task graph: no abstraction; tests run synchronously or wait on async callbacks.
126
+
127
+ ## Coverage map
128
+
129
+ ### What's tested
130
+
131
+ | Area | Maps | Notes |
132
+ |---|---|---|
133
+ | Graph evaluation | `GradientTest`, `CurveNode` | Height/volume graph outputs, curve sampling. |
134
+ | Stamping & blending | `PCGWorld`, `OverrideGraphs`, `SmoothBlendsAndSmartSurfaces` | Procedural stamp application, blend-mode overrides. |
135
+ | Voxel rendering | `MaterialRendering/*`, `Lumen`, `Metadata` | Material slots, translucency, emissive, per-voxel metadata. |
136
+ | Serialization & I/O | `DistanceFields` | Distance-field bake + round-trip. |
137
+ | Gameplay integration | `BasicGameplay`, `Navigation` | Voxel-aware AI, character movement, navmesh. |
138
+ | Advanced rendering | `TangentNormals`, `WPO`, `RVT`, `Velocity` | Tangent normals, world-position offset, runtime VT, motion vectors. |
139
+ | Splines | `BasicSplines` | Spline-driven voxel deformation. |
140
+
141
+ ### What's NOT tested
142
+
143
+ - Editor UI (menus, property panels).
144
+ - Networking / replication / multiplayer integration.
145
+ - Cross-module plugin build sanity beyond compile.
146
+ - Performance — maps exist but no automated perf gates; manual profiling only.
147
+
148
+ Maps are **functional full-stack integration tests**: spawn a VoxelWorld (or load a pre-baked one), run a gameplay loop, assert the final state from Blueprint. No unit tests for individual containers or utilities — those are guarded by the include-testing layer below.
149
+
150
+ ## Include self-containment checks
151
+
152
+ **File:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelCoreIncludeTestGenerator.cpp`
153
+
154
+ On startup (when `VOXEL_DEV_WORKFLOW && VOXEL_DEBUG`) the module:
155
+
156
+ 1. Scans `VoxelCore/Public/VoxelMinimal/` for every `.h`.
157
+ 2. Generates one `.cpp` stub per header, including it in isolation:
158
+ ```cpp
159
+ // Example: VoxelCoreIncludeTest_Containers_VoxelArray.cpp
160
+ #include "VoxelCoreMinimal.h"
161
+ #if VOXEL_DEV_WORKFLOW && VOXEL_DEBUG
162
+ #include "VoxelMinimal/Containers/VoxelArray.h" // the real include
163
+ #endif
164
+ ```
165
+ 3. Forces the PCH to `VoxelTestPCH.h` only when dev-workflow is on, so the linker compiles all 85+ stubs.
166
+ 4. Any header that fails standalone (missing transitive include, circular dep) breaks the build.
167
+
168
+ Why it matters: this catches the classic "works in unity build, fails in incremental compile" failure mode without anyone writing a manual test. Header hygiene is enforced by the build, not by code review.
169
+
170
+ ## Honest assessment
171
+
172
+ ### Strengths
173
+
174
+ 1. **Include-testing discipline is best-in-class.** The auto-generated stub generator is the standout pattern.
175
+ 2. **Lightweight infrastructure** — no Catch2, no GoogleTest, no UE Automation boilerplate.
176
+ 3. **Blueprint-testable gameplay** — designers can write integration tests in maps + event graphs.
177
+ 4. **JSON output for CI** — pipeline-friendly result format.
178
+ 5. **Built-in screenshot capture** — visual regression hook is in place even if not fully automated.
179
+
180
+ ### Weaknesses
181
+
182
+ 1. **Sparse unit-test coverage.** 91 `VoxelMinimal/` headers but only compile-validation, not runtime assertions on container ops.
183
+ 2. **No spec / BDD language.** Test intent is implicit in map names.
184
+ 3. **Content-heavy and fragile.** 23 maps × dozens of assets is a big footprint and renames silently break tests.
185
+ 4. **Limited documentation.** No README per map explaining what it validates.
186
+ 5. **Sequential map loading.** No parallelization for CI time savings.
187
+ 6. **Manual failure diagnosis.** Errors go to log + JSON; reading logs is required to debug.
188
+
189
+ ### Verdict
190
+
191
+ Solid but narrowly-focused. The include-testing pattern is excellent and worth lifting wholesale. The content-map integration layer is a workable smoke-test layer but not a template for comprehensive TDD.
192
+
193
+ ## Patterns worth borrowing
194
+
195
+ ### 1. Auto-generated header compliance tests
196
+
197
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelCoreIncludeTestGenerator.cpp`
198
+
199
+ A startup hook that scans a module's `Public/` tree, generates one `.cpp` per `.h` including it standalone, and gates the PCH so the linker compiles them all. Catches transitive-include bugs and missing forward decls without writing manual tests.
200
+
201
+ Wire it up by gating a dedicated test PCH on a dev flag:
202
+
203
+ ```csharp
204
+ if (bIsDevBuild)
205
+ {
206
+ PrivatePCHHeaderFile = "Private/YourModuleTestPCH.h";
207
+ }
208
+ ```
209
+
210
+ ### 2. Blueprint-callable test harness
211
+
212
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestLibrary.h`
213
+
214
+ Expose `StartTest(Name)`, `PassTest(Handle)`, `FailTest(Handle, Reason)` as `UFUNCTION(BlueprintCallable)`. Pairs naturally with map-driven testing — designers can author tests without touching C++.
215
+
216
+ Add gameplay-specific assertion helpers alongside:
217
+
218
+ ```cpp
219
+ UCLASS()
220
+ class YOURMODULE_API UYourTestLibrary : public UBlueprintFunctionLibrary
221
+ {
222
+ public:
223
+ UFUNCTION(BlueprintCallable, Category = "YourModule|Tests")
224
+ static void AssertActorCount(const FString& TestName, int32 Expected, int32 Actual);
225
+
226
+ UFUNCTION(BlueprintCallable, Category = "YourModule|Tests")
227
+ static void AssertFloatAlmostEqual(const FString& TestName, float Expected, float Actual, float Tolerance = 0.01f);
228
+ };
229
+ ```
230
+
231
+ ### 3. Automated screenshot capture for visual regression
232
+
233
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestLibrary.cpp` (~lines 81–113)
234
+
235
+ `TakeScreenshot(FGuid)` wraps `HighResShot` and saves to `Saved/VoxelTests/<MapName>/<Guid>.png`. Adding hash- or perceptual-diff comparison turns it into a real visual baseline system.
236
+
237
+ ### 4. Custom `FOutputDevice` for warning / error tracking
238
+
239
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestManager.cpp` (~lines 22–100, `FVoxelTestsOutputDevice`)
240
+
241
+ Subclass `FOutputDevice`, register with `GLog`, intercept warnings/errors with stack traces, serialize to JSON. Detects silent failures — `ensure()` firing without an explicit `FailTest`.
242
+
243
+ ### 5. Explicit test state machine
244
+
245
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestManager.h` (~lines 9–14, `EVoxelTestState`)
246
+
247
+ `{ Started, Succeeded, Failed }` enum with transition validation. Catches double-pass / double-fail bugs in the test code itself.
248
+
249
+ ### 6. Per-map JSON serialization for CI
250
+
251
+ **Source:** `Plugins/Voxel/Source/VoxelTests/Private/VoxelTestManager.cpp` (~lines 123–181)
252
+
253
+ Per-test pass/fail, screenshots, warnings, errors, raytracing status. Pipelines (Gitea Actions, Jenkins, GitHub Actions) parse this directly to fail the build and link to detailed reports.
254
+
255
+ ## Recommended adoption order
256
+
257
+ 1. **Include-testing pattern first.** Lowest friction, highest immediate value. Start with your smallest-surface module, then expand.
258
+ 2. **Project test library** with gameplay-specific assertions: fuzzy compare, actor count, component state, GAS attribute equality.
259
+ 3. **Visual baseline on top of screenshot capture** — hash or perceptual diff in CI.
260
+ 4. **Document test maps** with a README per map (goal, expected result, manual verification).
261
+ 5. **Defer parallelization** — sequential map loading is fine until tests exceed ~50.
262
+ 6. **Add perf gates separately:** log frame time, draw calls, memory per map; fail on delta thresholds. Voxel doesn't do this and probably should.
263
+
264
+ ## Summary
265
+
266
+ | Aspect | Voxel approach | Notes |
267
+ |---|---|---|
268
+ | Framework | Custom Blueprint + manager | Low overhead, gameplay-friendly. |
269
+ | Coverage | Content maps + include stubs | Integration-focused; unit coverage thin. |
270
+ | Assertion macros | None (UE `check`/`ensure` + custom output device) | No DSL to learn. |
271
+ | Fixtures | Disk-resident assets, per-map actors | Reusable, but fragile to refactor. |
272
+ | CI integration | JSON output | Parse anywhere. |
273
+ | Header safety | Auto-generated stubs | Best-in-class — adopt as-is. |
274
+ | BDD / spec | None | Consider adding for docs. |
275
+ | Mocking | Minimal (real GPU, threading) | May need expansion for subsystem tests. |
276
+
277
+ ## Cross-references
278
+
279
+ - The headers being include-tested live in [VoxelCore](VoxelCore.md).
280
+ - `FVoxelTestsOutputDevice` integrates with the [VoxelCore message system](VoxelCore.md#messages).