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

139 lines
4.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.SceneManagement;
using Debug = UnityEngine.Debug;
namespace BITKit.SceneManagement
{
[Serializable]
public class SceneServiceSingleton : SceneServiceImplement
{
protected override ISceneService _sceneServiceImplementation => SceneService.Singleton;
}
[Serializable]
public class SceneServiceSingletonProxy:ISceneService
{
public bool InitializeMainSceneOnLoad=>SceneService.Singleton.InitializeMainSceneOnLoad;
public UniTask LoadSceneAsync(string sceneName, CancellationToken cancellationToken,
LoadSceneMode loadSceneMode = LoadSceneMode.Additive, bool activateOnLoad = true)=>SceneService.Singleton.LoadSceneAsync(sceneName,cancellationToken,loadSceneMode,activateOnLoad);
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 class SceneService : MonoBehaviour,ISceneService
{
#if UNITY_EDITOR
public static bool AllowInitialize=true;
[RuntimeInitializeOnLoadMethod]
private static void Initialize()
{
if (AllowInitialize)
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;
private CancellationToken _cancellationToken;
private void Awake()
{
Singleton = this;
_cancellationToken = gameObject.GetCancellationTokenOnDestroy();
}
private void Start()
{
if (allowLoadMainScene.Allow is false) return;
LoadSceneAsync(allowLoadMainScene.Value,_cancellationToken,LoadSceneMode.Single,false).Forget();
}
public bool InitializeMainSceneOnLoad => true;
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);
}
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();
}
BIT4Log.Log<SceneService>($"场景:{sceneName}加载完成,耗时:{stopwatchWatcher.ElapsedMilliseconds}ms");
}
catch (OperationCanceledException)
{
}
}
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;
}
}
}