Example-Code / Utility / SceneAutoLoader.cs
SceneAutoLoader.cs
Raw
#if UNITY_EDITOR
#nullable enable

using System.Collections;
using System.Collections.Generic;
using CCG.Shared.DependencyInjection.Unity;
using UnityEngine;
using ILogger = Microsoft.Extensions.Logging.ILogger;
using UnityEditor;
using UnityEditor.SceneManagement;

namespace CCG.Bigfoot.TestScripts
{
    /// <summary>
    /// Scene auto loader.
    /// </summary>
    /// <description>
    /// This class adds a File > Scene Autoload menu containing options to select
    /// a "master scene" enable it to be auto-loaded when the user presses play
    /// in the editor. When enabled, the selected scene will be loaded on play,
    /// then the original scene will be reloaded on stop.
    ///
    /// Based on an idea on this thread:
    /// http://forum.unity3d.com/threads/157502-Executing-first-scene-in-build-settings-when-pressing-play-button-in-editor
    /// </description>
    [InitializeOnLoad]
    public static class SceneAutoLoader
    {
        public static bool shiftPressed = false;

        // Properties are remembered as editor preferences.
        private static string cEditorPrefLoadMasterOnPlay = Application.productName + ".SceneAutoLoader.LoadMasterOnPlay";
        private static string cEditorPrefMasterScene = Application.productName + ".SceneAutoLoader.MasterScene";
        private static string cEditorPrefPreviousScene = Application.productName + ".SceneAutoLoader.PreviousScene";

        private static bool IsLoadMasterOnPlay
        {
            get { return EditorPrefs.GetBool(cEditorPrefLoadMasterOnPlay, false); }
            set { EditorPrefs.SetBool(cEditorPrefLoadMasterOnPlay, value); }
        }

        private static string MasterSceneSetting
        {
            get { return EditorPrefs.GetString(cEditorPrefMasterScene, "Master.unity"); }
            set { EditorPrefs.SetString(cEditorPrefMasterScene, value); }
        }

        private static string LastSceneSetting
        {
            get { return EditorPrefs.GetString(cEditorPrefPreviousScene, EditorSceneManager.GetActiveScene().path); }
            set { EditorPrefs.SetString(cEditorPrefPreviousScene, value); }
        }

        // Static constructor binds a playmode-changed callback.
        // [InitializeOnLoad] above makes sure this gets executed.
        static SceneAutoLoader()
        {
            EditorApplication.playModeStateChanged += EditorApplication_playModeStateChanged;
            //SceneView.onSceneGUIDelegate += view =>
            //       {
            //           var e = Event.current;
            //           if (e != null && e.type == EventType.KeyDown && e.keyCode != KeyCode.None && e.keyCode == KeyCode.LeftShift)
            //	 {
            //		 shiftPressed = true;
            //	 }
            //	 else
            //           if (e != null && e.type == EventType.KeyUp && e.keyCode != KeyCode.None && e.keyCode == KeyCode.LeftShift)
            //	 {
            //		 shiftPressed = false;
            //	 }
            //       };
        }

        // Menu items to select the "master" scene and control whether or not to load it.
        [MenuItem("File/Scene Autoloader/Select Master Scene...")]
        static void SelectMasterScene()
        {
            string masterScene = EditorUtility.OpenFilePanel("Select Master Scene", Application.dataPath, "unity");
            masterScene = masterScene.Replace(Application.dataPath, "Assets");  //project relative instead of absolute path
            if (!string.IsNullOrEmpty(masterScene))
            {
                MasterSceneSetting = masterScene;
                IsLoadMasterOnPlay = true;
            }
        }

        [MenuItem("File/Scene Autoloader/Load Master On Play", true)]
        private static bool ShowLoadMasterOnPlay()
        {
            return !IsLoadMasterOnPlay;
        }
        [MenuItem("File/Scene Autoloader/Load Master On Play")]
        private static void EnableLoadMasterOnPlay()
        {
            IsLoadMasterOnPlay = true;
        }

        [MenuItem("File/Scene Autoloader/Don't Load Master On Play", true)]
        private static bool ShowDontLoadMasterOnPlay()
        {
            return IsLoadMasterOnPlay;
        }
        [MenuItem("File/Scene Autoloader/Don't Load Master On Play")]
        private static void DisableLoadMasterOnPlay()
        {
            IsLoadMasterOnPlay = false;
        }

        // Play mode change callback handles the scene load/reload.
        private static void EditorApplication_playModeStateChanged(PlayModeStateChange obj)
        {
            switch (obj)
            {
                case PlayModeStateChange.ExitingEditMode:
                {
                    LoadMasterScene();
                    break;
                }
                case PlayModeStateChange.EnteredEditMode:
                {
                    LoadPreviousScene();
                    break;
                }
            }
        }

        private static void LoadMasterScene()
        {
            if (!IsLoadMasterOnPlay)
            {
                LastSceneSetting = string.Empty;
                return;
            }

            if (shiftPressed)
            {
                LastSceneSetting = string.Empty;
                Debug.Log($"SceneAutoLoader - Shift held down so using current scene instead of master scene [MasterScene]");
                return;
            }

            try
            {
                string currentScene = EditorSceneManager.GetActiveScene().path;
                EditorSceneManager.OpenScene(MasterSceneSetting);
                LastSceneSetting = currentScene;
            }
            catch (System.Exception ex)
            {
                Debug.LogError($"SceneAutoLoader exception: " + ex.Message);
                Debug.LogError($"SceneAutoLoader: continuing without master scene");
            }
        }

        private static void LoadPreviousScene()
        {
            if (!IsLoadMasterOnPlay)
            {
                LastSceneSetting = string.Empty;
                return;
            }

            // User pressed stop -- reload previous scene.
            try
            {
                EditorSceneManager.OpenScene(LastSceneSetting);
            }
            catch (System.Exception ex)
            {
                Debug.LogError($"SceneAutoLoader exception: " + ex.Message);
                Debug.LogError($"SceneAutoLoader: Warning: scene not found: [{LastSceneSetting}]");
            }
        }
    }
}
#endif