refactor(input): extract the gameplay frame
This commit is contained in:
parent
0bc9fda9de
commit
c557038353
24 changed files with 2433 additions and 559 deletions
83
src/AcDream.App/Input/DispatcherMovementInputSource.cs
Normal file
83
src/AcDream.App/Input/DispatcherMovementInputSource.cs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
using AcDream.UI.Abstractions.Input;
|
||||
|
||||
namespace AcDream.App.Input;
|
||||
|
||||
internal interface IMovementInputSource
|
||||
{
|
||||
MovementInput Capture();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Owns held movement sampling and the retail autorun latch. The input
|
||||
/// dispatcher remains the only keyboard/mouse-button state source.
|
||||
/// </summary>
|
||||
internal sealed class DispatcherMovementInputSource : IMovementInputSource
|
||||
{
|
||||
private readonly IInputCaptureSource? _capture;
|
||||
private InputDispatcher? _dispatcher;
|
||||
|
||||
public DispatcherMovementInputSource(IInputCaptureSource? capture = null) =>
|
||||
_capture = capture;
|
||||
|
||||
public bool AutoRunActive { get; private set; }
|
||||
|
||||
public void Bind(InputDispatcher dispatcher)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dispatcher);
|
||||
if (_dispatcher is not null && !ReferenceEquals(_dispatcher, dispatcher))
|
||||
throw new InvalidOperationException(
|
||||
"The movement input source is already bound to another dispatcher.");
|
||||
_dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
public MovementInput Capture()
|
||||
{
|
||||
// Devtools owns the whole gameplay keyboard while active, including
|
||||
// a latched autorun. Retained chat owns physical key state only;
|
||||
// retail's autorun latch continues until an explicit cancel action.
|
||||
if (_capture?.DevToolsWantCaptureKeyboard == true)
|
||||
return default;
|
||||
|
||||
if (_dispatcher is not { } dispatcher)
|
||||
return default;
|
||||
|
||||
bool walking = dispatcher.IsActionHeld(InputAction.MovementWalkMode);
|
||||
bool forward = dispatcher.IsActionHeld(InputAction.MovementForward);
|
||||
return new MovementInput(
|
||||
Forward: forward || AutoRunActive,
|
||||
Backward: dispatcher.IsActionHeld(InputAction.MovementBackup),
|
||||
StrafeLeft: dispatcher.IsActionHeld(InputAction.MovementStrafeLeft),
|
||||
StrafeRight: dispatcher.IsActionHeld(InputAction.MovementStrafeRight),
|
||||
TurnLeft: dispatcher.IsActionHeld(InputAction.MovementTurnLeft),
|
||||
TurnRight: dispatcher.IsActionHeld(InputAction.MovementTurnRight),
|
||||
Run: !walking,
|
||||
Jump: dispatcher.IsActionHeld(InputAction.MovementJump));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the press-only autorun policy at the same point in the semantic
|
||||
/// action pipeline as the former GameWindow body.
|
||||
/// </summary>
|
||||
/// <returns>True when the action is fully consumed.</returns>
|
||||
public bool HandlePressedAction(InputAction action)
|
||||
{
|
||||
if (action == InputAction.MovementRunLock)
|
||||
{
|
||||
AutoRunActive = !AutoRunActive;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (AutoRunActive && action is (
|
||||
InputAction.MovementBackup
|
||||
or InputAction.MovementStop
|
||||
or InputAction.MovementStrafeLeft
|
||||
or InputAction.MovementStrafeRight))
|
||||
{
|
||||
AutoRunActive = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ResetSession() => AutoRunActive = false;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue