BITFALL/Assets/BITKit/Unity/Scripts/Scenes/SceneService.cs

229 lines
6.8 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using YooAsset;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;
// ReSharper disable Unity.LoadSceneWrongIndex
namespace BITKit.SceneManagement
{
[Serializable]
public class SceneServiceSingleton : SceneServiceImplement
{
protected override ISceneService _sceneServiceImplementation => SceneService.Singleton;
}
[Serializable]
public class SceneServiceSingletonProxy:ISceneService
{
private ISceneService _sceneServiceImplementation => SceneService.Singleton;
public bool InitializeMainSceneOnLoad=>SceneService.Singleton.InitializeMainSceneOnLoad;
public string[] GetScenes(params string[] tags)
{
return SceneService.Singleton.GetScenes(tags);
}
public UniTask LoadSceneAsync(string sceneName, CancellationToken cancellationToken,
LoadSceneMode loadSceneMode = LoadSceneMode.Additive, bool activateOnLoad = true)=>SceneService.Singleton.LoadSceneAsync(sceneName,cancellationToken,loadSceneMode,activateOnLoad);
public UniTask UnloadSceneAsync(string sceneName, CancellationToken cancellationToken)
{
return _sceneServiceImplementation.UnloadSceneAsync(sceneName, cancellationToken);
}
public event Action<string> OnLoadScene
{
add => SceneService.OnLoadScene += value;
remove => SceneService.OnLoadScene -= value;
}
public event Action<string, float> OnSceneLoadProgress
{
add => SceneService.OnSceneLoadProgress += value;
remove => SceneService.OnSceneLoadProgress -= value;
}
public event Action<string> OnSceneLoaded
{
add => SceneService.OnSceneLoaded += value;
remove => SceneService.OnSceneLoaded -= value;
}
public event Action<string> OnUnloadScene
{
add => _sceneServiceImplementation.OnUnloadScene += value;
remove => _sceneServiceImplementation.OnUnloadScene -= value;
}
public event Action<string> OnSceneUnloaded
{
add => _sceneServiceImplementation.OnSceneUnloaded += value;
remove => _sceneServiceImplementation.OnSceneUnloaded -= value;
}
}
public class SceneService : MonoBehaviour,ISceneService
{
[BITCommand]
public static async void Map(string mapName)
{
await UniTask.SwitchToMainThread(Singleton.destroyCancellationToken);
Singleton.LoadSceneAsync(mapName,Singleton.destroyCancellationToken).Forget();
}
#if UNITY_EDITOR
public static bool AllowInitialize=true;
[RuntimeInitializeOnLoadMethod]
private static void Initialize()
{
OnLoadScene =null;
OnSceneLoadProgress = null;
OnSceneLoaded = null;
if (AllowInitialize && SceneManager.sceneCount is not 0)
{
SceneManager.LoadSceneAsync(0);
}
}
#endif
public static event Action<string> OnLoadScene;
public static event Action<string, float> OnSceneLoadProgress;
public static event Action<string> OnSceneLoaded;
internal static SceneService Singleton;
#if UNITY_EDITOR
[SerializeField] private Optional<float> allowLoadDelay;
#endif
[SerializeField] private Optional<string> allowLoadMainScene;
[SerializeField] private Optional<string> allowMenuScene;
private readonly Dictionary<string, Scene> LoadedObjects = new();
private CancellationToken _cancellationToken;
private void Awake()
{
Singleton = this;
_cancellationToken = gameObject.GetCancellationTokenOnDestroy();
}
private void Start()
{
if (allowMenuScene.Allow)
{
YooAssets
.LoadSceneAsync(allowMenuScene.Value).ToUniTask(cancellationToken: _cancellationToken)
.Forget();
}
if (allowLoadMainScene.Allow is false) return;
LoadSceneAsync(allowLoadMainScene.Value,_cancellationToken,LoadSceneMode.Single,false).Forget();
}
public bool InitializeMainSceneOnLoad => true;
public string[] GetScenes(params string[] tags)
{
var infos = YooAssets.GetAssetInfos(tags);
return infos.Where(x=>x.Address.Split("_")[0] is "Maps").Select(x=>x.Address).ToArray();
}
public async UniTask LoadSceneAsync(string sceneName, CancellationToken cancellationToken,
LoadSceneMode loadSceneMode = LoadSceneMode.Additive,
bool activateOnLoad = true)
{
try
{
var stopwatchWatcher = new Stopwatch();
stopwatchWatcher.Start();
BIT4Log.Log<SceneService>($"正在加载场景:{sceneName}");
OnLoadScene?.Invoke(sceneName);
#if UNITY_EDITOR
if (allowLoadDelay.Allow)
{
var progress = 0f;
while (progress < allowLoadDelay.Value)
{
OnSceneLoadProgress?.Invoke(sceneName, progress += 1 / allowLoadDelay.Value * Time.deltaTime);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.NextFrame(cancellationToken);
}
}
#endif
// var asyncOperation = Addressables.LoadSceneAsync(sceneName, loadSceneMode, activateOnLoad);
// while (asyncOperation.IsDone is false)
// {
// await UniTask.NextFrame(cancellationToken);
// var progress = asyncOperation.PercentComplete;
// OnSceneLoadProgress?.Invoke(sceneName,progress);
// }
var sceneMode = UnityEngine.SceneManagement.LoadSceneMode.Single;
var handle = YooAssets.LoadSceneAsync(sceneName, sceneMode);
while (handle.IsDone is false)
{
var progress = handle.Progress;
await UniTask.NextFrame(cancellationToken);
OnSceneLoadProgress?.Invoke(sceneName, progress);
}
LoadedObjects.Add(sceneName, handle.SceneObject);
OnSceneLoadProgress?.Invoke(sceneName, 1);
await Task.Delay(100, cancellationToken);
OnSceneLoaded?.Invoke(sceneName);
stopwatchWatcher.Stop();
// if (activateOnLoad is false)
// {
// asyncOperation.Result.ActivateAsync().ToUniTask(cancellationToken: cancellationToken).Forget();
// _loadedObjects.Add(asyncOperation.Result);
// }
BIT4Log.Log<SceneService>($"场景:{sceneName}加载完成,耗时:{stopwatchWatcher.ElapsedMilliseconds}ms");
}
catch (OperationCanceledException)
{
}
}
public async UniTask UnloadSceneAsync(string sceneName, CancellationToken cancellationToken)
{
await UniTask.SwitchToMainThread();
if (LoadedObjects.TryRemove(sceneName) is false) return;
//await SceneManager.UnloadSceneAsync(scene);
SceneManager.LoadScene(1);
destroyCancellationToken.ThrowIfCancellationRequested();
OnUnloadScene?.Invoke(sceneName);
OnSceneUnloaded?.Invoke(sceneName);
}
event Action<string> ISceneService.OnLoadScene
{
add=>OnLoadScene+=value;
remove=>OnLoadScene-=value;
}
event Action<string, float> ISceneService.OnSceneLoadProgress
{
add=>OnSceneLoadProgress+=value;
remove => OnSceneLoadProgress -= value;
}
event Action<string> ISceneService.OnSceneLoaded
{
add=>OnSceneLoaded+=value;
remove => OnSceneLoaded -= value;
}
public event Action<string> OnUnloadScene;
public event Action<string> OnSceneUnloaded;
}
}