diff --git a/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs b/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs index c1227f086..8f06ed425 100644 --- a/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs +++ b/Assets/_DDD/_Scripts/AssetManagement/AssetManager.cs @@ -75,16 +75,16 @@ public static async Task> LoadAssetsByLabel(string label) where T : U Debug.LogError($"[AssetManager] Failed to load assets with label: {label}"); return new List(); } - - public static async Task LoadScene(string key, LoadSceneMode mode = LoadSceneMode.Additive) + + public static async Task LoadScene(AssetReference assetReference, LoadSceneMode mode = LoadSceneMode.Additive) { - var handle = Addressables.LoadSceneAsync(key, mode); + var handle = Addressables.LoadSceneAsync(assetReference, mode); await handle.Task; if (handle.Status == AsyncOperationStatus.Succeeded) return handle.Result; - Debug.LogError($"Scene load failed: {key}"); + Debug.LogError($"Scene load failed: {assetReference}"); return default; } diff --git a/Assets/_DDD/_Scripts/GameFlow/GameFlowSceneMappingSo.cs b/Assets/_DDD/_Scripts/GameFlow/GameFlowSceneMappingSo.cs index 19d68f72f..78f6393b2 100644 --- a/Assets/_DDD/_Scripts/GameFlow/GameFlowSceneMappingSo.cs +++ b/Assets/_DDD/_Scripts/GameFlow/GameFlowSceneMappingSo.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Sirenix.OdinInspector; using UnityEngine; +using UnityEngine.AddressableAssets; namespace DDD { @@ -9,5 +10,6 @@ namespace DDD public class GameFlowSceneMappingSo : SerializedScriptableObject { public Dictionary FlowToSceneMapping = new(); + public Dictionary AssetMapping = new(); } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs b/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs index a3a1bcd39..927e6399f 100644 --- a/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs +++ b/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs @@ -2,54 +2,80 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +#if UNITY_EDITOR +using UnityEditor; +#endif using UnityEngine; using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.SceneManagement; namespace DDD { public enum SceneType { - Entry = 0, - Restaurant = 1, - Voyage = 2 + None = 0, + Entry = 1, + Restaurant = 2, + Voyage = 3 + } + + public class SceneData + { + public Scene Scene { get; } + public SceneInstance? SceneInstance { get; } // 처음에 실행되는 씬은 SceneInstance를 가질 수 없음 Unload용 데이터 + + public SceneData(Scene scene, SceneInstance? sceneInstance) + { + Scene = scene; + SceneInstance = sceneInstance; + } } public class SceneManager : Singleton, IManager { [SerializeField] private SceneTransitionHandlerSo _sceneTransitionHandlerSo; - - private Dictionary _loadedScenes; - - private SceneInstance _currentSceneInstance; - public Action OnSceneChanged; + private Dictionary _loadedSceneDatas; + private SceneType _currentSceneType = SceneType.None; + public void PreInit() { Array sceneTypeArray = Enum.GetValues(typeof(SceneType)); - _loadedScenes = new Dictionary(sceneTypeArray.Length); + _loadedSceneDatas = new Dictionary(sceneTypeArray.Length - 1); } public async Task Init() { - try + var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); + var activeScenePath = activeScene.path; +#if UNITY_EDITOR + foreach (var kvp in GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping) { - foreach (SceneType sceneType in Enum.GetValues(typeof(SceneType))) + var asset = kvp.Value.editorAsset; + if (asset == null) continue; + + string assetPath = AssetDatabase.GetAssetPath(asset); + if (string.IsNullOrWhiteSpace(assetPath)) continue; + + if (assetPath == activeScenePath) { - if (sceneType == SceneType.Entry) continue; - var currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); - if (sceneType.ToString() == currentScene.name) - { - continue; - } - - await PreloadSceneAsync(sceneType); + _currentSceneType = kvp.Key; + _loadedSceneDatas.Add(_currentSceneType, new SceneData(activeScene, null)); + break; } } - catch (Exception e) + + if (_currentSceneType == SceneType.None) { - Debug.LogWarning($"Scene preload failed\n{e}"); + Debug.LogWarning($"[SceneManager] 활성 씬이 AssetMapping에 존재하지 않습니다: {activeScenePath}"); } +#else + _currentSceneType = SceneType.Entry; + _loadedSceneDatas.Add(_currentSceneType, new SceneData(activeScene, null)); +#endif + + await PreloadAll(); } public void PostInit() @@ -57,47 +83,70 @@ public void PostInit() } - public SceneInstance GetSceneInstance(SceneType sceneType) => _loadedScenes[sceneType]; - - public async Task PreloadSceneAsync(SceneType sceneType) + public async Task PreloadSceneBySceneType(SceneType sceneType) { - if (_loadedScenes.ContainsKey(sceneType)) - return; + if (_loadedSceneDatas.ContainsKey(sceneType)) return; - string key = sceneType.ToString(); - SceneInstance sceneInstance = await AssetManager.LoadScene(key); + var kvp = GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping.FirstOrDefault(kvp => kvp.Key == sceneType); + var preloadedSceneInstance = await AssetManager.LoadScene(kvp.Value); - if (sceneInstance.Scene.IsValid()) + if (preloadedSceneInstance.Scene.IsValid()) { - _loadedScenes[sceneType] = sceneInstance; - - foreach (var root in sceneInstance.Scene.GetRootGameObjects()) - { - root.SetActive(false); - } + DeactivateScene(preloadedSceneInstance.Scene); + _loadedSceneDatas.Add(kvp.Key, new SceneData(preloadedSceneInstance.Scene, preloadedSceneInstance)); } else { - Debug.LogError($"[SceneManager] Failed to preload scene: {sceneType}"); + Debug.LogError($"[SceneManager] {sceneType}의 씬이 존재하지 않습니다."); + } + } + + public async Task PreloadAll() + { + var assetMapping = GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping; + foreach (var kvp in assetMapping) + { + if (_loadedSceneDatas.ContainsKey(kvp.Key)) continue; + + var preloadedSceneInstance = await AssetManager.LoadScene(kvp.Value); + + if (preloadedSceneInstance.Scene.IsValid()) + { + DeactivateScene(preloadedSceneInstance.Scene); + _loadedSceneDatas.Add(kvp.Key, new SceneData(preloadedSceneInstance.Scene, preloadedSceneInstance)); + } + else + { + Debug.LogError($"[SceneManager] {kvp.Key}의 씬이 존재하지 않습니다."); + } } } public async Task ActivateScene(SceneType sceneType) { + if (_currentSceneType == sceneType) return; + foreach (var handler in _sceneTransitionHandlerSo.Handlers.Where(handler => handler != null)) { await handler.OnBeforeSceneActivate(sceneType); } - if (_loadedScenes.TryGetValue(sceneType, out var sceneInstance)) + if (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData)) { - foreach (var root in sceneInstance.Scene.GetRootGameObjects()) + foreach (var root in sceneData.Scene.GetRootGameObjects()) { root.SetActive(true); } - UnityEngine.SceneManagement.SceneManager.SetActiveScene(sceneInstance.Scene); - _currentSceneInstance = sceneInstance; + if (sceneData.Scene.IsValid()) + { + UnityEngine.SceneManagement.SceneManager.SetActiveScene(sceneData.Scene); + _currentSceneType = sceneType; + } + else + { + Debug.LogError($"[SceneManager] {sceneType}의 Scene이 유효하지 않습니다."); + } } else { @@ -112,20 +161,33 @@ public async Task ActivateScene(SceneType sceneType) public void DeactivateScene(SceneType sceneType) { - if (_loadedScenes.TryGetValue(sceneType, out var sceneInstance)) + if (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData)) { - foreach (var root in sceneInstance.Scene.GetRootGameObjects()) + foreach (var root in sceneData.Scene.GetRootGameObjects()) { root.SetActive(false); } } } - public async Task UnloadSceneAsync(SceneType sceneType) + private void DeactivateScene(Scene scene) { - if (_loadedScenes.TryGetValue(sceneType, out var sceneInstance)) + foreach (var root in scene.GetRootGameObjects()) { - await AssetManager.UnloadScene(GetSceneInstance(sceneType)); + root.SetActive(false); + } + } + + public async Task UnloadSceneBySceneType(SceneType sceneType) + { + if (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData)) + { + if (sceneData.SceneInstance == null) return; + + if (GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping.ContainsKey(sceneType)) + { + await AssetManager.UnloadScene((SceneInstance)sceneData.SceneInstance); + } } } }