442 lines
15 KiB
C#
442 lines
15 KiB
C#
using AlicizaX.Event.Runtime;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using AlicizaX.Resource.Runtime;
|
|
using Cysharp.Threading.Tasks;
|
|
using AlicizaX.Runtime;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using YooAsset;
|
|
|
|
namespace AlicizaX.Scene.Runtime
|
|
{
|
|
/// <summary>
|
|
/// 场景组件。
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
[AddComponentMenu("Game Framework/Scene")]
|
|
public sealed class SceneComponent : GameFrameworkComponent
|
|
{
|
|
private const int DefaultPriority = 0;
|
|
|
|
private IGameSceneManager _gameSceneManager = null;
|
|
private IResourceManager _resourceManager = null;
|
|
private EventComponent m_EventComponent = null;
|
|
|
|
private readonly SortedDictionary<string, int> m_SceneOrder = new SortedDictionary<string, int>(StringComparer.Ordinal);
|
|
|
|
private Camera m_MainCamera = null;
|
|
private UnityEngine.SceneManagement.Scene m_GameFrameworkScene = default(UnityEngine.SceneManagement.Scene);
|
|
|
|
[SerializeField] private bool m_EnableLoadSceneUpdateEvent = true;
|
|
|
|
[SerializeField] private bool m_EnableLoadSceneDependencyAssetEvent = true;
|
|
|
|
/// <summary>
|
|
/// 获取当前场景主摄像机。
|
|
/// </summary>
|
|
public Camera MainCamera
|
|
{
|
|
get { return m_MainCamera; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 游戏框架组件初始化。
|
|
/// </summary>
|
|
protected override void Awake()
|
|
{
|
|
ImplementationComponentType = Utility.Assembly.GetType(componentType);
|
|
InterfaceComponentType = typeof(IGameSceneManager);
|
|
base.Awake();
|
|
_gameSceneManager = SysModuleCenter.GetModule<IGameSceneManager>();
|
|
if (_gameSceneManager == null)
|
|
{
|
|
Log.Fatal("Scene manager is invalid.");
|
|
return;
|
|
}
|
|
|
|
_gameSceneManager.LoadSceneSuccess += OnLoadGameSceneSuccess;
|
|
_gameSceneManager.LoadSceneFailure += OnLoadGameSceneFailure;
|
|
|
|
if (m_EnableLoadSceneUpdateEvent)
|
|
{
|
|
_gameSceneManager.LoadSceneUpdate += OnLoadGameSceneUpdate;
|
|
}
|
|
|
|
if (m_EnableLoadSceneDependencyAssetEvent)
|
|
{
|
|
// _gameSceneManager.LoadSceneDependencyAsset += OnLoadGameSceneDependencyAsset;
|
|
}
|
|
|
|
_gameSceneManager.UnloadSceneSuccess += OnUnloadGameSceneSuccess;
|
|
_gameSceneManager.UnloadSceneFailure += OnUnloadGameSceneFailure;
|
|
|
|
m_GameFrameworkScene = UnityEngine.SceneManagement.SceneManager.GetSceneAt(0);
|
|
if (!m_GameFrameworkScene.IsValid())
|
|
{
|
|
Log.Fatal("Game Framework scene is invalid.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
BaseComponent baseComponent = GameEntry.GetComponent<BaseComponent>();
|
|
if (baseComponent == null)
|
|
{
|
|
Log.Fatal("Base component is invalid.");
|
|
return;
|
|
}
|
|
|
|
m_EventComponent = GameEntry.GetComponent<EventComponent>();
|
|
if (m_EventComponent == null)
|
|
{
|
|
Log.Fatal("Event component is invalid.");
|
|
return;
|
|
}
|
|
|
|
_resourceManager = SysModuleCenter.GetModule<IResourceManager>();
|
|
if (_resourceManager == null)
|
|
{
|
|
Log.Fatal("Asset Manager is invalid.");
|
|
return;
|
|
}
|
|
|
|
_gameSceneManager.SetResourceManager(_resourceManager);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取场景名称。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
/// <returns>场景名称。</returns>
|
|
public static string GetSceneName(string sceneAssetName)
|
|
{
|
|
if (string.IsNullOrEmpty(sceneAssetName))
|
|
{
|
|
Log.Error("Scene asset name is invalid.");
|
|
return null;
|
|
}
|
|
|
|
int sceneNamePosition = sceneAssetName.LastIndexOf('/');
|
|
if (sceneNamePosition + 1 >= sceneAssetName.Length)
|
|
{
|
|
Log.Error("Scene asset name '{0}' is invalid.", sceneAssetName);
|
|
return null;
|
|
}
|
|
|
|
string sceneName = sceneAssetName.Substring(sceneNamePosition + 1);
|
|
sceneNamePosition = sceneName.LastIndexOf(".unity");
|
|
if (sceneNamePosition > 0)
|
|
{
|
|
sceneName = sceneName.Substring(0, sceneNamePosition);
|
|
}
|
|
|
|
return sceneName;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取场景是否已加载。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
/// <returns>场景是否已加载。</returns>
|
|
public bool SceneIsLoaded(string sceneAssetName)
|
|
{
|
|
return _gameSceneManager.SceneIsLoaded(sceneAssetName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取已加载场景的资源名称。
|
|
/// </summary>
|
|
/// <returns>已加载场景的资源名称。</returns>
|
|
public string[] GetLoadedSceneAssetNames()
|
|
{
|
|
return _gameSceneManager.GetLoadedSceneAssetNames();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取已加载场景的资源名称。
|
|
/// </summary>
|
|
/// <param name="results">已加载场景的资源名称。</param>
|
|
public void GetLoadedSceneAssetNames(List<string> results)
|
|
{
|
|
_gameSceneManager.GetLoadedSceneAssetNames(results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取场景是否正在加载。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
/// <returns>场景是否正在加载。</returns>
|
|
public bool SceneIsLoading(string sceneAssetName)
|
|
{
|
|
return _gameSceneManager.SceneIsLoading(sceneAssetName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取正在加载场景的资源名称。
|
|
/// </summary>
|
|
/// <returns>正在加载场景的资源名称。</returns>
|
|
public string[] GetLoadingSceneAssetNames()
|
|
{
|
|
return _gameSceneManager.GetLoadingSceneAssetNames();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取正在加载场景的资源名称。
|
|
/// </summary>
|
|
/// <param name="results">正在加载场景的资源名称。</param>
|
|
public void GetLoadingSceneAssetNames(List<string> results)
|
|
{
|
|
_gameSceneManager.GetLoadingSceneAssetNames(results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取场景是否正在卸载。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
/// <returns>场景是否正在卸载。</returns>
|
|
public bool SceneIsUnloading(string sceneAssetName)
|
|
{
|
|
return _gameSceneManager.SceneIsUnloading(sceneAssetName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取正在卸载场景的资源名称。
|
|
/// </summary>
|
|
/// <returns>正在卸载场景的资源名称。</returns>
|
|
public string[] GetUnloadingSceneAssetNames()
|
|
{
|
|
return _gameSceneManager.GetUnloadingSceneAssetNames();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取正在卸载场景的资源名称。
|
|
/// </summary>
|
|
/// <param name="results">正在卸载场景的资源名称。</param>
|
|
public void GetUnloadingSceneAssetNames(List<string> results)
|
|
{
|
|
_gameSceneManager.GetUnloadingSceneAssetNames(results);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查场景资源是否存在。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">要检查场景资源的名称。</param>
|
|
/// <returns>场景资源是否存在。</returns>
|
|
public bool HasScene(string sceneAssetName)
|
|
{
|
|
if (string.IsNullOrEmpty(sceneAssetName))
|
|
{
|
|
Log.Error("Scene asset name is invalid.");
|
|
return false;
|
|
}
|
|
|
|
if (!sceneAssetName.StartsWith("Assets/", StringComparison.Ordinal) ||
|
|
!sceneAssetName.EndsWith(".unity", StringComparison.Ordinal))
|
|
{
|
|
Log.Error("Scene asset name '{0}' is invalid.", sceneAssetName);
|
|
return false;
|
|
}
|
|
|
|
return _gameSceneManager.HasScene(sceneAssetName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载场景。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
public UniTask<SceneHandle> LoadScene(string sceneAssetName)
|
|
{
|
|
return LoadScene(sceneAssetName, LoadSceneMode.Additive, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 加载场景。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
/// <param name="sceneMode">加载场景资源的优先级。</param>
|
|
/// <param name="userData">用户自定义数据。</param>
|
|
public UniTask<SceneHandle> LoadScene(string sceneAssetName, LoadSceneMode sceneMode, object userData = null)
|
|
{
|
|
if (string.IsNullOrEmpty(sceneAssetName))
|
|
{
|
|
Log.Error("Scene asset name is invalid.");
|
|
throw new ArgumentNullException(nameof(sceneAssetName));
|
|
}
|
|
|
|
if (!sceneAssetName.StartsWith("Assets/", StringComparison.Ordinal) ||
|
|
!sceneAssetName.EndsWith(".unity", StringComparison.Ordinal))
|
|
{
|
|
Log.Error("Scene asset name '{0}' is invalid.", sceneAssetName);
|
|
throw new ArgumentException(nameof(sceneAssetName));
|
|
}
|
|
|
|
return _gameSceneManager.LoadScene(sceneAssetName, sceneMode, userData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 卸载场景。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
/// <param name="userData">用户自定义数据。</param>
|
|
public void UnloadScene(string sceneAssetName, object userData = null)
|
|
{
|
|
if (string.IsNullOrEmpty(sceneAssetName))
|
|
{
|
|
Log.Error("Scene asset name is invalid.");
|
|
return;
|
|
}
|
|
|
|
if (!sceneAssetName.StartsWith("Assets/", StringComparison.Ordinal) ||
|
|
!sceneAssetName.EndsWith(".unity", StringComparison.Ordinal))
|
|
{
|
|
Log.Error("Scene asset name '{0}' is invalid.", sceneAssetName);
|
|
return;
|
|
}
|
|
|
|
_gameSceneManager.UnloadScene(sceneAssetName, userData);
|
|
m_SceneOrder.Remove(sceneAssetName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置场景顺序。
|
|
/// </summary>
|
|
/// <param name="sceneAssetName">场景资源名称。</param>
|
|
/// <param name="sceneOrder">要设置的场景顺序。</param>
|
|
public void SetSceneOrder(string sceneAssetName, int sceneOrder)
|
|
{
|
|
if (string.IsNullOrEmpty(sceneAssetName))
|
|
{
|
|
Log.Error("Scene asset name is invalid.");
|
|
return;
|
|
}
|
|
|
|
if (!sceneAssetName.StartsWith("Assets/", StringComparison.Ordinal) ||
|
|
!sceneAssetName.EndsWith(".unity", StringComparison.Ordinal))
|
|
{
|
|
Log.Error("Scene asset name '{0}' is invalid.", sceneAssetName);
|
|
return;
|
|
}
|
|
|
|
if (SceneIsLoading(sceneAssetName))
|
|
{
|
|
m_SceneOrder[sceneAssetName] = sceneOrder;
|
|
return;
|
|
}
|
|
|
|
if (SceneIsLoaded(sceneAssetName))
|
|
{
|
|
m_SceneOrder[sceneAssetName] = sceneOrder;
|
|
RefreshSceneOrder();
|
|
return;
|
|
}
|
|
|
|
Log.Error("Scene '{0}' is not loaded or loading.", sceneAssetName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 刷新当前场景主摄像机。
|
|
/// </summary>
|
|
public void RefreshMainCamera()
|
|
{
|
|
m_MainCamera = Camera.main;
|
|
}
|
|
|
|
private void RefreshSceneOrder()
|
|
{
|
|
if (m_SceneOrder.Count > 0)
|
|
{
|
|
string maxSceneName = null;
|
|
int maxSceneOrder = 0;
|
|
foreach (var sceneOrder in m_SceneOrder)
|
|
{
|
|
if (SceneIsLoading(sceneOrder.Key))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (maxSceneName == null)
|
|
{
|
|
maxSceneName = sceneOrder.Key;
|
|
maxSceneOrder = sceneOrder.Value;
|
|
continue;
|
|
}
|
|
|
|
if (sceneOrder.Value > maxSceneOrder)
|
|
{
|
|
maxSceneName = sceneOrder.Key;
|
|
maxSceneOrder = sceneOrder.Value;
|
|
}
|
|
}
|
|
|
|
if (maxSceneName == null)
|
|
{
|
|
SetActiveScene(m_GameFrameworkScene);
|
|
return;
|
|
}
|
|
|
|
var scene = UnityEngine.SceneManagement.SceneManager.GetSceneByName(GetSceneName(maxSceneName));
|
|
if (!scene.IsValid())
|
|
{
|
|
Log.Error("Active scene '{0}' is invalid.", maxSceneName);
|
|
return;
|
|
}
|
|
|
|
SetActiveScene(scene);
|
|
}
|
|
else
|
|
{
|
|
SetActiveScene(m_GameFrameworkScene);
|
|
}
|
|
}
|
|
|
|
private void SetActiveScene(UnityEngine.SceneManagement.Scene activeScene)
|
|
{
|
|
var lastActiveScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
|
|
if (lastActiveScene != activeScene)
|
|
{
|
|
UnityEngine.SceneManagement.SceneManager.SetActiveScene(activeScene);
|
|
m_EventComponent.Fire(this, ActiveSceneChangedEventArgs.Create(lastActiveScene, activeScene));
|
|
}
|
|
|
|
RefreshMainCamera();
|
|
}
|
|
|
|
private void OnLoadGameSceneSuccess(object sender, LoadSceneSuccessEventArgs eventArgs)
|
|
{
|
|
if (!m_SceneOrder.ContainsKey(eventArgs.SceneAssetName))
|
|
{
|
|
m_SceneOrder.Add(eventArgs.SceneAssetName, 0);
|
|
}
|
|
|
|
m_EventComponent.Fire(this, eventArgs);
|
|
RefreshSceneOrder();
|
|
}
|
|
|
|
private void OnLoadGameSceneFailure(object sender, LoadSceneFailureEventArgs eventArgs)
|
|
{
|
|
Log.Warning("Load scene failure, scene asset name '{0}', error message '{1}'.", eventArgs.SceneAssetName,
|
|
eventArgs.ErrorMessage);
|
|
m_EventComponent.Fire(this, eventArgs);
|
|
}
|
|
|
|
private void OnLoadGameSceneUpdate(object sender, LoadSceneUpdateEventArgs eventArgs)
|
|
{
|
|
m_EventComponent.Fire(this, eventArgs);
|
|
}
|
|
|
|
private void OnUnloadGameSceneSuccess(object sender, UnloadSceneSuccessEventArgs eventArgs)
|
|
{
|
|
m_EventComponent.Fire(this, eventArgs);
|
|
m_SceneOrder.Remove(eventArgs.SceneAssetName);
|
|
RefreshSceneOrder();
|
|
}
|
|
|
|
private void OnUnloadGameSceneFailure(object sender, UnloadSceneFailureEventArgs eventArgs)
|
|
{
|
|
Log.Warning("Unload scene failure, scene asset name '{0}'.", eventArgs.SceneAssetName);
|
|
m_EventComponent.Fire(this, eventArgs);
|
|
}
|
|
}
|
|
} |