When my scene is loaded, I want to load some data from my save system. This needs to happen ideally before each object’s Awake and OnEnable functions are called. What is the best way to do this?
Naive attempt:
if (levelLoadParamaters.saveGameDataBeforeLoad)
{
saveSystemManager.Save();
}
SceneManager.LoadScene(scene.BuildIndex);
if (levelLoadParamaters.loadGameDataAfterLoad)
{
saveSystemManager.Load();
}
This does not work as saveSystemManager.Load(); is called when we are still in the old scene, before the new scene objects are loaded.
The documentation explains this.
When using SceneManager.LoadScene, the scene loads in the next frame
My next attempt was to use SceneManager.sceneLoaded
private void OnEnable()
{
SceneManager.sceneLoaded += SceneLoaded;
}
private void SceneLoaded(Scene newScene, LoadSceneMode loadMode)
{
Debug.Log($"{nameof(SceneManager.sceneLoaded)} invoked to \"{newScene.name}\"");
saveSystemManager.Load();
}
However, this seems to happen after object's Awake and OnEnable
Log:
Player Awake
sceneLoaded invoked to "scene"
The documentation for this is terrible, but it seems this is intended behaviour.
My only other idea would be to create an object in each scene with this load function in its Awake and push it to the front of the execution order. But this seems a pretty hacky solution.
Is there a better way to invoke some logic as soon as a scene loads, before Awake and OnEnable?
EDIT:
Attempting to do this using async scene loading will also not work as even after the scene has reached "90% progress (fully loaded)" and is waiting for allowSceneActivation, it is not actually loaded in, and cannot be interacted with
. Allowing it to then load is equivalent to the naive attempt above.
sceneLoaded's docs state:
You can expect to receive the
sceneLoadednotification afterOnEnablebut beforeStartfor all objects in the scene
So that's not what you want. There is allowSceneActivation, along with SceneManager.LoadSceneAsync, where you can manually enable a scene instead of the SceneManager doing it for you. This should delay Awake/OnEnable/Start calls until you manually activate the scene by setting allowSceneActivation back to true:
public IEnumerator LoadSceneWithSaveData(string scene) {
AsyncOperation op = SceneManager.LoadSceneAsync(scene);
op.allowSceneActivation = false;
// 0.9 (90%) is used as a magic number, scene activation makes up the last 10%
while (!op.isDone && op.progress < 0.9f) {
yield return null;
}
// At this point, `scene` is loaded but *not* active.
// Do your save logic here.
// And finally... enable the scene.
op.allowSceneActivation = true;
}
Just be sure to start your scene load as a coroutine...
StartCoroutine(LoadSceneWithSaveData("scene name"));
The only problem after this is... well... the scene isn't active yet. Which might cause issues getting references to GameObjects / calling events, since the new objects wouldn't have the chance to subscribe to them. Are you sure your save system needs to run before even Awake?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With