Luna, integration round 2 (BuildHost only): AVoxelWorld::bUseVoxelForgeCore (default false) routes desired tiles, generation, upload/collision and carving through Core. Core-only CoreClipRadius=3 / CoreMaxClipLevel=8 (owner's asset untouched); 25 cm Core voxels in every cm<->voxel conversion; legacy brush sizes scaled to keep physical size; UE-task JobScheduler, epoch-checked Mpsc results, existing RMC upload + collision cook; carving via sequenced applyEditTransaction. Switch off: BuildDesiredTiles takes the old path unchanged. BuildHost proof (actor commandlet, staged copies of the owner's assets): all 2,226 initial tiles hash-match standalone Core; collision bodies as expected; anchor move requests 1 / releases 1 tile; carved tile hash matches standalone; peak ~2.68 GiB. Legacy CrossPlatformDigest automation: 115,000 samples pass (wrapper flagged an analytics write outside isolation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
195 lines
15 KiB
Markdown
195 lines
15 KiB
Markdown
# Unreal Core integration report — round 2
|
||
|
||
Date: 2026-10-08
|
||
Branch: `unreal/core-integration`
|
||
|
||
## Result
|
||
|
||
Goals 1 and 2 now pass in BuildHost: an `AVoxelWorld` with Core mode enabled matches standalone Core
|
||
tile-by-tile, checks expected collision bodies, streams an entering/leaving anchor tile, and applies a
|
||
carve transaction whose affected tile hashes match standalone Core. Goal 3 has a narrow legacy
|
||
generator baseline pass; it does not instantiate an actor with Core disabled, so that result is not
|
||
an actor-level A/B comparison. The owner can now try the opt-in switch in their editor after building
|
||
the plugin.
|
||
|
||
Core remains opt-in (`bUseVoxelForgeCore=false` by default). Core mode owns separate clip settings
|
||
(radius 3, max level 8), uses 25 cm Core voxels and Core tile keys, and routes mesh payloads through
|
||
the existing RealtimeMesh/collision path. No Core canonical source or owner asset was edited.
|
||
|
||
## Headless AVoxelWorld evidence
|
||
|
||
`Tools/TestVoxelForgeCoreWorldHost.ps1` stages the current plugin and the five copied owner world
|
||
assets into BuildHost, builds the Unreal modules, and runs
|
||
`VoxelForgeExplore -coreworldtest=1`. The commandlet resolves the staged settings/strate data and
|
||
spawns a transient `AVoxelWorld` with Core mode enabled.
|
||
|
||
- Initial desired set: 2,226 tiles. Density, mesh, payload, topology, triangle, empty-tile and
|
||
per-tile hashes match the standalone Core reference. Aggregate hashes are density
|
||
`0xd528cf02858dd01d`, mesh `0x747c531b4499a9a6`, payload `0x5d38ea99f9c2cad0`, topology
|
||
`0xd9974b32dc47fc8d`.
|
||
- Collision: the expected set is 125 level-0 tiles (a 5×5×5 box); all expected non-empty tiles have
|
||
cooked bodies (58), and all 67 expected empty tiles are explicitly checked as no-body. The final
|
||
log reports `collision_ready=58`; `collision_no_body=318` is the actor's global no-body bookkeeping
|
||
count, not the expected-box count.
|
||
- Anchor: moving the `CollisionOnly` anchor from Core tile `(20,0,0)` to `(21,0,0)` requests one
|
||
entering tile and releases one leaving tile. `FullVisual` follows the same reconciliation path but
|
||
has no independent assertion in this harness.
|
||
- Carve: sequence 1, digest `0xa1d628d0de1a6824`, four affected keys. The carved LOD0 tile
|
||
`(-1,-1,-1)` hashes to `0x633f3488c0800734`; every affected tile is compared to standalone Core
|
||
after applying the same transaction.
|
||
- Peak process memory: 2,881,925,120 bytes (approximately 2.68 GiB), below the 8 GiB cap. The run completed in seconds,
|
||
below the 15-minute stop limit.
|
||
|
||
The mesh bridge copies Core vertex positions directly: the Core API returns vertices in centimetres.
|
||
Inputs to Core (player/anchor/query/edit positions and brush dimensions) use 25 cm voxel conversion;
|
||
high-level brush radii/extents/falloff that came from legacy 12.5 cm voxel units are multiplied by
|
||
`12.5/25` to preserve their physical size. `ApplyModification` low-level callers supply active Core
|
||
voxel units.
|
||
|
||
## Switch-off baseline
|
||
|
||
The selected narrow existing test was
|
||
`VoxelForge.Determinism.CrossPlatformDigest`, run from `Tools/VoxelForgeTest.ps1` against the staged
|
||
BuildHost plugin. Unreal's automation result passed with exit 0: 115,000 legacy samples, shape digest
|
||
`0xB9F6E034156BDB7A`, field digest `0x212DA316FBBA4401`, 86,901 solid, 28,099 air, and zero NaNs.
|
||
The wrapper marked its overall run failed because Unreal wrote analytics files under
|
||
`C:\Users\Jahni\AppData\Local\UnrealEngine\common\analytics` despite the isolated user-data path
|
||
and `bSendUsageData=false`. This was an incidental external profile write; I did not alter or remove
|
||
it. The raw automation result is a legacy baseline, not a direct assertion that an actor with
|
||
`bUseVoxelForgeCore=false` is byte-for-byte unchanged.
|
||
|
||
## Files and architecture
|
||
|
||
- `Source/VoxelForgeCore/VoxelForgeCore.Build.cs` defines the runtime module. It validates the
|
||
canonical manifest and shim inventory, uses C++20/precise FP with no PCH or unity, and exposes
|
||
only `Standalone/Core/include` publicly.
|
||
- `Source/VoxelForgeCore/Private/Manifest/` contains one include shim for each of the 18 rows in
|
||
`Standalone/Core/core_sources.txt`. Canonical source files remain under `Standalone/`.
|
||
- `Source/VoxelForgeCore/Private/ModuleEntry/` supplies the Unreal module entry and the isolated
|
||
include of the engine `CoreMinimal.h`.
|
||
- `VoxelForge.Build.cs` and `VoxelForgeEditor.Build.cs` depend on `VoxelForgeCore`.
|
||
- `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` defines the empty standalone export
|
||
macro and the UBT module export macro. No Core generation logic changed in this round.
|
||
- `Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp` and
|
||
`Source/VoxelForge/Public/VoxelForgeCoreAssetAdapter.h` serialize resolved assets into schema-v1
|
||
values without passing UObjects to Core workers.
|
||
- `Source/VoxelForge/Private/VoxelWorld.cpp` and `Public/VoxelWorld.h` contain the opt-in route,
|
||
Unreal task scheduler, Core tile-key/scale bridge, MPSC/epoch handling, anchor integration, and
|
||
transaction edits. `VoxelForgeExploreCommandlet.cpp` contains the BuildHost actor proof.
|
||
- The commandlet adapter's compile scheduler still exercises the standalone compiler at worker
|
||
limits 1/8/16; the runtime scheduler is the separate Unreal-task implementation above.
|
||
|
||
## BuildHost evidence
|
||
|
||
`Tools/BuildVoxelForgeCoreHost.ps1` stages plugin source and copied owner assets only under
|
||
`Saved/BuildHost/HostProject`. The final UBT run completed successfully:
|
||
|
||
- `UnrealEditor-VoxelForgeCore.dll` and `UnrealEditor-VoxelForge.dll` linked in UnrealEditor
|
||
Win64 Development.
|
||
- All 18 expected Core shim objects were found and audited.
|
||
- `CheckCoreSymbols.ps1` reported `CORE_LINK_SAFETY_PASS`: 83,843 `dumpbin` symbol lines checked
|
||
against 399 copied Unreal-style type names, with no conflicts.
|
||
- Five staged asset copies matched their source SHA-256 values:
|
||
|
||
| Asset | SHA-256 |
|
||
|---|---|
|
||
| `DA_Settings` | `5D2977F57E75A63B6B73499CD6E0AA7FBBF3718CE7F70318107BF922F0819AB7` |
|
||
| `DA_Strate1` | `CDA1F985E589F28CA6E93A068FECC3CA92487E4AD5700F2C301C4B563E40E5F9` |
|
||
| `DA_Strate2` | `02F56A18CED991BAF93DFB2F69438152275E8353B5E279C1CB7DD6E079E352E2` |
|
||
| `DA_Strate3` | `F47437F8D156C608AA06E40C5B76716ED4A19FA0F057688E7FECC04DC976428C` |
|
||
| `DA_Strate4` | `279570AE3CBA7B3507269C8209A7C931EEB7A15CC3241CE07B50120996B1C656` |
|
||
|
||
The final logs are `Saved/BuildHost/UBT-CoreIntegration.log` and
|
||
`Saved/BuildHost/VoxelForgeCore_ue_link_safety.log`.
|
||
|
||
## Headless adapter evidence
|
||
|
||
`Tools/TestVoxelForgeCoreAdapterHost.ps1` launches the isolated BuildHost Unreal commandlet at
|
||
Normal priority. It sampled about 4.30 GiB private memory, below the 8 GiB limit. The generated JSON
|
||
is retained at
|
||
`Saved/BuildHost/HostProject/Plugins/VoxelForge/Saved/CoreAdapterValidation/Output/owner_world.json`;
|
||
the commandlet log is beside it under `Logs/CoreAdapterValidation.log`.
|
||
|
||
For Core compile worker limits 1, 8, and 16, the validator then generated and hashed the 2,226
|
||
desired tiles serially. Each pass matched:
|
||
|
||
| Hash | Expected / actual |
|
||
|---|---|
|
||
| Density | `0xdb2991c73215af4c` |
|
||
| Mesh | `0x8236c5edd7fc8e4f` |
|
||
| Payload | `0x4c48fa75a543d58e` |
|
||
| Topology | `0xbea22e76b34a4dfc` |
|
||
| Passage walkability | `5,642 / 5,642` |
|
||
|
||
The adapter first parses the unmodified asset-derived export. The test then reparses a validation
|
||
copy with the standalone CPU benchmark view settings `clip_radius=3` and `max_clip_level=8`. The
|
||
final export itself retains the asset values.
|
||
|
||
## Owner hand-off and known limits
|
||
|
||
- The staged `DA_Settings` exports `ClipRadius=6` and `MaxClipLevel=6`; the standalone owner JSON
|
||
has `clip_radius=6` and `max_clip_level=8`. Runtime Core mode intentionally does not read the old
|
||
asset clip values; its own defaults are radius 3 and max level 8. The adapter parity test preserves
|
||
the source export and applies those reference view values only to a separate validation copy.
|
||
- In the owner's Unreal editor, select the `AVoxelWorld` actor and enable **Voxel World | Core | Use
|
||
VoxelForge Core** in Details. Leave **Core Clip Radius = 3** and **Core Max Clip Level = 8** for the
|
||
first check. Save the level only if the owner wants to keep the actor setting. With the world
|
||
running, expect Core terrain to stream around the player, solid LOD0 terrain to block movement,
|
||
and the existing carve entry points to create a deterministic hole. Disable the switch to return
|
||
to the legacy route.
|
||
- BuildHost UBT compiled the current runtime and editor modules. If the owner's editor reports a
|
||
compile error, the likely integration seams to inspect first are the new reflected properties in
|
||
`VoxelWorld.h` (UHT), the Core module dependency in `VoxelForge.Build.cs`, the Core/RealtimeMesh
|
||
bridge in `VoxelWorld.cpp`, and the editor-only commandlet code. No owner-editor build was run.
|
||
- The commandlet warns that `/Game/VoxelForge/Blocks/NewDataAsset` is missing. `/Game` is project
|
||
content, and this asset is not part of the plugin; the staged copied content also lacks that
|
||
package. It did not prevent schema resolution, hash checks, or walkability. The owner should
|
||
verify whether that reference is stale or whether the asset needs restoring in project Content.
|
||
- Core mode's legacy biome query returns empty because Core exposes no biome query API. `CollisionOnly`
|
||
anchor movement is asserted; `FullVisual` uses the same reconciliation path but was not independently
|
||
checked. BuildHost runs with null rendering, so the test proves generated payload and collision
|
||
state, not a human visual review of the result.
|
||
- Only the five explicitly named world assets were copied and SHA-checked. No owner editor was
|
||
opened, and no owner project build or asset write was performed.
|
||
|
||
## Failed runs, retries, and crashes
|
||
|
||
No build or test exceeded the 15-minute limit. No process returned `0xC0000142`, so no automatic
|
||
retry was used. One new `UECC-Windows-7B23387E4235BCFEDE42BC9D637E41CB_0000` was written under
|
||
`Saved/BuildHost/HostProject/Plugins/VoxelForge/Saved/CoreWorldValidation/User/Saved/Crashes/`;
|
||
its fatal log records duplicate `WorldSettings` creation in the transient actor-test world. The
|
||
requested `Saved/BuildHost/HostProject/Saved/Crashes/` contains only the older 2026-09-17
|
||
`UECC-Windows-F1A3EFD5469F5DD62E68EBBACAC84376_0000`.
|
||
|
||
The run history, including corrected failures, is:
|
||
|
||
| Run | Outcome |
|
||
|---|---|
|
||
| Early UBT validation/build attempts 1–7 | Failed in sequence on a shim-preamble regex, stale staged Build.cs, duplicated UHT source tree, missing API export/incorrect CoreMinimal and forwarding-header paths, malformed macro quoting, canonical C4456/C4668 warnings-as-errors, and editor-only `FFilePath` compat fields. Each was corrected; no source `Binaries/`, `Intermediate/`, or generated header was edited. |
|
||
| Initial successful BuildHost UBT runs | Passed after defining the module export macro, isolating the actual engine CoreMinimal include, and setting `WITH_EDITORONLY_DATA=0`. They established module links and the first symbol audit. |
|
||
| Adapter commandlet: first launch | Failed the commandlet's output-path guard because `-out` was outside the staged plugin `Saved` directory. The path was moved under BuildHost. |
|
||
| Adapter commandlet: DDC path | Exited 3 with a fatal error because the DDC path exceeded Unreal's 119-character limit. The staged DDC was moved to the shorter `Saved/BuildHost/VFCoreAdapterDDC`; no new UECC folder appeared. |
|
||
| Adapter commandlet: scale | Failed schema resolution with `voxel_size_cm=12.5`; the adapter was corrected to emit Core's standalone 25 cm scale. |
|
||
| Adapter commandlet: clip bounds | The original radius 6 exceeded the validation compiler's 160-million-node bound. The harness now applies the documented radius 3 override to a copy only. |
|
||
| Adapter commandlet: hash comparison | Generated 6,498 tiles and walkability 5,642/5,642, but hashes differed because the staged asset max level is 6 and the standalone reference is 8. The validation copy now applies max level 8. |
|
||
| UBT/commandlet wrapper status | Unreal logged successful results, but two `Start-Process` handles exposed empty exit-code fields; one commandlet fallback also looked for a marker absent from the abslog. The scripts now require UBT's `Result: Succeeded` or the commandlet's `result 0` plus exact parity markers. Final UBT and adapter harness runs passed. |
|
||
| PowerShell helper checks | Two intermediate parser attempts failed while adding the UBT fallback; one parser check exposed a multiline `-and` in the commandlet fallback; a separate parser invocation also hit nested-shell variable expansion. These affected no Unreal run; the scripts were corrected and parsed successfully before final execution. |
|
||
| Staged standalone viewer build | The first launch failed before compilation because Start-Process split a path containing spaces. The corrected BuildHost run compiled the Core library and passed its symbol audit, then the viewer link failed with 12 unresolved `VoxelForgeGpuFarViewer` symbols: `Standalone/Build.ps1` does not link the `GpuFieldPort.cpp` implementation still referenced by `StandaloneViewer.cpp`. No canonical standalone build file was edited. |
|
||
| Core actor commandlet: world creation | Unreal aborted on duplicate `WorldSettings` creation in the transient validation level. The UECC folder above contains the fatal log. World creation was changed to use the engine initialization values; the passing actor run no longer hits this fatal. |
|
||
| Core actor commandlet: lifecycle attempts | One run was manually stopped after `BeginPlay` did not run; another had no desired tiles after roughly 15,000 manual ticks. The harness was corrected to initialize actors for play, supply a transient game instance/context and GameMode, and advance `GFrameCounter`. Both were stopped well before 15 minutes and produced no crash. |
|
||
| Core actor commandlet: UBT | One quick compile failed with C2027 for incomplete `AWorldSettings`; adding `GameFramework/WorldSettings.h` fixed it. |
|
||
| Core world host final run | Passed after the lifecycle fixes and again after correcting high-level brush dimensions from 12.5 cm to 25 cm Core units. The pre-correction carve run also passed parity but affected 8 tiles; the final scale-correct run affects 4 and is the reported result. |
|
||
| `RunVoxelForgeAutomationR2.ps1` switch-off attempt | Failed before launching Unreal because the expected `Saved/VoxelForgeHarnessCommon.ps1` helper was absent. The later direct `VoxelForgeTest.ps1` automation run executed the selected test and produced the analytics-write wrapper failure documented above. |
|
||
| Switch-off automation wrapper | Unreal automation itself passed `VoxelForge.Determinism.CrossPlatformDigest` with exit 0; the wrapper returned failure for the external `common\analytics` write. No retry was attempted and no crash was reported. |
|
||
|
||
The standalone viewer build failure is separate from Unreal integration. The final adapter and actor
|
||
passes match preserved standalone reference hashes; the Core worker-limit 1/8/16 adapter proof also
|
||
retains the original passage walkability result.
|
||
|
||
## Handoff status
|
||
|
||
The owner can now try the switch described above. BuildHost proves Core tile parity, expected
|
||
collision-body bookkeeping, anchor entering/leaving, and transaction-based carving. The remaining
|
||
validation is the owner's editor compile and an in-game visual/walkability/carve check; the narrow
|
||
switch-off automation is not an actor-level legacy-route assertion.
|