AlicizaX/Client/Packages/com.alicizax.unity.scene/Runtime/Scene/SceneComponent.cs
陈思海 eb38f67131 init
2025-01-23 19:06:48 +08:00

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);
}
}
}