using System; using System.Collections.Generic; using BriarQueen.Framework.Coordinators.Events; using BriarQueen.Framework.Events.Gameplay; using BriarQueen.Framework.Events.Input; using BriarQueen.Framework.Events.UI; using BriarQueen.Framework.Managers.UI; using BriarQueen.Framework.Services.Game; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.UI; using VContainer; namespace BriarQueen.Framework.Managers.Input { public enum DeviceInputType { KeyboardAndMouse, XboxController, PlaystationController, SwitchProController } public class InputManager : MonoBehaviour, IDisposable, IManager { [Header("Input")] [SerializeField] private PlayerInput _playerInput; [Header("Virtual Cursor")] [SerializeField] private float _controllerCursorSpeed = 1200f; [SerializeField] private bool _clampCursorToScreen = true; private readonly Dictionary _cachedByName = new(); private InputAction _clickAction; private InputAction _codexAction; private bool _codexShown; private bool _toolScreenShown; private GameService _gameService; private EventCoordinator _eventCoordinator; private InputAction _hideHudAction; private bool _hudHidden; private bool _initialized; private bool _isPaused; private InputAction _pauseAction; private InputAction _pointAction; private InputAction _rightClickAction; private InputAction _openToolsAction; private InputAction _nextToolAction; private InputAction _previousToolAction; private InputAction _nextItemAction; private InputAction _previousItemAction; private InputAction _virtualMouseAction; private InputAction _submitAction; private UICursorService _uiCursorService; private Vector2 _controllerCursorInput; public Vector2 PointerPosition { get; private set; } public DeviceInputType DeviceInputType { get; private set; } public string ActiveActionMap => _playerInput != null && _playerInput.currentActionMap != null ? _playerInput.currentActionMap.name : string.Empty; public bool Initialized => _initialized; public bool IsPaused => _isPaused; public bool UsingControllerCursor => DeviceInputType != DeviceInputType.KeyboardAndMouse; private void Awake() { PointerPosition = new Vector2(Screen.width * 0.5f, Screen.height * 0.5f); } private void Update() { if (!_initialized) return; UpdateControllerCursor(); if (_uiCursorService != null && UsingControllerCursor) _uiCursorService.SetVirtualCursorPosition(PointerPosition); } private void OnDestroy() { Dispose(); } public void Dispose() { if (!_initialized) return; if (_eventCoordinator != null) { _eventCoordinator.Unsubscribe(OnHudStateChanged); _eventCoordinator.Unsubscribe(OnCodexStateChanged); _eventCoordinator.Unsubscribe(OnToolScreenStateChanged); } UnbindCoreInputs(); _initialized = false; } [Inject] public void Construct( EventCoordinator eventCoordinator, UICursorService uiCursorService, GameService gameService) { _eventCoordinator = eventCoordinator; _uiCursorService = uiCursorService; _gameService = gameService; } public void Initialize() { Debug.Log("[InputManager] Initialize called"); if (_initialized) { Debug.Log("[InputManager] Already initialized"); return; } if (_eventCoordinator == null) { Debug.LogWarning("[InputManager] EventCoordinator is null"); return; } if (_playerInput == null) { Debug.LogWarning("[InputManager] PlayerInput is null"); return; } if (_playerInput.actions == null) { Debug.LogWarning("[InputManager] PlayerInput.actions is null"); return; } Debug.Log($"[InputManager] Current map before cache: {ActiveActionMap}"); CacheActions(); Debug.Log($"[InputManager] Point action: {_pointAction}"); Debug.Log($"[InputManager] Click action: {_clickAction}"); Debug.Log($"[InputManager] Virtual_Mouse action: {_virtualMouseAction}"); BindCoreInputs(); DeviceInputType = GetDeviceInputType(_playerInput); ApplyCursorModeForCurrentScheme(); _initialized = true; Debug.Log("[InputManager] Initialization complete"); } private void CacheActions() { _cachedByName.Clear(); _pointAction = CacheAction("Point"); _virtualMouseAction = CacheAction("Virtual_Mouse"); _pauseAction = CacheAction("Pause"); _clickAction = CacheAction("Click"); _rightClickAction = CacheAction("Right_Click"); _hideHudAction = CacheAction("Hide_HUD"); _codexAction = CacheAction("Codex"); _openToolsAction = CacheAction("Show_Tools"); _nextToolAction = CacheAction("Next_Tool"); _previousToolAction = CacheAction("Previous_Tool"); _nextItemAction = CacheAction("Next_Item"); _previousItemAction = CacheAction("Previous_Item"); _submitAction = CacheAction("Submit"); } private InputAction CacheAction(string actionName) { var action = GetAction(actionName); if (action != null && !string.IsNullOrWhiteSpace(action.name)) _cachedByName[action.name] = action; return action; } private void BindCoreInputs() { if (_pointAction != null) { Debug.Log("[InputManager] Binding Point"); _pointAction.performed += OnPoint; _pointAction.canceled += OnPoint; } else { Debug.LogWarning("[InputManager] Required action 'Point' not found."); } if (_virtualMouseAction != null) { _virtualMouseAction.performed += OnVirtualMouse; _virtualMouseAction.canceled += OnVirtualMouse; } if (_pauseAction != null) _pauseAction.performed += OnPause; else Debug.LogWarning("[InputManager] Action 'Pause' not found."); if (_clickAction != null) _clickAction.performed += OnClick; else Debug.LogWarning("[InputManager] Action 'Click' not found."); if (_rightClickAction != null) _rightClickAction.performed += OnRightClick; else Debug.LogWarning("[InputManager] Action 'Right_Click' not found."); if (_hideHudAction != null) _hideHudAction.performed += OnHideHUD; else Debug.LogWarning("[InputManager] Action 'Hide_HUD' not found."); if (_codexAction != null) _codexAction.performed += OnCodex; else Debug.LogWarning("[InputManager] Action 'Codex' not found."); if (_openToolsAction != null) _openToolsAction.performed += OnOpenTools; else Debug.LogWarning("[InputManager] Action 'Show_Tools' not found."); if (_nextToolAction != null) _nextToolAction.performed += OnNextToolClicked; else Debug.LogWarning("[InputManager] Action 'Next_Tool' not found."); if (_previousToolAction != null) _previousToolAction.performed += OnPreviousToolClicked; else Debug.LogWarning("[InputManager] Action 'Previous_Tool' not found."); if (_nextItemAction != null) _nextItemAction.performed += OnNextItemClicked; else Debug.LogWarning("[InputManager] Action 'Next_Item' not found."); if (_previousItemAction != null) _previousItemAction.performed += OnPreviousItemClicked; else Debug.LogWarning("[InputManager] Action 'Previous_Item' not found."); if (_playerInput != null) _playerInput.onControlsChanged += OnControlsChanged; } private void UnbindCoreInputs() { if (_pointAction != null) { _pointAction.performed -= OnPoint; _pointAction.canceled -= OnPoint; } if (_virtualMouseAction != null) { _virtualMouseAction.performed -= OnVirtualMouse; _virtualMouseAction.canceled -= OnVirtualMouse; } if (_pauseAction != null) _pauseAction.performed -= OnPause; if (_clickAction != null) _clickAction.performed -= OnClick; if (_rightClickAction != null) _rightClickAction.performed -= OnRightClick; if (_hideHudAction != null) _hideHudAction.performed -= OnHideHUD; if (_codexAction != null) _codexAction.performed -= OnCodex; if (_openToolsAction != null) _openToolsAction.performed -= OnOpenTools; if (_nextToolAction != null) _nextToolAction.performed -= OnNextToolClicked; if (_previousToolAction != null) _previousToolAction.performed -= OnPreviousToolClicked; if (_nextItemAction != null) _nextItemAction.performed -= OnNextItemClicked; if (_previousItemAction != null) _previousItemAction.performed -= OnPreviousItemClicked; if (_playerInput != null) _playerInput.onControlsChanged -= OnControlsChanged; } private void UpdateControllerCursor() { if (!UsingControllerCursor) return; if (_controllerCursorInput.sqrMagnitude <= 0.0001f) return; PointerPosition += _controllerCursorInput * (_controllerCursorSpeed * Time.unscaledDeltaTime); if (_clampCursorToScreen) { PointerPosition = new Vector2( Mathf.Clamp(PointerPosition.x, 0f, Screen.width), Mathf.Clamp(PointerPosition.y, 0f, Screen.height) ); } } private void OnControlsChanged(PlayerInput playerInput) { Debug.Log($"Controls changed. Scheme: {playerInput.currentControlScheme}"); DeviceInputType = GetDeviceInputType(playerInput); ApplyCursorModeForCurrentScheme(); } private void ApplyCursorModeForCurrentScheme() { if (_uiCursorService == null) return; var useVirtualCursor = UsingControllerCursor; _uiCursorService.SetUseVirtualCursor(useVirtualCursor); if (useVirtualCursor) _uiCursorService.SetVirtualCursorPosition(PointerPosition); } public void BindPauseForSkip(Action callback) { if (_pauseAction == null || callback == null) return; _pauseAction.performed -= OnPause; _pauseAction.performed += callback; } public void ResetPauseBind(Action callback) { if (_pauseAction == null || callback == null) return; _pauseAction.performed -= callback; _pauseAction.performed -= OnPause; _pauseAction.performed += OnPause; } public void BindSubmitForStart(Action callback) { if (_submitAction == null || callback == null) return; _submitAction.performed += callback; } public void ResetSubmitBind(Action callback) { if (_submitAction == null || callback == null) return; _submitAction.performed -= callback; } public void BindAction(string actionName, Action callback) { if (callback == null) return; var action = GetCachedAction(actionName); if (action == null) { Debug.LogWarning($"[InputManager] Action '{actionName}' not found."); return; } action.performed -= callback; action.performed += callback; } public void UnbindAction(string actionName, Action callback) { if (callback == null) return; var action = GetCachedAction(actionName); if (action == null) { Debug.LogWarning($"[InputManager] Action '{actionName}' not found."); return; } action.performed -= callback; } private InputAction GetCachedAction(string actionName) { if (string.IsNullOrWhiteSpace(actionName)) return null; if (_cachedByName.TryGetValue(actionName, out var cached)) return cached; var action = GetAction(actionName); if (action != null) _cachedByName[actionName] = action; return action; } private static DeviceInputType GetDeviceInputType(PlayerInput input) { if (input == null) return DeviceInputType.KeyboardAndMouse; return input.currentControlScheme switch { "Keyboard&Mouse" => DeviceInputType.KeyboardAndMouse, "Xbox" => DeviceInputType.XboxController, "Playstation" => DeviceInputType.PlaystationController, "Switch Pro" => DeviceInputType.SwitchProController, _ => DeviceInputType.KeyboardAndMouse }; } private void OnHudStateChanged(UIToggleHudEvent evt) { _hudHidden = !evt.Show; } private void OnCodexStateChanged(ToggleCodexEvent evt) { _codexShown = evt.Shown; } private void OnToolScreenStateChanged(ToggleToolScreenEvent evt) { _toolScreenShown = evt.Shown; } private void OnHideHUD(InputAction.CallbackContext ctx) { _hudHidden = !_hudHidden; _eventCoordinator?.PublishImmediate(new UIToggleHudEvent(_hudHidden)); } private void OnPause(InputAction.CallbackContext ctx) { if(_gameService.IsMainMenuSceneLoaded) return; _isPaused = !_isPaused; _eventCoordinator?.Publish(new PauseButtonClickedEvent()); } private void OnCodex(InputAction.CallbackContext ctx) { if(_gameService.IsMainMenuSceneLoaded) return; _codexShown = !_codexShown; _eventCoordinator?.Publish(new ToggleCodexEvent(_codexShown)); } private void OnClick(InputAction.CallbackContext ctx) { _eventCoordinator?.PublishImmediate(new OnClickEvent(ctx)); } private void OnRightClick(InputAction.CallbackContext ctx) { _eventCoordinator?.PublishImmediate(new OnRightClickEvent(ctx)); } private void OnPoint(InputAction.CallbackContext ctx) { PointerPosition = ctx.ReadValue(); } private void OnVirtualMouse(InputAction.CallbackContext ctx) { _controllerCursorInput = ctx.ReadValue(); } private void OnOpenTools(InputAction.CallbackContext ctx) { if(_gameService.IsMainMenuSceneLoaded) return; _toolScreenShown = !_toolScreenShown; _eventCoordinator?.Publish(new ToggleToolScreenEvent(_toolScreenShown)); } private void OnNextToolClicked(InputAction.CallbackContext ctx) { _eventCoordinator?.Publish(new OnNextToolChangedEvent()); } private void OnPreviousToolClicked(InputAction.CallbackContext ctx) { _eventCoordinator?.Publish(new OnPreviousToolChangedEvent()); } private void OnNextItemClicked(InputAction.CallbackContext ctx) { _eventCoordinator?.Publish(new OnNextItemClickedEvent()); } private void OnPreviousItemClicked(InputAction.CallbackContext ctx) { _eventCoordinator?.Publish(new OnPreviousItemClickedEvent()); } public InputAction GetAction(string actionName) { if (_playerInput == null || _playerInput.actions == null || string.IsNullOrWhiteSpace(actionName)) return null; try { return _playerInput.actions.FindAction(actionName, true); } catch { return null; } } } }