using System;
using System.Collections.Generic;
using AlicizaX.Resource.Runtime;
using AlicizaX;
using AlicizaX.Scene.Runtime;
using Cysharp.Threading.Tasks;
using UnityEngine.SceneManagement;
using YooAsset;
namespace AlicizaX.Scene.Runtime
{
///
/// 场景管理器。
///
internal class SceneModule : ISceneModule
{
private string _currentMainSceneName = string.Empty;
private SceneHandle _currentMainScene;
private readonly Dictionary _subScenes = new Dictionary();
private readonly HashSet _handlingScene = new HashSet();
///
/// 当前主场景名称。
///
public string CurrentMainSceneName => _currentMainSceneName;
void IModuleAwake.Awake()
{
_currentMainScene = null;
_currentMainSceneName = SceneManager.GetSceneByBuildIndex(0).name;
}
void IModule.Dispose()
{
var iter = _subScenes.Values.GetEnumerator();
while (iter.MoveNext())
{
SceneHandle subScene = iter.Current;
if (subScene != null)
{
subScene.UnloadAsync();
}
}
iter.Dispose();
_subScenes.Clear();
_handlingScene.Clear();
_currentMainSceneName = string.Empty;
}
///
/// 加载场景。
///
/// 场景的定位地址
/// 场景加载模式
/// 加载完毕时是否主动挂起
/// 优先级
/// 加载主场景是否回收垃圾。
/// 加载进度回调。
public async UniTask LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, uint priority = 100, bool gcCollect = true, Action progressCallBack = null)
{
if (!_handlingScene.Add(location))
{
Log.Error($"Could not load scene while loading. Scene: {location}");
return default;
}
if (sceneMode == LoadSceneMode.Additive)
{
if (_subScenes.TryGetValue(location, out SceneHandle subScene))
{
throw new Exception($"Could not load subScene while already loaded. Scene: {location}");
}
subScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
if (progressCallBack != null)
{
while (!subScene.IsDone && subScene.IsValid)
{
progressCallBack.Invoke(subScene.Progress);
await UniTask.Yield();
}
}
else
{
await subScene.ToUniTask();
}
_subScenes.Add(location, subScene);
_handlingScene.Remove(location);
return subScene.SceneObject;
}
else
{
if (_currentMainScene is { IsDone: false })
{
throw new Exception($"Could not load MainScene while loading. CurrentMainScene: {_currentMainSceneName}.");
}
_currentMainSceneName = location;
_currentMainScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
if (progressCallBack != null)
{
while (!_currentMainScene.IsDone && _currentMainScene.IsValid)
{
progressCallBack.Invoke(_currentMainScene.Progress);
await UniTask.Yield();
}
}
else
{
await _currentMainScene.ToUniTask();
}
ModuleSystem.GetModule().ForceUnloadUnusedAssets(gcCollect);
_handlingScene.Remove(location);
return _currentMainScene.SceneObject;
}
}
///
/// 加载场景。
///
/// 场景的定位地址
/// 场景加载模式
/// 加载完毕时是否主动挂起
/// 优先级
/// 加载回调。
/// 加载主场景是否回收垃圾。
/// 加载进度回调。
public void LoadScene(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, uint priority = 100,
Action callBack = null,
bool gcCollect = true, Action progressCallBack = null)
{
if (!_handlingScene.Add(location))
{
Log.Error($"Could not load scene while loading. Scene: {location}");
return;
}
if (sceneMode == LoadSceneMode.Additive)
{
if (_subScenes.TryGetValue(location, out SceneHandle subScene))
{
Log.Warning($"Could not load subScene while already loaded. Scene: {location}");
return;
}
subScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
subScene.Completed += handle =>
{
_handlingScene.Remove(location);
callBack?.Invoke(handle.SceneObject);
};
if (progressCallBack != null)
{
InvokeProgress(subScene, progressCallBack).Forget();
}
_subScenes.Add(location, subScene);
}
else
{
if (_currentMainScene is { IsDone: false })
{
Log.Warning($"Could not load MainScene while loading. CurrentMainScene: {_currentMainSceneName}.");
return;
}
_currentMainSceneName = location;
_currentMainScene = YooAssets.LoadSceneAsync(location, sceneMode, LocalPhysicsMode.None, suspendLoad, priority);
_currentMainScene.Completed += handle =>
{
_handlingScene.Remove(location);
callBack?.Invoke(handle.SceneObject);
};
if (progressCallBack != null)
{
InvokeProgress(_currentMainScene, progressCallBack).Forget();
}
ModuleSystem.GetModule().ForceUnloadUnusedAssets(gcCollect);
}
}
private async UniTaskVoid InvokeProgress(SceneHandle sceneHandle, Action progress)
{
if (sceneHandle == null)
{
return;
}
while (!sceneHandle.IsDone && sceneHandle.IsValid)
{
await UniTask.Yield();
progress?.Invoke(sceneHandle.Progress);
}
}
///
/// 激活场景(当同时存在多个场景时用于切换激活场景)。
///
/// 场景资源定位地址。
/// 是否操作成功。
public bool ActivateScene(string location)
{
if (_currentMainSceneName.Equals(location))
{
if (_currentMainScene != null)
{
return _currentMainScene.ActivateScene();
}
return false;
}
_subScenes.TryGetValue(location, out SceneHandle subScene);
if (subScene != null)
{
return subScene.ActivateScene();
}
Log.Warning($"IsMainScene invalid location:{location}");
return false;
}
///
/// 解除场景加载挂起操作。
///
/// 场景资源定位地址。
/// 是否操作成功。
public bool UnSuspend(string location)
{
if (_currentMainSceneName.Equals(location))
{
if (_currentMainScene != null)
{
return _currentMainScene.UnSuspend();
}
return false;
}
_subScenes.TryGetValue(location, out SceneHandle subScene);
if (subScene != null)
{
return subScene.UnSuspend();
}
Log.Warning($"IsMainScene invalid location:{location}");
return false;
}
///
/// 是否为主场景。
///
/// 场景资源定位地址。
/// 是否主场景。
public bool IsMainScene(string location)
{
// 获取当前激活的场景
UnityEngine.SceneManagement.Scene currentScene = SceneManager.GetActiveScene();
if (_currentMainSceneName.Equals(location))
{
if (_currentMainScene == null)
{
return false;
}
// 判断当前场景是否是主场景
if (currentScene.name == _currentMainScene.SceneName)
{
return true;
}
return _currentMainScene.SceneName == currentScene.name;
}
// 判断当前场景是否是主场景
if (currentScene.name == _currentMainScene?.SceneName)
{
return true;
}
Log.Warning($"IsMainScene invalid location:{location}");
return false;
}
///
/// 异步卸载子场景。
///
/// 场景资源定位地址。
/// 进度回调。
public async UniTask UnloadAsync(string location, Action progressCallBack = null)
{
_subScenes.TryGetValue(location, out SceneHandle subScene);
if (subScene != null)
{
if (subScene.SceneObject == default)
{
Log.Error($"Could not unload Scene while not loaded. Scene: {location}");
return false;
}
if (!_handlingScene.Add(location))
{
Log.Warning($"Could not unload Scene while loading. Scene: {location}");
return false;
}
var unloadOperation = subScene.UnloadAsync();
if (progressCallBack != null)
{
while (!unloadOperation.IsDone && unloadOperation.Status != EOperationStatus.Failed)
{
progressCallBack.Invoke(unloadOperation.Progress);
await UniTask.Yield();
}
}
else
{
await unloadOperation.ToUniTask();
}
_subScenes.Remove(location);
_handlingScene.Remove(location);
return true;
}
Log.Warning($"UnloadAsync invalid location:{location}");
return false;
}
///
/// 异步卸载子场景。
///
/// 场景资源定位地址。
/// 卸载完成回调。
/// 进度回调。
public void Unload(string location, Action callBack = null, Action progressCallBack = null)
{
_subScenes.TryGetValue(location, out SceneHandle subScene);
if (subScene != null)
{
if (subScene.SceneObject == default)
{
Log.Error($"Could not unload Scene while not loaded. Scene: {location}");
return;
}
if (!_handlingScene.Add(location))
{
Log.Warning($"Could not unload Scene while loading. Scene: {location}");
return;
}
subScene.UnloadAsync();
subScene.UnloadAsync().Completed += @base =>
{
_subScenes.Remove(location);
_handlingScene.Remove(location);
callBack?.Invoke();
};
if (progressCallBack != null)
{
InvokeProgress(subScene, progressCallBack).Forget();
}
return;
}
Log.Warning($"UnloadAsync invalid location:{location}");
}
///
/// 是否包含场景。
///
/// 场景资源定位地址。
/// 是否包含场景。
public bool IsContainScene(string location)
{
if (_currentMainSceneName.Equals(location))
{
return true;
}
return _subScenes.TryGetValue(location, out var _);
}
}
}