feat(core): Phase B.3 — CellPortal-based indoor/outdoor transitions in PhysicsEngine

Replace the disabled if(false) outdoor→indoor branch with real portal-plane
crossing logic. LandblockPhysics now carries IReadOnlyList<PortalPlane> Portals
(populated at load time; GameWindow passes Array.Empty for now until Task 3).

Resolve logic:
- Outdoor player: tests all portals where TargetCellId==0xFFFF (outside-facing);
  crossing enters the portal's OwnerCellId.
- Indoor player: tests portals where OwnerCellId==currentCell; crossing to
  TargetCellId==0xFFFF exits to terrain, otherwise transitions room-to-room.
- Landblock boundary crossing: unchanged — candidatePos landblock lookup already
  picks the adjacent block's terrain naturally.

Tests: renamed disabled test → Resolve_OutdoorThroughPortal_TransitionsToIndoor;
added Resolve_IndoorThroughExitPortal_TransitionsToOutdoor and
Resolve_LandblockBoundary_PicksAdjacentTerrain. 274 tests green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-12 18:22:55 +02:00
parent cb46d892d5
commit 8252523b8b
5 changed files with 318 additions and 62 deletions

View file

@ -1367,7 +1367,8 @@ public sealed class GameWindow : IDisposable
}
}
_physicsEngine.AddLandblock(lb.LandblockId, terrainSurface, cellSurfaces, origin.X, origin.Y);
_physicsEngine.AddLandblock(lb.LandblockId, terrainSurface, cellSurfaces,
Array.Empty<AcDream.Core.Physics.PortalPlane>(), origin.X, origin.Y);
}
// Upload every GfxObj referenced by this landblock's entities.
@ -1496,7 +1497,8 @@ public sealed class GameWindow : IDisposable
TurnLeft: kb.IsKeyPressed(Key.A),
TurnRight: kb.IsKeyPressed(Key.D),
Run: kb.IsKeyPressed(Key.ShiftLeft) || kb.IsKeyPressed(Key.ShiftRight),
MouseDeltaX: consumedMouseDeltaX);
MouseDeltaX: consumedMouseDeltaX,
Jump: kb.IsKeyPressed(Key.Space));
var result = _playerController.Update((float)dt, input);