using System.Numerics; using AcDream.Core.Physics; using Xunit; namespace AcDream.Core.Tests.Physics; /// /// #32 regression — the last-known contact plane must survive a steep /// mid-transition contact. /// /// /// CTransition::cliff_slide @0x0050a6d0 takes its slide direction from /// cross(steep contact normal, last_known_contact_plane.N). It needs /// the surface the mover was STANDING ON as the second vector. acdream's /// CollisionInfo.SetContactPlane used to latch the last-known group on /// every call, so by the time cliff_slide ran, last-known had already /// been overwritten with the steep face itself — the cross product of a vector /// with itself, which is zero. Degenerate direction, no slide applied, and the /// player walked off the cliff. /// /// /// /// Retail's COLLISIONINFO::set_contact_plane @0x00509d80 is 22 bytes /// and writes the CONTACT group only. The last-known group has four writers, /// none of them that function. /// /// /// /// Measured live at Rithwic on 2026-08-06 with /// ACDREAM_DUMP_EDGE_SLIDE=1: six branch2/steep-cliffslide /// events, every one reporting /// curN=(-0.954,0.000,0.301) lastN=(-0.954,0.000,0.301) angle=0.0000 /// apply=False with outcome degenerate-cross/last-known — the two /// vectors identical to three decimals. That capture is decision-table row 1 /// of docs/research/2026-08-06-32-local-edge-slide-research.md, and the /// normals below are taken from it verbatim rather than invented. /// /// /// /// Sabotage check. Restore the four last-known writes at the tail of /// SetContactPlane and /// /// fails on its lastN assertion while /// keeps passing — the pair /// separates "the latch is gone" from "nothing writes last-known at all", /// which a single test could not do. /// /// public sealed class Issue32LastKnownContactPlaneTests { private const uint Cell = 0x0001_0001u; /// The flat ground the mover is standing on before the rim. private static readonly Plane Walkable = new(Vector3.UnitZ, 0f); /// /// The Rithwic cliff face, verbatim from the live capture: a normal whose /// Z of 0.301 is about 72.5° from horizontal, far below /// , so it is rejected as walkable and /// routes to the cliff-slide branch. /// private static readonly Plane Steep = new(Vector3.Normalize(new Vector3(-0.954f, 0f, 0.301f)), 0f); [Fact] public void MidTransitionSteepContact_LeavesTheWalkableLastKnownPlaneIntact() { var ci = new CollisionInfo(); // Start of transition: standing on flat ground. Retail's // init_contact_plane seeds BOTH groups here, because there is no // earlier surface to remember. ci.InitContactPlane(Walkable, Cell); // Mid-transition: the sweep meets the cliff face. Retail's // set_contact_plane writes the contact group and nothing else. ci.SetContactPlane(Steep, Cell); Assert.True(ci.ContactPlaneValid); Assert.Equal(Steep.Normal, ci.ContactPlane.Normal); Assert.True( ci.LastKnownContactPlaneValid, "the seeded last-known plane must survive a steep contact — " + "cliff_slide has no second vector without it."); Assert.Equal(Walkable.Normal, ci.LastKnownContactPlane.Normal); // The consequence that actually mattered in play: a non-degenerate // slide direction. With the latch in place both vectors were the steep // face and this cross product was the zero vector. Vector3 slide = Vector3.Cross(Steep.Normal, ci.LastKnownContactPlane.Normal); Assert.True( slide.Length() > 1e-4f, $"cliff_slide's direction is degenerate: |cross| = {slide.Length():E3}. " + $"contactN = {Steep.Normal}, lastN = {ci.LastKnownContactPlane.Normal}."); } /// /// CONTROL. The seed path must still write both groups, or the test above /// would pass simply because nothing ever populates last-known. /// [Fact] public void InitContactPlane_SeedsBothGroups() { var ci = new CollisionInfo(); Assert.False(ci.LastKnownContactPlaneValid); ci.InitContactPlane(Walkable, Cell, isWater: true); Assert.True(ci.ContactPlaneValid); Assert.Equal(Walkable.Normal, ci.ContactPlane.Normal); Assert.Equal(Cell, ci.ContactPlaneCellId); Assert.True(ci.ContactPlaneIsWater); Assert.True(ci.LastKnownContactPlaneValid); Assert.Equal(Walkable.Normal, ci.LastKnownContactPlane.Normal); Assert.Equal(Cell, ci.LastKnownContactPlaneCellId); Assert.True(ci.LastKnownContactPlaneIsWater); } /// /// A second steep contact must not resurrect the defect through the /// no-op-if-unchanged guard: the guard returns early when the CONTACT /// group already matches, and an early return must not be the only thing /// protecting last-known. /// [Fact] public void RepeatedSteepContact_StillLeavesLastKnownIntact() { var ci = new CollisionInfo(); ci.InitContactPlane(Walkable, Cell); ci.SetContactPlane(Steep, Cell); ci.SetContactPlane(Steep, Cell); // hits the no-op guard ci.SetContactPlane(Steep, Cell); Assert.Equal(Walkable.Normal, ci.LastKnownContactPlane.Normal); } }