Cluster A's investigation pinned #86 (picker) as structural and closed it (Phase B). #84 and #85 both pinned on missing indoor cell tracking; Phase D promoted CellId via AABB containment which un-stuck the spawn-in-building case (closes #84 partially) but proved too tight for threshold/doorway cells to keep CellId indoor during normal walking. The proper fix is retail's portal-based cell traversal; filed as a new ISSUES.md issue (see body) for the follow-up phase. Phase E diagnostic infrastructure ([cell-cache] + extended [indoor-bsp]) stays in place as scaffolding for that work. ISSUES.md: #86 → Recently closed. #84 status updated to PARTIAL with resolution paragraph. #85 status update note added. New issue #87 filed for portal-based indoor cell tracking. Roadmap: Cluster A added to Recently shipped with partial-ship note. Forward entry added for the portal-traversal follow-up under Phase G. CLAUDE.md: current-phase paragraph updated to reflect Cluster A partial ship. Next phase deferred to Claude's choice in a future session. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 KiB
Indoor walking Phase 1 — BSP cluster (Cluster A) — handoff (2026-05-19)
Date: 2026-05-19.
Branch: claude/competent-robinson-dec1f4 (commits land here; merge to main handled by controller).
Predecessor: Indoor lighting + rendering Phase 2 (fix) — floors now render in Holtburg Inn. Nine pre-existing indoor bugs surfaced the moment floors were visible; this cluster addresses the collision/interaction subset (#84, #85, #86) and adds diagnostic infrastructure for the follow-up portal-traversal phase.
Plan: docs/superpowers/plans/2026-05-19-indoor-walking-phase1-bsp-cluster.md.
TL;DR
Cluster A shipped partially. Three of the five planned phases (A, B, D)
produced real behavior changes; two (C — obstacle audit — and E — cell-cache
diagnostics) are diagnostic/research phases. The cluster's investigation
confirmed that the wall-collision failures (#84, #85) all root in one cause:
the player's CellId is never promoted to an indoor cell during normal
walking, so the indoor-BSP collision branch in TransitionTypes.FindEnvCollisions
never fires. Phase D implemented an AABB-containment shortcut that resolves
the specific "spawn inside a building and be stuck above the floor" case but
proved too tight to keep CellId promoted through threshold/doorway cells
during normal outdoor→indoor entry.
#86 (click selection penetrates walls) is fully closed — a clean,
self-contained fix in WorldPicker.
#84 is partially closed — the spawn-in-building symptom is gone; the remaining wall-collision symptom during normal walking is tracked under the new #87.
#85 remains open; its root cause is confirmed identical to #84's remaining symptom and is also tracked under #87.
#87 (indoor portal-based cell tracking) is filed and ready for the follow-up phase.
Commits
| # | SHA | Subject | Phase |
|---|---|---|---|
| 1 | 18a2e28 |
docs(plan): implementation plan written |
Plan doc |
| 2 | 27d7de1 |
feat(physics): Cluster A — indoor BSP collision probe |
Phase A |
| 3 | 3764867 |
fix(picker): Cluster A #86 — cell-BSP ray occlusion in WorldPicker |
Phase B |
| 4 | 4e308d5 |
test(picker): Cluster A #86 — screen-rect cell-occlusion tests |
Phase B follow-up |
| 5 | c19d6fb |
fix(physics): Cluster A #84 + #85 — indoor cell tracking |
Phase D |
| 6 | fda6af7 |
feat(physics): Cluster A — cell-cache diagnostic |
Phase E (1st) |
| 7 | 1f11ba9 |
feat(diag): Cluster A — extend [cell-cache] with AABB + bsphere + recursive poly count |
Phase E (2nd) |
Build: clean on all commits.
Tests: dotnet test shows the same 8 pre-existing failures in
AcDream.Core.Tests (MotionInterpreter / BSPStepUp / etc., unchanged across
the entire cluster). All targeted test projects green. Phase B follow-up
adds screen-rect occlusion tests; Phase D adds RegisterCellStructForTest
helper used by caller-side tests.
What shipped
Phase A — [indoor-bsp] probe
New PhysicsDiagnostics.ProbeIndoorBspEnabled toggle (env var
ACDREAM_PROBE_INDOOR_BSP + DebugPanel checkbox under
ACDREAM_DEVTOOLS=1). When enabled, logs one [indoor-bsp] line each time
TransitionTypes.FindEnvCollisions takes the indoor-cell branch —
i.e., when CellId is an EnvCell id and the BSP contains physics polys. The
probe serves as a presence detector: if [indoor-bsp] never fires during
indoor walking, the BSP is not being consulted at all.
Phase B — WorldPicker cell-BSP ray occlusion (closes #86)
New CellBspRayOccluder class (in src/AcDream.App/Rendering/) computes
NearestWallT: the smallest ray parameter at which the pick ray intersects
any cached EnvCell BSP polygon. Both WorldPicker.Pick overloads now accept
an optional cellOccluder callback and filter out any hit candidate whose
ray T exceeds NearestWallT. The occluder is wired from GameWindow using
the PhysicsDataCache cell structs that Phase D also extends.
Before Phase B: clicking through a wall from the outside selected NPCs/items
inside the building — WorldPicker.BuildRay + Pick (Phase B.4b) tested only
entity AABBs and scenery BSPs, not EnvCell BSP geometry.
After Phase B: entities behind the nearest wall from the camera's perspective are filtered out of the candidate set. Screen-rect unit tests verify the filter across hit/miss/occlusion scenarios.
Phase D — AABB containment for indoor CellId (partial #84 fix)
PhysicsEngine.ResolveOutdoorCellId is extended with an indoor
cell-containment scan. After resolving the outdoor cell, the method checks
whether the player's world position falls inside any cached CellPhysics
AABB; if so, CellId is promoted to that EnvCell. This enables the
FindEnvCollisions indoor-BSP branch.
New PhysicsDataCache.TryFindContainingCell(worldPos) does the AABB scan.
New CellPhysics.WorldAabb caches the cell-local AABB in world space on
first call (transforms the BSP bounding sphere's local AABB by the cell
origin). New RegisterCellStructForTest helper allows unit test callers to
populate the cache directly.
Also fixes the L.2e bare-low-byte preservation bug: ResolveOutdoorCellId
was silently truncating the player CellId to the low 16 bits; the fix
preserves the full 32-bit value.
What this solved: player spawning inside a building (e.g., logging in
from a position inside Holtburg cottage) no longer sees walkable=False for
hundreds of resolves with world Z=94.000. Phase D promotes CellId to the
indoor cell, the floor's BSP polys are found, the player can move.
What this did NOT solve: the [indoor-bsp] probe fires only 6 times
during an entire indoor walking session (all mid-jump, when the body happens
to be at a height that falls inside a room AABB). During normal walking on
the floor, the player's world Z is at the AABB floor level or lower —
outside the AABB for threshold/doorway cells that have only a 0.2 m Z range.
See Phase E evidence below.
Phase E — Cell-cache diagnostic infrastructure
Two commits add [cell-cache] log output (env var
ACDREAM_PROBE_CELL_CACHE, also DebugPanel). For each EnvCell in the
physics cache, the probe logs:
[cell-cache] id=0xA9B40143 physicsPolyCount=14 bspTotalLeafPolys=14
bspUnmatchedIds=0 aabbMin=(-11.60,-1.60,0.00) aabbMax=(-6.20,7.60,2.80)
bspOrigin=(0.00,0.00,0.00) bspRadius=9.97
The extended second commit adds bspTotalLeafPolys, bspUnmatchedIds,
bspOrigin, and bspRadius fields to give a complete picture of cell
geometry from the physics cache perspective. This infrastructure stays in
place as scaffolding for the portal-traversal phase.
Issue status after Cluster A
| Issue | Status | Notes |
|---|---|---|
| #84 Blocked by air indoors | OPEN (partial) | Spawn-in-building variant resolved by Phase D. Threshold/doorway wall-blocking remains open under #87. |
| #85 Pass through walls outside→in | OPEN | Root cause confirmed as same as #84 remaining symptom. See #87. |
| #86 Click selection penetrates walls | CLOSED | Phase B. WorldPicker.Pick + CellBspRayOccluder. |
| #87 Indoor portal-based cell tracking | OPEN (new) | Filed 2026-05-19. Retail-faithful fix via CObjMaint::HandleObjectEnterCell. |
Probe evidence — log file findings
launch-cluster-a-capture.log
Initial probe run with ACDREAM_PROBE_INDOOR_BSP=1. Result: zero
[indoor-bsp] lines during outdoor walking and during approach to the
Holtburg cottage doorway. This was the first confirmation that the indoor-BSP
branch was entirely gated out. The player's CellId remained an outdoor cell
for all movement.
launch-cluster-a-verify.log
Post-Phase-D run. Observed [indoor-bsp] lines only during jump frames
(6 total). When the player jumped inside the cottage, the body briefly rose
to a height inside the room AABB, CellId promoted to 0xA9B40143, and the
indoor-BSP branch fired. On landing, the body returned to floor level, fell
outside the AABB, and CellId reverted to the outdoor cell. Confirmed that
AABB containment works for the room cell when the player is mid-air, but
fails at floor level.
launch-cluster-a-cache-diag2.log
First [cell-cache] probe run (Phase E first commit). Showed all cached
cells with their physics poly counts and local AABBs. Confirmed 14 physics
polys in cell 0xA9B40143 (the room), indicating BSP geometry is present
and complete. Identified cell 0xA9B40146 as a 4-poly threshold cell.
launch-cluster-a-cache-diag3.log
Extended [cell-cache] probe run (Phase E second commit). Full data:
[cell-cache] id=0xA9B40143 physicsPolyCount=14 bspTotalLeafPolys=14
bspUnmatchedIds=0 aabbMin=(-11.60,-1.60,0.00) aabbMax=(-6.20,7.60,2.80)
bspOrigin=(0.00,0.00,0.00) bspRadius=9.97
Room cell: 2.80 m AABB height — works for mid-air player.
[cell-cache] id=0xA9B40146 physicsPolyCount=4
aabbMin=(-11.60,2.80,-0.20) aabbMax=(-10.00,7.60,0.00)
bspRadius=2.3
Threshold/doorway cell: 0.20 m AABB Z range (from -0.20 to 0.00). A standing player at local Z=0.46 m is outside this AABB. This is why AABB containment fails for normal walking through doorways.
Key conclusion: the geometry is correct and complete (14/14 polys match between physics cache and BSP leaf count). The problem is purely in the cell-ownership tracking mechanism, not the collision data itself.
Diagnostic infrastructure remaining in place
Both probes stay committed and wired. They serve as scaffolding for the portal-traversal follow-up phase:
-
ACDREAM_PROBE_INDOOR_BSP=1/ DebugPanel "Indoor BSP probe": logs one[indoor-bsp]line each timeFindEnvCollisionstakes the indoor-cell branch. After portal traversal is implemented, this probe should fire consistently whenever the player is indoors. -
ACDREAM_PROBE_CELL_CACHE=1/ DebugPanel "Cell cache probe": dumps all cached EnvCell physics data (poly counts, BSP bounding sphere, AABB, unmatched ID count). Useful for verifying that cell structs load correctly and that portal connectivity data is present.
Both are gated behind PhysicsDiagnostics static class (existing pattern
from L.2a).
Follow-up items for the portal-traversal phase
1. Implement portal-based indoor cell tracking (issue #87).
Replace PhysicsDataCache.TryFindContainingCell AABB containment with retail's
CObjMaint::HandleObjectEnterCell portal traversal. When the player crosses
a cell portal boundary, CellId propagates through CEnvCell portal
connectivity data. PDB symbols in docs/research/named-retail/acclient_2013_pseudo_c.txt
and struct definitions in docs/research/named-retail/acclient.h lines
31715-31726 (CCellStructure shape). The retail reference implementation
is the right oracle — do not guess at the traversal algorithm.
2. Audit-trail note: add retail PDB symbol citations to TryFindContainingCell.
The current implementation in src/AcDream.Core/Physics/PhysicsDataCache.cs
~line 261 is documented as a shortcut. The follow-up phase should add
the PDB symbol citation (e.g., // retail: CObjMaint::HandleObjectEnterCell // docs/research/named-retail/acclient_2013_pseudo_c.txt:XXXXX)
per the Phase D code-review I1 note, so future readers know this is intentionally
replacing an interim implementation.
3. Consider renaming ResolveOutdoorCellId → ResolveCellId.
The method now handles both outdoor and indoor cell resolution. The rename
is low-risk (one call site in PhysicsEngine.cs) and would reduce the
cognitive overhead for the next phase's author. Noted as a Phase D code-review
M2 suggestion — do it in the same commit as the portal-traversal implementation
to keep the rename and the semantic change together.
State at handoff
- Branch:
claude/competent-robinson-dec1f4, 7 commits of implementation/test/diagnostic work. - Build state:
dotnet build -c Debugclean. - Tests: 8 pre-existing failures unchanged (MotionInterpreter / BSPStepUp baseline). All new tests green.
- Issues: #86 CLOSED; #84 PARTIAL; #85 OPEN; #87 OPEN (new).
- Diagnostic probes:
[indoor-bsp]+[cell-cache]active and wired. - Next: portal-based indoor cell tracking (#87) or M2 critical path — Claude's choice per work-order autonomy.