Files
VoxelForge/Standalone/Research/WorldAssemblerM3/Round4/REPORT.md
T
Fr0zkaandClaude Opus 5.5 111cf3d262 wip(assembler): M3 round 4 -- plans built inside Unreal from the owner's strates; no import needed
SurfaceWorld and FloatingIslands plans generate at startup from the resolved seed,
strate types and heights (hashed, cached). Imported JSON is an opt-in override (off by
default); an invalid override shows an on-screen notice and falls back to legacy.
BuildHost on staged owner assets: SurfaceWorld cross-system checks, islands at owner
height (route, collision, anchors, BP edits), seed 137501, W1/W8/W16, Core-off legacy.
XY-column cache verified (hashes kept); island LOD0 p95 91 ms vs 133 ms sprint deadline.
Not exercised: season-seed path (no Season in staged settings), rendered notice pixels.

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

13 KiB
Raw Blame History

World Assembler M3 Round 4 — Unreal plans from the owner’s settings

Date: 2026-10-10
Result: automatic startup plans and the owner-height SurfaceWorld/FloatingIslands BuildHost paths pass. The old imported JSON no longer blocks the default path.

Planning and multiplayer choice

AVoxelWorld now asks the adapter to build the assembly at startup from the already-resolved UVoxelStrateManager layout, each slot’s generator type and height bounds, its authored generation parameters, and the effective world seed. The effective seed is the assigned season’s seed when Season is set; otherwise it is UVoxelSettings::Seed. SurfaceWorld and FloatingIslands slots receive native plans. The adapter serializes the canonical manifest, hashes it, and the world caches that JSON and digest for the lifetime of the initialized world. It is also included in Core world/season content identity. It is not regenerated per tile.

This is a deterministic-startup artifact: clients with the same season or settings seed, resolved layout, definitions, and parameters produce the same canonical hash. W1/W8/W16 checks pass. The hash is exposed through the world content-hash API for a join-time comparison. This round did not add or verify a network handshake that distributes the server’s artifact or rejects a peer with a different hash, so multiplayer mismatch enforcement remains unproven.

Imported JSON is now an explicit override. Use Imported World Assembly Override defaults off; the previous imported bytes can remain on an old settings asset without suppressing automatic planning. The settings import action turns the checkbox on. With the checkbox on, a stale/mismatched manifest remains an error and follows the visible-notice/legacy-fallback path. The default owner workflow needs no import.

Strata types without a native assembly plan retain the existing Core behavior. Core still uses its current generic archetype interpretation (for example, TunnelNetwork’s approximate primitive/passage representation); unsupported or approximate strata are not silently rerouted to the legacy generator. The SurfaceWorld/FloatingIslands plan addition does not claim exact native plans for those types.

If Core cannot serialize, validate, or initialize, the runtime logs the reason, displays the reason in red for 20 seconds through AddOnScreenDebugMessage, disables Core for that world, clears the failed Core state, and initializes the legacy generator. The mismatch BuildHost test ran with NullRHI: it proves the message call/log marker and legacy fallback, not visible pixels in a PIE viewport.

Owner assets staged in BuildHost

All source assets were copied into the isolated BuildHost project and hash-checked by the build helper; no owner asset was edited. Recorded SHA-256 values:

Asset SHA-256
DA_Settings 8ABE8243104980260FECA0A6F4CF4927768E8E568221A6F6A2C2694F6D15D454
DA_Strate1 76063D691D5CE26D2014B587E1972A6724787BE1204E4652CA863BB8D5001BD0
DA_Strate2 02F56A18CED991BAF93DFB2F69438152275E8353B5E279C1CB7DD6E079E352E2
DA_Strate3 F47437F8D156C608AA06E40C5B76716ED4A19FA0F057688E7FECC04DC976428C
DA_Strate4 7C0DE7D06876035AC7BC4F117B9166AFD77402021843BA4900B470F4B0D0185B

The owner’s read-only Play log resolves one SurfaceWorld slot. The staged saved DA_Settings copy, however, references DA_Strate4 and has no season asset assigned; the staged DA_Strate1 is a 64-chunk SurfaceWorld. To reproduce the layout reported by the active editor log without changing assets, the commandlet used a transient copy of DA_Settings with DA_Strate1 in that one slot, seed 0, gap 0, and the original bounds [0,-63] (64 chunks). Runtime logs number that slot as zero-based strate 0. Thus the tests use the owner’s real definition and real height, but the staged saved settings bytes alone do not describe the active editor layout. No UVoxelSeasonAsset was assigned in those staged settings, so the season-seed path was not exercised; the code selects it when one is assigned.

