acdream/src/AcDream.App/Input/GameplayInputCommandController.cs
Erik 4eae9b4f5a refactor(input): own gameplay action routing
Move the sole semantic action-priority graph, combat and diagnostic commands, and retained-root item-drop lifetime behind focused typed owners. Preserve retail toggle behavior, explicit auto-wield cancellation, shutdown quiescence, and symmetric callback cleanup.

Co-authored-by: Codex <codex@openai.com>
2026-07-22 12:43:05 +02:00

210 lines
6.4 KiB
C#

using AcDream.App.Combat;
using AcDream.App.Diagnostics;
using AcDream.App.Rendering;
using AcDream.App.UI;
using AcDream.UI.Abstractions.Input;
namespace AcDream.App.Input;
internal interface IRetainedGameplayWindowCommands
{
void ToggleInventory();
}
internal sealed class RetainedGameplayWindowCommands(RetailUiRuntime? runtime)
: IRetainedGameplayWindowCommands
{
private readonly RetailUiRuntime? _runtime = runtime;
public void ToggleInventory() =>
_runtime?.ToggleWindow(WindowNames.Inventory);
}
internal interface IDevToolsGameplayCommands
{
void ToggleDebugPanel();
void FocusChatInput();
void ToggleSettingsPanel();
}
internal sealed class DevToolsGameplayCommands(DevToolsFramePresenter? presenter)
: IDevToolsGameplayCommands
{
private readonly DevToolsFramePresenter? _presenter = presenter;
public void ToggleDebugPanel() => _presenter?.ToggleDebugPanel();
public void FocusChatInput() => _presenter?.FocusChatInput();
public void ToggleSettingsPanel() => _presenter?.ToggleSettingsPanel();
}
internal interface IPlayerModeGameplayCommands
{
bool IsPlayerMode { get; }
void ToggleFlyOrChase();
void TogglePlayerMode();
void ExitPlayerMode();
}
internal sealed class PlayerModeGameplayCommands(
ILocalPlayerModeSource mode,
PlayerModeController controller) : IPlayerModeGameplayCommands
{
private readonly ILocalPlayerModeSource _mode = mode
?? throw new ArgumentNullException(nameof(mode));
private readonly PlayerModeController _controller = controller
?? throw new ArgumentNullException(nameof(controller));
public bool IsPlayerMode => _mode.IsPlayerMode;
public void ToggleFlyOrChase() => _controller.ToggleFlyOrChase();
public void TogglePlayerMode() => _controller.Toggle();
public void ExitPlayerMode() => _controller.Exit();
}
internal interface IItemTargetModeCommands
{
bool IsAnyTargetModeActive { get; }
void CancelTargetMode();
}
internal sealed class ItemTargetModeCommands(ItemInteractionController items)
: IItemTargetModeCommands
{
private readonly ItemInteractionController _items = items
?? throw new ArgumentNullException(nameof(items));
public bool IsAnyTargetModeActive => _items.IsAnyTargetModeActive;
public void CancelTargetMode() => _items.CancelTargetMode();
}
internal interface IGameplayCameraModeCommands
{
bool IsFlyMode { get; }
void ExitFlyMode();
}
internal sealed class GameplayCameraModeCommands(CameraController camera)
: IGameplayCameraModeCommands
{
private readonly CameraController _camera = camera
?? throw new ArgumentNullException(nameof(camera));
public bool IsFlyMode => _camera.IsFlyMode;
public void ExitFlyMode() => _camera.ToggleFly();
}
internal interface IGameplayWindowCommands
{
void Close();
}
internal sealed class GameplayWindowCommands(Action close) : IGameplayWindowCommands
{
private readonly Action _close = close
?? throw new ArgumentNullException(nameof(close));
public void Close() => _close();
}
internal interface IGameplayInputCommandTarget
{
bool Handle(InputAction action);
}
/// <summary>
/// Owns the final command tier of the frozen gameplay-action priority graph.
/// It coordinates canonical owners but stores no UI, camera, player, combat,
/// item-target, or diagnostic state of its own.
/// </summary>
internal sealed class GameplayInputCommandController : IGameplayInputCommandTarget
{
private readonly IRetainedGameplayWindowCommands _retained;
private readonly IDevToolsGameplayCommands _devTools;
private readonly IRuntimeDiagnosticCommands _diagnostics;
private readonly IPlayerModeGameplayCommands _playerMode;
private readonly IItemTargetModeCommands _targetMode;
private readonly IGameplayCameraModeCommands _camera;
private readonly ILiveCombatModeCommand _combat;
private readonly IGameplayWindowCommands _window;
public GameplayInputCommandController(
IRetainedGameplayWindowCommands retained,
IDevToolsGameplayCommands devTools,
IRuntimeDiagnosticCommands diagnostics,
IPlayerModeGameplayCommands playerMode,
IItemTargetModeCommands targetMode,
IGameplayCameraModeCommands camera,
ILiveCombatModeCommand combat,
IGameplayWindowCommands window)
{
_retained = retained ?? throw new ArgumentNullException(nameof(retained));
_devTools = devTools ?? throw new ArgumentNullException(nameof(devTools));
_diagnostics = diagnostics ?? throw new ArgumentNullException(nameof(diagnostics));
_playerMode = playerMode ?? throw new ArgumentNullException(nameof(playerMode));
_targetMode = targetMode ?? throw new ArgumentNullException(nameof(targetMode));
_camera = camera ?? throw new ArgumentNullException(nameof(camera));
_combat = combat ?? throw new ArgumentNullException(nameof(combat));
_window = window ?? throw new ArgumentNullException(nameof(window));
}
public bool Handle(InputAction action)
{
if (_diagnostics.Handle(action))
return true;
switch (action)
{
case InputAction.ToggleInventoryPanel:
_retained.ToggleInventory();
return true;
case InputAction.AcdreamToggleDebugPanel:
_devTools.ToggleDebugPanel();
return true;
case InputAction.AcdreamToggleFlyMode:
_playerMode.ToggleFlyOrChase();
return true;
case InputAction.AcdreamTogglePlayerMode:
_playerMode.TogglePlayerMode();
return true;
case InputAction.ToggleChatEntry:
_devTools.FocusChatInput();
return true;
case InputAction.ToggleOptionsPanel:
_devTools.ToggleSettingsPanel();
return true;
case InputAction.CombatToggleCombat:
_combat.Toggle();
return true;
case InputAction.EscapeKey:
HandleEscape();
return true;
default:
return false;
}
}
private void HandleEscape()
{
if (_targetMode.IsAnyTargetModeActive)
_targetMode.CancelTargetMode();
else if (_camera.IsFlyMode)
_camera.ExitFlyMode();
else if (_playerMode.IsPlayerMode)
_playerMode.ExitPlayerMode();
else
_window.Close();
}
}