Working synchronous Addressables settings loading
This commit is contained in:
@@ -10,7 +10,6 @@ namespace AppleHills.Editor
|
||||
public class SettingsMigrationWindow : EditorWindow
|
||||
{
|
||||
private GameSettings legacySettings;
|
||||
private bool settingsFolderExists;
|
||||
private bool addressablesInstalled;
|
||||
private AddressableAssetSettings addressableSettings;
|
||||
private AddressableAssetGroup settingsGroup;
|
||||
@@ -19,7 +18,7 @@ namespace AppleHills.Editor
|
||||
private Vector2 scrollPosition;
|
||||
private bool migrationCompleted = false;
|
||||
|
||||
[MenuItem("AppleHills/Migrate Legacy Settings")]
|
||||
[MenuItem("Tools/Migrate Legacy Settings")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
var window = GetWindow<SettingsMigrationWindow>("Settings Migration");
|
||||
@@ -28,9 +27,6 @@ namespace AppleHills.Editor
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// Check if Settings folder exists
|
||||
settingsFolderExists = AssetDatabase.IsValidFolder("Assets/Settings");
|
||||
|
||||
// Check if Addressables package is installed
|
||||
addressablesInstalled = AddressableAssetSettingsDefaultObject.SettingsExists;
|
||||
|
||||
@@ -60,8 +56,7 @@ namespace AppleHills.Editor
|
||||
|
||||
EditorGUILayout.HelpBox(
|
||||
"This tool will migrate your legacy GameSettings to the new modular settings system. " +
|
||||
"It will create new settings assets in the Assets/Settings folder, mark them as Addressables, " +
|
||||
"and copy values from your legacy settings.",
|
||||
"It will create new settings assets and mark them as Addressables for synchronous loading at runtime.",
|
||||
MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
@@ -112,7 +107,8 @@ namespace AppleHills.Editor
|
||||
EditorGUILayout.LabelField("Migration completed successfully!", successStyle);
|
||||
EditorGUILayout.HelpBox(
|
||||
"The legacy settings have been migrated to the new system. " +
|
||||
"You can now access these settings through the AppleHills > Settings Editor menu.",
|
||||
"You can now access these settings through the AppleHills > Settings Editor menu. " +
|
||||
"Settings are marked as Addressables and will load synchronously at runtime.",
|
||||
MessageType.Info);
|
||||
}
|
||||
|
||||
@@ -122,10 +118,9 @@ namespace AppleHills.Editor
|
||||
private void MigrateSettings()
|
||||
{
|
||||
// Create Settings folder if it doesn't exist
|
||||
if (!settingsFolderExists)
|
||||
if (!AssetDatabase.IsValidFolder("Assets/Settings"))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets", "Settings");
|
||||
settingsFolderExists = true;
|
||||
}
|
||||
|
||||
// Setup Addressables group for settings
|
||||
@@ -159,7 +154,7 @@ namespace AppleHills.Editor
|
||||
var guid = AssetDatabase.AssetPathToGUID(assetPath);
|
||||
var entry = addressableSettings.CreateOrMoveEntry(guid, settingsGroup);
|
||||
|
||||
// Set the address
|
||||
// Set the address - use without .asset extension for cleaner addresses
|
||||
entry.address = address;
|
||||
|
||||
Debug.Log($"Added {assetPath} to Addressables with address {address}");
|
||||
|
||||
@@ -1979,6 +1979,10 @@ PrefabInstance:
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7852204877518954380, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
|
||||
propertyPath: maxSpeed
|
||||
value: 15
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
using AppleHills.Core.Settings;
|
||||
using System.Collections;
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Singleton manager for global game state and settings. Provides accessors for various gameplay parameters.
|
||||
@@ -37,59 +37,88 @@ public class GameManager : MonoBehaviour
|
||||
|
||||
[Header("Settings Status")]
|
||||
[SerializeField] private bool _settingsLoaded = false;
|
||||
public bool SettingsLoaded => _settingsLoaded;
|
||||
|
||||
// Use this for fallback values when settings aren't loaded yet
|
||||
[Header("Fallback Settings")]
|
||||
[SerializeField] private GameSettings fallbackSettings;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_instance = this;
|
||||
|
||||
// If no fallback settings assigned, try to load them
|
||||
if (fallbackSettings == null)
|
||||
{
|
||||
fallbackSettings = Resources.Load<GameSettings>("DefaultSettings");
|
||||
}
|
||||
|
||||
// Create settings provider if it doesn't exist
|
||||
SettingsProvider.Instance.gameObject.name = "Settings Provider";
|
||||
|
||||
// Load all settings
|
||||
StartCoroutine(InitializeSettings());
|
||||
// Load all settings synchronously during Awake
|
||||
InitializeSettings();
|
||||
|
||||
// DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
private IEnumerator InitializeSettings()
|
||||
private void InitializeSettings()
|
||||
{
|
||||
// Initialize the settings provider
|
||||
var initComplete = false;
|
||||
SettingsProvider.Instance.PreloadAllSettings(() => initComplete = true);
|
||||
Debug.Log("Starting settings initialization...");
|
||||
|
||||
// Load settings synchronously
|
||||
var playerSettings = SettingsProvider.Instance.LoadSettingsSynchronous<PlayerFollowerSettings>();
|
||||
var interactionSettings = SettingsProvider.Instance.LoadSettingsSynchronous<InteractionSettings>();
|
||||
var minigameSettings = SettingsProvider.Instance.LoadSettingsSynchronous<MinigameSettings>();
|
||||
|
||||
// Wait for settings to be loaded
|
||||
while (!initComplete)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Register settings with service locator
|
||||
ServiceLocator.Register<IPlayerFollowerSettings>(
|
||||
SettingsProvider.Instance.GetSettings<PlayerFollowerSettings>());
|
||||
if (playerSettings != null)
|
||||
{
|
||||
ServiceLocator.Register<IPlayerFollowerSettings>(playerSettings);
|
||||
Debug.Log("PlayerFollowerSettings registered successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Failed to load PlayerFollowerSettings");
|
||||
}
|
||||
|
||||
ServiceLocator.Register<IInteractionSettings>(
|
||||
SettingsProvider.Instance.GetSettings<InteractionSettings>());
|
||||
if (interactionSettings != null)
|
||||
{
|
||||
ServiceLocator.Register<IInteractionSettings>(interactionSettings);
|
||||
Debug.Log("InteractionSettings registered successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Failed to load InteractionSettings");
|
||||
}
|
||||
|
||||
ServiceLocator.Register<IMinigameSettings>(
|
||||
SettingsProvider.Instance.GetSettings<MinigameSettings>());
|
||||
if (minigameSettings != null)
|
||||
{
|
||||
ServiceLocator.Register<IMinigameSettings>(minigameSettings);
|
||||
Debug.Log("MinigameSettings registered successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Failed to load MinigameSettings");
|
||||
}
|
||||
|
||||
// Log success
|
||||
Debug.Log("All settings loaded and registered with ServiceLocator");
|
||||
_settingsLoaded = true;
|
||||
_settingsLoaded = playerSettings != null && interactionSettings != null && minigameSettings != null;
|
||||
if (_settingsLoaded)
|
||||
{
|
||||
Debug.Log("All settings loaded and registered with ServiceLocator");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Some settings failed to load - check that all settings assets exist and are marked as Addressables");
|
||||
}
|
||||
|
||||
// Migrate settings if needed
|
||||
if (legacyGameSettings != null)
|
||||
if (legacyGameSettings != null && !playerSettings && !interactionSettings && !minigameSettings)
|
||||
{
|
||||
MigrateFromLegacySettings();
|
||||
Debug.LogWarning("Legacy settings detected but failed to load new settings. Consider running the migration tool.");
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace AppleHills.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Responsible for loading and caching settings from Addressables.
|
||||
/// Uses synchronous loading to ensure settings are available immediately.
|
||||
/// </summary>
|
||||
public class SettingsProvider : MonoBehaviour
|
||||
{
|
||||
@@ -43,64 +44,57 @@ namespace AppleHills.Core.Settings
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load settings asynchronously using Addressables
|
||||
/// Load settings synchronously using Addressables - blocks until complete
|
||||
/// </summary>
|
||||
public void LoadSettings<T>(Action<T> onLoaded) where T : BaseSettings
|
||||
public T LoadSettingsSynchronous<T>() where T : BaseSettings
|
||||
{
|
||||
string key = typeof(T).Name;
|
||||
|
||||
// Return from cache if already loaded
|
||||
if (_settingsCache.TryGetValue(key, out BaseSettings cachedSettings))
|
||||
{
|
||||
onLoaded?.Invoke(cachedSettings as T);
|
||||
return;
|
||||
return cachedSettings as T;
|
||||
}
|
||||
|
||||
// Load using Addressables
|
||||
Addressables.LoadAssetAsync<T>($"Settings/{key}.asset").Completed += handle =>
|
||||
// Load using Addressables synchronously
|
||||
try
|
||||
{
|
||||
if (handle.Status == AsyncOperationStatus.Succeeded)
|
||||
// WaitForCompletion blocks until the asset is loaded
|
||||
T settings = Addressables.LoadAssetAsync<T>($"Settings/{key}").WaitForCompletion();
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
_settingsCache[key] = handle.Result;
|
||||
onLoaded?.Invoke(handle.Result);
|
||||
_settingsCache[key] = settings;
|
||||
return settings;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Failed to load settings: {key}");
|
||||
onLoaded?.Invoke(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get cached settings
|
||||
/// </summary>
|
||||
public T GetSettings<T>() where T : BaseSettings
|
||||
{
|
||||
string key = typeof(T).Name;
|
||||
if (_settingsCache.TryGetValue(key, out BaseSettings settings))
|
||||
{
|
||||
return settings as T;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Error loading settings {key}: {e.Message}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Preload all settings - call this at game startup
|
||||
/// Get cached settings or load them synchronously if not cached
|
||||
/// </summary>
|
||||
public void PreloadAllSettings(Action onComplete)
|
||||
public T GetSettings<T>() where T : BaseSettings
|
||||
{
|
||||
// Load all necessary settings types
|
||||
int pendingLoads = 3; // Number of settings types
|
||||
Action decrementCounter = () => {
|
||||
pendingLoads--;
|
||||
if (pendingLoads <= 0)
|
||||
onComplete?.Invoke();
|
||||
};
|
||||
string key = typeof(T).Name;
|
||||
|
||||
LoadSettings<PlayerFollowerSettings>(settings => decrementCounter());
|
||||
LoadSettings<InteractionSettings>(settings => decrementCounter());
|
||||
LoadSettings<MinigameSettings>(settings => decrementCounter());
|
||||
// Return from cache if already loaded
|
||||
if (_settingsCache.TryGetValue(key, out BaseSettings cachedSettings))
|
||||
{
|
||||
return cachedSettings as T;
|
||||
}
|
||||
|
||||
// Load synchronously if not in cache
|
||||
return LoadSettingsSynchronous<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user