using System; using Core; using UnityEngine; using UnityEngine.SceneManagement; using Input; using Bootstrap; using UI.Core; using Pixelplacement; namespace UI { public class PauseMenu : UIPage { private static PauseMenu _instance; private static bool _isQuitting; /// /// Singleton instance of the PauseMenu. No longer creates an instance if one doesn't exist. /// public static PauseMenu Instance => _instance; [Header("UI References")] [SerializeField] private GameObject pauseMenuPanel; [SerializeField] private GameObject pauseButton; [SerializeField] private CanvasGroup canvasGroup; public event Action OnGamePaused; public event Action OnGameResumed; private bool _isPaused = false; /// /// Returns whether the game is currently paused /// public bool IsPaused => _isPaused; private void Awake() { _instance = this; // Ensure we have a CanvasGroup for transitions if (canvasGroup == null) canvasGroup = GetComponent(); if (canvasGroup == null) canvasGroup = gameObject.AddComponent(); canvasGroup.alpha = 0f; canvasGroup.interactable = false; canvasGroup.blocksRaycasts = false; gameObject.SetActive(false); // Register for post-boot initialization BootCompletionService.RegisterInitAction(InitializePostBoot); } private void InitializePostBoot() { // Subscribe to scene loaded events SceneManagerService.Instance.SceneLoadCompleted += SetPauseMenuByLevel; // SceneManagerService subscription moved to InitializePostBoot // Set initial state based on current scene SetPauseMenuByLevel(SceneManager.GetActiveScene().name); Logging.Debug("[PauseMenu] Subscribed to SceneManagerService events"); } private void OnDestroy() { // Unsubscribe when destroyed if (SceneManagerService.Instance != null) { SceneManagerService.Instance.SceneLoadCompleted -= SetPauseMenuByLevel; } } void OnApplicationQuit() { _isQuitting = true; } /// /// Sets the pause menu game object active or inactive based on the current level /// /// The name of the level/scene public void SetPauseMenuByLevel(string levelName) { HidePauseMenu(false); // TODO: Implement level-based pause menu visibility logic if needed /*if (string.IsNullOrEmpty(levelName)) return; bool isStartingLevel = levelName.ToLower().Contains("startingscene"); if(isStartingLevel) HidePauseMenu(false); // Ensure menu is hidden when switching to a game level Logging.Debug($"[PauseMenu] Setting pause menu active: {!isStartingLevel} for scene: {levelName}");*/ } /// /// Shows the pause menu and hides the pause button. Sets input mode to UI. /// public void ShowPauseMenu() { if (_isPaused) return; if (UIPageController.Instance != null) { UIPageController.Instance.PushPage(this); } else { // Fallback if no controller, just show if (pauseMenuPanel != null) pauseMenuPanel.SetActive(true); gameObject.SetActive(true); BeginPauseSideEffects(); // no animation fallback if (canvasGroup != null) { canvasGroup.alpha = 1f; canvasGroup.interactable = true; canvasGroup.blocksRaycasts = true; } } } /// /// Hides the pause menu and shows the pause button. Sets input mode to Game. /// public void HidePauseMenu(bool resetInput = true) { if (!_isPaused) { // Ensure UI is hidden if somehow active without state if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false); gameObject.SetActive(false); return; } if (UIPageController.Instance != null && UIPageController.Instance.CurrentPage == this) { UIPageController.Instance.PopPage(); } else { // Fallback if no controller, just hide if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false); if (pauseButton != null) pauseButton.SetActive(true); EndPauseSideEffects(resetInput); if (canvasGroup != null) { canvasGroup.alpha = 0f; canvasGroup.interactable = false; canvasGroup.blocksRaycasts = false; } gameObject.SetActive(false); } } /// /// Resumes the game by hiding the pause menu. /// public void ResumeGame() { HidePauseMenu(); } private void BeginPauseSideEffects() { _isPaused = true; if (pauseButton != null) pauseButton.SetActive(false); InputManager.Instance.SetInputMode(InputMode.UI); OnGamePaused?.Invoke(); Logging.Debug("[PauseMenu] Game Paused"); } private void EndPauseSideEffects(bool invokeEvent) { _isPaused = false; if (pauseButton != null) pauseButton.SetActive(true); InputManager.Instance.SetInputMode(InputMode.GameAndUI); if (invokeEvent) OnGameResumed?.Invoke(); Logging.Debug("[PauseMenu] Game Resumed"); } protected override void DoTransitionIn(Action onComplete) { // Ensure the panel root is active if (pauseMenuPanel != null) pauseMenuPanel.SetActive(true); BeginPauseSideEffects(); if (canvasGroup != null) { canvasGroup.interactable = true; canvasGroup.blocksRaycasts = true; canvasGroup.alpha = 0f; Tween.Value(0f, 1f, v => canvasGroup.alpha = v, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete); } else { onComplete?.Invoke(); } } protected override void DoTransitionOut(Action onComplete) { if (canvasGroup != null) { canvasGroup.interactable = false; canvasGroup.blocksRaycasts = false; Tween.Value(canvasGroup.alpha, 0f, v => canvasGroup.alpha = v, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, () => { EndPauseSideEffects(true); if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false); onComplete?.Invoke(); }); } else { EndPauseSideEffects(true); if (pauseMenuPanel != null) pauseMenuPanel.SetActive(false); onComplete?.Invoke(); } } /// /// Exits to the main menu scene. /// public async void ExitToAppleHills() { // Replace with the actual scene name as set in Build Settings var progress = new Progress(p => Logging.Debug($"Loading progress: {p * 100:F0}%")); await SceneManagerService.Instance.SwitchSceneAsync("AppleHillsOverworld", progress); } /// /// Exits the application. /// public void ExitGame() { #if UNITY_EDITOR UnityEditor.EditorApplication.isPlaying = false; #else Application.Quit(); #endif } public async void ReloadLevel() { var progress = new Progress(p => Logging.Debug($"Loading progress: {p * 100:F0}%")); await SceneManagerService.Instance.ReloadCurrentScene(progress); } /// /// Loads a level based on the selection from a dropdown menu. /// Connect this to a Dropdown's onValueChanged event and pass the selected option text. /// /// The selected level name or identifier from the dropdown public async void LoadLevel(int levelSelection) { // Hide the pause menu before loading a new level HidePauseMenu(); // Replace with the actual scene name as set in Build Settings var progress = new Progress(p => Logging.Debug($"Loading progress: {p * 100:F0}%")); switch (levelSelection) { case 0: await SceneManagerService.Instance.SwitchSceneAsync("AppleHillsOverworld", progress); break; case 1: await SceneManagerService.Instance.SwitchSceneAsync("Quarry", progress); break; case 2: await SceneManagerService.Instance.SwitchSceneAsync("DivingForPictures", progress); break; } } } }