Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Scripts / Managers / SceneGroupManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityUtils;

namespace MyCollections.SceneManagement
{
    public class SceneGroupManager
    {
        public event Action<string> OnSceneLoaded = delegate { };
        public event Action<string> OnSceneUnloaded = delegate { };
        public event Action OnSceneGroupLoaded = delegate { };

        private SceneGroup activeSceneGroup;

        public async Task LoadScenes(SceneGroup group, bool reloadDupScenes = false)
        {
            activeSceneGroup = group;
            List<string> loadedScenes = new List<string>();

            int sceneCount = SceneManager.sceneCount;
            Debug.Log("Get Scenes: " + sceneCount);
            for (int i = 0; i < sceneCount; i++)
            {
                Debug.Log("Get Scenes: " + SceneManager.GetSceneAt(i).name);
                loadedScenes.Add(SceneManager.GetSceneAt(i).name);
            }

            int totalScenesToLoad = activeSceneGroup.scenes.Count;

            AsyncOperationGroup operationGroup = new AsyncOperationGroup(totalScenesToLoad);

            for (int i = 0; i < totalScenesToLoad; i++)
            {
                SceneData sceneData = group.scenes[i];
                if (reloadDupScenes == false && loadedScenes.Contains(sceneData.Name)) continue;

                AsyncOperation operation = SceneManager.LoadSceneAsync(sceneData.reference.Path, LoadSceneMode.Additive);
                await Task.Delay(TimeSpan.FromSeconds(2.5f)); //Testing purposes

                operationGroup.operations.Add(operation);

                OnSceneLoaded.Invoke(sceneData.Name);
            }

            //Wait until AsyncOperatons in the group are done
            while (!operationGroup.isDone)
            {
                //progress?.Report(operationGroup.Progress);
                Debug.Log("Waiting operation");
                await Task.Delay(100);
            }

            await Task.Delay(100);

            Scene activeScene = SceneManager.GetSceneByName(activeSceneGroup.FindSceneNameByType(SceneType.ActiveScene));
                
            if (activeScene.IsValid())
                SceneManager.SetActiveScene(activeScene);

            await UnloadScenes();

            OnSceneGroupLoaded.Invoke();
        }

        //Unload scenes
        public async Task UnloadScenes()
        {
            //Creates a list for the scene names
            List<string> scenes = new List<string>();

            //Get's the current scene name
            string activeScene = SceneManager.GetActiveScene().name;

            Debug.Log($"Active scene name: {activeScene}");

            //Counts the number of scenes
            int sceneCount = SceneManager.sceneCount;

            Debug.Log($"Number of scenes: {sceneCount}");

            //Loop reversely
            for (int i = sceneCount - 1; i  >= 0; i--)
            {
                //Gets the scene by index
                Scene sceneAt = SceneManager.GetSceneAt(i);
                Debug.Log($"Checking scene: {sceneAt.name}");

                //Checks if it's not loaded, continues
                if(!sceneAt.isLoaded) continue;

                //gets the name of the current index scene
                string sceneName = sceneAt.name;

                //Checks if the index scene name is equal to the active scene
                if (sceneName.Equals(activeScene)) continue;

                //Add's the scene to the list
                scenes.Add(sceneName);
                Debug.Log($"Added scene: {sceneName}");
            }

            //Create an AsyncOperationGroup
            AsyncOperationGroup operationGroup = new AsyncOperationGroup(sceneCount);

            //foreach through the list
            foreach (string scene in scenes)
            {
                Debug.Log($"Unload Scene: {scene}");

                //Stores the operation
                AsyncOperation operation = SceneManager.UnloadSceneAsync(scene);
                if (operation == null) continue;

                //Adds the operation to the list of operations
                operationGroup.operations.Add(operation);
                Debug.Log($"Added operation: {operation}");

                foreach (AsyncOperation op in operationGroup.operations)
                {
                    Debug.Log($"Operation: {op}");
                }

                //invoke a message
                OnSceneUnloaded.Invoke(scene);
            }
            Debug.Log($"Operations count: {operationGroup.operations.Count}");

            //Wait until AsyncOperatons in the group are done
            while (!operationGroup.isDone)
            {
                Debug.Log("Operation is not Done!");
                await Task.Delay(100); //Delay to avoid tight loop
            }

            //Optional: UnloadUnusedAssets - Unloads all unused assets from memory
            //Expensive operation
            await AsyncOperationExtensions.AsTask(Resources.UnloadUnusedAssets());
        }
    }

    public readonly struct AsyncOperationGroup
    {
        public readonly List<AsyncOperation> operations;
        public float Progress => operations.Count == 0 ? 0 : operations.Average(o => o.progress);
        public bool isDone => operations.All(o => o.isDone);
        public AsyncOperationGroup(int initialCapacity) => operations = new List<AsyncOperation>(initialCapacity);
    }
}