295 lines
8.5 KiB
C#
295 lines
8.5 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BITKit.IO;
|
|
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 void RegisterLoadTaskAsync(Func<UniTask> task)
|
|
{
|
|
_sceneServiceImplementation.RegisterLoadTaskAsync(task);
|
|
}
|
|
|
|
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
|
|
{
|
|
_sceneServiceImplementation.UnRegisterLoadTaskAsync(task);
|
|
}
|
|
|
|
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
|
|
[UnityEditor.MenuItem("Tools/Scenes/Toggle Scene Service Once")]
|
|
public static void ToggleSceneServiceOnce()
|
|
{
|
|
AllowInitialize = !AllowInitialize;
|
|
Debug.Log("允许初始化场景设置为:"+AllowInitialize);
|
|
}
|
|
#endif
|
|
[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 readonly ConcurrentDictionary<string,ResourcePackage> _packages=new();
|
|
|
|
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)
|
|
{
|
|
try
|
|
{
|
|
_packages.Clear();
|
|
var list = new List<string>();
|
|
foreach (var package in YooAssetUtils.RegisteredResourcePackages)
|
|
{
|
|
foreach (var assetInfo in package.GetAssetInfos(tags))
|
|
{
|
|
list.Add(assetInfo.Address);
|
|
_packages.TryAdd(assetInfo.Address,package);
|
|
}
|
|
}
|
|
return list.ToArray();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
BIT4Log.Warning<ISceneService>(JsonHelper.Get(YooAssetUtils.RegisteredPackages) );
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public async UniTask LoadSceneAsync(string sceneName, CancellationToken cancellationToken,
|
|
LoadSceneMode loadSceneMode = LoadSceneMode.Additive,
|
|
bool activateOnLoad = true)
|
|
{
|
|
try
|
|
{
|
|
var stopwatchWatcher = new Stopwatch();
|
|
|
|
BIT4Log.Log<SceneService>($"正在加载场景:{sceneName}");
|
|
OnLoadScene?.Invoke(sceneName);
|
|
|
|
await Task.Delay(100, destroyCancellationToken);
|
|
|
|
stopwatchWatcher.Start();
|
|
|
|
#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 package = _packages[sceneName];
|
|
|
|
var handle = package.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(384, cancellationToken);
|
|
|
|
foreach (var x in _onSceneLoadedAsyncList.ToArray())
|
|
{
|
|
await x.Invoke();
|
|
if (destroyCancellationToken.IsCancellationRequested) return;
|
|
}
|
|
|
|
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);
|
|
|
|
await Task.Delay(100, destroyCancellationToken);
|
|
|
|
await UniTask.SwitchToMainThread();
|
|
|
|
if (LoadedObjects.TryRemove(sceneName) is false) return;
|
|
|
|
//await SceneManager.UnloadSceneAsync(scene);
|
|
SceneManager.LoadScene(1);
|
|
|
|
destroyCancellationToken.ThrowIfCancellationRequested();
|
|
await UniTask.SwitchToMainThread();
|
|
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;
|
|
}
|
|
|
|
private readonly List<Func<UniTask>> _onSceneLoadedAsyncList=new();
|
|
public void RegisterLoadTaskAsync(Func<UniTask> task)
|
|
{
|
|
_onSceneLoadedAsyncList.Add(task);
|
|
}
|
|
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
|
|
{
|
|
_onSceneLoadedAsyncList.Remove(task);
|
|
}
|
|
|
|
public event Action<string> OnUnloadScene;
|
|
public event Action<string> OnSceneUnloaded;
|
|
}
|
|
|
|
}
|