Files
VoxelForge/Standalone/UNREAL_INTEGRATION_REPORT.md
T
Fr0zkaandClaude Opus 5.5 22a6b30494 wip(assembler): M2 round 3 -- opt-in hybrid sharp mesher (WorldAssemblerHybridV1) in the Unreal Core route
Default MarchingCubesV1 unchanged (W1/W8/W16 = round-6 hashes). Hybrid DC only in LOD0 interior cells
with tagged features; tile-border cells and LOD1+ stay MC. BuildHost: fixtures repeat exactly, cooked
collision bounds = render bounds, same-LOD borders pass, sampled SurfaceWorld cliff bit-identical to MC.
Open: tagged tiles cost 5.7-6.7x MC; corner-top field contact error 20 cm; 5 MC doorway LOD cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
2026-10-10 09:53:04 +02:00

529 lines
47 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 — rounds 2–4
Date: 2026-10-08
Branch: `unreal/core-integration`
The initial sections preserve the round-2 integration baseline. Round 3 records the owner's first
visual review; the round-4 addendum below supersedes its SurfaceWorld status and adds the requested
strate coverage evidence.
## Result
The Unreal route remains verified in BuildHost: an `AVoxelWorld` with Core mode enabled matches
standalone Core tile-by-tile, checks expected collision bodies, streams an entering/leaving anchor
tile, applies a carve transaction, and travels to a layout containing SurfaceWorld. The round-4
coverage matrix also found that SurfaceWorld density is exact through a temporary copied-legacy
evaluator in Core. Other generator archetypes and boundary transitions remain approximate or absent;
the full owner requirement is not complete. Goal 3 still has only a narrow legacy-generator baseline
pass, not an actor-level switch-off A/B comparison.
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. Round 4 changed canonical Core source and the standalone
JSON reader; no .uasset or owner project file was touched.
## 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.
- At the end of round 2, Core mode's legacy biome query returned empty because Core exposed no biome
query API. Round 3 adds a Core-mode query through the copied owner biome evaluator; it does not add
biome terrain or decorations to the Core field. `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.
## Round 3 — owner visual report, classification, and fixes (2026-10-08)
The owner had already built the plugin in his own game and confirmed that the Core toggle worked and
performance looked fine. I compared the four small images in `Standalone/owner_shots/unreal_core_r2/`
with owner-field and shape-world viewer modes at the B and surface locations, checked the owner's
`BuildOriginLandingGeometry`/passage definitions, and extended the BuildHost actor proof to inspect
desired keys, hashes, meshes, and LOD faces. Viewer comparisons were captured before the geometry
correction; the final test recompiled the corrected field in BuildHost.
| Reported defect | Standalone and layout evidence | Unreal Core headless evidence | Classification and outcome |
|---|---|---|---|
| 1. Capsule rings at the city/surface opening | Owner passage is a short entry into a finite origin room. Core shape-world instead added a segmented 256-voxel bore; owner-field mode has no such continuation. | Room center `+4.125` (air); floor below center and side `-4.125` (solid); above floor center and side `+4.125` (air). | **(ii) Core world defect, also visible in shape-world. Fixed.** Removed the synthetic bore and added the finite room/floor. |
| 2. Bore continues through a normal cave room | Owner layout ends the entry at the room; no shaft continues through it or into the lower seal. The same Core bore passed through it. | 32 voxels below the room floor samples `-4.125` (solid). | **(ii) Core world defect, also visible in shape-world. Fixed.** |
| 3. B-side landing has jagged/sawtooth edges | At B, owner-field and shape-world fields differ: Core shows a smooth cavern/floor while owner reference has the authored landing/terrain form. The landing is in the lower biome/SurfaceWorld portion of the layout. | All expected 2,553 visual keys load and match standalone hashes. B travel compiled 960 fine tiles; 3,438 neighbour faces checked, including 432 LOD-transition faces; no expected visual key is missing. | **(iii) Missing Core SurfaceWorld/biome representation is best supported.** The suspected missing-neighbour/LOD coverage fault is absent at the tested pose. Null-render headless testing cannot rule out a final RMC presentation artifact; owner should recheck after rebuild. |
| 4a. Surface strate is not surfacy | Shape-world viewer lacks the owner's biome-composed SurfaceWorld; owner-field mode shows rolling biome terrain. The owner separately confirmed the surface strate type is absent in his viewer. | Core query reports `Biome_Surface_Plain`, index 2, but geometry remains the Core shape field. | **(iii) Missing Core feature: biome terrain. Not implemented this round.** Cheap biome query is implemented. |
| 4b. Coarse shapes may not page detail | Hypothesis: travel failed to trigger fine compilation. Standalone Core uses the same clipmap policy. | Surface travel compiled 640 fine tiles. Visual set and tile hashes match standalone; 3,588 neighbour faces checked, including 448 LOD-transition faces, with no missing expected visual key. | **(i) Unreal paging bug not reproduced.** `StartPendingCoreRegionCompile` paged detail at the tested location. Extra loaded keys included collision-only/stale support; validator filters these and proves the exact visual set. |
### Changes and hashes
- `Standalone/Core/src/ShapeWorldInternal.h`: add the owner-layout finite origin room/floor per
strate, remove the synthetic long surface-entry bore, and ignore invalid/default passage landing
descriptors that made tiny false landings.
- `Source/VoxelForge/Private/VoxelWorld.cpp`: Core-mode `GetBiomeAtWorldLocation` now calls the
copied owner biome evaluator using its authored 12.5 cm query scale. Core terrain still uses 25 cm
voxels; the exception is local to this legacy biome query.
- `Source/VoxelForgeEditor/Private/VoxelForgeExploreCommandlet.cpp` and
`Tools/TestVoxelForgeCoreWorldHost.ps1`: probe the room/floor, W1/W8/W16 determinism, travel to B
and surface, exact visual keys/hashes, LOD face coverage, fine compilation, and biome result.
The corrected world intentionally changes the four aggregate hashes. W1/W8/W16 initial clipmap
results are identical:
| Hash | New value | R2 value |
|---|---:|---:|
| Density | `0xa8bcb72d41092503` | `0xdb2991c73215af4c` |
| Mesh | `0x90f29ba15e24579f` | `0x8236c5edd7fc8e4f` |
| Payload | `0x82c6b489e7bb7fd7` | `0x4c48fa75a543d58e` |
| Topology | `0x7b99448a1f844f2c` | `0xbea22e76b34a4dfc` |
B travel hashes: density `0x02ffd603879b7fdc`, mesh `0xde3bfc6069854070`, payload
`0x14f98868de7986c5`, topology `0xdf960f8a26aafdc0`. Surface travel hashes: density
`0x7f878c0933972c7f`, mesh `0x18d63306f5215f10`, payload `0x18b6e682e2a17505`, topology
`0xe89da4150dc053c9`. At surface `desired=2553`, while actor `loaded=3334` includes support/stale
keys during the move. The validator filters collision-only support, then proves every expected visual
key and hash; it does not claim support-set quiescence.
### Biome design proposal
Recommended direction: add a deterministic `SurfaceWorld` evaluator to the Core shape-world model,
fed by resolved biome definitions, surface-generation parameters, and fixed-order noise. Keep biome
identity/blend selection in the immutable worker snapshot and add per-column height/biome caching so
mesh samples reuse height work. This makes the surface, biome query, and decoration inputs one pure
field. The port is medium-to-large work. Uncached per-sample biome/noise could slow detail tiles;
column caching bounds the added cost. Determinism is straightforward to preserve with fixed coordinate
hashing/math and worker-count hash tests.
Routing only SurfaceWorld strates through the copied legacy `UVoxelGenerator` in Core is a smaller
compatibility bridge with higher immediate visual fidelity. It likely costs about the legacy field
evaluation per sample, duplicates a second field implementation, and inherits legacy float/platform
behavior. It should be checked across worker counts and platforms. A better staged design is an
explicit strate-evaluator interface: use the port long-term and allow the copied evaluator as a
temporary per-strate fallback when exact behavior is needed earlier. This round implemented the cheap
biome query only; a full biome surface port did not fit alongside the geometry and streaming checks.
### BuildHost outcome and run ledger
`Tools/BuildVoxelForgeCoreHost.ps1` and `Tools/TestVoxelForgeCoreWorldHost.ps1 -TimeoutSeconds 900`
passed. The actor test reported `streaming=1 collision=1 anchor_move=1 carve=1`; peak commandlet
private memory was 2,997,526,528 bytes (about 2.8 GiB). No step exceeded 15 minutes, no `0xC0000142`
retry occurred, and no new UECC folder appeared. The requested `Saved/BuildHost/HostProject/Saved/Crashes/`
contained only its prior crash folder.
| Round-3 attempt | Outcome |
|---|---|
| First standalone viewer capture invocation | Failed because an owner-data path with spaces was passed in the wrong form. Corrected auto-discovery invocation produced all four Core/owner B/surface captures with exit 0. |
| `Standalone/Build.ps1 -Target All` | Core library built and symbol audit passed; viewer link failed on 12 unresolved `VoxelForgeGpuFarViewer` symbols because the script omits `GpuFieldPort.cpp`. Canonical build files were left unchanged. |
| First expanded surface actor test | Manually stopped after repeated collision-only region compiles prevented the overly broad settled-state condition from completing. Narrowed the test to expected visual keys/hashes; final run passed. No new UECC. |
| Origin-room sign assertion | Failed quickly because expected signs were reversed. Core uses positive=air and negative=solid; corrected assertion passed. |
| Intermediate commandlet builds | One failed on non-exported `GetEffectiveOriginSpineRadius`; another used protected `OriginSpineRadius`. Harness now computes effective radius from settings/season data. Later UBT builds passed. |
| Final UBT and Core world test | Passed W1/W8/W16 hashes, origin floor, B/surface coverage and paging, biome query, anchor movement, collision, and carve markers. |
After the owner's rebuild, with **Use VoxelForge Core** enabled, inspect these exact places:
1. At the city/surface opening, confirm one short entry reaches a finite rounded room without capsule
rings; stand on the floor and confirm it is flat and walkable.
2. Continue into the normal cave room and look down: the entry should not continue as a deep shaft.
3. Walk through the A→B landing to the B side. Check whether jagged edges/sky gaps remain after
nearby tiles settle. Headless key and LOD coverage is complete; a remaining artifact needs a
screenshot from this same view to isolate final mesh presentation.
4. Travel to the surface strate. Wait for coarse-to-fine transition and confirm nearby detail appears.
The biome query identifies `Biome_Surface_Plain`, but biome-driven surface geometry is still
missing, so the broad surface terrain should not yet be judged as fixed.
Switch-off continues through the legacy generator. The owner rebuild/editor review is the remaining
visual check.
## Round 4 — strate coverage and SurfaceWorld bridge (2026-10-08)
### Status
SurfaceWorld now has an exact-density compatibility route inside Core. Surface lattice hashes match
the owner reference at full resolution and at the tested coarse LODs. The bridge calls the copied
legacy generator for SurfaceWorld samples, including its resolved biome field and terrain operations,
then applies Core edit brushes. It is deterministic in the BuildHost W1/W8/W16 matrix. This is not a
native Core SurfaceWorld implementation, and the matched viewer captures still show a mesh/presentation
difference. The bridge also makes Core surface tile generation about as expensive as the owner field.
The reader now retains the serialized slab, maze, shaft, and floating-island parameter structs.
Parsing those values does not mean their terrain evaluators are implemented in Core.
### Generator archetype probes
Each probe has its own JSON under
[the probe directory](Research/OwnerShapeWorld/core_strate_coverage/probes/). The viewer comparison
uses 16 LOD0 tiles per row, except where the SurfaceWorld row also reports an explicit cross-LOD run.
“Changed” counts lattice samples whose density sign differs; the old/Core hashes catch magnitude
differences even when that count is zero. Capture links are matched owner-field/Core frames, reduced
to 640×400 JPEGs under 300 KB each.
| Generator type | Core result | Owner/Core numeric evidence | Matched capture pair |
|---|---|---|---|
| TunnelNetwork | **Approximate.** Core extracts room/tunnel primitives and passage chains, but not the complete owner density stack. | At the owner viewer start, 686,000 LOD0 samples: 2.167784% sign changes; symmetric sampled surface distance 1.0149 m mean / 5.1468 m max; 388 unmatched samples. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_0_TunnelNetwork.viewerstart.compare.stdout.log) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_0_TunnelNetwork_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_0_TunnelNetwork_core_small.jpg) |
| FlatPlain | **Native slab field missing; generic extracted cave geometry is only an approximation.** The legacy view has its slab/column structure while Core shows a cave-like passage. | 686,000 LOD0 samples: 1.284548% sign changes; 0.4040 m mean / 1.1567 m max surface distance. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_1_FlatPlain.compare.stdout.log) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_1_FlatPlain_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_1_FlatPlain_core_small.jpg) |
| CrystalChamber | **Native slab and crystal-ceiling field missing; generic cave geometry is only an approximation.** | 686,000 LOD0 samples: 1.284548% sign changes; 0.4040 m mean / 1.1567 m max surface distance. The fixture uses the authored crystal type and its slab parameters. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_2_CrystalChamber.compare.stdout.log) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_2_CrystalChamber_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_2_CrystalChamber_core_small.jpg) |
| Maze | **Native maze lattice and corridor field missing.** Core's room/tunnel extraction is a poor approximation in this view. | 686,000 LOD0 samples: 13.337026% sign changes; 1.0784 m mean / 5.9201 m max; 3,067 unmatched samples. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_3_Maze.compare.stdout.log) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_3_Maze_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_3_Maze_core_small.jpg) |
| SurfaceWorld | **Exact density through the temporary legacy route; mesh/presentation remains approximate.** | At the surface crossing, 686,000 LOD0 samples have identical hashes and zero sign changes; sampled surface distance is 0.0767 m mean / 1.0117 m max. At the matched viewer camera, LOD2 also has identical hashes across 109,744 samples; mean surface distance 0.1737 m, max 5.264 m, 63 unmatched samples. LOD0–LOD3 hashes matched in the matched-camera matrix. [LOD0 log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_4_SurfaceWorld.compare.stdout.log) · [cross-LOD logs](Research/OwnerShapeWorld/core_strate_coverage/probes/) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_4_SurfaceWorld_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_4_SurfaceWorld_core_small.jpg) |
| VerticalShafts | **Native shaft/ledge field missing.** The current Core shape is not a shaft approximation at the probe. | 686,000 LOD0 samples: 6.071137% sign changes; legacy had 3,970 sampled surface vertices while Core had none in those tiles. A center probe changed 2.368222% of signs. The walkability audit also failed 18,122/18,570 passage samples. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_5_VerticalShafts.compare.stdout.log) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_5_VerticalShafts_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_5_VerticalShafts_core_small.jpg) |
| FloatingIslands | **Native island SDF missing.** Core generates generic cave geometry instead of suspended islands. | 686,000 LOD0 samples: 95.751458% sign changes; 1.4638 m mean / 5.9236 m max surface distance. The center probe changed 100% of signs. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_6_FloatingIslands.compare.stdout.log) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_6_FloatingIslands_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_6_FloatingIslands_core_small.jpg) |
| Underwater | **Cave shape approximate; water presentation missing.** Core carries no water plane/material in its mesh payload. | At a surface-field sample point, 686,000 LOD0 samples: 8.116472% sign changes; 1.1988 m mean / 5.8131 m max surface distance, with 115 unmatched samples. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/type_7_Underwater.samplepoint.compare.stdout.log) | [Owner](Research/OwnerShapeWorld/core_strate_coverage/type_7_Underwater_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/type_7_Underwater_core_small.jpg) |
These numbers come from different authored fields and camera regions, so the percentages are evidence
for each probe, not a normalized cross-type score.
### Passage types and styles
The four authored styles map to four legacy passage types in VoxelStrateManager: Straight →
SlopedTunnel, Worm → CrackCrevice, Spiral → SpiralDescent, and Cascading → CascadingDrops.
VerticalShaft is the separate open-surface entry, not a selectable FStratePassageConfig style.
Core reads the manager-generated control-point chain, radii, and floor profile, then rebuilds tapered
capsules. That preserves the broad path but not the full passage density modifier.
| Passage type | Style / source | Numeric evidence, 16 LOD0 tiles | Walkability audit | Capture pair |
|---|---|---|---|---|
| SlopedTunnel | Straight | 1.585569% sign changes; 0.4532 m mean / 1.2473 m max. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/style_0_Straight.compare.stdout.log) | PASS, 5,642/5,642 | [Owner](Research/OwnerShapeWorld/core_strate_coverage/style_0_Straight_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/style_0_Straight_core_small.jpg) |
| VerticalShaft | Open-surface entry | 12.102187% sign changes; 0.9802 m mean / 5.3772 m max. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/vertical_shaft_entry.compare.stdout.log) | PASS, 5,642/5,642 | [Owner](Research/OwnerShapeWorld/core_strate_coverage/passage_type_VerticalShaft_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/passage_type_VerticalShaft_core_small.jpg) |
| SpiralDescent | Spiral | 1.905539% sign changes; 0.4692 m mean / 2.1429 m max. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/style_2_Spiral.compare.stdout.log) | PASS, 1,545/1,545 | [Owner](Research/OwnerShapeWorld/core_strate_coverage/style_2_Spiral_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/style_2_Spiral_core_small.jpg) |
| CascadingDrops | Cascading | 1.884840% sign changes; 0.4879 m mean / 2.2203 m max. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/style_3_Cascading.compare.stdout.log) | **FAIL, 365/1,495 solid centerline samples** | [Owner](Research/OwnerShapeWorld/core_strate_coverage/style_3_Cascading_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/style_3_Cascading_core_small.jpg) |
| CrackCrevice | Worm | 1.793440% sign changes; 0.4680 m mean / 2.1420 m max. [Log](Research/OwnerShapeWorld/core_strate_coverage/probes/style_1_Worm.compare.stdout.log) | **FAIL, 109/1,490 solid centerline samples** | [Owner](Research/OwnerShapeWorld/core_strate_coverage/style_1_Worm_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/style_1_Worm_core_small.jpg) |
The non-walkable Worm and Cascading probes violate the requested entrance-to-exit walkability
invariant. Those styles need correction before the Core route can claim passage coverage.
### Strate transitions
All three transition fixtures were compared at the generated passage crossing near the strata
boundary (16 LOD0 tiles, 514,500 lattice samples each). Owner hashes change per transition, while Core
returns the same hash, 0x7f9999008f887de6, for Gradient, Hard, and Interleaved. The Core representation
therefore does not yet reproduce the transition field. The Core mesh remains an approximate control-
point passage through the boundary.
| Transition | Sign changes | Mean / max surface distance | Capture pair |
|---|---:|---:|---|
| Gradient | 1.186395% | 0.4302 m / 2.0185 m | [Owner](Research/OwnerShapeWorld/core_strate_coverage/transition_0_Gradient_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/transition_0_Gradient_core_small.jpg) |
| Hard | 1.170262% | 0.4302 m / 2.0383 m | [Owner](Research/OwnerShapeWorld/core_strate_coverage/transition_1_Hard_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/transition_1_Hard_core_small.jpg) |
| Interleaved | 1.301846% | 0.4622 m / 2.5725 m | [Owner](Research/OwnerShapeWorld/core_strate_coverage/transition_2_Interleaved_legacy_small.jpg) / [Core](Research/OwnerShapeWorld/core_strate_coverage/transition_2_Interleaved_core_small.jpg) |
The captures were taken at the passage crossing, not in the solid-only boundary camera used by the
first probe attempt. Numeric logs are in the probe directory.
### Other terrain-changing strate inputs and implementation route
The legacy generator also reads world seed and strate bounds; FStrateGenerationParams (worm, room,
tunnel, cave warp, floor, and detail fields); the archetype structs FSlabGenerationParams,
FMazeGenerationParams, FSurfaceGenerationParams, FVerticalShaftParams, and FFloatingIslandParams;
disturbances; weighted/probabilistic terrain-operation stacks; biome definitions and biome-map
parameters; transition type/blend width; passage style/configuration and generated floor profiles;
and water-level and render-side water/biome presentation data. The round-4 reader carries the typed
parameter and operation assets into the standalone snapshot. SurfaceWorld's legacy fallback consumes
its full density-side stack. The shape-only path still does not evaluate all of those inputs for the
other archetypes.
Recommended next route, ordered by observed visual gap: implement native FloatingIslands, then native
VerticalShafts and Maze, then native FlatPlain/CrystalChamber slab fields; keep the passage chain native
but fix Worm/Cascading walkability; implement transition blending in the Core layer field; add
Underwater's water plane as a separate render payload. Keep the current TunnelNetwork primitive route
and refine its density operators. A copied-legacy evaluator is a valid temporary bridge where exact
density is the priority, but the SurfaceWorld timing below shows its cost. A density fallback alone
cannot create render-side water, biome materials, decorations, or atmosphere.
### SurfaceWorld performance and BuildHost verification
The matched-camera CPU viewer used 1,294 tiles through LOD8. Owner legacy generation took 23.914 s
wall / 188.705 worker-seconds; Core with the SurfaceWorld bridge took 23.085 s / 180.562 worker-
seconds. The prior Step29 Core viewer without the bridge took 0.785 s / 2.538 worker-seconds for the
same tile count, but it omitted the surface. This is not a controlled per-sample microbenchmark; it
shows the bridge costs approximately the legacy field route for the complete view. Captures and logs
are under core_strate_coverage.
BuildHost was rebuilt and the actor test passed with a SurfaceWorld strate. The initial W1/W8/W16
hashes are stable: density 0xccd5858289627767, mesh 0x33c4f191ee318a40, payload
0xd487ed030c6622cd, topology 0xf5f6262021a780a0. At the surface actor position, all 2,553 expected
visual tiles matched standalone; 640 fine tiles compiled, 3,588 neighbour faces and 448 LOD
transitions were checked, and the biome query returned Biome_Surface_Plain (index 2). Surface hashes:
density 0xb80442b34787eb4e, mesh 0xfecc9327337abbfb, payload 0xca57a4e295ce0602, topology
0x7f187a07e5c19f7f. The extra loaded count (3,288) includes support/stale keys; visual keys remain
complete. Full log: [CoreWorldValidation.stdout.log](../Saved/BuildHost/HostProject/Plugins/VoxelForge/Saved/CoreWorldValidation/Logs/CoreWorldValidation.stdout.log).
The UBT host build passed. The actor test took 12m59s and peaked at 3,042,344,960 private bytes
(about 2.83 GiB), below the 15-minute / 8-GiB limits. No 0xC0000142 retry occurred. The only crash
folder under BuildHost is the pre-existing UECC-Windows-F1A3EFD5469F5DD62E68EBBACAC84376_0000;
there was no new crash.
### Round-4 failed attempts and retries
| Attempt | Outcome |
|---|---|
| Surface numeric probe at viewer z = −1,024 m | Wrong vertical slice for the standalone JSON's SurfaceWorld strate; no surface triangles. Corrected to the terrain crossing near z = −400 m and matched capture camera z = −340 m. |
| First style matrix | The fixture changed nested asset PassageConfig while the reader consumes the duplicated top-level passage_config. All four probes therefore stayed Straight. Regenerated each fixture with both copies updated and reran. |
| Vertical-shaft probe invocation | Exit 2 because the loop named a JSON file that had not been generated. Reran against the original layout, which contains the open-surface VerticalShaft entry. |
| First LOD matrix invocation | Exit 2 because PowerShell split a computed area argument and the viewer treated surface_lod0 as a data path. Reran with explicit argument strings; LOD0–LOD3 hashes matched. |
| Step30 viewer build | The script printed that vswhere.exe was unavailable, then used the installed compiler toolchain; Core compile, symbol audit, and viewer link passed. |
No round-4 run crashed or needed a retry. No build/test step exceeded 15 minutes. Switch-off remains the
legacy route. After the owner rebuild, recheck the SurfaceWorld shoreline, hills, and biome transitions
at the matched camera after fine tiles settle; also recheck the opening-room floor. The captures show
the exact-density bridge improves the surface field, but water/presentation and the other missing
archetypes are still open work.
### Round-5 native SurfaceWorld delivery
Round 4 above is historical. The native manifest route now supersedes the temporary legacy density
bridge for a reviewed `SurfaceWorld` when `AVoxelWorld::bUseVoxelForgeCore` is enabled. Existing Core
cave generation remains supported when there is no world-assembly manifest. With the switch off,
legacy generation and the existing season identity hash remain on the old path.
The editor `UVoxelSettings` asset now has a `SourceWorldAssemblyManifestJson` picker and
`ImportWorldAssemblyManifestJson` button. Import stores canonical JSON plus the verified Core content
hash in the settings asset. `GetCurrentSeasonContentHash()` combines that hash only while Core is
active. Core adapter initialization checks the manifest seed against the resolved layout and
requires exact, unique `SurfaceWorld` slot index/top/bottom matches. The test passes the reviewed
JSON to BuildHost through `-coreworldassembly`; it does not edit an asset. Manifest, recipe and plan
hashes were `8933693d9560ba9f`, `c37de78b759c0a4c` and `1ca84619c8600ee5`.
The final BuildHost commandlet passed the W1/W8/W16 matrix, cave initial streaming, anchor movement,
carving, lower-surface travel and native SurfaceWorld travel. At `(37,165,-2011)` Core voxels, all
2,553 expected visual tile hashes matched standalone Core. Coverage checked 573 local tiles, 3,438
neighbour faces and 432 LOD transitions across two regions. The collision gate checked 125 expected
near tiles: 36 non-empty tiles had cooked bodies; 89 expected-empty tiles correctly had none. Native
SurfaceWorld hashes were density `56ccc76575aa5f5f`, mesh `f3aeb31de1f967c1`, payload
`95cb4781a1be4b73`, topology `26ac366d430599bd`. The BuildHost path uses Unreal mesh upload and
Chaos collision cooking; standalone checks field and mesh output only.
The narrow switch-off check is source-level, not a second runtime actor session: Core remains
default-off; the legacy `UpdateChunksAroundPosition` branch is retained; Core-only manifest
initialization and collision admission are guarded by the switch; and the legacy hash returns before
reading optional manifest data when disabled. This does not claim a full flag-off runtime replay.
In the same BuildHost session, 2,553 identical keys were generated with hashes on. Native
`Heightfield2D` vs the legacy bridge took 0.015903 vs 0.012752 s for region compilation and
96.800984 vs 197.333401 s for summed tile generation; compile plus tiles was 96.816887 vs 197.346153
s (2.038× speedup). This is serial headless tile generation, not rendered frame time. The ~1.57 s
full-view aim remains unmet: the last full 529-tile LOD8 stream measured 4.446 s, 2.83× the aim.
No full-view viewer benchmark ran in round 5.
The existing downscaled native/owner cliff overlook pair was inspected. The sharp ridge peaks remain
attached to the highland surface with no detached shard trail, so the field/mesh was not altered;
their appearance is left for the owner to judge in-game. Handoff instructions and actor-local camera
targets for the surface, coast, cliff, route and cap are in
[`ASSEMBLER_M1_REPORT.md`](ASSEMBLER_M1_REPORT.md). Likely project compile touchpoints are
`VoxelSettings.h/.cpp`, `VoxelForgeCoreAdapter.cpp`, `VoxelWorld.cpp` and
`VoxelForgeExploreCommandlet.cpp`.
Round-5 BuildHost run ledger: the first UBT compile failed to link non-exported settings methods;
exporting them made the retry pass. Actor attempt 1 found a surface support-tile hash mismatch;
attempt 2 reproduced it and exposed collision work starting before region admission. Actor attempt 3
failed the legacy biome-query assertion because the native surface does not provide that legacy
decorator query; it was replaced with direct native heightfield sampling. After the collision-admission
fix, the actor test passed. The final rerun after gating the manifest hash on the Core switch also
passed in 9m20s with 3,880,357,888 bytes peak sampled private memory (3.61 GiB). No `0xC0000142`
retry or new UECC folder occurred. The owner's project was not opened or built and no `.uasset` was
edited.
### M2 round-3 hybrid mesher integration (2026-10-10)
`WorldAssemblerHybridV1` is an opt-in Core recipe; `MarchingCubesV1` and
`bUseVoxelForgeCore=false` remain the defaults. Tagged type-2 plan boxes use sharp hybrid cells only
at LOD0 interior cells. Tile-border cells and LOD1+ use MC, with the existing skirt retained. The
full BuildHost actor commandlet passed its W1/W8/W16 matrix at the round-6 Core hashes,
anchor/edit/travel checks, height agreement, switch-off gate, Blueprint carve/fill, native
SurfaceWorld route and five cooked collision contacts. It ran in null-RHI BuildHost for 11 minutes
and logged zero engine errors. A PowerShell status-format cast initially made the outer wrapper
return 1 after the engine had passed; the script was fixed, focused fixture and cliff checks
returned 0, and the corrected full wrapper rerun also returned 0 in 11m06s at a sampled 3.73 GiB
peak.
The BuildHost fixture plan has nine stable type-2 feature boxes for the corner, doorway, riser and
ledge, plus the existing type-4 SurfaceWorld cliff. Five contacts hit the Pawn channel and the same
RMC component; direct component traces agreed with world traces, and cooked Chaos body bounds
matched render bounds. Field contact error ranged from 0 to 20.332 cm. The separate sampled native
cliff check passed bit-identity: 10,231 vertices, 10,360 triangles, mesh hash
`0xfc7bd7a3cf997992`. Same-LOD independent borders passed with 63 segments; the 125-phase LOD0/LOD1
doorway probe had no contours over 50 cm and a 22.844 cm worst mismatch.
That LOD probe is not a topology proof. The standalone full transition suite still records five MC
doorway failures out of 625, with skirts serving as the current repair. At the 25 cm Core grid, the
17.68 cm corner bevel is 0.35 of a LOD1 sample and may round off or pop at the threshold. Null RHI
cannot show or measure this visually; owner review remains necessary.
Plugin fixture timings show a 5.66–6.70× hybrid/MC meshing cost on the tagged sharp fixtures; the
organic cave is 0.992× MC. See the M2 round-3 tables and complete failed-run ledger in
[`WorldAssemblerM2/REPORT.md`](Research/WorldAssemblerM2/REPORT.md). BuildHost artifacts include
the owner-previewable [`surface_hybrid_fixture_plan.json`](Research/WorldAssemblerM2/round3/surface_hybrid_fixture_plan.json).
Owner preview: duplicate the settings asset, import the fixture manifest through
`SourceWorldAssemblyManifestJson` / `ImportWorldAssemblyManifestJson`, enable Core on the test
`AVoxelWorld`, and select `World Assembler Hybrid V1`. Review the corner and doorway while crossing
the LOD distance, then compare riser and ledge contacts. The owner builds the plugin and judges the
live view. No owner `.uasset`, project build, or editor session was used here.
New source files are the mirrored private headers
`Source/VoxelForge/Private/VoxelHybridSharpMesher.h` and
`Standalone/Source/VoxelForge/Private/VoxelHybridSharpMesher.h`; no new `.cpp` or generated header
was added. Likely compile touchpoints are `VoxelWorld.h/.cpp`, `VoxelTypes.h`,
`VoxelMarchingCubesMesher.h/.cpp`, both hybrid mesher headers, the Core public header and
`VoxelForgeCore.cpp`, `VoxelForgeExploreCommandlet.cpp`, and `VoxelForgeEditor.Build.cs`.