208 lines
7.1 KiB
C#
208 lines
7.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
using UnityEngine;
|
|
using UnityEngine.AddressableAssets;
|
|
using UnityEngine.ResourceManagement.ResourceProviders;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace DDD
|
|
{
|
|
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<SceneManager>, IManager
|
|
{
|
|
[SerializeField]
|
|
private SceneTransitionHandlerSo _sceneTransitionHandlerSo;
|
|
|
|
private readonly Dictionary<GameFlowState, SceneData> _loadedSceneDatas = new();
|
|
private readonly Dictionary<string, SceneData> _assetKeyToSceneData = new();
|
|
|
|
public void PreInit()
|
|
{
|
|
_loadedSceneDatas.Clear();
|
|
_assetKeyToSceneData.Clear();
|
|
}
|
|
|
|
public async Task Init()
|
|
{
|
|
var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
|
#if UNITY_EDITOR
|
|
var flowToSceneMapping = GameFlowManager.Instance.GameFlowSceneMappingSo.FlowToSceneMapping;
|
|
|
|
foreach (var pair in flowToSceneMapping)
|
|
{
|
|
var editorAsset = pair.Value.editorAsset;
|
|
if (editorAsset == null) continue;
|
|
|
|
var path = AssetDatabase.GetAssetPath(editorAsset);
|
|
if (string.IsNullOrWhiteSpace(path) == false && path == activeScene.path)
|
|
{
|
|
var data = new SceneData(activeScene, null);
|
|
_loadedSceneDatas[pair.Key] = data;
|
|
_assetKeyToSceneData[GetRuntimeKey(pair.Value)] = data;
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
var data = new SceneData(activeScene, null);
|
|
_loadedSceneDatas[GameFlowState.None] = data;
|
|
#endif
|
|
await PreloadAll();
|
|
}
|
|
|
|
public void PostInit()
|
|
{
|
|
|
|
}
|
|
|
|
public async Task PreloadScene(GameFlowState gameFlowState)
|
|
{
|
|
if (_loadedSceneDatas.ContainsKey(gameFlowState)) return;
|
|
|
|
if (!GameFlowManager.Instance.GameFlowSceneMappingSo.FlowToSceneMapping.TryGetValue(gameFlowState, out var assetRef))
|
|
{
|
|
Debug.LogError($"[SceneManager] {gameFlowState}의 AssetReference가 없습니다.");
|
|
return;
|
|
}
|
|
|
|
var runtimeKey = GetRuntimeKey(assetRef);
|
|
if (_assetKeyToSceneData.TryGetValue(runtimeKey, out var existing))
|
|
{
|
|
_loadedSceneDatas[gameFlowState] = existing;
|
|
return;
|
|
}
|
|
|
|
var loadedInstance = await AssetManager.LoadScene(assetRef);
|
|
if (!loadedInstance.Scene.IsValid())
|
|
{
|
|
Debug.LogError($"[SceneManager] {gameFlowState}의 씬 로딩 실패");
|
|
return;
|
|
}
|
|
|
|
DeactivateScene(loadedInstance.Scene);
|
|
|
|
var data = new SceneData(loadedInstance.Scene, loadedInstance);
|
|
_loadedSceneDatas[gameFlowState] = data;
|
|
_assetKeyToSceneData[runtimeKey] = data;
|
|
}
|
|
|
|
public async Task PreloadAll()
|
|
{
|
|
var flowToSceneMapping = GameFlowManager.Instance.GameFlowSceneMappingSo.FlowToSceneMapping;
|
|
|
|
foreach (var pair in flowToSceneMapping)
|
|
{
|
|
if (_loadedSceneDatas.ContainsKey(pair.Key)) continue;
|
|
|
|
var runtimeKey = GetRuntimeKey(pair.Value);
|
|
if (_assetKeyToSceneData.TryGetValue(runtimeKey, out var existing))
|
|
{
|
|
_loadedSceneDatas[pair.Key] = existing;
|
|
continue;
|
|
}
|
|
|
|
var instance = await AssetManager.LoadScene(pair.Value);
|
|
if (!instance.Scene.IsValid())
|
|
{
|
|
Debug.LogError($"[SceneManager] {pair.Key}의 씬 로딩 실패");
|
|
continue;
|
|
}
|
|
|
|
DeactivateScene(instance.Scene);
|
|
var data = new SceneData(instance.Scene, instance);
|
|
_loadedSceneDatas[pair.Key] = data;
|
|
_assetKeyToSceneData[runtimeKey] = data;
|
|
}
|
|
}
|
|
|
|
public async Task ActivateScene(GameFlowState newFlowState)
|
|
{
|
|
if (!_loadedSceneDatas.TryGetValue(newFlowState, out var sceneData))
|
|
{
|
|
Debug.LogError($"[SceneManager] Scene not loaded: {newFlowState}");
|
|
return;
|
|
}
|
|
|
|
var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
|
if (sceneData.Scene == activeScene)
|
|
{
|
|
Debug.Log($"[SceneManager] 이미 활성화된 씬입니다: {newFlowState}");
|
|
return;
|
|
}
|
|
|
|
foreach (var handler in _sceneTransitionHandlerSo.Handlers.Where(handler => handler != null))
|
|
{
|
|
await handler.OnBeforeSceneActivate();
|
|
}
|
|
|
|
foreach (var root in sceneData.Scene.GetRootGameObjects())
|
|
{
|
|
root.SetActive(true);
|
|
}
|
|
|
|
if (sceneData.Scene.IsValid())
|
|
{
|
|
UnityEngine.SceneManagement.SceneManager.SetActiveScene(sceneData.Scene);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"[SceneManager] {newFlowState}의 Scene이 유효하지 않습니다.");
|
|
}
|
|
|
|
foreach (var handler in _sceneTransitionHandlerSo.Handlers.Where(handler => handler != null))
|
|
{
|
|
await handler.OnAfterSceneActivate();
|
|
}
|
|
}
|
|
|
|
public void DeactivateScene(GameFlowState gameFlowState)
|
|
{
|
|
if (_loadedSceneDatas.TryGetValue(gameFlowState, out var sceneData))
|
|
{
|
|
DeactivateScene(sceneData.Scene);
|
|
}
|
|
}
|
|
|
|
private void DeactivateScene(Scene scene)
|
|
{
|
|
foreach (var root in scene.GetRootGameObjects())
|
|
{
|
|
root.SetActive(false);
|
|
}
|
|
}
|
|
|
|
public async Task UnloadScene(GameFlowState gameFlowState)
|
|
{
|
|
if (_loadedSceneDatas.TryGetValue(gameFlowState, out var sceneData))
|
|
{
|
|
if (sceneData.SceneInstance == null) return;
|
|
|
|
if (GameFlowManager.Instance.GameFlowSceneMappingSo.FlowToSceneMapping
|
|
.TryGetValue(gameFlowState, out var assetRef))
|
|
{
|
|
_assetKeyToSceneData.Remove(GetRuntimeKey(assetRef));
|
|
}
|
|
|
|
_loadedSceneDatas.Remove(gameFlowState);
|
|
await AssetManager.UnloadScene(sceneData.SceneInstance.Value);
|
|
}
|
|
}
|
|
|
|
private string GetRuntimeKey(AssetReference reference) => reference.RuntimeKey.ToString();
|
|
}
|
|
} |