The staged settings contain the previous manifest JSON. The post-change plan test deliberately restored those bytes while leaving the new override checkbox off; automatic planning succeeded (stored_manifest_ignored=1). The recurring missing /Game/VoxelForge/Blocks/NewDataAsset reference is logged by BuildHost but did not prevent the world or checks from resolving.

BuildHost acceptance matrix

Case Result and evidence Would fail if…
(a) Core on, SurfaceWorld unchanged PASS. Startup generated 1 SurfaceWorld / 0 island plans, hash 2bb89236290414d5. Biome field: ID 4099, three biomes sampled. W1/W8/W16 density/mesh/payload/topology 0cd2a1a4152ee4aa / 17775c835711e5a3 / a27224958fc27d7b / 3821fea90b134ce4. Height agreement delta 0 cm; water -36575.977 cm; atmosphere bounds [-50400,800] cm; BP carve and fill pass. No startup-generated SurfaceWorld plan/hash, any worker hash differs, height/content/water/atmosphere or BP edit marker fails, or the actor test does not complete.
(b) SurfaceWorld definition changed to FloatingIslands PASS on a transient copy at owner bounds [0,-63]. Plan hash 9c372e7bfb5b8310, recipe 5e0370d9f95f1c15, plan dbbda4932378047a; four islands, three connectors, 28 route segments, minimum route clearance 119 subvoxels, fixed water. Top and connector-span content anchors agree with terrain within 0.4 cm; both capsule contacts hit cooked collision. BP carve/fill and Core-to-legacy switch-off pass. W1/W8/W16 aggregates: density/mesh/payload/topology 4dcfb37585d7d986 / 725a18374c5623de / fb345d8cb319d18b / 76f2846be8efb5f4. No plan at [0,-63], route audit fails, any W hash differs, either content/terrain anchor or capsule contact fails, Blueprint edits fail, or Core-off changes legacy scale/density.
(c) Nonzero seed PASS. Seed 137501 produced hash 15c54ba04b430e42; two canonical serializations matched. The stored prior JSON was present and ignored with override off. The generated JSON/hash differs between identical resolutions, seed is not reflected in the plan, or an inactive stored manifest prevents planning.
(d) Worker stability PASS. SurfaceWorld and FloatingIslands actor tests both report W1/W8/W16 stable; the exact Round 3 standalone fixture also reports matching W1/W8/W16. Any deterministic hash differs across worker counts.
(e) Core off PASS. Legacy generator remained enabled; voxel scale 12.5 cm; three density samples unchanged. Core-off toggling changes the sampled legacy densities, disables the legacy generator, or changes the legacy scale.
(f) Mismatched old manifest override PASS when the override is explicitly enabled. It reports the exact 0 SurfaceWorld/1 island versus 1 SurfaceWorld/0 island mismatch, prints the 20-second on-screen notice, disables Core, initializes the legacy generator, and returns finite density 70.0000. The commandlet logs the expected Core errors and exits process status 1 although its test result is 0; the wrapper accepts only this combination with the fallback marker, complete marker, and no new crash. A mismatch silently yields no world, no visible-notice call, Core stays enabled, legacy is not initialized, density is non-finite, or the commandlet lacks the explicit pass/result markers.

XY-column cache verification and timing

Rebuilt the canonical Core library, compiled the Round 3 audit against its same probe, and wrote new results under Round4/results/xy_cache_audit so the Round 3 record stayed unchanged. The Round 3 recipe/plan/manifest hashes remain ef1340d32b072ba3 / 61fd58f65c5fe157 / 54160b4d25d0279f; W1/W8/W16 remain 5764b702482740e8. Stable island/connector IDs, open-sky fraction (91.8919%), bounds (515 boxes / 13,851 samples / zero missed), thickness (minimum 0.75), and route results (28 segments, clearance 99) match the Round 3 audit. The XY-column cache is compiled and verified; no revert was needed.

On the same 32,768-query audit, native elapsed time was 38.91 ms versus the recorded 46.30 ms before the cache; legacy was 65.64 ms versus 64.33 ms. These are one-run elapsed measurements, not a controlled benchmark series. The owner-height actor’s LOD0 island p95 was 91.429 ms and mixed p95 90.652 ms against the 133.333 ms sprint deadline; legacy was 25.635/25.803 ms. Round 3’s actor measurement was 153–158 ms Core and 42–44 ms legacy, so the current owner-height measurement is under the target. A deeper speed change is not needed for this round.

