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;
}
}