using System;
namespace AcDream.Core.Physics.Motion;
///
/// R2-Q5 — the that dispatches the
/// CMotionInterp funnel's retail-ordered motion events STRAIGHT into the
/// entity's motion-table stack via
/// (lazy initialize_state +
/// MotionTableManager::PerformMovement 0x0051c0b0).
///
///
/// This replaces the App-side RemoteMotionSink (deleted): no axis
/// collection, no single-cycle priority pick, no Commit pass, no HasCycle
/// probe, no Run→Walk→Ready missing-cycle chain — retail's
/// GetObjectSequence (0x00522860) + is_allowed decide what
/// plays. Forward locomotion installs the substate cycle (Branch 2);
/// sidesteps resolve by the dat (cycle when authored, else modifier);
/// turns are Branch-4 physics-only modifiers blended over the substate via
/// combine_motion/re_modify — the composition the retired
/// AP-73 row approximated with one cycle.
///
///
///
/// The / callbacks are the
/// interim ObservedOmega seam: the App seeds the remote body's angular
/// velocity from the wire turn so rotation starts the same tick (retail
/// rotates the body from the sequence omega inside the per-tick
/// apply_physics chain — R6 scope; register row). They fire BEFORE
/// the dispatch so a consumer sees the seed even if the dat lacks the
/// modifier entry.
///
///
public sealed class MotionTableDispatchSink : IInterpretedMotionSink
{
private readonly AnimationSequencer _sequencer;
/// Turn-class dispatch observed: (motion, signedSpeed) —
/// TurnLeft arrives either as the explicit 0x0E command or as
/// TurnRight + negative speed (adjust_motion wire convention).
public Action? TurnApplied { get; set; }
/// Turn-class stop observed.
public Action? TurnStopped { get; set; }
public MotionTableDispatchSink(AnimationSequencer sequencer)
{
ArgumentNullException.ThrowIfNull(sequencer);
_sequencer = sequencer;
}
private static bool IsTurn(uint motion)
=> (motion & 0xFF000000u) == 0x65000000u && (motion & 0xFFu) is 0x0D or 0x0E;
public void ApplyMotion(uint motion, float speed)
{
if (IsTurn(motion))
TurnApplied?.Invoke(motion, speed);
_sequencer.PerformMovement(MotionTableMovement.Interpreted(motion, speed));
}
public void StopMotion(uint motion)
{
if (IsTurn(motion))
TurnStopped?.Invoke();
_sequencer.PerformMovement(MotionTableMovement.StopInterpreted(motion, 1f));
}
}