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:
parent
6a2c432e5a
commit
28cd97be62
8 changed files with 1134 additions and 40 deletions
|
|
@ -168,6 +168,35 @@ public static class CellTransit
|
|||
/// adds the primary cell plus up to 3 neighbours when the radius
|
||||
/// reaches a cell boundary.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// <see cref="worldSphereCenter"/> is in the landblock-local coord
|
||||
/// space the rest of the engine uses (X/Y in [0, 192]; landblock
|
||||
/// world origin is at the streaming center, so all landblock-local
|
||||
/// positions are also world positions for the player's landblock).
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// A6.P4 door fix (2026-05-24): pre-fix this function subtracted the
|
||||
/// landblock's "absolute" world origin (lbX=0xA9*192=32448) from the
|
||||
/// sphere position, which made sense only if sphere coords were the
|
||||
/// absolute world position (32580). But production has used
|
||||
/// landblock-local coords since Phase A.1 (streaming-center landblock
|
||||
/// at world origin, so lbOffset for the center is (0,0); see
|
||||
/// <c>GameWindow.BuildInteriorEntitiesForStreaming</c>'s lbOffset
|
||||
/// formula). With landblock-local sphere coords, the old subtraction
|
||||
/// produced <c>localX = 132.36 - 32448 = -32316</c> → <c>gridX = -1346</c>
|
||||
/// → out-of-range → early return → ZERO outdoor cells added. For
|
||||
/// indoor primary cells (where issue #98 gates the GetNearbyObjects
|
||||
/// outdoor radial sweep) this meant the cottage door's outdoor cell
|
||||
/// 0xA9B40029 never reached <c>portalReachableCells</c>, the door's
|
||||
/// BSP was never queried, and the player walked through unimpeded —
|
||||
/// the user-reported Holtburg-door walkthrough bug. The fix:
|
||||
/// treat <c>worldSphereCenter</c> as landblock-local directly, no
|
||||
/// landblock-world-origin subtraction. This matches retail's
|
||||
/// <c>CLandCell::add_all_outside_cells</c> which uses the per-cell
|
||||
/// 6-byte position struct (landblock-relative).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static void AddAllOutsideCells(
|
||||
Vector3 worldSphereCenter,
|
||||
|
|
@ -179,10 +208,8 @@ public static class CellTransit
|
|||
|
||||
uint lbPrefix = currentCellId & 0xFFFF0000u;
|
||||
|
||||
float lbXf = ((lbPrefix >> 24) & 0xFFu) * 192f;
|
||||
float lbYf = ((lbPrefix >> 16) & 0xFFu) * 192f;
|
||||
float localX = worldSphereCenter.X - lbXf;
|
||||
float localY = worldSphereCenter.Y - lbYf;
|
||||
float localX = worldSphereCenter.X;
|
||||
float localY = worldSphereCenter.Y;
|
||||
|
||||
float cellLocalX = localX % CellSize;
|
||||
float cellLocalY = localY % CellSize;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue