using System; 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 { 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 _loadedSceneDatas; private SceneType _currentSceneType = SceneType.None; public void PreInit() { Array sceneTypeArray = Enum.GetValues(typeof(SceneType)); _loadedSceneDatas = new Dictionary(sceneTypeArray.Length - 1); } public async Task Init() { var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); var activeScenePath = activeScene.path; #if UNITY_EDITOR foreach (var sceneAssetPair in GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping) { var asset = sceneAssetPair.Value.editorAsset; if (asset == null) continue; string assetPath = AssetDatabase.GetAssetPath(asset); if (string.IsNullOrWhiteSpace(assetPath)) continue; if (assetPath == activeScenePath) { _currentSceneType = sceneAssetPair.Key; _loadedSceneDatas.Add(_currentSceneType, new SceneData(activeScene, null)); break; } } if (_currentSceneType == SceneType.None) { Debug.LogWarning($"[SceneManager] 활성 씬이 AssetMapping에 존재하지 않습니다: {activeScenePath}"); } #else _currentSceneType = SceneType.Entry; _loadedSceneDatas.Add(_currentSceneType, new SceneData(activeScene, null)); #endif await PreloadAll(); } public void PostInit() { } public async Task PreloadSceneBySceneType(SceneType sceneType) { if (_loadedSceneDatas.ContainsKey(sceneType)) return; var kvp = GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping.FirstOrDefault(kvp => kvp.Key == sceneType); 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] {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 (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData)) { foreach (var root in sceneData.Scene.GetRootGameObjects()) { root.SetActive(true); } if (sceneData.Scene.IsValid()) { UnityEngine.SceneManagement.SceneManager.SetActiveScene(sceneData.Scene); _currentSceneType = sceneType; } else { Debug.LogError($"[SceneManager] {sceneType}의 Scene이 유효하지 않습니다."); } } else { Debug.LogError($"[SceneManager] Scene not loaded: {sceneType}"); } foreach (var handler in _sceneTransitionHandlerSo.Handlers.Where(handler => handler != null)) { await handler.OnAfterSceneActivate(sceneType); } } public void DeactivateScene(SceneType sceneType) { if (_loadedSceneDatas.TryGetValue(sceneType, out var sceneData)) { foreach (var root in sceneData.Scene.GetRootGameObjects()) { root.SetActive(false); } } } private void DeactivateScene(Scene scene) { foreach (var root in scene.GetRootGameObjects()) { 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); } } } } }