using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.ResourceManagement.ResourceProviders; using UnityEngine.SceneManagement; /// /// This class manages the scene loading and unloading. /// public class SceneLoader : MonoBehaviour { [SerializeField] private GameSceneSO _gameplayScene = default; [Header("Load Events")] [SerializeField] private LoadEventChannelSO _loadLocation = default; [SerializeField] private LoadEventChannelSO _loadMenu = default; [Header("Broadcasting on")] [SerializeField] private BoolEventChannelSO _toggleLoadingScreen = default; [SerializeField] private VoidEventChannelSO _onSceneReady = default; private List> _loadingOperationHandles = new List>(); private AsyncOperationHandle _gameplayManagerLoadingOpHandle; //Parameters coming from scene loading requests private GameSceneSO[] _scenesToLoad; private GameSceneSO[] _currentlyLoadedScenes = new GameSceneSO[] { }; private bool _showLoadingScreen; private SceneInstance _gameplayManagerSceneInstance = new SceneInstance(); private void OnEnable() { _loadLocation.OnLoadingRequested += LoadLocation; _loadMenu.OnLoadingRequested += LoadMenu; } private void OnDisable() { _loadLocation.OnLoadingRequested -= LoadLocation; _loadMenu.OnLoadingRequested -= LoadMenu; } /// /// This function loads the location scenes passed as array parameter /// private void LoadLocation(GameSceneSO[] locationsToLoad, bool showLoadingScreen) { _scenesToLoad = locationsToLoad; _showLoadingScreen = showLoadingScreen; //In case we are coming from the main menu, we need to load the persistent Gameplay manager scene first if (_gameplayManagerSceneInstance.Scene == null || !_gameplayManagerSceneInstance.Scene.isLoaded) { StartCoroutine(ProcessGameplaySceneLoading(locationsToLoad, showLoadingScreen)); } else { UnloadPreviousScenes(); } } private IEnumerator ProcessGameplaySceneLoading(GameSceneSO[] locationsToLoad, bool showLoadingScreen) { _gameplayManagerLoadingOpHandle = _gameplayScene.sceneReference.LoadSceneAsync(LoadSceneMode.Additive, true); while (_gameplayManagerLoadingOpHandle.Status != AsyncOperationStatus.Succeeded) { yield return null; } _gameplayManagerSceneInstance = _gameplayManagerLoadingOpHandle.Result; UnloadPreviousScenes(); } /// /// Prepares to load the main menu scene, first removing the Gameplay scene in case the game is coming back from gameplay to menus. /// private void LoadMenu(GameSceneSO[] menusToLoad, bool showLoadingScreen) { _scenesToLoad = menusToLoad; _showLoadingScreen = showLoadingScreen; //In case we are coming from a Location back to the main menu, we need to get rid of the persistent Gameplay manager scene if (_gameplayManagerSceneInstance.Scene != null && _gameplayManagerSceneInstance.Scene.isLoaded) Addressables.UnloadSceneAsync(_gameplayManagerLoadingOpHandle, true); UnloadPreviousScenes(); } /// /// In both Location and Menu loading, this function takes care of removing previously loaded temporary scenes. /// private void UnloadPreviousScenes() { for (int i = 0; i < _currentlyLoadedScenes.Length; i++) { _currentlyLoadedScenes[i].sceneReference.UnLoadScene(); } LoadNewScenes(); } /// /// Kicks off the asynchronous loading of an array of scenes, either menus or Locations. /// private void LoadNewScenes() { if (_showLoadingScreen) { _toggleLoadingScreen.RaiseEvent(true); } _loadingOperationHandles.Clear(); //Build the array of handles of the temporary scenes to load for (int i = 0; i < _scenesToLoad.Length; i++) { _loadingOperationHandles.Add(_scenesToLoad[i].sceneReference.LoadSceneAsync(LoadSceneMode.Additive, true, 0)); } StartCoroutine(LoadingProcess()); } private IEnumerator LoadingProcess() { bool done = _loadingOperationHandles.Count == 0; //This while will exit when all scenes requested have been unloaded while (!done) { for (int i = 0; i < _loadingOperationHandles.Count; ++i) { if (_loadingOperationHandles[i].Status != AsyncOperationStatus.Succeeded) { break; } else { done = true; } } yield return null; } //Save loaded scenes (to be unloaded at next load request) _currentlyLoadedScenes = _scenesToLoad; SetActiveScene(); if (_showLoadingScreen) { _toggleLoadingScreen.RaiseEvent(false); } } /// /// This function is called when all the scenes have been loaded /// private void SetActiveScene() { //All the scenes have been loaded, so we assume the first in the array is ready to become the active scene Scene s = ((SceneInstance)_loadingOperationHandles[0].Result).Scene; SceneManager.SetActiveScene(s); LightProbes.TetrahedralizeAsync(); _onSceneReady.RaiseEvent(); //Spawn system will spawn the PigChef } private void ExitGame() { Application.Quit(); Debug.Log("Exit!"); } }