Skip to content

Commit 1b999f8

Browse files
committed
Add coroutine-based scene loader
1 parent d15a8d7 commit 1b999f8

File tree

69 files changed

+15551
-21
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+15551
-21
lines changed

Runtime/Interfaces/IAddressableSceneLoaderAsync.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public interface IAddressableSceneLoaderAsync : IAddressableSceneLoader
3838
/// or runtime key (<see cref="AddressableLoadSceneReferenceKey"/>).
3939
/// If null, the transition will not have an intermediate loading scene.
4040
/// </param>
41-
/// <returns>The transition awaitable <see cref="Task{TResult}"/>"/> with the resulting <see cref="SceneInstance"/>.</returns>
41+
/// <returns>The transition awaitable <see cref="Task{TResult}"/> with the resulting <see cref="SceneInstance"/>.</returns>
4242
Task<SceneInstance> TransitionToSceneAsync(IAddressableLoadSceneReference targetSceneReference, IAddressableLoadSceneReference intermediateSceneReference = null);
4343

4444
/// <summary>
@@ -54,7 +54,7 @@ public interface IAddressableSceneLoaderAsync : IAddressableSceneLoader
5454
/// Should the loaded scene be marked as active?
5555
/// Equivalent to calling <see cref="IAddressableSceneManager.SetActiveSceneHandle(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle{UnityEngine.ResourceManagement.ResourceProviders.SceneInstance})"/>.
5656
/// </param>
57-
/// <returns>The load awaitable <see cref="Task{TResult}"/>"/> with the resulting <see cref="SceneInstance"/>.</returns>
57+
/// <returns>The load awaitable <see cref="Task{TResult}"/> with the resulting <see cref="SceneInstance"/>.</returns>
5858
Task<SceneInstance> LoadSceneAsync(IAddressableLoadSceneReference sceneReference, bool setActive = false);
5959

