Skip to content

Commit

Permalink
implemented LoadSceneAsync force load from LoadScene
Browse files Browse the repository at this point in the history
  • Loading branch information
Eddio0141 committed Nov 18, 2024
1 parent ef0d68c commit 9096cc9
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Compatibility

- AsyncOperation's InvokeCompletionEvent is only disabled for tracked AsyncOperation instances
- Implemented LoadScene forcing pending LoadSceneAsync to be all loaded
- Fixed accidentally obliterating return value of LoadScene instances

# [v0.6.0] - 2024-11-18

Expand Down
8 changes: 8 additions & 0 deletions UniTAS/Patcher/Implementations/PatchReverseInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ public void Invoke(Action method)
_invoking.Value = false;
}

public void Invoke<T1>(Action<T1> method, T1 arg1)
{
_invoking.Value = true;
method(arg1);
_invoking.Value = false;
}


public TRet Invoke<TRet>(Func<TRet> method)
{
_invoking.Value = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using UniTAS.Patcher.Implementations.UnitySafeWrappers.SceneManagement;
using UniTAS.Patcher.Interfaces.Patches.PatchTypes;
using UniTAS.Patcher.Models.UnitySafeWrappers.SceneManagement;
using UniTAS.Patcher.Services;
using UniTAS.Patcher.Services.Logging;
using UniTAS.Patcher.Services.UnityAsyncOperationTracker;
using UniTAS.Patcher.Services.UnityEvents;
Expand Down Expand Up @@ -56,12 +57,30 @@ public class SceneManagerAsyncLoadPatch

private static readonly ILogger Logger = ContainerStarter.Kernel.GetInstance<ILogger>();

private static readonly IPatchReverseInvoker ReverseInvoker =
ContainerStarter.Kernel.GetInstance<IPatchReverseInvoker>();

private static bool AsyncSceneLoad(bool mustCompleteNextFrame, string sceneName, int sceneBuildIndex,
object parameters, bool? isAdditive, AsyncOperation __result)
object parameters, bool? isAdditive, ref AsyncOperation __result)
{
// everything goes through here, so yeah why not
if (ReverseInvoker.Invoking)
return true;

__result = new();

if (mustCompleteNextFrame)
{
SceneLoadInvoke.SceneLoadCall();

// uh oh, time to do the wacky thing unity does!!!
//
// https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html
/*
* Because loading is set to complete in the next rendered frame, calling SceneManager.LoadScene
* forces all previous AsyncOperations to complete, even if AsyncOperation.allowSceneActivation is set to false
*/
SceneLoadTracker.NonAsyncSceneLoad();
return true;
}

Expand Down Expand Up @@ -226,8 +245,7 @@ private static Exception Cleanup(MethodBase original, Exception ex)
private static bool Prefix(string sceneName, int sceneBuildIndex, bool isAdditive, bool mustCompleteNextFrame,
ref AsyncOperation __result)
{
__result = new();
return AsyncSceneLoad(mustCompleteNextFrame, sceneName, sceneBuildIndex, null, isAdditive, __result);
return AsyncSceneLoad(mustCompleteNextFrame, sceneName, sceneBuildIndex, null, isAdditive, ref __result);
}
}

Expand All @@ -254,8 +272,7 @@ private static Exception Cleanup(MethodBase original, Exception ex)
private static bool Prefix(bool mustCompleteNextFrame, string sceneName, int sceneBuildIndex, object parameters,
ref AsyncOperation __result)
{
__result = new();
return AsyncSceneLoad(mustCompleteNextFrame, sceneName, sceneBuildIndex, parameters, null, __result);
return AsyncSceneLoad(mustCompleteNextFrame, sceneName, sceneBuildIndex, parameters, null, ref __result);
}
}

Expand All @@ -275,8 +292,7 @@ private static Exception Cleanup(MethodBase original, Exception ex)
private static bool Prefix(string sceneName, int sceneBuildIndex, object parameters, bool mustCompleteNextFrame,
ref AsyncOperation __result)
{
__result = new();
return AsyncSceneLoad(mustCompleteNextFrame, sceneName, sceneBuildIndex, parameters, null, __result);
return AsyncSceneLoad(mustCompleteNextFrame, sceneName, sceneBuildIndex, parameters, null, ref __result);
}
}
}
1 change: 1 addition & 0 deletions UniTAS/Patcher/Services/IPatchReverseInvoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public interface IPatchReverseInvoker
{
bool Invoking { get; }
void Invoke(Action method);
void Invoke<T1>(Action<T1> method, T1 arg1);
TRet Invoke<TRet>(Func<TRet> method);
TRet Invoke<TRet, T>(Func<T, TRet> method, T arg1);
TRet Invoke<TRet, T1, T2>(Func<T1, T2, TRet> method, T1 arg1, T2 arg2);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using HarmonyLib;
using UniTAS.Patcher.Interfaces.DependencyInjection;
Expand All @@ -18,7 +19,7 @@ namespace UniTAS.Patcher.Services.UnityAsyncOperationTracker;

// ReSharper disable once ClassNeverInstantiated.Global
[Singleton]
public class AsyncOperationTracker(ISceneWrapper sceneWrapper, ILogger logger)
public class AsyncOperationTracker(ISceneWrapper sceneWrapper, ILogger logger, IPatchReverseInvoker reverseInvoker)
: ISceneLoadTracker, IAssetBundleCreateRequestTracker, IAssetBundleRequestTracker,
IOnLastUpdateUnconditional, IAsyncOperationIsInvokingOnComplete, IOnPreGameRestart, IOnUpdateActual
{
Expand Down Expand Up @@ -133,6 +134,22 @@ public void AsyncSceneLoad(string sceneName, int sceneBuildIndex, LoadSceneMode
new(sceneName, sceneBuildIndex, asyncOperation, loadSceneMode, localPhysicsMode));
}

public void NonAsyncSceneLoad()
{
foreach (var pair in _asyncLoads.Concat(_asyncLoadStalls))
{
var scene = pair.Value;
logger.LogDebug(
$"force loading scene, name: {scene.SceneName}, index: {scene.SceneBuildIndex}, manually loading in loop");
reverseInvoker.Invoke(s => sceneWrapper.LoadSceneAsync(s.SceneName, s.SceneBuildIndex,
s.LoadSceneMode,
s.LocalPhysicsMode, true), scene);
_pendingLoadCallbacks.Add(scene.AsyncOperationInstance);
}

_asyncLoads.Clear();
}

public void AllowSceneActivation(bool allow, AsyncOperation asyncOperation)
{
logger.LogDebug($"allow scene activation {allow}, {new StackTrace()}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ public interface ISceneLoadTracker
{
void AsyncSceneLoad(string sceneName, int sceneBuildIndex, LoadSceneMode loadSceneMode,
LocalPhysicsMode localPhysicsMode, AsyncOperation asyncOperation);


void NonAsyncSceneLoad();

void AsyncSceneUnload(AsyncOperation asyncOperation);

void AllowSceneActivation(bool allow, AsyncOperation asyncOperation);
Expand Down

0 comments on commit 9096cc9

Please sign in to comment.