using System.Collections; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using OctoRef = OctoCore.OctoCore; namespace Unheimlich.Navigation.Debuging { /// /// Listens for debug input combos and drives DebugNavigation. /// /// — Gamepad : L3+R3 simultaneously → unlock/lock. L2/R2 → prev/next scene. /// — Keyboard : backquote (² AZERTY / ~ QWERTY) → unlock/lock. A/E → prev/next. /// /// Device display: switches based on last active input, not physical connection. /// public class DebugMenuUnlocker : MonoBehaviour { [Header("Data")] [SerializeField] private DebugNavigation _debugNavigation; [Header("Unlock Events")] public UnityEvent OnDebugMenuUnlockedGamepad; public UnityEvent OnDebugMenuUnlockedKeyboard; public UnityEvent OnDebugMenuLocked; [Header("Navigation Events")] public UnityEvent OnPreviousScene; public UnityEvent OnNextScene; [Header("Device Switch Events")] [Tooltip("Fired when gamepad input is detected and last input was keyboard/mouse.")] public UnityEvent OnSwitchedToGamepad; [Tooltip("Fired when keyboard/mouse input is detected and last input was gamepad.")] public UnityEvent OnSwitchedToKeyboard; // ── State ──────────────────────────────────────────────────────────── private bool _isUnlocked = false; private bool _lastWasGamepad = false; // Input Actions private InputAction _keyboardUnlockAction; private InputAction _gamepadUnlockAction; private InputAction _gamepadPreviousAction; private InputAction _gamepadNextAction; private InputAction _keyboardPreviousAction; private InputAction _keyboardNextAction; private InputAction _anyGamepadAction; private InputAction _anyKeyboardAction; // ── Unity lifecycle ────────────────────────────────────────────────── private void Awake() => BuildInputActions(); private void OnEnable() => EnableActions(); private void Start() { DebugManager.instance.enableRuntimeUI = false; StartCoroutine(InitWhenReady()); SceneManager.sceneLoaded += OnUnitySceneLoaded; } private void OnDisable() { DisableActions(); UnsubscribeFromSceneEvents(); SceneManager.sceneLoaded -= OnUnitySceneLoaded; } private void OnDestroy() => DisposeActions(); // ── Build ──────────────────────────────────────────────────────────── private void BuildInputActions() { // Keyboard unlock : backquote (² AZERTY / ~ QWERTY) _keyboardUnlockAction = new InputAction("DebugUnlockKeyboard", InputActionType.Button); _keyboardUnlockAction.AddBinding("/backquote"); _keyboardUnlockAction.performed += _ => ToggleDebugMenu(false); // Gamepad unlock : L3 + R3 simultaneously _gamepadUnlockAction = new InputAction("DebugUnlockGamepad", InputActionType.Button); _gamepadUnlockAction.AddCompositeBinding("ButtonWithOneModifier") .With("Modifier", "/leftStickPress") .With("Button", "/rightStickPress"); _gamepadUnlockAction.performed += _ => ToggleDebugMenu(true); // Gamepad navigation : L2 / R2 _gamepadPreviousAction = new InputAction("DebugPrevGamepad", InputActionType.Button); _gamepadPreviousAction.AddBinding("/leftTrigger") .WithProcessor("AxisDeadzone(min=0.5,max=1)"); _gamepadPreviousAction.performed += _ => TryPrevious(); _gamepadNextAction = new InputAction("DebugNextGamepad", InputActionType.Button); _gamepadNextAction.AddBinding("/rightTrigger") .WithProcessor("AxisDeadzone(min=0.5,max=1)"); _gamepadNextAction.performed += _ => TryNext(); // Keyboard navigation : A / E _keyboardPreviousAction = new InputAction("DebugPrevKeyboard", InputActionType.Button); _keyboardPreviousAction.AddBinding("/q"); _keyboardPreviousAction.performed += _ => TryPrevious(); _keyboardNextAction = new InputAction("DebugNextKeyboard", InputActionType.Button); _keyboardNextAction.AddBinding("/e"); _keyboardNextAction.performed += _ => TryNext(); // Device detection _anyGamepadAction = new InputAction("AnyGamepad", InputActionType.PassThrough); _anyGamepadAction.AddBinding("/leftStick"); _anyGamepadAction.AddBinding("/rightStick"); _anyGamepadAction.AddBinding("/buttonSouth"); _anyGamepadAction.AddBinding("/buttonNorth"); _anyGamepadAction.AddBinding("/buttonEast"); _anyGamepadAction.AddBinding("/buttonWest"); _anyGamepadAction.AddBinding("/leftShoulder"); _anyGamepadAction.AddBinding("/rightShoulder"); _anyGamepadAction.AddBinding("/leftTrigger"); _anyGamepadAction.AddBinding("/rightTrigger"); _anyGamepadAction.AddBinding("/start"); _anyGamepadAction.AddBinding("/select"); _anyGamepadAction.AddBinding("/dpad"); _anyGamepadAction.performed += _ => OnAnyGamepadInput(); _anyKeyboardAction = new InputAction("AnyKeyboard", InputActionType.PassThrough); _anyKeyboardAction.AddBinding("/anyKey"); _anyKeyboardAction.AddBinding("/delta"); _anyKeyboardAction.AddBinding("/leftButton"); _anyKeyboardAction.AddBinding("/rightButton"); _anyKeyboardAction.performed += _ => OnAnyKeyboardInput(); } private void EnableActions() { _keyboardUnlockAction?.Enable(); _gamepadUnlockAction?.Enable(); _gamepadPreviousAction?.Enable(); _gamepadNextAction?.Enable(); _keyboardPreviousAction?.Enable(); _keyboardNextAction?.Enable(); _anyGamepadAction?.Enable(); _anyKeyboardAction?.Enable(); } private void DisableActions() { _keyboardUnlockAction?.Disable(); _gamepadUnlockAction?.Disable(); _gamepadPreviousAction?.Disable(); _gamepadNextAction?.Disable(); _keyboardPreviousAction?.Disable(); _keyboardNextAction?.Disable(); _anyGamepadAction?.Disable(); _anyKeyboardAction?.Disable(); } private void DisposeActions() { _keyboardUnlockAction?.Dispose(); _gamepadUnlockAction?.Dispose(); _gamepadPreviousAction?.Dispose(); _gamepadNextAction?.Dispose(); _keyboardPreviousAction?.Dispose(); _keyboardNextAction?.Dispose(); _anyGamepadAction?.Dispose(); _anyKeyboardAction?.Dispose(); } // ── Init ───────────────────────────────────────────────────────────── private IEnumerator InitWhenReady() { yield return new WaitUntil(() => OctoRef.Instance != null); yield return new WaitUntil(() => OctoRef.Instance.Navigation.CurrentScene != null); SyncDebugNavigation(); SubscribeToSceneEvents(); } // ── Scene events ───────────────────────────────────────────────────── private void SubscribeToSceneEvents() { if (OctoRef.Instance == null) return; OctoRef.Instance.Navigation.OnSceneLoadCompleted += OnSceneLoadCompleted; } private void UnsubscribeFromSceneEvents() { if (OctoRef.Instance == null) return; OctoRef.Instance.Navigation.OnSceneLoadCompleted -= OnSceneLoadCompleted; } private void OnUnitySceneLoaded(Scene scene, LoadSceneMode mode) { UnsubscribeFromSceneEvents(); SubscribeToSceneEvents(); } private void OnSceneLoadCompleted(OctoCore.Navigation.Data.OctoSceneData sceneData) { _debugNavigation?.SyncWithCurrentScene(sceneData); } // ── Device switch ──────────────────────────────────────────────────── private void OnAnyGamepadInput() { if (_lastWasGamepad) return; _lastWasGamepad = true; OnSwitchedToGamepad?.Invoke(); } private void OnAnyKeyboardInput() { if (!_lastWasGamepad) return; _lastWasGamepad = false; OnSwitchedToKeyboard?.Invoke(); } // ── Logic ──────────────────────────────────────────────────────────── private void SyncDebugNavigation() { if (_debugNavigation == null || OctoRef.Instance == null) return; _debugNavigation.SyncWithCurrentScene(OctoRef.Instance.Navigation.CurrentScene); } private void ToggleDebugMenu(bool isGamepad) { _isUnlocked = !_isUnlocked; if (_isUnlocked) { SyncDebugNavigation(); if (isGamepad) OnDebugMenuUnlockedGamepad?.Invoke(); else OnDebugMenuUnlockedKeyboard?.Invoke(); Debug.Log($"[DebugMenuUnlocker] Unlocked ({(isGamepad ? "Gamepad" : "Keyboard")})."); } else { OnDebugMenuLocked?.Invoke(); Debug.Log("[DebugMenuUnlocker] Locked."); } } private void TryPrevious() { if (!_isUnlocked || _debugNavigation == null) return; OnPreviousScene?.Invoke(); _debugNavigation.Previous(); } private void TryNext() { if (!_isUnlocked || _debugNavigation == null) return; OnNextScene?.Invoke(); _debugNavigation.Next(); } /// Called directly by Debug Menu UI buttons (0-based index). public void LoadSceneByIndex(int index) { if (_debugNavigation == null) return; _debugNavigation.LoadByIndex(index); } public bool IsUnlocked => _isUnlocked; } }