/// <summary>
 /// Starts loading the given extendedScene and applies the scene unload rules for its ring.
 /// </summary>
 public void StageForLoading(ExtendedScene extendedScene)
 {
     if (loadPhase == LoadPhase.Unloading)
     {
         Util.Crash(new Exception("Can't stage " + extendedScene.metadata.path + " to load because ExtendedSceneManager is in the unload phase!"));
     }
     if (extendedScene.isLoaded)
     {
         Util.Crash(new Exception(extendedScene.metadata.path + " is already loaded!"));
     }
     if (extendedScene.metadata.buildIndex == 0)
     {
         Util.Crash(new Exception("Can't reload Universe start scene!"));
     }
     if (Debug.isDebugBuild && verbose)
     {
         Debug.Log("Staged scene for loading: " + extendedScene.metadata.path + " in phase " + loadPhase);
     }
     scenesToLoad.Enqueue(extendedScene);
     ApplySceneRingRules(extendedScene);
     if (!loading)
     {
         LoadStarted();
     }
 }
        /// <summary>
        /// Take a build index and return a new ExtendedScene that corresponds to it.
        /// The new ExtendedScene will be added to the dictionaries.
        /// </summary>
        private ExtendedScene CreateExtendedSceneForIndex(int buildIndex)
        {
            ExtendedScene extendedScene = new ExtendedScene(SceneDatatable.metadata[buildIndex]);

            AddExtendedSceneToArray(extendedScene);
            return(extendedScene);
        }
        /// <summary>
        /// Fetch the appropriate ruleset for the given ExtendedScene to use when loading in.
        /// </summary>
        private Action <ExtendedScene>[] AcquireSceneRingRules(ExtendedScene loadingScene)
        {
            Action <ExtendedScene>[] ruleset = new Action <ExtendedScene> [0];
            switch (loadingScene.metadata.sceneRing)
            {
            case SceneRing.None:
            case SceneRing.GlobalScenes:
                break;

            case SceneRing.SystemScenes:
                ruleset = systemScenesRules;
                break;

            case SceneRing.VenueScenes:
                ruleset = venueScenesRules;
                break;

            case SceneRing.WorldScenes:
                Util.Crash(new NotImplementedException());
                break;

            default:
                Util.Crash(new Exception("Invalid ring for scene " + loadingScene.metadata.path + ": " + loadingScene.metadata.sceneRing));
                break;
            }
            return(ruleset);
        }
        /// <summary>
        /// Gets the currently active scene as an ExtendedScene. Syncs that with the ring-active scenes.
        /// </summary>
        private void SyncActiveScene()
        {
            ExtendedScene extendedScene = GetExtendedScene(SceneManager.GetActiveScene().buildIndex);

            if (GetActiveScene(extendedScene.metadata.sceneRing) != extendedScene)
            {
                lastScenesActiveInRings[extendedScene.metadata.sceneRing] = extendedScene;
            }
        }
 /// <summary>
 /// Removes the given extendedScene from the list of loaded scenes.
 /// </summary>
 public void MarkSceneUnloaded(ExtendedScene extendedScene)
 {
     if (!loadedScenes.Contains(extendedScene))
     {
         Util.Crash(new Exception(extendedScene.metadata.path + " isn't loaded!"));
     }
     loadedScenes.Remove(extendedScene);
     timing.RunCoroutineOnInstance(Util._WaitOneFrame(LoadPhaseAdvance));
 }
 /// <summary>
 /// Applies the scene unload/suspend rules to all loaded scenes based on the ring of the scene that'd being loaded in.
 /// This allows for automation of complex behaviors like (ex:) "unload all scenes in ring x when entering scene of ring y"
 /// or "load only one scene in ring z" or "when loading scenes from ring a, suspend all scenes in ring b but the last active one."
 /// </summary>
 public void ApplySceneRingRules(ExtendedScene loadingScene)
 {
     Action <ExtendedScene>[] ruleset = AcquireSceneRingRules(loadingScene);
     for (int r = 0; r < ruleset.Length; r++)
     {
         for (int s = 0; s < loadedScenes.Count; s++)
         {
             if (loadedScenes[s] != loadingScene)
             {
                 ruleset[r](loadedScenes[s]);
             }
         }
     }
 }
 /// <summary>
 /// Starts unloading the given extendedScene.
 /// </summary>
 public void StageForUnloading(ExtendedScene extendedScene)
 {
     if (!extendedScene.isLoaded)
     {
         Util.Crash(new Exception(extendedScene.metadata.path + " isn't loaded!"));
     }
     if (Debug.isDebugBuild && verbose)
     {
         Debug.Log("Staged scene for unloading: " + extendedScene.metadata.path + " in phase " + loadPhase);
     }
     if (extendedScene.hasRootHandle)
     {
         extendedScene.SuspendScene();
     }
     scenesToUnload.Enqueue(extendedScene);
     if (!loading)
     {
         LoadStarted();
     }
 }
        /// <summary>
        /// MonoBehaviour.Awake()
        /// </summary>
        void Awake()
        {
            SceneRing[] rings = (SceneRing[])Enum.GetValues(typeof(SceneRing));
            timing                  = gameObject.AddComponent <Timing>();
            currentLoadingOps       = new List <AsyncOperation>(32);
            extendedScenesArray     = new ExtendedScene[SceneDatatable.metadata.Length];
            loadedScenes            = new List <ExtendedScene>(32);
            scenesToLoad            = new Queue <ExtendedScene>(32);
            scenesToUnload          = new Queue <ExtendedScene>(32);
            scenesBufferList        = new List <ExtendedScene>(128);
            sceneMetadataBufferList = new List <SceneMetadata>(128);
            lastScenesActiveInRings = new Dictionary <SceneRing, ExtendedScene>(rings.Length);
            scenesBySceneRings      = new Dictionary <SceneRing, ExtendedScene[]>(rings.Length);
            Action onceOnline = () =>
            {
                for (int r = 0; r < rings.Length; r++)
                {
                    SceneRing ring = rings[r];
                    scenesBufferList.Clear();
                    for (int s = 0; s < SceneDatatable.metadata.Length; s++)
                    {
                        ExtendedScene extendedScene = GetExtendedScene(s);
                        if (extendedScene.metadata.sceneRing == ring)
                        {
                            scenesBufferList.Add(extendedScene);
                        }
                    }
                    scenesBySceneRings[ring]      = scenesBufferList.ToArray();
                    lastScenesActiveInRings[ring] = null;
                }
                LoadGlobalScenes();
                SceneManager.activeSceneChanged += (sceneA, sceneB) => { SyncActiveScene(); };
            };

            timing.RunCoroutineOnInstance(_WaitUntilOnline(onceOnline));
        }
        /// <summary>
        /// Called once we've finished a batch of loading operations.
        /// Either stages the next batch or marks us done, depending.
        /// We don't actually care about the arguments, but the sceneLoaded
        /// and sceneUnloaded delegates want this signature.
        /// </summary>
        private void LoadPhaseAdvance()
        {
            Action loadDone = () =>
            {
                if (GetProgressOfLoad() < 1.0f)
                {
                    Util.Crash(new Exception());
                }
                if (loadPhase != LoadPhase.NotLoading)
                {
                    loadPhase = LoadPhase.NotLoading;
                    if (Debug.isDebugBuild && verbose)
                    {
                        Debug.Log("Completed batch scene load/unload operations.");
                    }
                }
            };
            Action <int> load = (count) =>
            {
                loadPhase = LoadPhase.Loading;
                for (int i = 0; i < count; i++)
                {
                    ExtendedScene extendedScene = scenesToLoad.Dequeue();
                    if (Debug.isDebugBuild && verbose)
                    {
                        Debug.Log("Started loading: " + extendedScene.metadata.path);
                    }
                    currentLoadingOps.Add(SceneManager.LoadSceneAsync(extendedScene.metadata.buildIndex, LoadSceneMode.Additive));
                }
            };
            Action <int> unload = (count) =>
            {
                loadPhase = LoadPhase.Unloading;
                for (int i = 0; i < count; i++)
                {
                    ExtendedScene extendedScene = scenesToUnload.Dequeue();
                    if (Debug.isDebugBuild && verbose)
                    {
                        Debug.Log("Started unloading: " + extendedScene.metadata.path);
                    }
                    currentLoadingOps.Add(SceneManager.UnloadSceneAsync(extendedScene.metadata.buildIndex));
                }
            };

            if (Debug.isDebugBuild && verbose)
            {
                Debug.Log("Phase " + loadPhase + ", progress " + GetProgressOfLoad() + ", scenes in load queue " + scenesToLoad.Count +
                          ", scenes in unload queue" + scenesToUnload.Count + " operations in progress" + currentLoadingOps.Count);
            }
            switch (loadPhase)
            {
            case LoadPhase.NotLoading:
            case LoadPhase.Loading:
                if (scenesToLoad.Count > 0 || Util.AverageCompletionOfOps(currentLoadingOps.ToArray()) < 1.0f)
                {
                    load(scenesToLoad.Count);
                }
                else if (scenesToUnload.Count > 0)
                {
                    unload(scenesToUnload.Count);
                }
                else if (GetProgressOfLoad() >= 1.0f)
                {
                    loadDone();
                }
                break;

            case LoadPhase.Unloading:
                if (scenesToUnload.Count > 0 || Util.AverageCompletionOfOps(currentLoadingOps.ToArray()) < 1.0f)
                {
                    unload(scenesToUnload.Count);
                }
                else if (scenesToLoad.Count > 0)
                {
                    load(scenesToLoad.Count);
                }
                else if (GetProgressOfLoad() >= 1.0f)
                {
                    loadDone();
                }
                break;
            }
        }
 /// <summary>
 /// Adds the extended scene to the datatables.
 /// </summary>
 private void AddExtendedSceneToArray(ExtendedScene extendedScene)
 {
     extendedScenesArray[extendedScene.metadata.buildIndex] = extendedScene;
 }
 /// <summary>
 /// Sets active scene based on given extended scene.
 /// </summary>
 public void SetActiveScene(ExtendedScene extendedScene)
 {
     lastScenesActiveInRings[extendedScene.metadata.sceneRing] = extendedScene;
     SceneManager.SetActiveScene(SceneManager.GetSceneByBuildIndex(extendedScene.metadata.buildIndex));
 }