using System.Numerics; using AcDream.Core.Physics; using Xunit; using Plane = System.Numerics.Plane; namespace AcDream.Core.Tests.Physics; /// /// Campaign P Slice P2, TS-1 gap #1 (2026-07-30 research pass, /// docs/research/2026-07-30-response-layer-edge-family-pseudocode.md /// §2). Pins the specific state Transition.EdgeSlideAfterStepDownFailed's /// back-probe fallback (TransitionTypes.cs:2015-2031) hands to /// : a walkable polygon rediscovered /// near GlobalCurrCenter (the last-known-good grounded position), /// tested against GlobalSphere[0] restored to the ORIGINAL failed /// move target (off the polygon's edge) after RestoreCheckPos(). /// /// /// Retail's SPHEREPATH::edge_slide back-probe branch /// (acclient_2013_pseudo_c.txt:274316-274326, 0050b4e0-0050b507) /// re-caches walkable_check_pos/localspace_sphere from /// SPHEREPATH::get_walkable_pos (0050a8f0) via /// SPHEREPATH::cache_localspace_sphere (0050c9d0) and /// SPHEREPATH::set_walkable_check_pos (00509ce0) before calling /// precipice_slide a second time. That machinery exists to solve a /// coordinate-FRAME problem: retail's walkable polygon and /// check_pos are each expressed relative to a PER-CELL local frame /// (cache_localspace_sphere re-projects one into the other's frame via /// Position::localtolocal, and precipice_slide itself applies a /// LandDefs::get_block_offset landblock correction, pc:274341). /// /// /// /// acdream's / /// are populated in UNIFIED WORLD SPACE at assignment time (see /// SpherePath.SetWalkable/SetWalkableTransformed, /// TransitionTypes.cs:667-739, which bake worldOrigin and /// scale in immediately), and is /// likewise always world-space (SpherePath.SetCheckPos/ /// RestoreCheckPos, TransitionTypes.cs:621-650). Both operands /// compares are therefore ALREADY /// commensurable without any recache step — retail's local-frame /// re-projection is a no-op correction in acdream's flat-world-space design. /// also never reads a sphere radius /// (only sphereCenter), so retail's radius/walkable_scale /// correction has no acdream counterpart to begin with. /// /// /// /// This test does not add a recache step (there is nothing for it to /// correct in this architecture); it instead PINS the claim: given exactly /// the field values the back-probe fallback produces (a world-space walkable /// polygon near GlobalCurrCenter, a restored GlobalSphere[0] at /// the original off-edge target), PrecipiceSlide must find the /// crossed edge and slide — not wedge into Collided. /// /// public class EdgeSlideBackProbePrecipiceSlideTests { /// /// Back-probe re-discovers a flat platform's edge polygon near the last /// known good center; the restored (failed) target sphere sits just past /// the +X edge. PrecipiceSlide must cross that edge and slide, matching /// retail's post-recache precipice_slide result (ADJUSTED_TS/SLID_TS, /// never a stuck COLLIDED_TS). /// [Fact] public void PrecipiceSlide_BackProbeState_CrossesEdge_DoesNotWedge() { var transition = new Transition(); var sp = transition.SpherePath; // Last known good grounded center — where the back-probe offset // points back toward (retail: global_curr_center). sp.GlobalCurrCenter[0].Origin = new Vector3(0f, 0f, 1f); sp.GlobalCurrCenter[0].Radius = 0.5f; // The walkable polygon the back-probe's DoStepDown rediscovered near // that center: a flat 2x2 platform, top face at Z=1. var plane = new Plane(Vector3.UnitZ, -1f); sp.SetWalkable( plane, new[] { new Vector3(-1f, -1f, 1f), new Vector3(1f, -1f, 1f), new Vector3(1f, 1f, 1f), new Vector3(-1f, 1f, 1f), }, Vector3.UnitZ); // GlobalSphere[0] after RestoreCheckPos(): the ORIGINAL failed move // target, just past the platform's +X edge (off the polygon, over // open air) — exactly what the back-probe fallback hands to // PrecipiceSlide once retail's edge_slide restores check_pos. sp.CheckPos = new Vector3(1.2f, 0f, 1f); sp.GlobalSphere[0].Origin = sp.CheckPos; sp.GlobalSphere[0].Radius = 0.5f; var result = sp.PrecipiceSlide(transition); Assert.NotEqual(TransitionState.Collided, result); Assert.True( result is TransitionState.Slid or TransitionState.Adjusted or TransitionState.OK, $"Back-probe PrecipiceSlide must slide/adjust across the found edge, not wedge; got {result}."); // The walkable context is consumed (retail: this->walkable = nullptr // inside precipice_slide before slide_sphere runs). Assert.False(sp.WalkableValid); } /// /// Sanity inverse: when the restored target sphere is still WELL INSIDE /// the rediscovered polygon (no edge crossed — e.g. the back-probe found /// the same ground the mover is standing on), retail's raw /// precipice_slide returns COLLIDED_TS /// (acclient_2013_pseudo_c.txt:274322-274326: eax==0 → walkable /// = nullptr; return 2). Confirms the "no wedge" claim above is about /// the edge-crossing case specifically, not a blanket "never Collided." /// [Fact] public void PrecipiceSlide_NoEdgeCrossed_ReturnsCollided_MatchingRetail() { var transition = new Transition(); var sp = transition.SpherePath; sp.GlobalCurrCenter[0].Origin = new Vector3(0f, 0f, 1f); sp.GlobalCurrCenter[0].Radius = 0.5f; var plane = new Plane(Vector3.UnitZ, -1f); sp.SetWalkable( plane, new[] { new Vector3(-1f, -1f, 1f), new Vector3(1f, -1f, 1f), new Vector3(1f, 1f, 1f), new Vector3(-1f, 1f, 1f), }, Vector3.UnitZ); // Restored target well inside the polygon — no edge crossed. sp.CheckPos = new Vector3(0.1f, 0f, 1f); sp.GlobalSphere[0].Origin = sp.CheckPos; sp.GlobalSphere[0].Radius = 0.5f; var result = sp.PrecipiceSlide(transition); Assert.Equal(TransitionState.Collided, result); } }