refactor(runtime): own local movement and outbound cadence

Move the canonical local movement controller, body/motion managers, object clock, movement wire data, and MTS/jump/AP sender into AcDream.Runtime. Replace process skill defaults with typed Runtime character options, make graphical and direct commands borrow one autorun owner, retain the construction-time PartArray seam, and include movement in terminal ownership convergence.

Preserve the accepted pre-inbound movement/jump and post-inbound autonomous-position order while moving the exact packet/cadence fixtures into Runtime tests. Add graphical/direct parity, two-instance isolation, teardown, allocation, architecture, and divergence-path coverage.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-26 12:33:53 +02:00
parent 3456dff038
commit aa3f4a60f8
36 changed files with 878 additions and 276 deletions

View file

@ -8,18 +8,25 @@ internal interface IMovementInputSource
}
/// <summary>
/// Owns held movement sampling and the retail autorun latch. The input
/// dispatcher remains the only keyboard/mouse-button state source.
/// Samples held graphical input and maps press edges onto the Runtime-owned
/// retail autorun latch. The dispatcher remains the only physical
/// keyboard/mouse-button state source.
/// </summary>
internal sealed class DispatcherMovementInputSource : IMovementInputSource
{
private readonly RuntimeLocalPlayerMovementState _movement;
private readonly IInputCaptureSource? _capture;
private InputDispatcher? _dispatcher;
public DispatcherMovementInputSource(IInputCaptureSource? capture = null) =>
public DispatcherMovementInputSource(
RuntimeLocalPlayerMovementState movement,
IInputCaptureSource? capture = null)
{
_movement = movement ?? throw new ArgumentNullException(nameof(movement));
_capture = capture;
}
public bool AutoRunActive { get; private set; }
public bool AutoRunActive => _movement.AutoRunActive;
public bool IsAvailable => _dispatcher is not null;
public void Bind(InputDispatcher dispatcher)
@ -70,10 +77,8 @@ internal sealed class DispatcherMovementInputSource : IMovementInputSource
public bool HandlePressedAction(InputAction action)
{
if (action == InputAction.MovementRunLock)
{
AutoRunActive = !AutoRunActive;
return true;
}
return _movement.Execute(
AcDream.Runtime.RuntimeMovementCommand.ToggleRunLock);
if (AutoRunActive && action is (
InputAction.MovementBackup
@ -81,11 +86,11 @@ internal sealed class DispatcherMovementInputSource : IMovementInputSource
or InputAction.MovementStrafeLeft
or InputAction.MovementStrafeRight))
{
AutoRunActive = false;
_movement.CancelAutoRun();
}
return false;
}
public void ResetSession() => AutoRunActive = false;
public void ResetSession() => _movement.ResetInputIntent();
}