feat(L.2g-S2a): CMotionInterp inbound funnel in Core + live-retail conformance harness (DEV-1 core)

Port the inbound funnel verbatim into MotionInterpreter:
- MoveToInterpretedState (0x005289c0): raw-state style adopt, FLAT
  copy_movement_from overwrite, apply, then action replay under the
  15-bit server_action_stamp wraparound gate (local player skips its
  own autonomous echoes).
- ApplyInterpretedMovement (0x00528600): my_run_rate cache from
  RunForward speed, then retail dispatch order style -> forward-or-
  Falling -> sidestep(-stop) -> turn(-stop), turn early-return.
- DispatchInterpretedMotion (0x00528360): contact-gated sink dispatch
  (IInterpretedMotionSink = the GetObjectSequence backend the App
  implements); blocked non-action motions take the apply-only path —
  retail's real mechanism behind K-fix17's 'airborne remotes keep
  their cycle' empirical guard.
- contact_allows_move REWRITTEN VERBATIM from the real 0x00528240
  (pseudo-C 305471): Falling/0x40000011 + turns always allowed,
  non-creature weenies + no-gravity bypass, else Contact+OnWalkable.
  The previous body conflated jump_charge_is_allowed (0x00527a50)
  posture checks — the 2026-06-04 deep-dive divergence, now retired.
  Six tests that pinned the misattributed behavior corrected
  (grounded posture does NOT block motion; airborne accepts
  Falling/turns only).
- IWeenieObject.IsCreature (default true) for the gate's non-creature
  bypass.

Conformance harness (the user-requested 'prove it equals retail'
apparatus, layer 1): RetailObserverTraceConformanceTests parses the
LIVE cdb trace of a retail observer (Fixtures/l2g-observer-trace.log,
captured via tools/cdb/l2g-observer.cdb) into 183 golden cases —
each [MTIS] input state replayed through our funnel must produce
retail's exact [DIM] dispatch sequence. 183/183 conformant, including
the airborne jump case (replayed contact-free; pre-gate vs post-gate
accounting + HitGround second-pass truncation documented in-test).
13 synthetic funnel tests cover the branches the trace missed
(actions, stamps, longjump, sidestep).

GameWindow integration (S2b) follows; funnel not yet wired.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-02 18:50:09 +02:00
parent 97e098bf91
commit 7b0cbbda2c
6 changed files with 3693 additions and 55 deletions

View file

@ -673,35 +673,24 @@ public sealed class MotionInterpreterTests
Assert.True(allowLeft);
}
[Fact]
public void ContactAllowsMove_FallenState_RejectsMove()
{
var body = MakeGrounded();
var interp = MakeInterp(body);
interp.InterpretedState.ForwardCommand = MotionCommand.Fallen;
bool allowed = interp.contact_allows_move(MotionCommand.WalkForward);
Assert.False(allowed);
}
[Fact]
public void ContactAllowsMove_DeadState_RejectsMove()
{
var body = MakeGrounded();
var interp = MakeInterp(body);
interp.InterpretedState.ForwardCommand = MotionCommand.Dead;
bool allowed = interp.contact_allows_move(MotionCommand.WalkForward);
Assert.False(allowed);
}
// L.2g S2 (2026-07-02): the posture-rejection tests that used to live
// here pinned a MISATTRIBUTED port — the Fallen/Dead/crouch-range checks
// belong to jump_charge_is_allowed (0x00527a50) / motion_allows_jump
// (0x005279e0), NOT to contact_allows_move. The real contact_allows_move
// (0x00528240, pseudo-C 305471) never reads the forward-command posture:
// a grounded creature in ANY posture may receive motion
// (GetObjectSequence handles the posture→locomotion transition via
// links). Verified against the live retail-observer trace
// (RetailObserverTraceConformanceTests, 183/183 dispatch conformant).
[Theory]
[InlineData(MotionCommand.Fallen)]
[InlineData(MotionCommand.Dead)]
[InlineData(MotionCommand.Crouch)]
[InlineData(MotionCommand.Sitting)]
[InlineData(MotionCommand.Sleeping)]
public void ContactAllowsMove_PostureState_RejectsMove(uint postureCommand)
[InlineData(0x41000012u)] // inside the crouch range (0x41000011, 0x41000015)
public void ContactAllowsMove_GroundedPosture_StillAllowsMove(uint postureCommand)
{
var body = MakeGrounded();
var interp = MakeInterp(body);
@ -709,20 +698,25 @@ public sealed class MotionInterpreterTests
bool allowed = interp.contact_allows_move(MotionCommand.WalkForward);
Assert.False(allowed);
Assert.True(allowed);
}
[Fact]
public void ContactAllowsMove_CrouchRange_RejectsMove()
public void ContactAllowsMove_AirborneCreature_AcceptsFallingAndTurns_BlocksWalk()
{
var body = MakeGrounded();
// Verbatim 0x00528240: Falling (0x40000015) / Dead-class (0x40000011)
// and TurnLeft/TurnRight are ALWAYS allowed; a gravity-bound creature
// without Contact+OnWalkable is blocked for everything else
// (including the style command, which falls through to the gate).
var body = new PhysicsBody { State = PhysicsStateFlags.Gravity };
var interp = MakeInterp(body);
// 0x41000012 is inside (0x41000011, 0x41000015) — crouch state
interp.InterpretedState.ForwardCommand = 0x41000012u;
bool allowed = interp.contact_allows_move(MotionCommand.WalkForward);
Assert.False(allowed);
Assert.True(interp.contact_allows_move(MotionCommand.Falling));
Assert.True(interp.contact_allows_move(0x40000011u));
Assert.True(interp.contact_allows_move(MotionCommand.TurnRight));
Assert.True(interp.contact_allows_move(MotionCommand.TurnLeft));
Assert.False(interp.contact_allows_move(MotionCommand.WalkForward));
Assert.False(interp.contact_allows_move(0x8000003Du));
}
[Fact]