feat(core): native lattice generator, slice 1 -- helix-ramp spine + small maze (L58); research R27

Core.Lattice.PrimitiveField v1, opt-in per strate (legacy Maze/VerticalShaft stay legacy): resolves the real
arrival and departure mouths first, plans a mandatory spine, then maze cells and two dead ends (9 rooms,
9 edges, stable IDs). The spine descends 20 m through four helix turns (6 m radius, 3 m clear width, 5 m
pitch, 2.6 m clearance; max grade 10.0 deg); each feature is one filleted void (0.57 m measured). Final-field
reachability passes at 883 stations; an orphaned shaft control is rejected; exact intervals (0 misses) and
a whole-surface audit with 0 flags. Whole view 1.69 s (above the 1 s target). fast/medium/full PASS.
Research R27 (self-checked): static stream-to-pool water design.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-25 15:45:32 +01:00
1 parent 1e3e04bbac
commit 6c6cc37e1d
25 files changed
+280497 -117

No files matched your search

@@ -0,0 +1,81 @@
# VoxelForge R27 — revised self-check
**Read-only review.** I read the cited code and docs. I made no source changes and ran no scripts, tests, builds, or binaries.
## What exists
**Core:** `HeightfieldPointSample` carries a stratum `waterSurfaceSubvoxels` and a point-level `waterFillSubvoxels` field ([VoxelForgeCore.h:1297](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h:1297>)). `Heightfield2D::point` computes fill only for an enabled water plan and an air sample between the ground and the stratum-wide water level:
```cpp
if(recipe_->evaluatorVersion>=2&&plan_->waterEnabled&&out.densitySubvoxels>=0
&&z>out.groundHeightSubvoxels&&z<plan_->waterSurfaceSubvoxels
&&out.groundHeightSubvoxels<plan_->waterSurfaceSubvoxels)
out.waterFillSubvoxels=std::min(z-out.groundHeightSubvoxels,
plan_->waterSurfaceSubvoxels-z);
```
([WorldAssemblerInternal.h:2610](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/WorldAssemblerInternal.h:2610>)). The Unreal adapter sets that surface from `BottomVoxel + HeightVoxels * WaterLevelRelative` ([VoxelForgeCoreAdapter.cpp:383](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:383>)).
The only `waterFillSubvoxels` consumer I found is the standalone evaluator’s determinism hash: it adds the value to the sample hash and compares results from 1, 8, and 16 workers ([StandaloneViewer.cpp:8448](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Source/StandaloneViewer.cpp:8448>)). I found no local water-body records, water-specific interval query, or water BVH. The existing `FieldInterval` is for density ([VoxelForgeCore.h:1301](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h:1301>)). R24’s separate occupancy channel and local mesh are proposals, not current behavior ([R24 water notes](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Research24/REPORT.md:25>)).
**Unreal:** `UVoxelContentManager::UpdateWater` gets a water height for the player’s current stratum, using the Core snapshot when available and otherwise the legacy stratum lookup ([VoxelContentManager.cpp:2530](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelContentManager.cpp:2530>)). It creates one `UStaticMeshComponent` using `PlaneMesh`:
> `WaterPlane->SetCollisionEnabled(ECollisionEnabled::NoCollision);`
> ([VoxelContentManager.cpp:2575](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelContentManager.cpp:2575>))
It scales the engine plane to cover the view distance (or uses a large fallback size) ([VoxelContentManager.cpp:2585](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelContentManager.cpp:2585>)), snaps its center to a coarse player cell, and places it at the selected water height ([VoxelContentManager.cpp:2592](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelContentManager.cpp:2592>)). It assigns the stratum’s `WaterMaterial` ([VoxelContentManager.cpp:2597](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelContentManager.cpp:2597>)). The code comment calls it one global plane that follows the player ([VoxelContentManager.h:94](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelContentManager.h:94>)); `VoxelWorld` calls it each tick ([VoxelWorld.cpp:7039](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelWorld.cpp:7039>)). It is not local stream or pool geometry, and it has no collision. I found no swimming-volume or underwater post-process implementation in this plugin. The `Underwater` generator shares the tunnel density graph and an “water” flag; it does not implement swimming ([VoxelGenerator.cpp:2638](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelGenerator.cpp:2638>)).
## Reference image
I did **not** find the requested image in `Docs/`: the `Docs` tree in this checkout contains archived Markdown files and no image assets. The nearest water-named image I found is `Standalone/data/owner_normals_pool_before.png`, outside `Docs`. It shows a broad blue-grey surface against uneven rocky ground, but no clear stream entering a bounded pool. I can’t claim the design matches the missing reference. It does match the written R24 proposal for a local pool, fixed stream, separate water channel, and local mesh ([R24](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Research24/REPORT.md:27>)).
## Proposed design
Use a **plan-time deterministic steepest-descent trace** on the resolved terrain, then store its quantized points as an immutable polyline. Sample on a 1 m XY grid; at each step choose the neighboring sample with the greatest downhill grade, breaking ties by a fixed compass order. A local sink ends the trace and becomes the pool site. This follows the earlier drainage note and makes the result reproducible across peers. The polyline is stored data, not simulated flow. Reject a candidate that exceeds the grade limits below rather than altering its path at runtime.
Initial dimensions for one fixture:
- **Stream:** 20 m centerline; target surface fall 2 cm per horizontal metre (2%), with no segment above 5 cm/m (5%). Use a **sloped sheet**, linearly interpolated between fixed-point controls, meeting the pool level exactly. Flat-per-segment surfaces would introduce visible steps at joins.
- **Channel:** 0.60 m flat invert; 0.30 m maximum cut depth; banks at 1 vertical to 4 horizontal. Place the water 0.20 m above the invert, yielding about 2.2 m of wet surface width before edge smoothing.
- **Pool:** 4 m radius, up to 0.60 m deep, with a bowl bed rising to the waterline at its rim. Set the fixed, flat surface 0.05 m below the basin’s lowest spill saddle; blend the carved shoreline into native terrain. The stream’s final surface height equals this level.
Treat all of those dimensions as **unvalidated starting values**. Reject a trace that cannot meet the sheet grade or fit the banks under the resolved terrain.
Add immutable Core pool and stream records. Keep water occupancy `W` separate from rock density `D`; for example:
```text
Wpool = min(z - hpool(r), zpool - z, 4.0 - r)
Wstream = min(z - bed(s,d), zw(s) - z, 1.1 - |d|, s, L - s)
W = max(Wpool, Wstream)
```
Here `s` is distance along the centerline, `d` is cross-stream distance, and positive `W` means inside the water. Keep the rock bed in `D`; clip rendered water to the air side of the bed.
Give each pool and stream segment an outward-rounded AABB in fixed-point units. The pool box covers its 4 m radius and bed-to-surface height. A stream occupancy box covers the segment, 1.1 m wet half-width, and bed-to-surface height; the separate bed-carve bounds should include the wider banks and blend. Query a BVH of these boxes, then conservatively bound `W` over each candidate using interval arithmetic and combine candidates with `max`. If a query misses every water box, it is dry; if a bound is unknown, don’t cull it. This follows R24’s proposed separate `W`, but adds concrete bounds and dimensions ([R24](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Research24/REPORT.md:27>)).
**Game references, at the player-facing level:** Minecraft represents water as blocks; it spreads into nearby air, while generated rivers sit at sea level and are calm ([water](https://www.minecraft.net/en-us/article/block-week-water), [rivers](https://www.minecraft.net/en-us/article/around-block--river)). Astroneer’s official notes describe its Simulated Aquarium as a decoration that needs no water, not a terrain stream ([Megatech notes](https://blog.astroneer.space/patch-notes/megatech-update/)). Enshrouded is a more ambitious contrast: its update describes dynamically simulated, redirectable water and swimming/diving ([Wake of the Water](https://enshrouded.com/en-US/news/enshrouded-wake-of-the-water-update)). Valheim documents ocean sailing by boat ([FAQ](https://valheim.com/faq/)). No Man’s Sky emphasizes water rendering and underwater play ([Worlds Part II](https://www.nomanssky.com/worlds-part-ii-update/)). Deep Rock Galactic’s cited update treats frozen lakes as slippery hazards ([update notes](https://www.deeprockgalactic.com/updatesold)). These examples inform the experience; they do not establish those games’ internal water implementations.
## Unreal minimum
The smallest local implementation is a separate water surface mesh generated from the Core records. The plugin already uses `URealtimeMeshComponent` for terrain tiles and declares its module dependency ([VoxelWorld.h:424](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelWorld.h:424>), [VoxelForge.Build.cs:75](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/VoxelForge.Build.cs:75>)); reuse it for water tiles with separate material and no surface collision. The bed remains the walkable collider. For VR, give the surface clear reflection/Fresnel and refraction cues, subtle normal motion, and a readable shoreline. Keep wave and screen-space distortion modest.
Unreal’s Water plugin offers `AWaterBodyRiver`, `AWaterBodyLake`, and `AWaterBodyCustom`; its Water Zone generates water mesh tiles. Its automatic terrain brush works with Landscape edit layers, so it won’t carve these voxel beds for us. A custom water body can use a mesh for a pool, with the bed carved separately ([Water Body Actors](https://dev.epicgames.com/documentation/en-us/unreal-engine/water-body-actors-in-unreal-engine)). The plugin is not listed in VoxelForge’s module dependencies; whether the host project enables it is unverified. `UProceduralMeshComponent` is another runtime mesh option ([API](https://dev.epicgames.com/documentation/unreal-engine/API/Plugins/ProceduralMeshComponent/UProceduralMeshComponent?lang=en-US)), but the existing `URealtimeMeshComponent` is the smaller project fit.
This MVP’s 0.60 m pool and shallow stream don’t need swimming or underwater post-processing to read as water. If deeper pools are later allowed, `APhysicsVolume` exposes `bWaterVolume` and `UCharacterMovementComponent` supports swimming ([APhysicsVolume](https://dev.epicgames.com/documentation/unreal-engine/API/Runtime/Engine/APhysicsVolume?lang=en-US), [CharacterMovementComponent](https://dev.epicgames.com/documentation/unreal-engine/API/Runtime/Engine/UCharacterMovementComponent?lang=en-US)). Unreal’s Water Body underwater post-process relies on collision to detect submersion ([UWaterBodyComponent](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Plugins/Water/UWaterBodyComponent)).
## Walkability
Keep the water path outside the route corridor by default. The current Core route audit checks a 0.34 m radius, 1.76 m capsule and a 15° maximum grade, but checks density and support, not water depth ([API.md:140](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/API.md:140>)). Extend that audit to water.
I recommend allowing an **intentional ford up to 0.30 m deep**, measured from its walkable bed to the sheet, as a non-swimming crossing. Deeper water must be bypassed or bridged. Keep the 0.60 m pool outside the route corridor. If “dry route” means no wet crossing at all, use the bridge or bypass every time.
## Slices and verification
1. **Core records and bounds:** add fixed-point records, deterministic path output, `W` queries, interval bounds, and BVH. Capture a plan view with the path and bounds overlaid; compare record digests across peers and worker counts.
2. **Carved bed:** apply the stream and pool cuts to density. Capture channel and pool cross-sections; audit route capsule clearance, grade, support, and water depth.
3. **Water mesh:** emit a separate pool disk and stream sheet. Capture the stream-to-pool join, shoreline, and tile boundaries from above and at walking height.
4. **Unreal:** stream local water tiles, apply the material, and add swimming volume/post-process only if deeper water is approved. Capture headset views of the ford, pool edge, and—if implemented—submersion.
I’m unsure whether the missing reference image exists outside this checkout, whether the host project has the Water plugin enabled, and whether the proposed dimensions and 2% grade suit the intended scene. The current route audit also has no water-depth check.
**Owner questions:** Can you provide the reference image’s path or attach it again? Is a 0.30 m ford acceptable, or must the mouth-to-mouth route stay entirely dry?
@@ -0,0 +1,56 @@
# VoxelForge R27 — water MVP research
## What exists
- **Core:** `BuildSurfaceStratumPlan` resolves one fixed water level and enable flag per stratum. `Heightfield2D::point` returns `waterSurfaceSubvoxels` and, for evaluator v2+, a `waterFillSubvoxels` value only in open space between the local ground and that level. It is a useful starting channel, but it describes a stratum-wide vertical fill; there are no pool or stream records. [`WorldAssemblyStratumPlanV1` and sample fields](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h:560>), [`BuildSurfaceStratumPlan`](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp:320>), [`Heightfield2D::point`](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/WorldAssemblerInternal.h:2576>)
- **Bounds and meshing:** Core’s `FieldInterval` bounds density, not water; it has no water interval query or water-body BVH. The Core contract mentions a water channel, but the current bounds do not cover it. The existing terrain mesh and collision paths are density based, so water needs its own surface-mesh path. [`FieldInterval`](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h:1301>), [Core interval contract](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/API.md:120>)
- **Unreal:** `UVoxelContentManager::UpdateWater` uses the player’s stratum water level to place one large, movable `/Engine/BasicShapes/Plane` at the player’s snapped cell, scaled to cover the view. The component has collision disabled and uses the stratum’s `WaterMaterial`. `AVoxelWorld::Tick` calls it each tick. The asset comment explicitly describes water as aesthetic, with no swim or flow simulation. [`UpdateWater`](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelContentManager.cpp:2499>), [`WaterMaterial` and water settings](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Public/VoxelStrateDefinition.h:211>), [tick call](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelWorld.cpp:7038>)
- **Reusable pieces:** retain Core’s fixed-point sampling, stratum water datum, `WaterMaterial`/`WaterColor`, and the terrain bed’s normal collision. Replace the global plane for this profile with a local water-body renderer. Legacy `Underwater` currently builds the same tunnel density stack as `TunnelNetwork`; its water flag is consumed on the rendering side. The atmosphere manager provides fog and skylight, but I found no water-specific swim handling or underwater post-processing. [`Underwater` dispatch](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelGenerator.cpp:2638>), [`ApplyFogSky`](</home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelAtmosphereManager.cpp:127>)
## Design
Resolve the terrain and mouth route first. At plan time, trace a deterministic steepest-descent path from a chosen source toward the pool across the resolved surface, then store the result as a fixed polyline or spline. Use Core’s integer coordinates, fixed sampling steps and tie-breaking order; if descent reaches a local minimum, use a deterministic path search to the basin. Store the resolved path, elevations, width and stable body ID in the plan so clients can reproduce or receive the same geometry. This honors the earlier downhill-path preference without simulating water.
Carve a shallow channel along that path, joining it into a basin with a **flat, fixed pool surface**. As initial design ranges, try a 1–2 m stream, a bed about 0.3–0.5 m below adjacent ground, and 0.15–0.3 m of water over the bed. The pool can start in R24’s 4–12 m radius and 0.3–1 m depth range; the shoreline is where the surrounding bank meets the fixed surface. Make stream elevation descend into the pool and record a stable downstream direction for its material. [R24 water proposal](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Research24/REPORT.md:25>), [R20 pool dimensions and route guidance](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Research20/REPORT.md:133>)
Add a separate positive-inside occupancy field `W` for the pool and stream. Return occupancy and local surface height per query, independently of rock density. Give water its own conservative interval query and BVH over body bounds; use those bounds to schedule water-only tiles even where the rock field classifies as air. Emit a separate water surface mesh from the body records or water field. The density mesher should continue to own rock geometry and collision. This follows R24’s proposed pool/stream records and water-specific tile scheduling. [R24 records and mesh proposal](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Research24/REPORT.md:27>)
Comparable games offer different scopes; these references describe player-facing behavior, not necessarily their internal representations:
- **Minecraft** treats water as blocks that spread into adjacent air; its generated rivers are calm and held at sea level. That is a useful example of authored water bodies without visible flow simulation. [Water](https://www.minecraft.net/en-us/article/block-week-water), [Rivers](https://www.minecraft.net/en-us/article/around-block--river)
- **Astroneer:** official material I found describes fluid canisters and a simulated aquarium that needs no water; separate **STARSEEKER** material advertises swimming and diving. I found no official outdoor river or pool system for mainline Astroneer. [Megatech notes](https://blog.astroneer.space/patch-notes/megatech-update/), [STARSEEKER overview](https://blog.astroneer.space/p/starseeker-direct-recap/)
- **Enshrouded** is the full-simulation comparison: its 2025 update adds dynamic water, flow redirection, swimming, diving and oxygen gameplay. That is well beyond this static MVP. [Wake of the Water](https://enshrouded.com/en-US/news/enshrouded-wake-of-the-water-update)
- **Valheim** uses water as world traversal, including sailing; official patch notes also track water VFX and water damage. Those notes do not document its rendering implementation. [Official FAQ](https://www.valheimgame.com/faq/), [Patch 1.0.14](https://www.valheimgame.com/news/patch-1-0-14/)
- **No Man’s Sky** is a richer presentation reference: its official notes describe enhanced water rendering, waves, deep-water hazards and underwater effects. [Worlds Part II](https://www.nomanssky.com/worlds-part-ii-update/), [The Abyss](https://www.nomanssky.com/abyss-update/)
- **Deep Rock Galactic** presents frozen lakes as slippery environmental hazards, a useful cave-navigation comparison rather than a flowing-water model. [Official updates](https://www.deeprockgalactic.com/updatesold)
## Unreal minimum
Use local pool and stream surface meshes with the existing water material as a starting point, plus visible bed, bank and shoreline geometry to establish depth. Add restrained reflection/Fresnel, water tint and depth cues; keep directional flow cues stable and avoid strong animated motion in VR.
Keep the water surface non-colliding. The carved terrain bed remains the walking collision. Add a query-only water volume for immersion state; if the pool is deep enough to swim in, that volume can also switch character movement to swimming. Apply a subtle underwater post-process when the player’s camera is inside the body and below its surface. If the MVP stays shallow, swimming and underwater effects can wait.
Unreal’s Water plugin documents separate spline-defined water bodies, generated surface meshes, depth/flow queries and underwater post-processing. Its automatic terrain carving is Landscape-brush based, so it would not replace the Core bed and occupancy work here. [Water System](https://dev.epicgames.com/documentation/unreal-engine/water-system-in-unreal-engine), [Water Body Actors](https://dev.epicgames.com/documentation/en-us/unreal-engine/water-body-actors-in-unreal-engine)
## Walkability
Keep the mouth-to-mouth capsule route supported and never dependent on swimming. Core already audits a 0.34 m radius, 1.76 m high capsule, support and a 15° maximum grade, but that audit does not evaluate water depth. Extend the route checks to the water channel. A ford can be allowed where water over the walking bed is at most about **0.3 m**; any deeper crossing needs a dry bypass or bridge. [Route audit contract](</home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/API.md:140>)
## Slices and evidence
1. **Core records:** Add stable pool/stream records, occupancy and surface queries, intervals and BVH. Verify determinism and bounds; capture a diagnostic cross-section showing water and rock separately.
2. **Carved bed:** Add the channel and basin to the resolved terrain. Verify bank/shoreline shape, capsule support and grade; capture an oblique view and a cutaway.
3. **Water mesh:** Generate the pool and stream surfaces separately from density, including water-only tiles. Verify body bounds and tile joins; capture the whole source-to-pool view, shoreline and ford/bridge.
4. **Unreal:** Add local rendering, immersion volumes and optional underwater presentation. Check host/client agreement; capture eye-level, waterline and underwater views where applicable.
No scripts, tests, builds, binaries or edits were made.
**Reference image:** I could not find an image under `Docs`; that directory contains archived Markdown only. The nearest file is [owner_normals_pool_before.png](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/data/owner_normals_pool_before.png), an older global-plane capture rather than a local stream-to-pool reference.
## Owner questions
- Should the first pool remain wadeable at ≤0.3 m, or should the MVP include swimming and underwater post-processing?
- Can you point me to the missing `Docs` reference image or restore it in this checkout?