using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; using Opsive.UltimateCharacterController.Input.VirtualControls; namespace Opsive.UltimateCharacterController.Input { public class UnityInput : PlayerInput { [Header("New Input System Settings")] [Tooltip("The Input Action Asset containing your mappings.")] [SerializeField] private InputActionAsset m_InputAsset; [Tooltip("The name of the Action Map to use (e.g., 'Player' or 'Gameplay').")] [SerializeField] private string m_ActionMapName = "Gameplay"; [Header("Standalone Settings")] [SerializeField] protected bool m_ForceInput; [SerializeField] protected bool m_DisableCursor = true; [SerializeField] protected bool m_EnableCursorWithEscape = true; [SerializeField] protected bool m_PreventLookVectorChanges = true; [Header("Controller")] [Range(0, 1)] [SerializeField] protected float m_JoystickUpThreshold = 1f; private InputActionMap m_ActionMap; private readonly Dictionary m_ActionCache = new Dictionary(); private VirtualControlsManager m_VirtualControlsManager; protected override bool CanCheckForController => false; protected override void Awake() { base.Awake(); if (m_InputAsset == null) { Debug.LogError("Error: No Input Action Asset assigned to UnityInput.", this); return; } m_ActionMap = m_InputAsset.FindActionMap(m_ActionMapName); if (m_ActionMap == null) { Debug.LogError($"Error: Action Map '{m_ActionMapName}' not found in {m_InputAsset.name}. Check the name in the Asset editor.", this); return; } // Cache all actions for high-performance string lookup m_ActionCache.Clear(); foreach (var action in m_ActionMap.actions) { m_ActionCache[action.name] = action; } m_ActionMap.Enable(); Debug.Log($"UnityInput: Initialized with Action Map '{m_ActionMapName}' and cached {m_ActionCache.Count} actions."); } protected virtual void OnEnable() { m_ActionMap?.Enable(); if (m_DisableCursor) { Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } } protected virtual void OnDisable() { m_ActionMap?.Disable(); } // --- OPSIVE OVERRIDES --- protected override bool GetButtonInternal(string name) { // 1. Virtual Controls (Mobile UI) if (m_VirtualControlsManager != null && m_VirtualControlsManager.GetButton(name, InputBase.ButtonAction.GetButton)) { return true; } // 2. Hardware Input if (m_ActionCache.TryGetValue(name, out var action)) { return action.IsPressed(); } return false; } protected override bool GetButtonDownInternal(string name) { if (m_VirtualControlsManager != null && m_VirtualControlsManager.GetButton(name, InputBase.ButtonAction.GetButtonDown)) { return true; } if (m_ActionCache.TryGetValue(name, out var action)) { return action.WasPressedThisFrame(); } return false; } protected override bool GetButtonUpInternal(string name) { if (m_VirtualControlsManager != null && m_VirtualControlsManager.GetButton(name, InputBase.ButtonAction.GetButtonUp)) { return true; } if (m_ActionCache.TryGetValue(name, out var action)) { return action.WasReleasedThisFrame(); } return false; } protected override float GetAxisInternal(string name) { if (m_VirtualControlsManager != null) { var vValue = m_VirtualControlsManager.GetAxis(name); if (vValue != 0) return vValue; } // --- SPECIAL CASE: ALIASING --- // If Opsive asks for standard names but your Asset uses Vector2 Move/Look // 1. Movement Aliasing if (name == "Horizontal" || name == "Vertical") { if (m_ActionCache.TryGetValue("Move", out var moveAction)) { var moveVal = moveAction.ReadValue(); return name == "Horizontal" ? moveVal.x : moveVal.y; } } // 2. Look/Mouse Aliasing if (name == "Mouse X" || name == "Mouse Y") { if (m_ActionCache.TryGetValue("Look", out var lookAction)) { var lookVal = lookAction.ReadValue(); return name == "Mouse X" ? lookVal.x : lookVal.y; } } // 3. Direct Float lookup if (m_ActionCache.TryGetValue(name, out var action)) { return action.ReadValue(); } return 0; } protected override float GetAxisRawInternal(string name) => GetAxisInternal(name); public override Vector2 GetMousePosition() => Mouse.current != null ? Mouse.current.position.ReadValue() : Vector2.zero; // --- VIRTUAL CONTROLS INTEGRATION --- public bool RegisterVirtualControlsManager(VirtualControlsManager virtualControlsManager) { m_VirtualControlsManager = virtualControlsManager; return m_VirtualControlsManager != null; } public void UnegisterVirtualControlsManager() { m_VirtualControlsManager = null; } // --- UTILITY --- protected override void OnApplicationFocus(bool hasFocus) { if (m_ForceInput) { hasFocus = true; } base.OnApplicationFocus(hasFocus); if (enabled && hasFocus && m_DisableCursor) { Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } } public bool ForceInput { get => m_ForceInput; set => m_ForceInput = value; } public bool DisableCursor { get => m_DisableCursor; set { m_DisableCursor = value; if (m_DisableCursor && Cursor.visible) { Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } else if (!m_DisableCursor && !Cursor.visible) { Cursor.lockState = CursorLockMode.None; Cursor.visible = true; } } } public bool EnableCursorWithEscape { get => m_EnableCursorWithEscape; set => m_EnableCursorWithEscape = value; } public bool PreventLookMovementWithEscape { get => m_PreventLookVectorChanges; set => m_PreventLookVectorChanges = value; } public float JoystickUpThreshold { get => m_JoystickUpThreshold; set => m_JoystickUpThreshold = value; } } }