185 lines
5.6 KiB
C#
185 lines
5.6 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.ResourceManagement.ResourceProviders;
|
|
using UnityEngine.SceneManagement;
|
|
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 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
|
|
{
|
|
#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;
|
|
|
|
private CancellationToken _cancellationToken;
|
|
private readonly List<SceneInstance> _loadedObjects = new();
|
|
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();
|
|
_loadedObjects.Add(asyncOperation.Result);
|
|
}
|
|
BIT4Log.Log<SceneService>($"场景:{sceneName}加载完成,耗时:{stopwatchWatcher.ElapsedMilliseconds}ms");
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
public async UniTask UnloadSceneAsync(string sceneName, CancellationToken cancellationToken)
|
|
{
|
|
await UniTask.SwitchToMainThread();
|
|
OnUnloadScene?.Invoke(sceneName);
|
|
foreach (var x in _loadedObjects)
|
|
{
|
|
await Addressables.UnloadSceneAsync(x);
|
|
}
|
|
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;
|
|
}
|
|
|
|
}
|