From 39d4e6512b2b58ac51cb36b72019f3e289f06606 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 20 May 2026 07:58:37 +0200 Subject: [PATCH] test(physics): BSPQuery.FindCollisions writes world-space plane with translated origin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression test for indoor BSP world-origin fix (Bug B). Verifies that BSPQuery.FindCollisions with path.StepDown=true and a non-zero worldOrigin parameter writes a world-space ContactPlane to CollisionInfo (not a cell-local-space one). Passes before the call-site fix at TransitionTypes.cs:1442 because BSPQuery itself is correct when called with the right args — it's the caller that was passing the defaults. This test locks in the BSPQuery contract so the relationship between worldOrigin/localToWorld input and ContactPlane.D output cannot regress silently. Spec: docs/superpowers/specs/2026-05-20-indoor-bsp-worldorigin-fix-design.md. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Physics/BSPQueryTests.cs | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/AcDream.Core.Tests/Physics/BSPQueryTests.cs b/tests/AcDream.Core.Tests/Physics/BSPQueryTests.cs index 31c175b..a80c743 100644 --- a/tests/AcDream.Core.Tests/Physics/BSPQueryTests.cs +++ b/tests/AcDream.Core.Tests/Physics/BSPQueryTests.cs @@ -418,4 +418,96 @@ public class BSPQueryTests Assert.False(found); } + + // ========================================================================= + // FindCollisions — world-origin / world-rotation correctness (spec 2026-05-20) + // ========================================================================= + + /// + /// Build a single-leaf BSP with one horizontal floor polygon at the given + /// cell-local Z. Vertex array forms a 4x4 m square centered at cell-local + /// (0, 0). + /// + private static (PhysicsBSPNode root, Dictionary resolved) + BuildSingleFloorBsp(float floorZ) + { + var verts = new[] + { + new Vector3(-2f, -2f, floorZ), + new Vector3( 2f, -2f, floorZ), + new Vector3( 2f, 2f, floorZ), + new Vector3(-2f, 2f, floorZ), + }; + + var root = new PhysicsBSPNode + { + Type = BSPNodeType.Leaf, + BoundingSphere = new Sphere + { + Origin = new Vector3(0f, 0f, floorZ), + Radius = 3f, + }, + }; + root.Polygons.Add(0); + + var resolved = new Dictionary + { + [0] = new ResolvedPolygon + { + Vertices = verts, + Plane = new Plane(Vector3.UnitZ, -floorZ), + NumPoints = 4, + SidesType = CullMode.None, + }, + }; + + return (root, resolved); + } + + [Fact] + public void FindCollisions_StepDown_TranslatedWorldOrigin_WritesWorldSpacePlane() + { + // Cell is translated +94 m in world Z (i.e., the cell-local floor at + // Z=0 sits at world Z=94). This mirrors the Holtburg cottage scenario + // captured in launch-cp-probe.log (cell 0xA9B40150, floor world + // Z≈94.02). + var (root, resolved) = BuildSingleFloorBsp(floorZ: 0f); + + var transition = new Transition(); + transition.SpherePath.WalkableAllowance = PhysicsGlobals.FloorZ; + transition.SpherePath.WalkInterp = 1.0f; + transition.SpherePath.StepDown = true; + transition.SpherePath.StepDownAmt = 0.5f; + + // Foot sphere in cell-local space: overlapping the floor (Z=0.4 with + // radius 0.48 → dist 0.4 < radius−epsilon = 0.4798, so the precise + // overlap test accepts the contact). + var localSphere = new Sphere + { + Origin = new Vector3(0f, 0f, 0.4f), + Radius = 0.48f, + }; + + var state = BSPQuery.FindCollisions( + root, + resolved, + transition, + localSphere, + localSphere1: null, + localCurrCenter: localSphere.Origin, + localSpaceZ: Vector3.UnitZ, + scale: 1.0f, + localToWorld: Quaternion.Identity, + engine: null, + worldOrigin: new Vector3(0f, 0f, 94f)); + + // Path 3 step-down should fire and adjust the sphere onto the floor. + Assert.Equal(TransitionState.Adjusted, state); + + // ContactPlane must be in world space: normal stays (0,0,1) since the + // cell rotation is identity; D = -world_floor_Z = -94. + Assert.True(transition.CollisionInfo.ContactPlaneValid); + Assert.Equal(1.0f, transition.CollisionInfo.ContactPlane.Normal.Z, precision: 3); + Assert.Equal(-94.0f, transition.CollisionInfo.ContactPlane.D, precision: 2); + } }