I have Main menu provider:
class MainMenuProvider
{
private static SceneInstance _cachedScene;
private static bool _isLoaded;
public async Task<SceneInstance> Load()
{
if (!_isLoaded)
{
var mainMenuLoadHandle =
Addressables.LoadSceneAsync("Assets/Bundles/UI/Scenes/MainMenu.unity", LoadSceneMode.Single, false);
await mainMenuLoadHandle.Task;
_cachedScene = mainMenuLoadHandle.Result;
_isLoaded = true;
}
return _cachedScene;
}
}
When I firstly invoke Load
and then scene.ActivateSync
it works perfect, but when I invoke Load
and ActivateAsync
the second time and my scene is cached, nothing happens.
_cachedScene.m_Operation.isDone == true
You set _isLoaded
static
so this whole thing is definitely only executed exactly once the entire application session lifecycle.
However, if you then ever happen to use LoadSceneMode.Single
for any other scene at any time, then this _cachedScene
is unloaded and doesn't exist anymore.
=> _cachedScene
will then contain an invalid scene which isn't loaded anymore and will never be loaded again.
You would need to decouple the loading of the addressable and the actual loading of the scene. The Addressables.LoadSceneAsync
already contains directly also the call to SceneManagement.SceneManager.LoadSceneAsync
. You want to split that and only use e.g. only Addressables.LoadAssetAsync
for your caching.
And then only load and unload this scene via the mentioned SceneManagement.SceneManager.LoadSceneAsync
somewhat like e.g.
class MainMenuProvider
{
private static AsyncOperationHandle<Scene>? _sceneHandle;
private static Scene? _loadedScene;
public async Task<Scene> Load()
{
if(TryGetLoadedScene(out var scene))
{
return scene;
}
if (_sceneHandle == null)
{
_sceneHandle = Addressables.LoadAssetAsync<Scene>("Assets/Bundles/UI/Scenes/MainMenu.unity");
}
await _sceneHandle.Task;
if(TryGetLoadedScene(out var scene))
{
return scene;
}
var path = _sceneHandle.Result.path;
await SceneManager.LoadSceneAsync(path, LoadSceneMode.Single, false);
_loadedScene = SceneManager.GetSceneByPath(path);
return _loadedScene;
}
private static bool TryGetLoadedScene(out Scene? loadedScene)
{
if(_loadedScene == null)
{
loadedScene = null;
return false;
}
loadedScene = SceneManager.GetSceneByPath(_loadedScene.path);
if(scene.isValid)
{
_loadedScene = loadedScene;
return true;
}
return false;
}
}
This would to certain extent reduce the advantage of the addressable of course since one of them is less memory usage by unloading the scene while it isn't used.