diff --git a/Runtime/Assets/Compatibility/CompatibleSceneLoader.cs b/Runtime/Assets/Compatibility/CompatibleSceneLoader.cs index 49f5574..e1271e8 100644 --- a/Runtime/Assets/Compatibility/CompatibleSceneLoader.cs +++ b/Runtime/Assets/Compatibility/CompatibleSceneLoader.cs @@ -7,26 +7,10 @@ using Cysharp.Threading.Tasks; #endif -#if UNITY_EDITOR -using UnityEditor.SceneManagement; -#endif - namespace Mew.Core.Assets { internal static class CompatibleSceneLoader { - internal static async ValueTask LoadSceneAsync(UnifiedScene unifiedScene, LoadSceneParameters parameters) - { -#if UNITY_2023_2_OR_NEWER || USE_UNITASK - await SceneManager.LoadSceneAsync(unifiedScene.SceneReference, parameters); -#else - var asyncOp = SceneManager.LoadSceneAsync(unifiedScene.SceneReference, parameters); - while (!asyncOp.isDone) await TaskHelper.NextFrame(); -#endif - var loadedScene = SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1); - return new SceneHandle(loadedScene); - } - internal static async ValueTask UnloadSceneAsync(SceneHandle sceneHandle) { #if UNITY_2023_2_OR_NEWER || USE_UNITASK @@ -36,20 +20,5 @@ internal static async ValueTask UnloadSceneAsync(SceneHandle sceneHandle) while (!asyncOp.isDone) await TaskHelper.NextFrame(); #endif } - -#if UNITY_EDITOR - public static async Task LoadEditorSceneAsync(UnifiedScene unifiedScene, LoadSceneParameters parameters) - { - -#if UNITY_2023_2_OR_NEWER || USE_UNITASK - await EditorSceneManager.LoadSceneAsyncInPlayMode(unifiedScene.EditorScenePath , parameters ) ; -#else - var asyncOp = EditorSceneManager.LoadSceneAsyncInPlayMode(unifiedScene.EditorScenePath , parameters ) ; - while (!asyncOp.isDone) await TaskHelper.NextFrame(); -#endif - var loadedScene = SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1); - return new SceneHandle(loadedScene); - } -#endif } } \ No newline at end of file diff --git a/Runtime/Assets/Scene/ISceneHandle.cs b/Runtime/Assets/Scene/ISceneHandle.cs index e9367e8..50ebc6c 100644 --- a/Runtime/Assets/Scene/ISceneHandle.cs +++ b/Runtime/Assets/Scene/ISceneHandle.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using UnityEngine.SceneManagement; @@ -6,6 +7,8 @@ namespace Mew.Core.Assets { public interface ISceneHandle : IEquatable { - ValueTask GetScene(); + ValueTask GetScene(CancellationToken ct); + public float Progress { get; } + bool Completed { get; } } } diff --git a/Runtime/Assets/Scene/SceneHandle.cs b/Runtime/Assets/Scene/SceneHandle.cs index 96a407b..5b083a7 100644 --- a/Runtime/Assets/Scene/SceneHandle.cs +++ b/Runtime/Assets/Scene/SceneHandle.cs @@ -1,20 +1,55 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; +using Mew.Core.TaskHelpers; +using UnityEngine; using UnityEngine.SceneManagement; namespace Mew.Core.Assets { public class SceneHandle : ISceneHandle { - public Scene Scene { get; } + public AsyncOperation AsyncOp { get; } + public Scene Scene { get; private set; } + public float Progress => AsyncOp.progress; + public bool Completed => AsyncOp.isDone; + + public SceneHandle(AsyncOperation asyncOp) + { + AsyncOp = asyncOp; + AsyncOp.completed += OnCompleted; + } public SceneHandle(Scene scene) { Scene = scene; } - public async ValueTask GetScene() + private void OnCompleted(AsyncOperation operation) + { + AsyncOp.completed -= OnCompleted; + Scene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1); + } + + public async ValueTask GetScene(CancellationToken ct) { - return await Task.FromResult(Scene); + if (!AsyncOp.isDone) + { +#if UNITY_2023_2_OR_NEWER + await AsyncOp; +#else + while (!AsyncOp.isDone) await TaskHelper.NextFrame(ct); +#endif + } + + // not pass cancellation token to SceneManager.UnloadSceneAsync + if (!Scene.IsValid()) await TaskHelper.NextFrame(); + + if (ct.IsCancellationRequested) + { + SceneManager.UnloadSceneAsync(Scene); + ct.ThrowIfCancellationRequested(); + } + return Scene; } public bool Equals(Scene other) diff --git a/Runtime/Assets/Scene/SceneInstanceHandle.cs b/Runtime/Assets/Scene/SceneInstanceHandle.cs index 1bc27a2..43751d5 100644 --- a/Runtime/Assets/Scene/SceneInstanceHandle.cs +++ b/Runtime/Assets/Scene/SceneInstanceHandle.cs @@ -1,4 +1,5 @@ #if USE_MEW_CORE_ASSETS +using System.Threading; using System.Threading.Tasks; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.Exceptions; @@ -10,17 +11,25 @@ namespace Mew.Core.Assets public class SceneInstanceHandle : ISceneHandle { public AsyncOperationHandle Handle { get; } - private bool Comeleted => Handle.IsDone; + public float Progress => Handle.PercentComplete; + public bool Completed => Handle.IsDone; public SceneInstanceHandle(AsyncOperationHandle asyncOperationHandle) { Handle = asyncOperationHandle; } - public async ValueTask GetScene() + public async ValueTask GetScene(CancellationToken ct) { if (!Handle.IsDone) await Handle.Task; + + if (ct.IsCancellationRequested) + { + await UnifiedSceneLoader.UnloadAsync(this); + ct.ThrowIfCancellationRequested(); + } + return Handle.Result.Scene; } diff --git a/Runtime/Assets/Scene/SceneLoader.cs b/Runtime/Assets/Scene/SceneLoader.cs index 4e8037f..1d75c30 100644 --- a/Runtime/Assets/Scene/SceneLoader.cs +++ b/Runtime/Assets/Scene/SceneLoader.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Mew.Core.TaskHelpers; +using UnityEngine; using UnityEngine.SceneManagement; namespace Mew.Core.Assets @@ -10,12 +12,18 @@ namespace Mew.Core.Assets public class SceneLoader : IAsyncDisposable { private List SceneHandles { get; } = new(); + private List LoadingHandles { get; } = new(); private bool Disposed { get; set; } + public float Progression + => LoadingHandles.Any() + ? LoadingHandles.Sum(x => x.Progress) / LoadingHandles.Count + : 1f; public async ValueTask LoadAsync(UnifiedScene unifiedScene, CancellationToken cancellationToken = default) { - var handle = await UnifiedSceneLoader.LoadAsync(unifiedScene, cancellationToken); - var scene = await handle.GetScene(); + var handle = UnifiedSceneLoader.LoadAsync(unifiedScene); + LoadingHandles.Add(handle); + var scene = await handle.GetScene(cancellationToken); if (Disposed) { @@ -27,6 +35,7 @@ public async ValueTask LoadAsync(UnifiedScene unifiedScene, CancellationT throw new TaskCanceledException(); } + LoadingHandles.Remove(handle); SceneHandles.Add(handle); return scene; } diff --git a/Runtime/Assets/Scene/UnifiedSceneLoader.cs b/Runtime/Assets/Scene/UnifiedSceneLoader.cs index 4d7c8b6..23f0107 100644 --- a/Runtime/Assets/Scene/UnifiedSceneLoader.cs +++ b/Runtime/Assets/Scene/UnifiedSceneLoader.cs @@ -17,7 +17,7 @@ namespace Mew.Core.Assets { public static class UnifiedSceneLoader { - public static async Task LoadAsync(UnifiedScene unifiedScene, CancellationToken cancellationToken) + public static ISceneHandle LoadAsync(UnifiedScene unifiedScene) { var parameters = new LoadSceneParameters(LoadSceneMode.Additive, LocalPhysicsMode.None); ISceneHandle handle; @@ -42,13 +42,15 @@ public static async Task LoadAsync(UnifiedScene unifiedScene, Canc #endif if (unifiedScene.SceneReference is not null && unifiedScene.SceneReference.IsValid) { - handle = await CompatibleSceneLoader.LoadSceneAsync(unifiedScene, parameters); + var asyncOp = SceneManager.LoadSceneAsync(unifiedScene.SceneReference, parameters); + handle = new SceneHandle(asyncOp); } #if UNITY_EDITOR // for test use else if (!string.IsNullOrEmpty(unifiedScene.EditorScenePath)) { - handle = await CompatibleSceneLoader.LoadEditorSceneAsync(unifiedScene, parameters); + var asyncOp = EditorSceneManager.LoadSceneAsyncInPlayMode(unifiedScene.EditorScenePath , parameters ) ; + handle = new SceneHandle(asyncOp); } #endif else