6060
/// <summary>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#if ENABLE_ADDRESSABLES
2+
/**
3+
* IAddressableSceneLoaderCoroutine.cs
4+
* Created by: João Borks [joao.borks@gmail.com]
5+
* Created on: 9/4/2022 (en-US)
6+
*/
7+
8+
using UnityEngine;
9+
10+
namespace MyUnityTools.SceneLoading.AddressablesSupport
11+
{
12+
/// <summary>
13+
/// Interface to standardize <see cref="Coroutine"/> addressable scene operations.
14+
/// </summary>
15+
public interface IAddressableSceneLoaderCoroutine : IAddressableSceneLoader
16+
{
17+
/// <summary>
18+
/// Triggers a scene transition asynchronously.
19+
/// It will transition from the current active scene (<see cref="IAddressableSceneManager.GetActiveSceneHandle"/>)
20+
/// to the target scene (<paramref name="targetSceneReference"/>), with an optional intermediate loading scene (<paramref name="intermediateSceneReference"/>).
21+
/// If the <paramref name="intermediateSceneReference"/> is not set, the transition will have no intermediate loading scene and will instead simply load the target scene directly.
22+
/// The complete transition flow is:
23+
/// <br/><br/>
24+
/// 1. Load the intermediate scene (if provided).<br/>
25+
/// 2. Load the target scene.<br/>
26+
/// 3. Unload the intermediate scene (if provided).<br/>
27+
/// 4. Unload the previous scene
28+
/// </summary>
29+
/// <param name="targetSceneReference">
30+
/// The scene that's going to be transitioned to.
31+
/// Can be the scene's addressable <see cref="UnityEngine.AddressableAssets.AssetReference"/> (<see cref="AddressableLoadSceneReferenceAsset"/>)
32+
/// or runtime key (<see cref="AddressableLoadSceneReferenceKey"/>).
33+
/// </param>
34+
/// <param name="intermediateSceneReference">
35+
/// The scene that's going to be loaded as the transition intermediate (as a loading scene).
36+
/// Can be the scene's addressable <see cref="UnityEngine.AddressableAssets.AssetReference"/> (<see cref="AddressableLoadSceneReferenceAsset"/>)
37+
/// or runtime key (<see cref="AddressableLoadSceneReferenceKey"/>).
38+
/// If null, the transition will not have an intermediate loading scene.
39+
/// </param>
40+
/// <returns>The transition <see cref="Coroutine"/>.</returns>
41+
Coroutine TransitionToSceneRoutine(IAddressableLoadSceneReference targetSceneReference, IAddressableLoadSceneReference intermediateSceneReference = null);
42+
43+
/// <summary>
44+
/// Loads a scene additively asynchronously on top of the current scene stack, optionally marking it as the active scene
45+
/// (<see cref="IAddressableSceneManager.SetActiveSceneHandle(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle{UnityEngine.ResourceManagement.ResourceProviders.SceneInstance})"/>).
46+
/// </summary>
47+
/// <param name="sceneInfo">
48+
/// The scene that's going to be loaded.
49+
/// Can be the scene's addressable <see cref="UnityEngine.AddressableAssets.AssetReference"/> (<see cref="AddressableLoadSceneReferenceAsset"/>)
50+
/// or runtime key (<see cref="AddressableLoadSceneReferenceKey"/>).
51+
/// </param>
52+
/// <param name="setActive">
53+
/// Should the loaded scene be marked as active?
54+
/// Equivalent to calling <see cref="IAddressableSceneManager.SetActiveSceneHandle(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle{UnityEngine.ResourceManagement.ResourceProviders.SceneInstance})"/>.
55+
/// </param>
56+
/// <returns>The load <see cref="Coroutine"/>.</returns>
57+
Coroutine LoadSceneRoutine(IAddressableLoadSceneReference sceneReference, bool setActive = false);
58+
59+
/// <summary>
60+
/// Unloads the given scene asynchronously from the current scene stack.
61+
/// </summary>
62+
/// <param name="sceneInfo">
63+
/// Target scene info.
64+
/// Can be the scene's addressable <see cref="UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle{TObject}"/> (<see cref="AddressableLoadSceneInfoOperationHandle"/>),
65+
/// its <see cref="UnityEngine.ResourceManagement.ResourceProviders.SceneInstance"/> (<see cref="AddressableLoadSceneInfoInstance"/>),
66+
/// or its name (<see cref="AddressableLoadSceneInfoName"/>).
67+
/// </param>
68+
/// <returns>The unload awaitable <see cref="Coroutine"/>.</returns>
69+
Coroutine UnloadSceneRoutine(IAddressableLoadSceneInfo sceneInfo);
70+
}
71+
}
72+
#endif

Runtime/Interfaces/IAddressableSceneLoaderCoroutine.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Interfaces/IAddressableSceneLoaderUniTask.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public interface IAddressableSceneLoaderUniTask : IAddressableSceneLoader
3838
/// or runtime key (<see cref="AddressableLoadSceneReferenceKey"/>).
3939
/// If null, the transition will not have an intermediate loading scene.
4040
/// </param>
41-
/// <returns>The transition awaitable <see cref="UniTask{TResult}"/>"/> with the resulting <see cref="SceneInstance"/>.</returns>
41+
/// <returns>The transition awaitable <see cref="UniTask{TResult}"/> with the resulting <see cref="SceneInstance"/>.</returns>
4242
UniTask<SceneInstance> TransitionToSceneAsync(IAddressableLoadSceneReference targetSceneReference, IAddressableLoadSceneReference intermediateSceneReference = null);
4343

