using AcDream.App.Combat; using AcDream.App.Update; using AcDream.UI.Abstractions.Input; namespace AcDream.App.Input; internal interface ICombatInputFrameController { void Tick(); void HandleMovementInput(InputAction action, ActivationType activation); bool HandleInputAction(InputAction action, ActivationType activation); } internal sealed class CombatAttackInputFrameAdapter : ICombatInputFrameController { private readonly CombatAttackController _owner; public CombatAttackInputFrameAdapter(CombatAttackController owner) => _owner = owner ?? throw new ArgumentNullException(nameof(owner)); public void Tick() => _owner.Tick(); public void HandleMovementInput(InputAction action, ActivationType activation) => _owner.HandleMovementInput(action, activation); public bool HandleInputAction(InputAction action, ActivationType activation) => _owner.HandleInputAction(action, activation); } /// /// Owns the complete pre-object input frame: held semantic dispatch, one raw /// mouse-look sample, and combat attack intent. /// internal sealed class GameplayInputFrameController : IGameplayInputFramePhase, AcDream.App.Streaming.ILocalPlayerTeleportInputLifetime { private readonly InputDispatcher? _dispatcher; private readonly DispatcherMovementInputSource _movement; private readonly IMouseLookInputFrameController? _mouseLook; private readonly ICombatInputFrameController _combat; public GameplayInputFrameController( InputDispatcher? dispatcher, DispatcherMovementInputSource movement, IMouseLookInputFrameController? mouseLook, ICombatInputFrameController combat) { _dispatcher = dispatcher; _movement = movement ?? throw new ArgumentNullException(nameof(movement)); _mouseLook = mouseLook; _combat = combat ?? throw new ArgumentNullException(nameof(combat)); } public bool MouseLookActive => _mouseLook?.Active == true; public void Tick(UpdateFrameTiming timing) { _ = timing; _dispatcher?.Tick(); _mouseLook?.Tick(); _combat.Tick(); } public bool HandlePointerAction(InputAction action, ActivationType activation) => _mouseLook?.HandlePointerAction(action, activation) == true; public bool HandleCombatAction(InputAction action, ActivationType activation) { // ACCmdInterp::HandleNewForwardMovement @ 0x0058B1F0 aborts // automatic combat before the movement command enters the interpreter. _combat.HandleMovementInput(action, activation); return _combat.HandleInputAction(action, activation); } public bool HandlePressedMovementAction(InputAction action) => _movement.HandlePressedAction(action); public void QueueRawMouseDelta(float dx, float dy) => _mouseLook?.QueueRawDelta(dx, dy); public void EndMouseLook() => _mouseLook?.EndForLifecycle(); public void ResetSession() { _mouseLook?.ResetSession(); _movement.ResetSession(); } }