fix(phys): A6.P4 door bug — AddAllOutsideCells coord convention + replay apparatus

CellTransit.AddAllOutsideCells assumed sphere coords were absolute world
coords (subtracting lbXf = 0xA9 * 192 = 32448 from the sphere position).
Production has used landblock-local coords since Phase A.1
(streaming-center landblock at world origin), so the subtraction
produced localX = -32316, gridX = -1346 → out-of-range → early return
→ ZERO outdoor cells added.

For outdoor primary cells the bug was masked by GetNearbyObjects's
radial sweep. For indoor primary cells (where #98 gates the outdoor
sweep), the door's outdoor cell 0xA9B40029 never reached
portalReachableCells, the door's BSP was never queried, and the player
walked through Holtburg cottage doors unimpeded.

Fix: AddAllOutsideCells treats worldSphereCenter as landblock-local
directly. Matches retail CLandCell::add_all_outside_cells which uses
the per-cell 6-byte landblock-relative position struct.

Existing CellTransitAddAllOutsideCellsTests + CellTransitFindCellSetTests
updated to use landblock-local sphere coords (they were the only callers
using the world-coord convention; production never did).

Apparatus shipped:
- DoorBugTrajectoryReplayTests — live-capture-driven replay harness
  that pinpointed the bug per-field at unit-test speed (<500ms iteration)
- AddAllOutsideCells_LandblockLocalSphere_AddsDoorOutdoorCell — direct
  unit test that demonstrates the fix
- FindTransitCellsSphere_IndoorExitPortal_AddsOutsideForCapturedSpherePos
  — verifies cell-portal traversal at the captured sphere position
- DoorSetupGfxObjInspectionTests.HoltburgCottage_CellPortals_DatInspection
  — dat-direct EnvCell + Environment.Cells + portal-poly inspector
- Fixture: tests/AcDream.Core.Tests/Fixtures/door-bug/live-capture.jsonl
  (tick 13558 walkthrough + tick 22760 outdoor block)

Visual verification (user-driven at Holtburg cottage door, ~50cm off-center):
- outside→inside RUN: now BLOCKS (was: walks through)
- outside→inside WALK: presumed blocks (not retested)
- inside→outside RUN: PARTIAL — body intersects door, sphere slides through
- inside→outside WALK: same partial behavior

The remaining inside→outside asymmetry is a SEPARATE bug in BSP
collision response for two-sided polygons. The [bsp-test] probe now
fires 245 times for the door entity from indoor (was 0 pre-fix) —
door IS being queried; the BSP polygon-level collision response is
the new bug. Handoff at
docs/research/2026-05-25-door-bug-partial-fix-shipped.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-25 07:53:34 +02:00
parent 6a2c432e5a
commit 28cd97be62
8 changed files with 1134 additions and 40 deletions

View file

@ -10,15 +10,14 @@ public class CellTransitAddAllOutsideCellsTests
[Fact]
public void SphereWellInsideCell_AddsOneCell()
{
// Player at world (12, 12, 0) in landblock 0xA9B40000 → cell (0,0).
// Landblock origin: 0xA9 = 169 → world X = 169*192 = 32448.
// 0xB4 = 180 → world Y = 180*192 = 34560.
// Player needs to be in cell (0,0) RELATIVE to landblock origin:
// world X = 32448 + 12 = 32460
// world Y = 34560 + 12 = 34572
// A6.P4 (2026-05-24): coords are LANDBLOCK-LOCAL (X/Y in [0, 192]).
// Player at landblock-local (12, 12, 0) → cell (0,0) in landblock 0xA9B40000.
// Pre-fix this test passed world coords (32460, 34572) and the function
// subtracted lbXf=32448 to get local 12. Post-fix the function expects
// landblock-local directly.
var candidates = new HashSet<uint>();
CellTransit.AddAllOutsideCells(
worldSphereCenter: new Vector3(32460f, 34572f, 0f),
worldSphereCenter: new Vector3(12f, 12f, 0f),
sphereRadius: 0.5f,
currentCellId: 0xA9B40001u,
candidates);
@ -30,11 +29,12 @@ public class CellTransitAddAllOutsideCellsTests
[Fact]
public void SphereAtCellEastBoundary_AddsTwoCells()
{
// Player at world (32448 + 23.6, 34560 + 12, 0) — near +X edge of cell (0,0).
// Sphere reach to localX = 23.6 + 0.5 = 24.1 → cell (1,0) added.
// A6.P4 (2026-05-24): landblock-local coords. Player at (23.6, 12, 0)
// — near +X edge of cell (0,0). Sphere reaches to local X = 23.6 + 0.5
// = 24.1 → cell (1,0) added.
var candidates = new HashSet<uint>();
CellTransit.AddAllOutsideCells(
worldSphereCenter: new Vector3(32448f + 23.6f, 34560f + 12f, 0f),
worldSphereCenter: new Vector3(23.6f, 12f, 0f),
sphereRadius: 0.5f,
currentCellId: 0xA9B40001u,
candidates);