using System; using System.Collections.Generic; using System.Linq; using RebootKit.Engine.Foundation; using UnityEngine; using UnityEngine.Assertions; using UnityEngine.InputSystem; using UnityEngine.Profiling; using Logger = RebootKit.Engine.Foundation.Logger; namespace RebootKit.Engine.Input { public class InputState : IDisposable { static readonly Logger s_Logger = new Logger(nameof(InputState)); public string Name { get; private set; } bool m_IsActive; public bool IsActive { get { return m_IsActive; } set { m_IsActive = value; Service?.UpdateUnityInputState(); } } int m_Priority; public int Priority { get { return m_Priority; } set { m_Priority = value; Service?.UpdateUnityInputState(); } } bool m_HideCursor; public bool HideCursor { get { return m_HideCursor; } set { m_HideCursor = value; Service?.UpdateUnityInputState(); } } bool m_LockCursor; public bool LockCursor { get { return m_LockCursor; } set { m_LockCursor = value; Service?.UpdateUnityInputState(); } } internal List ActiveMaps = new List(4); internal InputService Service; internal InputState(string name, InputService service) { IsActive = true; Name = name; Service = service; } public void Dispose() { Service.UnregisterInputState(this); Service = null; } public void AddActiveMap(string mapName) { if (ActiveMaps.Contains(mapName)) { s_Logger.Warning($"Action Map '{mapName}' is already active in InputState '{Name}'"); return; } ActiveMaps.Add(mapName); Service.UpdateUnityInputState(); } public void RemoveActiveMap(string mapName) { ActiveMaps.Remove(mapName); Service.UpdateUnityInputState(); } public bool IsMapActive(string mapName) { return ActiveMaps.Contains(mapName); } } public class InputService : IService { static readonly Logger s_Logger = new Logger(nameof(InputService)); readonly Config m_Config; InputActionAsset m_InputActionAsset; readonly List m_States = new List(16); public InputService(Config config) { m_Config = config; m_InputActionAsset = config.inputActionAsset; } public void Dispose() { m_InputActionAsset = null; } public InputState NewInputState(string name) { Assert.IsNull(m_States.FirstOrDefault(t => t.Name.Equals(name, StringComparison.Ordinal)), $"State with name '{name}' already exists in the input service."); var inputState = new InputState(name, this); m_States.Add(inputState); return inputState; } internal void UnregisterInputState(InputState state) { m_States.Remove(state); } internal void UpdateUnityInputState() { Profiler.BeginSample("Find Active State"); InputState activeState = m_States.Where(t => t.IsActive) .OrderByDescending(t => t.Priority) .FirstOrDefault(); Profiler.EndSample(); if (activeState == null) { s_Logger.Warning("No Active input state found"); return; } Cursor.visible = !activeState.HideCursor; Cursor.lockState = activeState.LockCursor ? CursorLockMode.Locked : CursorLockMode.None; foreach (InputActionMap inputActionMap in m_InputActionAsset.actionMaps) { if (activeState.IsMapActive(inputActionMap.name)) { inputActionMap.Enable(); } else { inputActionMap.Disable(); } } } public void EnableControls() { if (m_InputActionAsset == null) { return; } m_InputActionAsset.Enable(); } public void DisableControls() { if (m_InputActionAsset == null) { return; } m_InputActionAsset.Disable(); } [Serializable] public class Config { public InputActionAsset inputActionAsset; } } }