4444
/// <summary>
@@ -54,7 +54,7 @@ public interface IAddressableSceneLoaderUniTask : IAddressableSceneLoader
5454
/// Should the loaded scene be marked as active?
5555
/// Equivalent to calling <see cref="IAddressableSceneManager.SetActiveSceneHandle(UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle{UnityEngine.ResourceManagement.ResourceProviders.SceneInstance})"/>.
5656
/// </param>
57-
/// <returns>The load awaitable <see cref="UniTask{TResult}"/>"/> with the resulting <see cref="SceneInstance"/>.</returns>
57+
/// <returns>The load awaitable <see cref="UniTask{TResult}"/> with the resulting <see cref="SceneInstance"/>.</returns>
5858
UniTask<SceneInstance> LoadSceneAsync(IAddressableLoadSceneReference sceneReference, bool setActive = false);
5959

6060
/// <summary>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* ISceneLoaderCoroutine.cs
3+
* Created by: João Borks [joao.borks@gmail.com]
4+
* Created on: 9/4/2022 (en-US)
5+
*/
6+
7+
using UnityEngine;
8+
9+
namespace MyUnityTools.SceneLoading
10+
{
11+
/// <summary>
12+
/// Interface to standardize <see cref="Coroutine"/> scene operations.
13+
/// </summary>
14+
public interface ISceneLoaderCoroutine : ISceneLoader
15+
{
16+
/// <summary>
17+
/// Triggers a scene transition asynchronously.
18+
/// It will transition from the current active scene (<see cref="UnityEngine.SceneManagement.SceneManager.GetActiveScene()"/>)
19+
/// to the target scene (<paramref name="targetSceneInfo"/>), with an optional intermediate loading scene (<paramref name="intermediateSceneInfo"/>).
20+
/// If the <paramref name="intermediateSceneInfo"/> is not set, the transition will have no intermediate loading scene and will instead simply load the target scene directly.
21+
/// The complete transition flow is:
22+
/// <br/><br/>
23+
/// 1. Load the intermediate scene (if provided).<br/>
24+
/// 2. Load the target scene.<br/>
25+
/// 3. Unload the intermediate scene (if provided).<br/>
26+
/// 4. Unload the previous scene
27+
/// </summary>
28+
/// <param name="targetSceneInfo">
29+
/// The scene that's going to be transitioned to.
30+
/// Can be the scene's build index (<see cref="LoadSceneInfoIndex"/>) or name (<see cref="LoadSceneInfoName"/>).
31+
/// </param>
32+
/// <param name="intermediateSceneInfo">
33+
/// The scene that's going to be loaded as the transition intermediate (as a loading scene).
34+
/// Can be the scene's build index (<see cref="LoadSceneInfoIndex"/>) or name (<see cref="LoadSceneInfoName"/>).
35+
/// If null, the transition will not have an intermediate loading scene.
36+
/// </param>
37+
/// <returns>The transition <see cref="Coroutine"/>.</returns>
38+
Coroutine TransitionToSceneRoutine(ILoadSceneInfo targetSceneInfo, ILoadSceneInfo intermediateSceneInfo = null);
39+
40+
/// <summary>
41+
/// Unloads the given scene asynchronously from the current scene stack.
42+
/// </summary>
43+
/// <param name="sceneInfo">
44+
/// Target scene info.
45+
/// Can be the scene's build index (<see cref="LoadSceneInfoIndex"/>) or name (<see cref="LoadSceneInfoName"/>).
46+
/// </param>
47+
/// <returns>The unload <see cref="Coroutine"/>.</returns>
48+
Coroutine UnloadSceneRoutine(ILoadSceneInfo sceneInfo);
49+
50+
/// <summary>
51+
/// Loads a scene additively on top of the current scene stack, optionally marking it as the active scene
52+
/// (<see cref="UnityEngine.SceneManagement.SceneManager.SetActiveScene(UnityEngine.SceneManagement.Scene)"/>).
53+
/// </summary>
54+
/// <param name="sceneInfo">
55+
/// The scene that's going to be loaded.
56+
/// Can be the scene's build index (<see cref="LoadSceneInfoIndex"/>) or name (<see cref="LoadSceneInfoName"/>).
57+
/// </param>
58+
/// <param name="setActive">Should the loaded scene be marked as active? Equivalent to calling <see cref="UnityEngine.SceneManagement.SceneManager.SetActiveScene(UnityEngine.SceneManagement.Scene)"/>.</param>
59+
/// <returns>The load awaitable <see cref="Coroutine"/>.</returns>
60+
Coroutine LoadSceneRoutine(ILoadSceneInfo sceneInfo, bool setActive = false);
61+
}
62+
}

