diff --git a/src/AcDream.Core/Physics/TransitionTypes.cs b/src/AcDream.Core/Physics/TransitionTypes.cs index e5f1e86..11dbd7c 100644 --- a/src/AcDream.Core/Physics/TransitionTypes.cs +++ b/src/AcDream.Core/Physics/TransitionTypes.cs @@ -1502,7 +1502,7 @@ public sealed class Transition } } - internal TransitionState FindEnvCollisions(PhysicsEngine engine) + private TransitionState FindEnvCollisions(PhysicsEngine engine) { var sp = SpherePath; var ci = CollisionInfo; @@ -1618,21 +1618,6 @@ public sealed class Transition return cellState; } - // ── Phase A4 (2026-05-20): query every other cell ────────── - // Retail oracle: CTransition::check_other_cells at - // acclient_2013_pseudo_c.txt:272717-272798. The vestibule - // walls bug (cell 0xA9B40164 has only 4 polys; adjacent - // 0xA9B40157 has the actual walls) closes here. - // - // Discard the containing-cell return — sp.CheckCellId is - // already authoritative for the primary cell we just queried. - _ = CellTransit.FindCellSet(engine.DataCache, footCenter, sphereRadius, - sp.CheckCellId, out var cellSet); - var otherCellsState = CheckOtherCells(engine, footCenter, sphereRadius, cellSet); - if (otherCellsState != TransitionState.OK) - return otherCellsState; - // ────────────────────────────────────────────────────────── - // ── Synthesize indoor walkable contact plane ────────────── // Indoor walking Phase 2 follow-up (2026-05-19). When the BSP // returns OK (no wall collision), the player is standing on a diff --git a/tests/AcDream.Core.Tests/Physics/FindEnvCollisionsMultiCellTests.cs b/tests/AcDream.Core.Tests/Physics/FindEnvCollisionsMultiCellTests.cs deleted file mode 100644 index d973305..0000000 --- a/tests/AcDream.Core.Tests/Physics/FindEnvCollisionsMultiCellTests.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Numerics; -using DatReaderWriter.Enums; -using DatReaderWriter.Types; -using AcDream.Core.Physics; -using Xunit; - -namespace AcDream.Core.Tests.Physics; - -/// -/// End-to-end test that the indoor branch of -/// queries the cells the -/// sphere overlaps, not just the cell whose CellBSP contains the -/// sphere center. This is the core Phase A4 behaviour test — the -/// Holtburg inn vestibule (cell 0xA9B40164) bug reduced to a minimal -/// synthetic fixture. -/// -public class FindEnvCollisionsMultiCellTests -{ - // Indoor cell IDs — both have low-byte ≥ 0x100 to trigger the - // indoor branch of FindEnvCollisions. Vestibule has the lower id so - // CellTransit.FindCellSet's sorted iteration encounters it first. - private const uint VestibuleCellId = 0xA9B40157u; - private const uint InteriorCellId = 0xA9B40164u; - - private static CellBSPTree LeafCellBsp() => new CellBSPTree - { - Root = new CellBSPNode { Type = BSPNodeType.Leaf }, - }; - - private static PhysicsBSPTree EmptyLeafBsp() => new PhysicsBSPTree - { - Root = new PhysicsBSPNode - { - Type = BSPNodeType.Leaf, - BoundingSphere = new Sphere { Origin = Vector3.Zero, Radius = 10f }, - } - }; - - [Fact] - public void IndoorSphereOverlappingAdjacentCellWithWall_HaltsTransition() - { - // ── Secondary cell (interior) ───────────────────────────────────── - // Reuse BSPStepUp's TallWall fixture — proven to halt a grounded mover - // that can't scale it (test B2_GroundedMover_TallWall_BlockedOrSlides). - // Wall is at interior-local x=0.5. Translate the interior cell by - // +0.3 in world X so the wall ends up at world x=0.8, within reach - // of a sphere walking from x=0.1 toward x=0.6 (sphere radius 0.2). - var (wallRoot, wallResolved) = BSPStepUpFixtures.TallWall(); - var interiorWT = Matrix4x4.CreateTranslation(new Vector3(0.3f, 0f, 0f)); - Matrix4x4.Invert(interiorWT, out var interiorInv); - - var interior = new CellPhysics - { - BSP = new PhysicsBSPTree { Root = wallRoot }, - WorldTransform = interiorWT, - InverseWorldTransform = interiorInv, - Resolved = wallResolved, - CellBSP = LeafCellBsp(), - }; - - // ── Primary cell (vestibule) ────────────────────────────────────── - // Empty PhysicsBSP — no walls of its own. CellBSP contains a portal - // at world x=0.5 (vestibule-local x=0.5 since vestibule WorldTransform - // = Identity) leading to the interior cell. The sphere's foot reaches - // the portal at world x=0.5 during the sweep — that triggers - // CellTransit.FindCellSet to add the interior to the candidate set. - var portalPoly = new ResolvedPolygon - { - Vertices = new[] - { - new Vector3(0.5f, -2.5f, 0f), - new Vector3(0.5f, 2.5f, 0f), - new Vector3(0.5f, 2.5f, 5f), - new Vector3(0.5f, -2.5f, 5f), - }, - Plane = new Plane(new Vector3(1f, 0f, 0f), -0.5f), - NumPoints = 4, - SidesType = CullMode.None, - }; - - var vestibule = new CellPhysics - { - BSP = EmptyLeafBsp(), - WorldTransform = Matrix4x4.Identity, - InverseWorldTransform = Matrix4x4.Identity, - Resolved = new Dictionary(), - CellBSP = LeafCellBsp(), - PortalPolygons = new Dictionary { [10] = portalPoly }, - Portals = new[] - { - new PortalInfo(otherCellId: (ushort)(InteriorCellId & 0xFFFFu), - polygonId: 10, flags: 0), - }, - }; - - // ── Engine + cache ──────────────────────────────────────────────── - var engine = new PhysicsEngine(); - engine.DataCache = new PhysicsDataCache(); - - // Provide a flat terrain strip at z=0 so FindEnvCollisions's outdoor - // fall-through has something to sample if it ever fires. - var heights = new byte[81]; - Array.Fill(heights, (byte)0); - var ht = new float[256]; - for (int i = 0; i < 256; i++) ht[i] = i * 1.0f; - engine.AddLandblock(0xA9B4FFFFu, new TerrainSurface(heights, ht), - Array.Empty(), Array.Empty(), - worldOffsetX: 0f, worldOffsetY: 0f); - - engine.DataCache.RegisterCellStructForTest(VestibuleCellId, vestibule); - engine.DataCache.RegisterCellStructForTest(InteriorCellId, interior); - - // ── Transition ──────────────────────────────────────────────────── - // Grounded mover, foot at world x=0.1 walking to x=0.7. The sphere - // (radius 0.2, center at foot + 0.2 in Z) ends with its center at - // world x=0.7 = interior-local x=0.4 (since interior translation is - // +0.3). The TallWall sits at interior-local x=0.5 with normal -X — - // the sphere reach (0.4 + 0.2 = 0.6) penetrates the wall by 0.1. - // StepUpHeight 0.04 means the mover can't scale the 5m TallWall. - // MakeGroundedTransition seeds Contact + OnWalkable + - // LastKnownContactPlane so Path 5 fires for any wall the BSP query - // encounters. - var from = new Vector3(0.1f, 0f, 0f); - var to = new Vector3(0.7f, 0f, 0f); - var t = BSPStepUpFixtures.MakeGroundedTransition(from, to, - stepUpHeight: 0.04f, - cellId: VestibuleCellId); - - // SetCheckPos sets the candidate position FindEnvCollisions evaluates. - t.SpherePath.SetCheckPos(to, VestibuleCellId); - - // ── Act ─────────────────────────────────────────────────────────── - // Call FindEnvCollisions directly (now internal). Bypasses - // FindTransitionalPosition's sub-step iteration so we can assert on - // the single result. - var result = t.FindEnvCollisions(engine); - - // ── Assert ──────────────────────────────────────────────────────── - // Pre-A4: empty vestibule BSP returns OK, interior is never queried, - // result == OK (sphere walks through the wall). - // Post-A4: CheckOtherCells iterates the interior cell, BSPQuery on - // TallWall returns Slid (the wall-slide path matching B2), and - // FindEnvCollisions returns Slid via ApplyOtherCellResult. - Assert.NotEqual(TransitionState.OK, result); - } -}