Hello everyone! You don’t believe me but I know how to fix your issue. Because I also faced it.
But first, let me enjoy the moment: I am your messiah, I am your savior, I am Unity’s Jesus. What would you do without me, huh? Huh?
I finished, thank you, now to the solution:
Indeed, the error is about the scene already loaded, you cannot load it twice.
Then we need to unload it and load it again, which is already happening in the UnloadPreviousScene() method:
_currentlyLoadedScene.sceneReference.UnLoadScene();
But the Unity community decided to do all these things asynchronically, which is good in general and not good for our case - they call LoadNewScene() without waiting for the unload to complete. This approach is also not good because the _sceneToLoad reference can be lost during such risky transitions between scenes when you cannot be sure in the load ordering.
Now, let’s wait until the unload complete:
AsyncOperationHandle<SceneInstance> unloadingHandle = _currentlyLoadedScene.sceneReference.UnLoadScene();
yield return new WaitUntil(() => unloadingHandle.IsDone);
Good, yes? Not yet.
The problem with lost reference in the _sceneToLoad is now 100% reproducible because, for some reason, Unity cannot keep references to previous scene assets if there is no at least one scene that could “handle”/“keep” it. You will be always noticing that _sceneToLoad is lost until you add a temporary/blank/fake scene before you unload the previous scene. Just create a ScriptableObject scene that will contain an empty scene Addressable inside, add it to the SceneLoader as a SerializableField, set it in the editor and load it before the _currentlyLoadedScene.sceneReference.UnLoadScene():
// We create an empty scene to keep references
AsyncOperationHandle<SceneInstance> emptySceneHandle = _emptyScene.sceneReference.LoadSceneAsync(LoadSceneMode.Additive, true);
yield return new WaitUntil(() => emptySceneHandle.IsDone);
Of course, don’t forget to remove it after your scene is loaded:
bool isLoaded = _emptyScene.sceneReference.OperationHandle.IsValid();
if (isLoaded)
{
_emptyScene.sceneReference.UnLoadScene();
}
Congratulations, now, with the help of the method below you can reload levels:
private void OnReloadCurrentScene()
{
if (_currentlyLoadedScene == null)
{
return;
}
LoadGameplayScene(_currentlyLoadedScene, new LoadSceneOptions(true, true));
}
Thank you!