Runtime/Interfaces/ISceneLoaderCoroutine.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/SceneLoaders/AddressableSceneLoaderAsync.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ public async Task<SceneInstance> LoadSceneAsync(IAddressableLoadSceneReference s
4242

4343
public Task UnloadSceneAsync(IAddressableLoadSceneInfo sceneInfo) => sceneInfo.UnloadSceneAsync(_sceneManager).Task;
4444

45-
async Task<AsyncOperationHandle<SceneInstance>> LoadSceneAsyncWithReport(IAddressableLoadSceneReference sceneReference, SceneLoadProgressDelegate progressCallback)
45+
async Task<AsyncOperationHandle<SceneInstance>> LoadSceneAsyncWithReport(IAddressableLoadSceneReference sceneReference, System.IProgress<float> progress)
4646
{
4747
var operation = sceneReference.LoadSceneAsync(_sceneManager);
4848
while (!operation.IsDone)
4949
{
50-
progressCallback?.Invoke(operation.PercentComplete);
50+
progress.Report(operation.PercentComplete);
5151
await Task.Yield();
5252
}
5353
_sceneManager.SetActiveSceneHandle(operation);
@@ -67,7 +67,7 @@ async Task<SceneInstance> TransitionToSceneFlowAsync(IAddressableLoadSceneRefere
6767
while (!loadingBehavior.Active)
6868
await Task.Yield();
6969

70-
var operation = await LoadSceneAsyncWithReport(sceneReference, loadingBehavior.Report);
70+
var operation = await LoadSceneAsyncWithReport(sceneReference, loadingBehavior);
7171
loadingBehavior.CompleteLoading();
7272

7373
if (currentSceneHandle.IsValid())
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#if ENABLE_ADDRESSABLES
2+
/**
3+
* AddressableSceneLoaderCoroutine.cs
4+
* Created by: João Borks [joao.borks@gmail.com]
5+
* Created on: 9/4/2022 (en-US)
6+
*/
7+
8+
using System.Collections;
9+
using UnityEngine;
10+
11+
namespace MyUnityTools.SceneLoading.AddressablesSupport
12+
{
13+
public class AddressableSceneLoaderCoroutine : IAddressableSceneLoaderCoroutine
14+
{
15+
public IAddressableSceneManager SceneManager => _sceneManager;
16+
17+
readonly IAddressableSceneManager _sceneManager;
18+
readonly RoutineBehaviour _routineBehaviour;
19+
20+
public AddressableSceneLoaderCoroutine(IAddressableSceneManager sceneManager)
21+
{
22+
_sceneManager = sceneManager;
23+
_routineBehaviour = RoutineBehaviour.Instance;
24+
}
25+
26+
public void TransitionToScene(IAddressableLoadSceneReference targetSceneReference, IAddressableLoadSceneReference intermediateSceneReference) => TransitionToSceneRoutine(targetSceneReference, intermediateSceneReference);
27+
28+
public void LoadScene(IAddressableLoadSceneReference sceneReference, bool setActive) => LoadSceneRoutine(sceneReference, setActive);
29+
30+
public void UnloadScene(IAddressableLoadSceneInfo sceneInfo) => UnloadSceneRoutine(sceneInfo);
31+
32+
public Coroutine TransitionToSceneRoutine(IAddressableLoadSceneReference targetSceneReference, IAddressableLoadSceneReference intermediateSceneReference) => _routineBehaviour.StartCoroutine(intermediateSceneReference == null ? TransitionDirectlyRoutine(targetSceneReference) : TransitionWithIntermediateRoutine(targetSceneReference, intermediateSceneReference));
33+
34+
public Coroutine LoadSceneRoutine(IAddressableLoadSceneReference sceneReference, bool setActive) => _routineBehaviour.StartCoroutine(LoadRoutine(sceneReference, setActive));
35+
36+
public Coroutine UnloadSceneRoutine(IAddressableLoadSceneInfo sceneInfo) => _routineBehaviour.StartCoroutine(UnloadRoutine(sceneInfo));
37+
38+
IEnumerator LoadRoutine(IAddressableLoadSceneReference sceneReference, bool setActive)
39+
{
40+
var operation = sceneReference.LoadSceneAsync(_sceneManager);
41+
yield return operation;
42+
if (setActive)
43+
_sceneManager.SetActiveSceneHandle(operation);
44+
}
45+
46+
IEnumerator UnloadRoutine(IAddressableLoadSceneInfo sceneInfo)
47+
{
48+
yield return sceneInfo.UnloadSceneAsync(_sceneManager);
49+
}
50+
51+
IEnumerator TransitionWithIntermediateRoutine(IAddressableLoadSceneReference targetSceneReference, IAddressableLoadSceneReference intermediateSceneReference)
52+
{
53+
var currentSceneHandle = _sceneManager.GetActiveSceneHandle();
54+
var loadingSceneHandle = intermediateSceneReference.LoadSceneAsync(_sceneManager);
55+
yield return loadingSceneHandle;
56+
_sceneManager.SetActiveSceneHandle(loadingSceneHandle);
57+
58+
var loadingBehavior = Object.FindObjectOfType<LoadingBase>();
59+
if (loadingBehavior)
60+
{
61+
yield return new WaitUntil(() => loadingBehavior.Active);
62+
63+
yield return LoadSceneRoutineWithReport(targetSceneReference, loadingBehavior);
64+
loadingBehavior.CompleteLoading();
65+
66+
if (currentSceneHandle.IsValid())
67+
UnloadSceneRoutine(new AddressableLoadSceneInfoOperationHandle(currentSceneHandle));
68+
69+
yield return new WaitWhile(() => loadingBehavior.Active);
70+
71+
UnloadSceneRoutine(new AddressableLoadSceneInfoOperationHandle(loadingSceneHandle));
72+
}
73+
else
74+
{
75+
yield return LoadSceneRoutine(targetSceneReference, true);
76+
if (currentSceneHandle.IsValid())
77+
UnloadSceneRoutine(new AddressableLoadSceneInfoOperationHandle(currentSceneHandle));
78+
UnloadSceneRoutine(new AddressableLoadSceneInfoOperationHandle(loadingSceneHandle));
79+
}
80+
}
81+
82+
IEnumerator TransitionDirectlyRoutine(IAddressableLoadSceneReference targetSceneReference)
83+
{
84+
var currentSceneHandle = _sceneManager.GetActiveSceneHandle();
85+
yield return LoadSceneRoutine(targetSceneReference, true);
86+
UnloadSceneRoutine(new AddressableLoadSceneInfoOperationHandle(currentSceneHandle));
87+
}
88+
89+
IEnumerator LoadSceneRoutineWithReport(IAddressableLoadSceneReference targetSceneReference, System.IProgress<float> progress)
90+
{
91+
var operation = targetSceneReference.LoadSceneAsync(_sceneManager);
92+
while (!operation.IsDone)
93+
{
94+
progress.Report(operation.PercentComplete);
95+
yield return null;
96+
}
97+
_sceneManager.SetActiveSceneHandle(operation);
98+
}
99+
}
100+
}
101+
#endif

Runtime/SceneLoaders/AddressableSceneLoaderCoroutine.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)