docs(phase): Indoor walking Phase 2 — Portal-based cell tracking shipped

Closes ISSUES.md #87 + #85 + the remaining wall-pass-through portion of
#84 (fully closes #84). Portal-graph cell traversal replaces Phase D's
AABB containment. Walking through doors promotes/demotes CellId correctly
via portal traversal; walls block from inside indoor cells; indoor walkable
plane is synthesized from the cell's floor poly so the resolver tracks
walkability correctly during indoor movement.

Files two new issues: #88 (indoor static objects vibrate — pre-existing,
spotted during Phase 2 testing) and #89 (BSPQuery.SphereIntersectsCellBsp
— follow-up to make CheckBuildingTransit retail-faithful; currently uses
radius-less PointInsideCellBsp as a documented approximation).

ISSUES.md: #87, #85, #84 moved to DONE. #88 + #89 filed.
Roadmap: Indoor walking Phase 2 added to shipped table.
CLAUDE.md: recent-phase paragraph updated to reflect Phase 2 shipped.
New handoff: docs/research/2026-05-19-indoor-walking-phase2-shipped-handoff.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-19 19:31:22 +02:00
parent eb0f772f0f
commit a9c74d153a
4 changed files with 391 additions and 88 deletions

View file

@ -237,9 +237,10 @@ to the second floor without getting stuck.
---
## #84 — Blocked by air indoors
## #84 [DONE 2026-05-19] Blocked by air indoors
**Status:** OPEN (partial fix 2026-05-19)
**Status:** DONE
**Closed:** 2026-05-19
**Severity:** HIGH (blocks indoor navigation)
**Filed:** 2026-05-19
**Component:** physics, collision
@ -274,58 +275,68 @@ enables the `FindEnvCollisions` indoor-BSP branch. This resolved the
"spawn in building and be stuck above the floor" variant of #84
player's CellId now promotes to the interior cell on spawn-in, the floor
is walkable, and the player can move freely. The "invisible air obstacle"
symptom for rooms the player walks INTO from outside is now superseded by
the root cause in #87 (AABB containment is too tight for threshold/
doorway cells to keep CellId promoted during normal walking). That
remaining symptom will be resolved by the portal-based cell tracking
fix.
symptom for rooms the player walks INTO from outside was tracked under #87
and required portal-based cell tracking.
**Resolution (2026-05-19 full · `1969c55, aad6976, 069534a, 702b30a, 3ffe1e4, eb0f772`):**
Indoor walking Phase 2 replaced AABB containment with portal-graph cell traversal
(`CellTransit.FindCellList` + `CheckBuildingTransit`). CellId now promotes to indoor
cells via portals and remains promoted during normal walking through doorways. Indoor
cell-BSP collision fires consistently. Indoor walkable plane synthesized from floor
poly (`TryFindIndoorWalkablePlane`) so the resolver tracks walkability correctly when
the player is standing on an indoor floor. User visually verified at Holtburg cottage:
walls block from inside, multi-room navigation works, walking outdoors through a door
works. Issue fully closed.
---
## #85 — Pass through walls from outside→in
## #85 [DONE 2026-05-19 · 1969c55, aad6976, 069534a, 702b30a, 3ffe1e4, eb0f772] Pass through walls from outside→in
**Status:** OPEN
**Severity:** HIGH (gameplay-breaking)
**Status:** DONE
**Closed:** 2026-05-19
**Commits:** `1969c55, aad6976, 069534a, 702b30a, 3ffe1e4, eb0f772`
**Filed:** 2026-05-19
**Component:** physics, collision
**Description:** Approaching a building from the outside, the player
**Resolution (2026-05-19 · Indoor walking Phase 2):** The root cause (CellId never promoted
to the indoor cell during outdoor→indoor walking) was resolved by portal-graph cell
traversal in `CellTransit.CheckBuildingTransit`. Once `CellId` promotes to the indoor
cell, the indoor-BSP collision branch in `FindEnvCollisions` fires for approaches from
both inside and outside. User visually verified walls block from outside (player must
use the door portal to enter). See #87 and handoff:
[`docs/research/2026-05-19-indoor-walking-phase2-shipped-handoff.md`](2026-05-19-indoor-walking-phase2-shipped-handoff.md).
**Original description:** Approaching a building from the outside, the player
can walk THROUGH walls into the interior — one-directional wall
collision. From the inside trying to exit, the wall does block.
**Root cause / status:** Cell BSP polygons likely have one-sided
normals (front-facing only). Approach from the inside hits the front;
approach from the outside hits the back which BSP traversal treats as
"behind the plane" → no collision. Retail handles this via two-sided
collision polys or per-poly back-face handling.
**Files:**
- `src/AcDream.Core/Physics/BSPQuery.cs`
- `src/AcDream.Core/Physics/TransitionTypes.cs` (`FindObjCollisions` cell
branch).
**Acceptance:** Walking into an inn wall from outside collides; player
must enter via the door portal.
**Status update (2026-05-19):** The root cause is now pinned as the
same failure as #84's remaining symptom — `CellId` isn't promoted to
the indoor cell during normal outdoor→indoor walking because AABB
containment is too tight for threshold/doorway cells. Without CellId
in the indoor cell, the indoor-BSP collision branch in
`FindEnvCollisions` never fires regardless of approach direction.
See new issue #87 (portal-based indoor cell tracking) for the
retail-faithful fix.
The root cause was pinned (Cluster A 2026-05-19) as the same failure as
#84's remaining symptom — `CellId` wasn't promoted to the indoor cell
during normal outdoor→indoor walking because AABB containment was too
tight for threshold/doorway cells. Without CellId in the indoor cell,
the indoor-BSP collision branch in `FindEnvCollisions` never fired
regardless of approach direction.
---
## #87 — Indoor cell tracking uses AABB containment instead of portal traversal
## #87 — [DONE 2026-05-19 · 1969c55, aad6976, 069534a, 702b30a, 3ffe1e4, eb0f772] Indoor cell tracking uses AABB containment instead of portal traversal
**Status:** OPEN
**Severity:** HIGH
**Status:** DONE
**Closed:** 2026-05-19
**Commits:** `1969c55, aad6976, 069534a, 702b30a, 3ffe1e4, eb0f772`
**Filed:** 2026-05-19
**Component:** physics
**Description:** `PhysicsDataCache.TryFindContainingCell` promotes the
**Resolution (2026-05-19 · Indoor walking Phase 2):** Portal-graph cell traversal
(`CellTransit.FindCellList` + `CheckBuildingTransit`) replaced the AABB containment
shortcut. Player CellId now correctly promotes to indoor cells via portals;
indoor cell-BSP collision branch fires consistently; walls block from inside.
Outdoor→indoor entry via `BuildingPhysics` + `BldPortalInfo` (`CheckBuildingTransit`)
wires the building-shell portal graph. Indoor walkable plane synthesized from the
cell's floor poly so the resolver tracks walkability during indoor movement (`TryFindIndoorWalkablePlane`).
See handoff: [`docs/research/2026-05-19-indoor-walking-phase2-shipped-handoff.md`](2026-05-19-indoor-walking-phase2-shipped-handoff.md).
**Original description:** `PhysicsDataCache.TryFindContainingCell` promotes the
player's `CellId` to an indoor EnvCell when their world position falls
inside any cached cell's local AABB. This is too tight to keep `CellId`
promoted to an indoor cell during normal walking. Threshold/doorway cells
@ -338,34 +349,44 @@ physics is unreliable. The retail fix is portal-based cell traversal —
when the player crosses a cell portal boundary, the cell ownership
propagates through portal connectivity data in `CEnvCell`.
**Evidence:** `launch-cluster-a-cache-diag3.log` (Cluster A Phase E
capture). Cell `0xA9B40143` (real room) has
`physicsPolyCount=14 bspTotalLeafPolys=14 bspUnmatchedIds=0
aabbMin=(-11.60,-1.60,0.00) aabbMax=(-6.20,7.60,2.80)` — geometry is
complete and the AABB spans 2.8 m height, which works. Cell `0xA9B40146`
(threshold/doorway) has `physicsPolyCount=4
aabbMin=(-11.60,2.80,-0.20) aabbMax=(-10.00,7.60,0.00)` — Z range is
only 0.2 m; a standing player is always outside it. Only 6 `[indoor-bsp]`
lines fired across an entire indoor walking session (all during mid-jump
frames when the player was briefly inside the room AABB at jump height).
---
## #88 — Indoor static objects vibrate (bookshelves, open furnaces)
**Status:** OPEN
**Severity:** MEDIUM (visual jitter; doesn't block gameplay)
**Filed:** 2026-05-19
**Component:** rendering, animation
**Description:** Static objects inside cells (bookshelves, open furnaces, possibly other interior props) show per-frame transform jitter / vibration. Pre-existing (user noticed before Phase 2 shipped). Likely candidates:
1. `EntityScriptActivator.OnCreate/OnRemove` firing repeatedly as the player's CellId promotes/demotes near cell boundaries (less likely after Phase 2's portal-based tracking — but worth investigating).
2. Per-part transforms for cell-static `WorldEntity` instances getting recomputed each frame with floating-point drift.
3. Particle-emitter offsets accumulating instead of resetting.
**Files to investigate:**
- `src/AcDream.App/Rendering/Vfx/EntityScriptActivator.cs` — OnCreate/OnRemove call patterns
- `src/AcDream.App/Rendering/GpuWorldState.cs` — entity transform updates per frame
- `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs` — per-batch transform composition
**Acceptance:** Indoor static objects render stable (no per-frame jitter).
---
## #89 — Port BSPQuery.SphereIntersectsCellBsp for retail-faithful CheckBuildingTransit
**Status:** OPEN
**Severity:** LOW (Phase 2 ships with a documented approximation)
**Filed:** 2026-05-19
**Component:** physics
**Description:** Retail's `CEnvCell::check_building_transit` uses `CCellStruct::sphere_intersects_cell` — a radius-aware sphere-vs-BSP test that returns Inside/Crossing/Outside. Phase 2's `CellTransit.CheckBuildingTransit` uses `BSPQuery.PointInsideCellBsp` (radius-less, tests only the sphere CENTER). Practical effect: outdoor→indoor entry fires ~sphereRadius (~0.48m) deeper into the doorway than retail. The sphereRadius parameter is plumbed through but currently unused.
**Files:**
- `src/AcDream.Core/Physics/PhysicsDataCache.cs` (`TryFindContainingCell`,
approximately line 261)
- `src/AcDream.Core/Physics/PhysicsEngine.cs` (`ResolveOutdoorCellId`,
approximately line 238)
- `src/AcDream.Core/Physics/TransitionTypes.cs` (`FindEnvCollisions` cell
branch, approximately line 1188)
- `src/AcDream.Core/Physics/CellTransit.cs::CheckBuildingTransit` (line ~162)
- `src/AcDream.Core/Physics/BSPQuery.cs::PointInsideCellBsp` (line ~940) — existing point test to model the new sphere variant after
**Retail reference:** PDB symbols `CObjMaint::HandleObjectEnterCell` and
`CEnvCell` portal data. See `docs/research/named-retail/acclient.h` lines
31715-31726 for `CCellStructure` shape; `acclient_2013_pseudo_c.txt` for
the implementations.
**Acceptance:** Player walking from outside the Holtburg cottage into the
interior crosses portals and `CellId` updates accordingly; walls block
from both inside and outside; the `[indoor-bsp]` probe fires consistently
during indoor walking (not just during mid-jump frames).
**Acceptance:** `CellTransit.CheckBuildingTransit` calls a new `BSPQuery.SphereIntersectsCellBsp(node, sphereCenter, sphereRadius)` that returns `Inside`/`Crossing`/`Outside`. Entry timing matches retail visually at the Holtburg cottage door.
---