using UnityEngine; using UnityEngine.InputSystem; using RR.Common.Controls; using RR.Common.Settings; using RR.Game2D.Core.Managers; namespace RR.Common.Managers { /// /// Менеджер отслеживания бездействия игрока. /// При отсутствии ввода в течение заданного времени выкидывает игрока в главное меню. /// public class InactivityManager : MonoBehaviour { public static InactivityManager Instance { get; private set; } [Header("Настройки бездействия")] [SerializeField] private float inactivityTimeout = 300f; // 5 минут в секундах [SerializeField] private bool enableInactivityCheck = true; [Header("Отладка")] [SerializeField] private bool showDebugInfo; private float lastInputTime; private bool isInMainMenu = true; private bool isGameActive; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); Initialize(); } private void Initialize() { lastInputTime = Time.unscaledTime; // Подписываемся на все возможные источники ввода SubscribeToInputEvents(); // Подписываемся на события смены сцены UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded; // Подписываемся на изменения настроек var settingsManager = SettingsManager.Instance; if (settingsManager != null) { settingsManager.OnSettingsLoaded += LoadSettingsValues; settingsManager.OnSettingsSaved += LoadSettingsValues; LoadSettingsValues(); } Debug.Log("[InactivityManager] Инициализирован"); } private void OnDestroy() { UnsubscribeFromInputEvents(); UnityEngine.SceneManagement.SceneManager.sceneLoaded -= OnSceneLoaded; var settingsManager = SettingsManager.Instance; if (settingsManager != null) { settingsManager.OnSettingsLoaded -= LoadSettingsValues; settingsManager.OnSettingsSaved -= LoadSettingsValues; } } /// /// Загружает значения из настроек /// private void LoadSettingsValues() { var settings = SettingsManager.Instance; if (settings == null) { Debug.LogWarning("[InactivityManager] SettingsManager is null!"); return; } inactivityTimeout = settings.GetInt("gameplay.inactivityTimeout"); if (inactivityTimeout == 0) { Debug.Log("[InactivityManager] Отслеживание бездействия отключено (таймаут = 0)"); } else { Debug.Log($"[InactivityManager] Таймаут бездействия: {inactivityTimeout}s"); } } private void SubscribeToInputEvents() { // Подписываемся на события ComSystemManager (кнопки автомата) if (ComSystemManager.OnInputReceived != null) { ComSystemManager.OnInputReceived.AddListener(OnComInput); } // InputSystem.onAnyButtonPress - это событие, которое срабатывает каждый раз // когда нажимается любая кнопка. Мы просто слушаем его в Update через CheckForAnyInput } private void UnsubscribeFromInputEvents() { if (ComSystemManager.OnInputReceived != null) { ComSystemManager.OnInputReceived.RemoveListener(OnComInput); } } private void Update() { // Проверяем на наличие любого ввода каждый кадр CheckForAnyInput(); // Проверяем таймер бездействия if (enableInactivityCheck && !isInMainMenu && isGameActive) { float timeSinceLastInput = Time.unscaledTime - lastInputTime; if (showDebugInfo && Time.frameCount % 60 == 0) { Debug.Log($"[InactivityManager] Время бездействия: {timeSinceLastInput:F1}s / {inactivityTimeout}s"); } if (timeSinceLastInput >= inactivityTimeout) { OnInactivityTimeout(); } } } /// /// Проверяет на наличие любого ввода с клавиатуры, мыши или геймпада /// private void CheckForAnyInput() { if (isInMainMenu || !isGameActive) return; // Проверяем клавиатуру if (Keyboard.current != null && Keyboard.current.anyKey.wasPressedThisFrame) { ResetInactivityTimer(); return; } // Проверяем мышь if (Mouse.current != null) { if (Mouse.current.leftButton.wasPressedThisFrame || Mouse.current.rightButton.wasPressedThisFrame || Mouse.current.middleButton.wasPressedThisFrame || Mouse.current.delta.ReadValue().sqrMagnitude > 0.1f) { ResetInactivityTimer(); return; } } // Проверяем геймпад if (Gamepad.current != null) { foreach (var control in Gamepad.current.allControls) { if (control is UnityEngine.InputSystem.Controls.ButtonControl button && button.wasPressedThisFrame) { ResetInactivityTimer(); return; } } } } private void OnComInput(string input) { if (!isInMainMenu && isGameActive) { ResetInactivityTimer(); } } /// /// Сбрасывает таймер бездействия /// public void ResetInactivityTimer() { lastInputTime = Time.unscaledTime; if (showDebugInfo) { Debug.Log("[InactivityManager] Таймер сброшен"); } } /// /// Вызывается при достижении таймаута бездействия /// private void OnInactivityTimeout() { Debug.Log("[InactivityManager] Таймаут бездействия! Возврат в главное меню..."); enableInactivityCheck = false; // Отключаем проверку до следующей игры // Останавливаем игру if (GameManager.Instance != null) { GameManager.Instance.SetPause(false); GameManager.Instance.LoadScene("MainMenu", false); } ResetInactivityTimer(); } /// /// Обработчик загрузки сцены /// private void OnSceneLoaded(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode mode) { isInMainMenu = scene.name == "MainMenu"; if (isInMainMenu) { enableInactivityCheck = false; isGameActive = false; Debug.Log("[InactivityManager] Главное меню загружено - проверка отключена"); } ResetInactivityTimer(); } /// /// Включает проверку бездействия (вызывается при старте игры) /// public void EnableInactivityCheck() { enableInactivityCheck = true; isGameActive = true; ResetInactivityTimer(); Debug.Log("[InactivityManager] Проверка бездействия включена"); } /// /// Отключает проверку бездействия /// public void DisableInactivityCheck() { enableInactivityCheck = false; isGameActive = false; Debug.Log("[InactivityManager] Проверка бездействия отключена"); } /// /// Устанавливает время таймаута бездействия. /// Если установлено 0, отслеживание бездействия отключается. /// public void SetInactivityTimeout(float timeoutSeconds) { inactivityTimeout = Mathf.Max(0f, timeoutSeconds); // 0 = отключено, минимум 0 if (inactivityTimeout == 0f) { Debug.Log("[InactivityManager] Отслеживание бездействия отключено (таймаут = 0)"); } else { Debug.Log($"[InactivityManager] Таймаут установлен: {inactivityTimeout}s"); } } /// /// Получает текущее время таймаута /// public float GetInactivityTimeout() => inactivityTimeout; /// /// Получает время с момента последнего ввода /// public float GetTimeSinceLastInput() => Time.unscaledTime - lastInputTime; } }