Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Scripts / Managers / SceneLoader.cs
using Eflatun.SceneReference;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace MyCollections.SceneManagement
{
    public class SceneLoader : MonoBehaviour
    {
        public SceneGroup[] sceneGroups;
        private static SceneLoader instance;
        [SerializeField] private GameObject loadingScreen;
        [SerializeField] private SceneReference loading;

        //Singleton
        public static SceneLoader Instance => instance;


        private void Awake()
        {
            if (instance == null)
            {
                instance = this;
                DontDestroyOnLoad(gameObject);
            }

            else
            {
                Destroy(gameObject);
            }

        }

        private void Start()
        {
        }

        private SceneGroup FindSceneGroupByName(string name) =>
            Array.Find(sceneGroups, group => group.groupName == name);

        public void LoadScenes(string groupName, LoadType type)
        {
            SceneGroup sceneGroup = FindSceneGroupByName(groupName);

            switch (type)
            {
                case LoadType.Loading:
                    StartCoroutine(LoadWithLoadingScreenAsync(sceneGroup));
                break;

                case LoadType.Trigger:
                    LoadScenes(groupName);
                break;

            }
        }

        public void LoadSceneTrigger(SceneReference sceneReference)
        {
            int count = SceneManager.sceneCount;

            for (int i = 0; i < count; i++)
            {
                Scene scene = SceneManager.GetSceneAt(i);

                if (scene.name == sceneReference.Name) return;
            }

            Debug.LogWarning("LoadingScene:  " + sceneReference.Name);
            SceneManager.LoadSceneAsync(sceneReference.Name, LoadSceneMode.Additive);
        }

        public void UnloadSceneTrigger(SceneReference unloadScene, SceneReference newActiveScene)
        {
            int count = SceneManager.sceneCount;
            bool isSceneLoaded = false;

            for (int i = 0; i < count; i++)
            {
                Scene scene = SceneManager.GetSceneAt(i);

                if (scene.name == unloadScene.Name)
                {
                    isSceneLoaded = true;
                    break;
                }
            }

            if (!isSceneLoaded)
            {
                Debug.LogWarning("Scene to unload not loaded: " + unloadScene.Name);
                return;
            }

            SceneManager.UnloadSceneAsync(unloadScene.Name);
            SetActiveScene(newActiveScene);
        }

        private void SetActiveScene(SceneReference sceneReference)
        {
            int count = SceneManager.sceneCount;

            for (int i = 0; i < count; i++)
            {
                Scene scene = SceneManager.GetSceneAt(i);

                if (scene.name == sceneReference.Name)
                {
                    SceneManager.SetActiveScene(scene);
                    return;
                }
            }
        }

        public void LoadScenes(string groupName)
        {
            SceneGroup group = FindSceneGroupByName(groupName);
            Debug.Log($"Group Found: {group.groupName}");

            if (group == null)
                return;

            List<string> scenesToLoad = new List<string>();
            int count = SceneManager.sceneCount;
            Debug.Log($"Scene Count: {count}");

            for (int i = 0; i < group.scenes.Count; i++)
            {
                bool isSceneLoaded = false;
                for (int j = 0; j < count; j++)
                {
                    Scene loadedScene = SceneManager.GetSceneAt(j);

                    if (loadedScene.name == group.scenes[i].Name)
                    {
                        isSceneLoaded = true;
                        break;
                    }
                }

                if (!isSceneLoaded)
                {
                    Debug.Log($"Scene to Load Added: {group.scenes[i].Name}");
                    scenesToLoad.Add(group.scenes[i].Name);
                }
            }

            StartCoroutine(LoadAndSetActiveScene(scenesToLoad, group));
        }

        private IEnumerator LoadWithLoadingScreenAsync(SceneGroup group)
        {

            List<string> scenesToLoad = new List<string>();
            string sceneName = loading.Name; //Get the scene name

            //Load the Loading Scene
            AsyncOperation op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);

            //Wait until the Loading Scene is loaded
            yield return new WaitUntil(() => op.isDone);

            // Update scene count dynamically
            int s = SceneManager.sceneCount;

            //Get the loading screen
            GameObject loadingCanvas = GameObject.FindGameObjectWithTag("LoadingCanvas");
            loadingScreen = loadingCanvas.transform.GetChild(0).gameObject;

            if (loadingScreen == null)
            {
                Debug.LogError("Loading Screen is Null");
                yield break;
            }

            //Enables the login screen
            loadingScreen.SetActive(true); //Automatically will trigger the fadeout animation

            Animator animator;

            //Try to get the animator from the loading screen
            if (!loadingScreen.TryGetComponent(out animator))
            {
                Debug.LogError("Animator is Null");
                yield break;
            }

            AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
            float duration = stateInfo.length;

            //Wait for the rest of the loading screen animation to finish
            yield return new WaitForSeconds(duration);

            //Get the all the scenes to Load
            for (int i = 0; i < group.scenes.Count; i++)
            {
                bool isSceneLoaded = false;

                // Update scene count dynamically
                int currentSceneCount = SceneManager.sceneCount;
                Debug.Log($"Current Scene Count: {currentSceneCount}");

                for (int j = 0; j < currentSceneCount; j++)
                {
                    //Get the Scene at index in the SceneManager's list of loaded Scenes
                    Scene loadedScene = SceneManager.GetSceneAt(j);
                    Debug.Log($"LoadedScene: {loadedScene.name}");

                    // Skip checking if it's the "Loading" scene, which should only be loaded once
                    if (loadedScene.name == sceneName)
                    {
                        continue; // Skip the loading scene
                    }

                    //Compare the names of the SceneManager's list with the group of scenes
                    if (loadedScene.name == group.scenes[i].Name)
                    {
                        //if the scene is loaded flags to true
                        Debug.Log($"The Scene is Loaded: {loadedScene.name}");
                        isSceneLoaded = true;
                        break;
                    }
                }

                //Adds the scenes to load list
                if (!isSceneLoaded)
                {
                    Debug.Log($"Scene to Load Added: {group.scenes[i].Name}");
                    scenesToLoad.Add(group.scenes[i].Name);
                }
            }

            //Unload scenes
            UnloadScene(group);

            //load the all the scenes
            for (int i = 0; i < scenesToLoad.Count; i++)
            {
                AsyncOperation loadSceneOp = SceneManager.LoadSceneAsync(scenesToLoad[i], LoadSceneMode.Additive);

                //Wait until the operation is done
                yield return new WaitUntil(() => loadSceneOp.isDone);

                //Set active the scene
                SceneManager.SetActiveScene(SceneManager.GetSceneByName(scenesToLoad[i]));
            }

            //We invoke the fadeout animation of the loading screen
            animator.SetTrigger("FadeOut");

            //Get the current state info
            stateInfo = animator.GetCurrentAnimatorStateInfo(0);
            duration = stateInfo.length; //get the state lenght

            //Wait for the animation to finish
            yield return new WaitForSeconds(duration);


            //After the animation is finished
            //we unload the Loading screen
            AsyncOperation unloadOp = SceneManager.UnloadSceneAsync(sceneName);

            yield return new WaitUntil(() => unloadOp.isDone);

        }

        private IEnumerator LoadAndSetActiveScene(List<string> scenesToLoad, SceneGroup group)
        {
            for (int i = 0; i < scenesToLoad.Count; i++)
            {
                AsyncOperation op = SceneManager.LoadSceneAsync(scenesToLoad[i], LoadSceneMode.Additive);
                Debug.Log($"Loading Scene: {scenesToLoad[i]}");

                // Wait for the scene to fully load
                yield return new WaitUntil(() => op.isDone);

                // After the scene has loaded, set it as active
                SceneManager.SetActiveScene(SceneManager.GetSceneByName(scenesToLoad[i]));
                Debug.Log($"Scene {scenesToLoad[i]} set as active.");
            }

            // Once all scenes are loaded, unload the required scenes
            UnloadScene(group);
        }

        private void UnloadScene(SceneGroup group)
        {
            List<Scene> scenesToUnload = group.FindSceneRefByType(SceneType.DisableScene);
            Debug.Log($"Scenes Found To Unload: {scenesToUnload.Count}");
            List<string> unloadScenes = new List<string>();

            if (scenesToUnload.Count == 0)
                return;

            for (int i = 0; i < scenesToUnload.Count; i++)
            {
                Scene sceneToUnload = scenesToUnload[i];

                if (sceneToUnload.isLoaded)
                {
                    Debug.Log($"Scene to Unload: {sceneToUnload.name}");
                    unloadScenes.Add(sceneToUnload.name);
                }
            }

            if (unloadScenes.Count > 0)
            {
                for (int i = 0; i < unloadScenes.Count; i++)
                {
                    SceneManager.UnloadSceneAsync(unloadScenes[i]);
                    Debug.Log($"Unloading Scene: {unloadScenes[i]}");
                }
            }
        }
    }

    [Serializable]
    public struct SceneDataSaver
    {
        //Position where the player should be after changing scene
        public Vector3 position;
        public string groupName;
    }

    //The trigger loadtype doesn't affect the player gameplay
    //The Loading loadtype triggers a loading screen

    public enum LoadType
    {
        Trigger,
        Loading
    }

    public enum SceneAction
    {
        LoadScene,
        UnloadScene
    }
}