Phase 7 start checkpoint

This commit is contained in:
2026-10-30 16:47:10 +03:00
parent 65066e6d29
commit 7e0a74d837
+159 -25
View File
@@ -5786,33 +5786,167 @@ boarding-standoff snap on NPC 1099511627776 and no rotation.
stats and persistence layers exist; architecture can be
designed earlier).
### Phase 7 — CellGrid stair generation - before interiors
### Phase 7 — CellGrid stair generation — before interiors
Multi-storey CellGrid buildings (`height` > 1) generate stacked floors
with no connection between them — interiors above ground level are
unreachable. Add stairs to the CellGrid generator (engine-level, not
taxi-specific):
**Goal.** Multi-storey CellGrid buildings (`height` > 1) currently
generate stacked floors with no connection between them, so interiors
above ground level are unreachable. Add stairs to the CellGrid
generator — **engine-level, not taxi-specific** — so that both the
player (Jolt character) and NPCs (Recast navmesh) can travel between
every floor. Phase 8's interior generator consumes the result.
- Stair cell: a cell flag (like the existing door/window flags) marking
a stairwell; the generator cuts the matching opening in the
floor/ceiling above and emits a stair mesh (steps sized within the
Jolt character's and Recast's climb limits) plus walkable colliders.
- Placement rules: stairwell position comes from the room layout
(RoomLayoutSystem integration) or an explicit cell flag in
hand-authored grids; a stairwell column stacks through all floors.
- Navmesh: stairs rasterize as walkable (Recast step/slope limits), so
NPCs can path between floors; verify doorway-area costs and door
obstacles still behave.
- should support stairwells and explicit floor connections between rooms where a room has stair in it which connects to above location. Like single-floor stairwell. Floors and ceilings are removed for the stair to pass. The space between floors should be hidden by geometry to avoid gaps.
- should support exterior stairs outside walls (like in many motels)
- should support procedural material the same as walls/floors, using squares for walls and floors by default, depending on surface.
- Editor + serialization + Lua binding, per the component rules
(serialized flag, Cell Grid editor toggle, `cellgrid_door_test`-style
headless coverage).
- Headless: multi-floor grid with a stairwell — character walks from
ground floor to the top floor (physics), navmesh query finds a
ground->top path; grids without stair flags are unchanged.
- from DSL and scene components point of view, the easiest way to create stairwell would be to create a room with type of stairwell. However sometimes for lobby rooms we want a large stair which leads to next floor, like in some hotels, theatres, administrative buildings... Needs research.
**Status:** planned (decomposed 2026-10-30); nothing implemented yet.
**How to read this phase.** 7.1 is the vertical slice: one hand-
authored grid, one stairwell, real geometry. 7.2 proves traversal.
7.3 adds the authoring paths (rooms, DSL, editor, Lua). 7.4 and 7.5
are independent extensions. Every slice ends buildable with headless
verification, and every slice keeps the global invariant:
> **Invariant:** grids without stair flags produce bit-identical
> geometry to what they produce today.
**What the code already gives us (verified 2026-10-30):**
- `CellFlags` bits 0-25 are used (`components/CellGrid.hpp`); bits
26-63 are free. Cell flags serialize as a raw `uint64` per cell, so
a new flag needs **no JSON schema change** and old scenes keep
loading. `LayoutLib::PlanFlags` is bit-identical to `CellFlags`
(static_asserted in `TownGenSystem.cpp`) — a new bit must be
mirrored there with a new assert.
- Openings are free: `buildFloorsAndCeilings` only emits a floor/
ceiling plane for cells carrying the `Floor`/`Ceiling` flag, so
clearing those flags on stair cells cuts the hole with no special
mesh surgery. Roofs are separate (`RoofComponent` children).
- Colliders follow the mesh lists in `buildPhysicsColliders` — a new
stair mesh added there gets its static collider automatically.
- Recast limits (`NavMeshComponent` defaults): `agentMaxClimb` 1.0 m
(5 voxels at `cellHeight` 0.2), `agentMaxSlope` 20 deg,
`agentRadius` 0.5 m. Stepped treads rasterize walkable; a smooth
ramp does **not** help (4 m of rise at 20 deg needs an 11 m run).
- Jolt character: no explicit step-height knob (supporting-volume
plane at -0.2 m). The proven climbing envelope is the existing
entrance stairs (`TownGenSystem::createStairs`: rise 0.18 / tread
0.30 / width 1.4 m boxes with box colliders). Step size for
interior stairs starts from those numbers and is tuned empirically
in 7.2 — do not assume Recast's 1.0 m climb means the character can
climb 1.0 m steps.
- Navmesh geometry collection drops mesh names containing
"ceiling"/"frame"/"furniture" (`isNavMeshGeometry`) — stair meshes
must avoid those substrings.
- Default cell is 4 x 4 m with `cellHeight` 4 m; the floor surface
sits at `floorSurfaceY()` = 0.2 m above the cell base, so a
floor-to-floor connection rises exactly `cellHeight`.
**Shared geometry contract (all slices):**
- A **stair connection** between level y and y+1 occupies one or more
cells at the same (x, z) on both levels: the generator clears
`Ceiling` at level y and `Floor` at level y+1 on those cells and
fills the opening with a stepped stair mesh plus walkable
colliders. A **stairwell column** chains connections upward through
consecutive floors at the same (x, z).
- Steps: tread 0.30 m, rise 0.18-0.25 m (exact value settled in 7.2),
flight width >= 1.2 m (twice the Recast agent radius plus margin).
- One 4 x 4 m cell fits a **dogleg** (two flights + mid-landing);
a **straight flight** needs two or more cells in a row. The
generator picks the layout from the stair cell run's shape.
- The space between floors around the opening is closed by geometry
(shaft sides and top cap): no visible void, no gaps at slab edges.
How the top cap interacts with the per-row-run roofs of cut
footprints is settled in 7.1.
- Stairs use the grid's procedural material like walls/floors:
treads default to the floor rect, shaft sides to the wall rect
(square UV mapping per surface), with a serialized `stairRectName`
override.
#### Phase 7.1 — Core stairwell cells (vertical slice)
Hand-authored grids only; no DSL, no RoomLayoutSystem yet.
- New `CellFlags::StairWell` bit (mirrored `PlanFlags` bit + static
assert). A stair cell marks "a stair passes through here"; the
column/run shape comes from the flagged cells themselves.
- `buildCellGrid` pass: cut the openings per the geometry contract,
emit straight-flight and dogleg stair meshes + shaft closure, add
them to the collider lists, apply the procedural-material UV
mapping. Serialized `stairRectName` field (empty = floor/wall
rect defaults).
- Serialization: flags ride the existing raw-uint64 cell format;
`stairRectName` round-trips like the other rect names.
Verify:
- `cellgrid_door_test`-style case: flag + `stairRectName` round trip,
old scenes load with defaults.
- New terrain-tests step (`TERRAIN_TEST_FILTER=cellGridStairs`):
multi-floor grid with a stairwell builds openings, stair mesh and
colliders; a grid without stair flags is unchanged.
#### Phase 7.2 — Traversal acceptance (physics + navmesh)
- Character physics: tune rise/tread inside the proven envelope so
the Jolt character climbs without snagging; verify headroom under
landings and at the top opening.
- Navmesh: stairs rasterize walkable (per the Recast limits above);
doorway-area costs and locked-door obstacles keep behaving (the
`navMeshDoors` step stays green).
Verify:
- Headless: a character walks from the ground floor to the top floor
over the stairs (physics), and a navmesh query finds a
ground-to-top path. No-stair grids: no path between floors, as
today.
#### Phase 7.3 — Authoring paths (rooms, DSL, editor, Lua)
- **RoomLayoutSystem:** a room of type `stairwell` marks its cells;
single-floor stairwells connect a room to the level directly above
it (floors/ceilings removed for the stair to pass, per the shared
contract). A stairwell room column stacks through all floors it
spans. `processRoom` must not re-stamp `Floor`/`Ceiling` over the
openings it just cut.
- **Layout DSL:** `(room ... :type stairwell)` records the same
cells in `BuildingPlan` (rooms-first claims skip the opening
flags; filled-shell mode stays metadata + flags). `fillBuildingCells`
needs no change — flags flow through verbatim.
- **Editor:** Cell Grid editor per-cell stair toggle (next to the
door/window toggles) plus the `stairRectName` widget.
- **Lua:** stair flag/rect exposed per the component rules.
- Docs (`editScene/AGENTS.md`, this file) updated with the slice.
Verify:
- DSL grammar probes in `road_geometry_overlap_test`; Lua round trip
in `component_lua_test`; a DSL-authored two-storey stairwell
building passes the 7.1/7.2 checks.
#### Phase 7.4 — Exterior stairs (motel-style)
- Stairs outside the shell walls: exterior corridors/galleries on
upper floors reached by an external flight (as in many motels).
Reuses the 7.1 step geometry and materials; placement is driven by
authored cells/DSL, not by a town-wide rule.
Verify:
- Headless: character climbs from terrain level to the upper
gallery and enters through its exterior door; navmesh connects
terrain to the gallery.
#### Phase 7.5 — Grand / lobby stairs (research, then implement)
Open design question carried over from the original phase notes:
typing a room `stairwell` is the easiest DSL/component authoring
path, but lobbies of hotels, theatres and administrative buildings
want a **large stair inside an ordinary room** — wide flights,
possibly curved or branching, not a utilitarian shaft. Research
first: how a wide multi-cell flight is authored (room option vs.
dedicated cells), whether the 7.1 straight/dogleg layouts suffice
when scaled up, and what railing/balustrade geometry is needed.
Only then implement.
**Explicitly out of scope for Phase 7:** interior scene generation
and door wiring (Phase 8), spiral stairs, elevators, and town-wide
rules for where stairwells go (layouts decide; default layouts get
stairwells when Phase 8 makes upper floors enterable).
### Phase 8 — Enterable buildings (on-the-fly interiors)