using System.Numerics; using AcDream.Core.Physics; namespace AcDream.Runtime.Tests.Physics; /// /// AD-10 — the remote slope projection. Retail projects the per-sub-step /// movement offset onto collision_info.contact_plane INSIDE the sweep /// (CTransition::adjust_offset 0x0050a370, pc:272271-272393, /// called once per step from find_transitional_position /// 0x0050bdf0). acdream ports that faithfully in /// Transition.AdjustOffset, and remotes run that sweep — so the extra /// pre-sweep projection the remote tick used to apply at the combiner boundary /// was a second copy of the same operation against a single-point terrain /// sample. It was deleted 2026-08-06 after the measurement these tests carry. /// /// Every assertion here runs the production /// tick and /// takes its expected Z from the fixture's own terrain geometry, never from a /// re-implementation of the projection formula — so a projection against the /// WRONG plane produces a wrong answer rather than a self-consistent one. /// public sealed class RuntimeRemoteSlopeProjectionTests { /// /// A comfortably walkable ramp steep enough that a failure to track it is /// unmistakable: plane normal Z = 1/sqrt(1.36) ≈ 0.8575 (30.96 degrees) /// against retail's 0.6642 floor_z limit (48.4 degrees). The ramp descends /// along +Y, so +Y root motion is downhill. /// private const float WalkableSlopeGradient = 0.6f; /// /// Body-local root displacement per tick — the locomotion-cycle push that /// moves a running remote between server position updates. 0.1 m at 30 Hz /// is a 3 m/s run. /// private const float RootMotionPerTick = 0.10f; private const int TrackedTicks = 30; /// /// How far the body's root may drift from the terrain surface directly /// below it, relative to where the settled fixture put it. The measured /// drift on this fixture is under 1e-4 m; 30 unprojected ticks down this /// ramp accumulate about 1.8 m, so this band is ~350x below the failure it /// must catch and ~50x above the float noise it must tolerate. /// private const float SurfaceTrackingToleranceMeters = 0.005f; /// /// The ramp's own plane, derived from the fixture heightmap rather than /// from anything the code under test computed. The ramp descends along +Y /// at gradient, so its plane is gradient*y + z = c and its /// unit normal is (0, gradient, 1) normalized. /// private static Vector3 RampNormal(float gradient) => Vector3.Normalize(new Vector3(0f, gradient, 1f)); /// /// Fixture validation, run before any motion assertion: the sweep really /// does report this ramp's own geometric plane, and that plane is walkable. /// A fixture whose contact plane were flat could not discriminate anything. /// [Fact] public void TheFixtureRampIsWalkableAndItsPlaneIsTheGeometricOne() { using RemoteRampHarness harness = RemoteRampHarness.OnRamp(WalkableSlopeGradient); Assert.True(harness.Remote.Body.OnWalkable); Assert.True(harness.Remote.Body.ContactPlaneValid); Vector3 expected = RampNormal(WalkableSlopeGradient); Vector3 actual = harness.Remote.Body.ContactPlane.Normal; Assert.True( Vector3.Distance(expected, actual) < 0.001f, $"contact plane normal was {actual}, expected the ramp's {expected}"); Assert.True(actual.Z >= PhysicsGlobals.FloorZ); } /// /// The artifact the deleted projection existed to remove: a remote running /// across a slope must have its feet track the ground CONTINUOUSLY between /// server position updates, not ratchet down in ~5 Hz steps. /// /// Asserted on every tick rather than at the end, because a /// start/end comparison passes a staircase that happens to catch up on the /// final tick. /// /// Sabotage-verified 2026-08-06: discarding the sweep's answer /// (rm.Body.Position = postIntegratePos instead of /// resolveResult.Position) reddens this at tick 1 with the body /// 0.05999 m off the surface. /// /// What this test does NOT discriminate, stated so nobody infers /// it later. Short-circuiting Transition.AdjustOffset to /// return offset; leaves it GREEN. On terrain the sweep has a /// second, independent way to put the body on the surface: /// ValidateWalkable's push-out re-plants the sphere at its natural /// resting distance from the terrain plane on every sub-step, so the Z /// outcome survives even with the offset projection gone (what changes is /// the XY, which adjust_offset shortens). Removing the step-down /// probe does not change that either — measured. So this test asserts the /// OUTCOME "a running remote's feet stay on the ground", which is what the /// deleted projection was there for; it is not a unit test of /// adjust_offset, and it must not be cited as one. /// [Fact] public void TheRemoteTickTracksTheSurfaceWhileRunningDownhill() { using RemoteRampHarness harness = RemoteRampHarness.OnRamp(WalkableSlopeGradient); AssertTracksSurface(harness); } /// /// Anti-vacuity guard for the two tests above: on flat ground they pass /// without Z ever having to move, so a fixture that quietly flattened /// would make them meaningless. This asserts the ramp genuinely forces a /// large Z excursion over the same number of ticks. /// [Fact] public void TheTrackingFixtureActuallyRequiresTheBodyToChangeZ() { using RemoteRampHarness harness = RemoteRampHarness.OnRamp(WalkableSlopeGradient); float startZ = harness.Remote.Body.Position.Z; harness.Tick(TrackedTicks, new Vector3(0f, RootMotionPerTick, 0f)); float dz = harness.Remote.Body.Position.Z - startZ; Assert.True( dz < -1.0f, $"fixture is not exercising slope descent: dz = {dz:F4} m"); } private static void AssertTracksSurface(RemoteRampHarness harness) { Assert.True(harness.Remote.Body.OnWalkable); // The settled resting offset between the body's root and the terrain // directly beneath it. Measured, not assumed: the spawn settle may put // the root a hair off the sampled surface. float restingOffset = harness.Remote.Body.Position.Z - harness.SurfaceZUnderBody(); for (int tick = 1; tick <= TrackedTicks; tick++) { harness.Tick(1, new Vector3(0f, RootMotionPerTick, 0f)); float offset = harness.Remote.Body.Position.Z - harness.SurfaceZUnderBody(); Assert.True( MathF.Abs(offset - restingOffset) < SurfaceTrackingToleranceMeters, $"tick {tick}: body root sits {offset:F5} m above the terrain " + $"under it, expected {restingOffset:F5} m " + $"(pos {harness.Remote.Body.Position})"); } } }