Files
AppleHillsProduction/Assets/Scripts/Core/GameManager.cs

256 lines
9.0 KiB
C#

using System;
using System.Collections.Generic;
using AppleHills.Core.Interfaces;
using AppleHills.Core.Settings;
using Bootstrap;
using UI;
using UnityEngine;
namespace Core
{
/// <summary>
/// Singleton manager for global game state and settings. Provides accessors for various gameplay parameters.
/// </summary>
public class GameManager : MonoBehaviour
{
// Singleton implementation
private static GameManager _instance;
public static GameManager Instance => _instance;
private static bool _isQuitting = false;
private bool _settingsLoaded = false;
private bool _developerSettingsLoaded = false;
// Pausable implementation
private bool _isPaused = false;
public bool IsPaused => _isPaused;
// List of pausable components that have registered with the GameManager
private List<IPausable> _pausableComponents = new List<IPausable>();
// Events for pause state changes
public event Action OnGamePaused;
public event Action OnGameResumed;
void Awake()
{
_instance = this;
// Create settings providers if it doesn't exist
SettingsProvider.Instance.gameObject.name = "Settings Provider";
DeveloperSettingsProvider.Instance.gameObject.name = "Developer Settings Provider";
// Load all settings synchronously during Awake
InitializeSettings();
InitializeDeveloperSettings();
// Register for post-boot initialization
BootCompletionService.RegisterInitAction(InitializePostBoot);
// DontDestroyOnLoad(gameObject);
}
private void InitializePostBoot()
{
// For post-boot correct initialization order
}
/// <summary>
/// Register a component as pausable, so it receives pause/resume notifications
/// </summary>
/// <param name="component">The pausable component to register</param>
public void RegisterPausableComponent(IPausable component)
{
if (component != null && !_pausableComponents.Contains(component))
{
_pausableComponents.Add(component);
// If the game is already paused, pause the component immediately
if (_isPaused)
{
component.Pause();
}
Logging.Debug($"[GameManager] Registered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
}
}
/// <summary>
/// Unregister a pausable component
/// </summary>
/// <param name="component">The pausable component to unregister</param>
public void UnregisterPausableComponent(IPausable component)
{
if (component != null && _pausableComponents.Contains(component))
{
_pausableComponents.Remove(component);
Logging.Debug($"[GameManager] Unregistered pausable component: {(component as MonoBehaviour)?.name ?? "Unknown"}");
}
}
// TODO: Revisit this with proper pause menu request implementation
public void RequestGamePause()
{
PauseGame();
}
public void RequestGameResume()
{
ResumeGame();
}
/// <summary>
/// Pause the game and notify all registered pausable components
/// </summary>
private void PauseGame()
{
if (_isPaused) return; // Already paused
_isPaused = true;
// Pause all registered components
foreach (var component in _pausableComponents)
{
component.Pause();
}
// Broadcast pause event
OnGamePaused?.Invoke();
Logging.Debug($"[GameManager] Game paused. Paused {_pausableComponents.Count} components.");
}
/// <summary>
/// Resume the game and notify all registered pausable components
/// </summary>
private void ResumeGame()
{
if (!_isPaused) return; // Already running
_isPaused = false;
// Resume all registered components
foreach (var component in _pausableComponents)
{
component.DoResume();
}
// Broadcast resume event
OnGameResumed?.Invoke();
Logging.Debug($"[GameManager] Game resumed. Resumed {_pausableComponents.Count} components.");
}
private void InitializeSettings()
{
Logging.Debug("Starting settings initialization...");
// Load settings synchronously
var playerSettings = SettingsProvider.Instance.LoadSettingsSynchronous<PlayerFollowerSettings>();
var interactionSettings = SettingsProvider.Instance.LoadSettingsSynchronous<InteractionSettings>();
var minigameSettings = SettingsProvider.Instance.LoadSettingsSynchronous<DivingMinigameSettings>();
// Register settings with service locator
if (playerSettings != null)
{
ServiceLocator.Register<IPlayerFollowerSettings>(playerSettings);
Logging.Debug("PlayerFollowerSettings registered successfully");
}
else
{
Debug.LogError("Failed to load PlayerFollowerSettings");
}
if (interactionSettings != null)
{
ServiceLocator.Register<IInteractionSettings>(interactionSettings);
Logging.Debug("InteractionSettings registered successfully");
}
else
{
Debug.LogError("Failed to load InteractionSettings");
}
if (minigameSettings != null)
{
ServiceLocator.Register<IDivingMinigameSettings>(minigameSettings);
Logging.Debug("MinigameSettings registered successfully");
}
else
{
Debug.LogError("Failed to load MinigameSettings");
}
// Log success
_settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null;
if (_settingsLoaded)
{
Logging.Debug("All settings loaded and registered with ServiceLocator");
}
else
{
Logging.Warning("Some settings failed to load - check that all settings assets exist and are marked as Addressables");
}
}
/// <summary>
/// Check for and initialize developer settings.
/// </summary>
private void InitializeDeveloperSettings()
{
Logging.Debug("Starting developer settings initialization...");
// Load developer settings
var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings<DivingDeveloperSettings>();
_developerSettingsLoaded = divingDevSettings != null;
if (_developerSettingsLoaded)
{
Logging.Debug("All developer settings loaded successfully");
}
else
{
Logging.Warning("Some developer settings failed to load");
}
}
void OnApplicationQuit()
{
_isQuitting = true;
ServiceLocator.Clear();
}
// Helper method to get settings
private T GetSettings<T>() where T : class
{
return ServiceLocator.Get<T>();
}
/// <summary>
/// Returns the entire settings object of specified type.
/// </summary>
/// <typeparam name="T">Type of settings to retrieve</typeparam>
/// <returns>The settings object or null if not found</returns>
public static T GetSettingsObject<T>() where T : class
{
return Instance?.GetSettings<T>();
}
/// <summary>
/// Returns the developer settings object of specified type.
/// </summary>
/// <typeparam name="T">Type of developer settings to retrieve</typeparam>
/// <returns>The developer settings object or null if not found</returns>
public static T GetDeveloperSettings<T>() where T : BaseDeveloperSettings
{
return DeveloperSettingsProvider.Instance?.GetSettings<T>();
}
// LEFTOVER LEGACY SETTINGS
public float PlayerStopDistance => GetSettings<IInteractionSettings>()?.PlayerStopDistance ?? 6.0f;
public float PlayerStopDistanceDirectInteraction => GetSettings<IInteractionSettings>()?.PlayerStopDistanceDirectInteraction ?? 2.0f;
public float DefaultPuzzlePromptRange => GetSettings<IInteractionSettings>()?.DefaultPuzzlePromptRange ?? 3.0f;
}
}