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)); } }