Files
VoxelForge/Standalone/UNREAL_INTEGRATION_REPORT.md
T
Fr0zkaandClaude Opus 5.5 075e58187e wip(unreal): AVoxelWorld Core mode -- streaming, collision and carving through VoxelForgeCore
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
2026-10-08 20:33:46 +02:00

195 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.