feat(editor): walk a composed candidate in PIE + why rooms read angular

PART B -- the thing Jahni asked for: "any way to test those in game?"
A candidate existed only as measurements and PNGs. Now he can stand in one.

  Select the VoxelWorld actor in PIE -> Live Edit|Composer ->
  ComposerSeed / ComposerCandidateIndex / ComposerTargetStrateIndex /
  bComposerRollStructure -> click Apply Composer Candidate.

The button and the automation tests call the SAME roll wrapper, which was
the load-bearing requirement: a second roll path could drift, and then he
would be judging a different world than the contact sheet describes. A
determinism sample is logged on apply (seed, index, recipe, archetype,
metrics, epoch, eight-point density verdict) so drift is caught the day it
happens rather than in a month.

Hazards handled, since this is the first composer code to touch the live
runtime path: preflight materialisation before any live mutation, generation
and decoration tasks drained, PassagesVersion bumped to invalidate
thread_local caches, reuse of the existing RegenerateAllChunks / Epoch
invalidation rather than a new path, no Initialize() or GeneratePassages()
during apply (the re-entrancy trap), DiffLayer locks untouched, and custom
recipes conservatively force ClassifyTile to Mixed.

Scope is deliberate: a DENSITY-ONLY overlay. Layout height, authored
passages, content, water and biome metadata stay from the existing slot;
RebuildStrates() clears it. A full composed layout replacement needs a safe
rebuild path that does not exist yet.

Editor-only, verified: a Shipping build succeeds with the bridge excluded
(96/96 actions), so §3.1's "offline only, never on a player's machine"
still holds.

⚠️ UNVERIFIED BY DESIGN: a button cannot be tested headlessly and Codex was
told not to claim it works. Jahni presses it and confirms the visual plus
the "determinism=PASS" log line.

PART A -- why rooms read angular, measured not guessed. One of three room
shapes is VoxelSDF::RoundedBox:
  ShapeA = (.8 Rxy, .8 Rxy, .8 Rz)   ShapeR = .25 Rxy
so rounding is 31% of the horizontal half-extent but 78% of the vertical.
Corners are rounded; the broad planar FACES survive. SmoothMin (blend 4)
softens room/tunnel junctions not isolated corners; the cave warp bends
geometry but preserves flat regions; roughness is surface-scale only.
The name is accurate -- "rounded box" is not "blob".

NOT ACTED ON. Jahni corrected his own read: the angular archetype is Maze
(lattice source, rectilinear BY DESIGN and correct), and TunnelNetwork is
"alright-ish". Codex's recommendation is recorded for if he ever wants it:
~5-10% boxes, 10-20% capsules, rest ellipsoids, or a larger ShapeR.

Also closed REVIEW_FINDINGS EVoxelPassageType/Style as WONTFIX, enacting a
2026-08-16 judgement that recommended closure and was left open.

Build clean (Editor + Shipping), 25 succeeded / 0 failed, run by me.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJiTcTSDNkKBtnNdiBtdaU
This commit is contained in:
Fr0zkaandClaude Opus 5 committed 2026-09-04 22:03:01 +02:00
1 parent 90c40c8d5a
commit d717bc74ff
13 files changed
+1182 -32

No files matched your search

+17
View File
@@ -118,6 +118,15 @@ Provided per chunk by `StrateManager::GetDisturbanceParamsForChunk`.
**If you add a connectivity rule with longer edges, the COLLECT region must still cover the
max edge reach, and decisions must not depend on the stored window.**
The editor composer walk-through preserves this invariant by avoiding a layout rebuild. AVoxelWorld::ApplyComposerCandidate
pauses and drains active generation, installs one temporary override on an existing slot, increments
the manager's layout/passages version, and then reuses RegenerateAllChunks to bump GenerationEpoch.
The slot's Z range and passages therefore remain stable; worker tasks copy the immutable override during
their versioned refetch. A parameter candidate uses the production native stack mapping, while a
structure candidate uses VF_BuildStackFromRecipe; custom recipes conservatively return Mixed from
ClassifyTile so no unproven box bound can skip their mesh. The bridge and its editable properties are
WITH_EDITOR/WITH_EDITORONLY_DATA only and do not exist in a shipping build.
### 8.5 Content scatter & water — `VoxelContentManager.h/.cpp` (NEW)
`UVoxelContentManager` (owned by `AVoxelWorld`, game-thread). TWO INDEPENDENT subsystems:
@@ -658,6 +667,14 @@ driven by `EditorBrush*` props.
### 8.11 Live tuning & debug (`AVoxelWorld`, CallInEditor / PIE)
- `RebuildStrates` — re-reads ALL of `VoxelSettings` and rebuilds layout/gap/passages/spine +
regenerates. Use after changing those (plain `RegenerateAllChunks` keeps the old layout/passages).
- ApplyComposerCandidate — editor-only PIE walk-through for one offline candidate. Set
ComposerSeed, ComposerCandidateIndex, ComposerTargetStrateIndex (0 = topmost), and
bComposerRollStructure in Live Edit|Composer, then click Apply Composer Candidate. It uses the
shared composer roll, overlays density on the existing slot, pauses/drains workers, bumps the
manager version, and reuses RegenerateAllChunks for the epoch/re-stream. It does not rebuild
passages or change the authoritative Settings->Seed; RebuildStrates removes the overlay. The
action logs recipe, archetype, air/largest-component/walkable/feature metrics, and an eight-point
bit-level density verdict. The button itself still requires owner verification in PIE.
- `ValidateDeterminism` (F2) — one-click §8.4 regression test: samples chunk-boundary points under
two different thread_local cache alignments (left-chunk warm vs right-chunk warm) + a repeat
pass; every delta must be EXACTLY 0. Run it after any hot-path refactor that claims