2025-09-04 00:00:46 +02:00
|
|
|
|
using UnityEngine;
|
2025-09-23 14:43:02 +02:00
|
|
|
|
using AppleHills.Core.Settings;
|
|
|
|
|
|
using System.Collections;
|
2025-09-04 00:00:46 +02:00
|
|
|
|
|
2025-09-06 21:01:54 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Singleton manager for global game state and settings. Provides accessors for various gameplay parameters.
|
|
|
|
|
|
/// </summary>
|
2025-09-04 00:00:46 +02:00
|
|
|
|
public class GameManager : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
private static GameManager _instance;
|
2025-09-08 08:45:13 +02:00
|
|
|
|
private static bool _isQuitting = false;
|
|
|
|
|
|
|
2025-09-06 21:01:54 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Singleton instance of the GameManager.
|
|
|
|
|
|
/// </summary>
|
2025-09-04 00:00:46 +02:00
|
|
|
|
public static GameManager Instance
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2025-09-08 08:45:13 +02:00
|
|
|
|
if (_instance == null && Application.isPlaying && !_isQuitting)
|
2025-09-04 00:00:46 +02:00
|
|
|
|
{
|
|
|
|
|
|
_instance = FindAnyObjectByType<GameManager>();
|
|
|
|
|
|
if (_instance == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var go = new GameObject("GameManager");
|
|
|
|
|
|
_instance = go.AddComponent<GameManager>();
|
2025-09-08 08:45:13 +02:00
|
|
|
|
// DontDestroyOnLoad(go);
|
2025-09-04 00:00:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return _instance;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:43:02 +02:00
|
|
|
|
[Header("Legacy Game Settings (Deprecated)")]
|
|
|
|
|
|
[Tooltip("This is only used for migration to the new settings system")]
|
|
|
|
|
|
public GameSettings legacyGameSettings;
|
|
|
|
|
|
|
|
|
|
|
|
[Header("Settings Status")]
|
|
|
|
|
|
[SerializeField] private bool _settingsLoaded = false;
|
2025-09-04 00:00:46 +02:00
|
|
|
|
|
|
|
|
|
|
void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
_instance = this;
|
2025-09-23 14:43:02 +02:00
|
|
|
|
|
|
|
|
|
|
// Create settings provider if it doesn't exist
|
|
|
|
|
|
SettingsProvider.Instance.gameObject.name = "Settings Provider";
|
|
|
|
|
|
|
|
|
|
|
|
// Load all settings
|
|
|
|
|
|
StartCoroutine(InitializeSettings());
|
|
|
|
|
|
|
|
|
|
|
|
// DontDestroyOnLoad(gameObject);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator InitializeSettings()
|
|
|
|
|
|
{
|
|
|
|
|
|
// Initialize the settings provider
|
|
|
|
|
|
var initComplete = false;
|
|
|
|
|
|
SettingsProvider.Instance.PreloadAllSettings(() => initComplete = true);
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for settings to be loaded
|
|
|
|
|
|
while (!initComplete)
|
2025-09-12 16:47:45 +02:00
|
|
|
|
{
|
2025-09-23 14:43:02 +02:00
|
|
|
|
yield return null;
|
2025-09-12 16:47:45 +02:00
|
|
|
|
}
|
2025-09-23 14:43:02 +02:00
|
|
|
|
|
|
|
|
|
|
// Register settings with service locator
|
|
|
|
|
|
ServiceLocator.Register<IPlayerFollowerSettings>(
|
|
|
|
|
|
SettingsProvider.Instance.GetSettings<PlayerFollowerSettings>());
|
|
|
|
|
|
|
|
|
|
|
|
ServiceLocator.Register<IInteractionSettings>(
|
|
|
|
|
|
SettingsProvider.Instance.GetSettings<InteractionSettings>());
|
|
|
|
|
|
|
|
|
|
|
|
ServiceLocator.Register<IMinigameSettings>(
|
|
|
|
|
|
SettingsProvider.Instance.GetSettings<MinigameSettings>());
|
|
|
|
|
|
|
|
|
|
|
|
// Log success
|
|
|
|
|
|
Debug.Log("All settings loaded and registered with ServiceLocator");
|
|
|
|
|
|
_settingsLoaded = true;
|
|
|
|
|
|
|
|
|
|
|
|
// Migrate settings if needed
|
|
|
|
|
|
if (legacyGameSettings != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
MigrateFromLegacySettings();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void MigrateFromLegacySettings()
|
|
|
|
|
|
{
|
|
|
|
|
|
// This method can be used to copy settings from the old GameSettings to the new system
|
|
|
|
|
|
// Implement if needed for your production environment
|
|
|
|
|
|
Debug.Log("Legacy settings migration available but not implemented.");
|
2025-09-08 08:45:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OnApplicationQuit()
|
|
|
|
|
|
{
|
|
|
|
|
|
_isQuitting = true;
|
2025-09-23 14:43:02 +02:00
|
|
|
|
ServiceLocator.Clear();
|
2025-09-04 00:00:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 14:43:02 +02:00
|
|
|
|
// Helper method to get settings
|
|
|
|
|
|
private T GetSettings<T>() where T : class
|
|
|
|
|
|
{
|
|
|
|
|
|
return ServiceLocator.Get<T>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PLAYER & FOLLOWER SETTINGS
|
|
|
|
|
|
|
|
|
|
|
|
// Player settings
|
|
|
|
|
|
public float MoveSpeed => GetSettings<IPlayerFollowerSettings>()?.MoveSpeed ?? 5f;
|
|
|
|
|
|
public float StopDistance => GetSettings<IPlayerFollowerSettings>()?.StopDistance ?? 0.1f;
|
|
|
|
|
|
public bool UseRigidbody => GetSettings<IPlayerFollowerSettings>()?.UseRigidbody ?? true;
|
|
|
|
|
|
public GameSettings.HoldMovementMode DefaultHoldMovementMode =>
|
|
|
|
|
|
GetSettings<IPlayerFollowerSettings>()?.DefaultHoldMovementMode ?? GameSettings.HoldMovementMode.Pathfinding;
|
|
|
|
|
|
|
|
|
|
|
|
// Follower settings
|
|
|
|
|
|
public float FollowDistance => GetSettings<IPlayerFollowerSettings>()?.FollowDistance ?? 1.5f;
|
|
|
|
|
|
public float ManualMoveSmooth => GetSettings<IPlayerFollowerSettings>()?.ManualMoveSmooth ?? 8f;
|
|
|
|
|
|
public float ThresholdFar => GetSettings<IPlayerFollowerSettings>()?.ThresholdFar ?? 2.5f;
|
|
|
|
|
|
public float ThresholdNear => GetSettings<IPlayerFollowerSettings>()?.ThresholdNear ?? 0.5f;
|
|
|
|
|
|
public float StopThreshold => GetSettings<IPlayerFollowerSettings>()?.StopThreshold ?? 0.1f;
|
|
|
|
|
|
public float FollowUpdateInterval => GetSettings<IPlayerFollowerSettings>()?.FollowUpdateInterval ?? 0.1f;
|
|
|
|
|
|
public float FollowerSpeedMultiplier => GetSettings<IPlayerFollowerSettings>()?.FollowerSpeedMultiplier ?? 1.2f;
|
|
|
|
|
|
public float HeldIconDisplayHeight => GetSettings<IPlayerFollowerSettings>()?.HeldIconDisplayHeight ?? 2.0f;
|
|
|
|
|
|
|
|
|
|
|
|
// INTERACTION SETTINGS
|
|
|
|
|
|
|
|
|
|
|
|
public float PlayerStopDistance => GetSettings<IInteractionSettings>()?.PlayerStopDistance ?? 6.0f;
|
|
|
|
|
|
public float PlayerStopDistanceDirectInteraction => GetSettings<IInteractionSettings>()?.PlayerStopDistanceDirectInteraction ?? 2.0f;
|
|
|
|
|
|
public float FollowerPickupDelay => GetSettings<IInteractionSettings>()?.FollowerPickupDelay ?? 0.2f;
|
|
|
|
|
|
public LayerMask InteractableLayerMask => GetSettings<IInteractionSettings>()?.InteractableLayerMask ?? -1;
|
|
|
|
|
|
public GameObject BasePickupPrefab => GetSettings<IInteractionSettings>()?.BasePickupPrefab;
|
|
|
|
|
|
public GameObject LevelSwitchMenuPrefab => GetSettings<IInteractionSettings>()?.LevelSwitchMenuPrefab;
|
2025-09-04 13:08:14 +02:00
|
|
|
|
|
2025-09-06 21:01:54 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns the combination rule for two items, if any.
|
|
|
|
|
|
/// </summary>
|
2025-09-04 13:08:14 +02:00
|
|
|
|
public GameSettings.CombinationRule GetCombinationRule(PickupItemData item1, PickupItemData item2)
|
|
|
|
|
|
{
|
2025-09-23 14:43:02 +02:00
|
|
|
|
var settings = GetSettings<IInteractionSettings>();
|
|
|
|
|
|
if (settings == null || settings.CombinationRules == null) return null;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var rule in settings.CombinationRules)
|
2025-09-04 13:08:14 +02:00
|
|
|
|
{
|
2025-09-12 16:47:45 +02:00
|
|
|
|
if ((PickupItemData.AreEquivalent(rule.itemA, item1) && PickupItemData.AreEquivalent(rule.itemB, item2)) ||
|
|
|
|
|
|
(PickupItemData.AreEquivalent(rule.itemA, item2) && PickupItemData.AreEquivalent(rule.itemB, item1)))
|
2025-09-04 13:08:14 +02:00
|
|
|
|
{
|
|
|
|
|
|
return rule;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-09-04 14:24:28 +02:00
|
|
|
|
|
2025-09-06 21:01:54 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns the slot item config for a given slot item.
|
|
|
|
|
|
/// </summary>
|
2025-09-04 14:24:28 +02:00
|
|
|
|
public GameSettings.SlotItemConfig GetSlotItemConfig(PickupItemData slotItem)
|
|
|
|
|
|
{
|
2025-09-23 14:43:02 +02:00
|
|
|
|
var settings = GetSettings<IInteractionSettings>();
|
|
|
|
|
|
if (settings == null || settings.SlotItemConfigs == null || slotItem == null) return null;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var config in settings.SlotItemConfigs)
|
2025-09-04 14:24:28 +02:00
|
|
|
|
{
|
2025-09-12 16:47:45 +02:00
|
|
|
|
if (PickupItemData.AreEquivalent(slotItem, config.slotItem))
|
2025-09-04 14:24:28 +02:00
|
|
|
|
return config;
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2025-09-23 14:43:02 +02:00
|
|
|
|
|
|
|
|
|
|
// MINIGAME SETTINGS
|
|
|
|
|
|
|
|
|
|
|
|
// Endless Descender settings
|
|
|
|
|
|
public float EndlessDescenderLerpSpeed => GetSettings<IMinigameSettings>()?.EndlessDescenderLerpSpeed ?? 12f;
|
|
|
|
|
|
public float EndlessDescenderMaxOffset => GetSettings<IMinigameSettings>()?.EndlessDescenderMaxOffset ?? 3f;
|
|
|
|
|
|
public float EndlessDescenderClampXMin => GetSettings<IMinigameSettings>()?.EndlessDescenderClampXMin ?? -3.5f;
|
|
|
|
|
|
public float EndlessDescenderClampXMax => GetSettings<IMinigameSettings>()?.EndlessDescenderClampXMax ?? 3.5f;
|
|
|
|
|
|
public float EndlessDescenderSpeedExponent => GetSettings<IMinigameSettings>()?.EndlessDescenderSpeedExponent ?? 2.5f;
|
2025-09-04 00:00:46 +02:00
|
|
|
|
}
|