Failed attempts and corrections

  • The first owner SurfaceWorld commandlet completed its world assertions, but the PowerShell wrapper rejected the actual 2,850-tile layout because it expected exactly 2,553 tiles. The assertion now checks for a positive tile count; the owner SurfaceWorld run then passed.
  • The first generated-island actor attempt used a hard-coded slot 1 although the owner-height layout resolves to zero-based slot 0. The harness now uses the resolved slot index.
  • The next island attempt passed plan, route, height anchors, and collision, but timed out after 90 seconds waiting for an injected transient tree decoration. That random placement was not needed for the requested anchor proof; the test now checks native top/span content anchors against terrain and their collision contacts directly. No production decoration behavior was changed by this correction.
  • The first mismatch-fallback actor attempt had no GameMode/BeginPlay in its transient world. The fixture now starts play explicitly. A subsequent expected LogTemp Error made Unreal return process status 1 despite commandlet result 0; the wrapper was narrowed to accept only the exact tested fallback/pass/no-crash markers. The final mismatch run passed with that condition.
  • Initial compile iterations caught and corrected an IsSet/has_value mismatch, a missing CoreError local, and a link to an unavailable GetEffectiveWorldSeed symbol. Final UBT passed after the override checkbox and test changes.
  • The first standalone-audit wrapper invocation referenced a memory-probe type that existed only in a previous PowerShell session. It printed that preflight error but proceeded to launch; an immediate independent system-memory query showed 19.18 GiB available. The audit passed in 1.66 seconds with a 154 MiB peak. No audit retry was made.

No run returned 0xC0000142; no retry for that status was needed. All commandlets stayed below 8 GiB private memory and under 15 minutes (SurfaceWorld about 12m, final islands 3m28s, plan/fallback under 30s). No new UECC-* folder appeared; the sole BuildHost crash folder is dated 2026-09-17. Commandlets ran sequentially at BelowNormal priority with the launcher's 4 GiB free-memory gate. The owner’s editor/project was not opened, closed, or built. No .uasset, junction, symlink, commit, push, or stash was made.

Files changed and compile impact

No new C++ source file was added. Modified sources:

  • Runtime: Source/VoxelForge/Private/VoxelContentManager.cpp, VoxelForgeCoreAdapter.cpp, VoxelSettings.cpp, VoxelWorld.cpp; headers Source/VoxelForge/Public/VoxelSettings.h, VoxelWorld.h.
  • Core API/implementation: Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h, Standalone/Core/src/WorldAssemblerInternal.h.
  • BuildHost harness: Source/VoxelForgeEditor/Private/VoxelForgeExploreCommandlet.cpp, Tools/BuildVoxelForgeCoreHost.ps1, Tools/TestVoxelForgeCoreWorldHost.ps1.

Likely compile spots are UHT/reflected VoxelSettings.h and its generated code, runtime settings/adapter/world/content translation units, the Core public API and assembly internals, and the editor commandlet. The BuildHost UBT/UHT compile passed at max 4 actions and BelowNormal priority; Core link audit passed (18 shims; 94,368 symbol lines checked against 415 Unreal-style type names). The Standalone Core rebuild and its symbol audit also passed. Existing compiler output included the known VoxelStrateManager.cpp double-to-float warnings and a missing vswhere.exe notice; neither failed the build.

Owner hand-off

  1. Select the AVoxelWorld actor in the level. In Details, under Voxel World | Core, check Use VoxelForge Core.
  2. In the current settings asset, open Voxel | Strates | Fixed Strates and duplicate the strate definition assigned to the desired slot (for the tested slot, the asset is DA_Strate1). In that duplicate, set Strate | Generation | Generator Type to FloatingIslands, then assign the duplicate to the same Fixed Strates entry. Keep Use Imported World Assembly Override unchecked; no world-plan file is needed. Keep the existing seed and water settings.
  3. The staged settings currently have no Season assigned, so Fixed Strates and Seed are active. If a Season is assigned later, its reviewed manifest owns the layout and seed instead; edit that season definition for a different seasonal layout.
  4. Start at actor-local (-980, 431.8, -12438.2) cm (transform that point by the world actor’s transform) and follow the generated route.

For SurfaceWorld, leave that slot’s Generator Type as SurfaceWorld. Its plan is generated at startup the same way.