ProjectDDD/Assets/_DDD/_Scripts/GameFramework/Scene/SceneManager.cs

194 lines
6.5 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.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<SceneManager>, IManager
{
[SerializeField]
private SceneTransitionHandlerSo _sceneTransitionHandlerSo;
private Dictionary<SceneType, SceneData> _loadedSceneDatas;
private SceneType _currentSceneType = SceneType.None;
public void PreInit()
{
Array sceneTypeArray = Enum.GetValues(typeof(SceneType));
_loadedSceneDatas = new Dictionary<SceneType, SceneData>(sceneTypeArray.Length - 1);
}
public async Task Init()
{
var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
var activeScenePath = activeScene.path;
#if UNITY_EDITOR
foreach (var kvp in GameFlowManager.Instance.GameFlowSceneMappingSo.AssetMapping)
{
var asset = kvp.Value.editorAsset;
if (asset == null) continue;
string assetPath = AssetDatabase.GetAssetPath(asset);
if (string.IsNullOrWhiteSpace(assetPath)) continue;
if (assetPath == activeScenePath)
{
_currentSceneType = kvp.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);
}
}
}
}
}