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 +14 -5
- package/dist/tasks/GetWorldStatus.d.ts +27 -0
- package/dist/tasks/GetWorldStatus.js +57 -0
- package/dist/tasks/GetWorldStatus.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 +11 -0
package/README.md
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
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
|
-
| `pcg` | `voxel_build_scatter_graph`
|
|
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
|
-
|
|
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"}
|
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.
|
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).
|