// =============================================================================== // SmartBootstrapper - Auto-Boot Scene Loader for Unity // // Creator: Scove // Last Updated: 2026-03-03 // Version: 3.0 (Drag & Drop UI Added) // // Purpose: // Forces the Unity Editor to always start from an initialization (Boot) scene // when hitting Play, regardless of which scene is currently open. // // Key Features: // 1. Drag & Drop UI: Easily assign your Boot Scene via a settings window. // 2. Persistent Settings: Saves your configuration automatically via EditorPrefs. // 3. Quick Toggle: Enable or disable the feature directly from the window. // 4. Smart Play Mode: Gracefully returns to your working scene after testing. // // How to Use: // 1. Place this script in an 'Editor' folder. // 2. Open via: Menu -> Tools -> Smart Boot Settings. // 3. Drag and drop your Boot Scene into the slot and enable the tool. // =============================================================================== using System.IO; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; namespace Editor {[InitializeOnLoad] public class SmartBootstrapper : EditorWindow { // EditorPrefs Keys private const string PREFS_TOGGLE_KEY = "SmartBoot_Enabled"; private const string PREFS_PATH_KEY = "SmartBoot_ScenePath"; private static bool IsEnabled { get => EditorPrefs.GetBool(PREFS_TOGGLE_KEY, false); set => EditorPrefs.SetBool(PREFS_TOGGLE_KEY, value); } private static string BootScenePath { get => EditorPrefs.GetString(PREFS_PATH_KEY, ""); set => EditorPrefs.SetString(PREFS_PATH_KEY, value); }[MenuItem("Tools/Smart Boot Settings")] public static void ShowWindow() { SmartBootstrapper window = GetWindow("Smart Boot"); window.minSize = new Vector2(350, 150); window.maxSize = new Vector2(500, 160); window.Show(); } private void OnGUI() { GUILayout.Space(10); EditorGUILayout.LabelField("Boot Scene Configuration", EditorStyles.boldLabel); GUILayout.Space(5); SceneAsset currentScene = null; if (!string.IsNullOrEmpty(BootScenePath)) { currentScene = AssetDatabase.LoadAssetAtPath(BootScenePath); } EditorGUI.BeginChangeCheck(); SceneAsset draggedScene = (SceneAsset)EditorGUILayout.ObjectField( "Boot Scene", currentScene, typeof(SceneAsset), false ); // IF THE USER DRAGS AND DROPS A NEW SCENE if (EditorGUI.EndChangeCheck()) { if (draggedScene == null) { BootScenePath = ""; EditorSceneManager.playModeStartScene = null; // Clear immediately } else { BootScenePath = AssetDatabase.GetAssetPath(draggedScene); EditorSceneManager.playModeStartScene = draggedScene; // Update immediately } } GUILayout.Space(10); EditorGUI.BeginChangeCheck(); bool newToggleState = EditorGUILayout.Toggle("Enable Auto-Boot", IsEnabled); // IF THE USER TOGGLES THE SWITCH if (EditorGUI.EndChangeCheck()) { IsEnabled = newToggleState; if (!IsEnabled) EditorSceneManager.playModeStartScene = null; // Clear cache immediately when disabled } GUILayout.Space(15); if (string.IsNullOrEmpty(BootScenePath)) { EditorGUILayout.HelpBox("Please drag and drop a Boot Scene into the slot above.", MessageType.Warning); } else if (IsEnabled) { EditorGUILayout.HelpBox($"Ready! Hitting PLAY will always start from:\n{Path.GetFileName(BootScenePath)}", MessageType.Info); } else { EditorGUILayout.HelpBox("Auto-Boot is currently disabled. The active scene will play normally.", MessageType.None); } } static SmartBootstrapper() { // Avoid registering the event multiple times on recompile EditorApplication.playModeStateChanged -= OnPlayModeChanged; EditorApplication.playModeStateChanged += OnPlayModeChanged; } private static void OnPlayModeChanged(PlayModeStateChange state) { if (state != PlayModeStateChange.ExitingEditMode) return; // 1. Feature disabled or no scene assigned if (!IsEnabled || string.IsNullOrEmpty(BootScenePath)) { EditorSceneManager.playModeStartScene = null; return; } // 2. Find Scene Asset SceneAsset bootScene = AssetDatabase.LoadAssetAtPath(BootScenePath); if (bootScene == null) { Debug.LogWarning($"[SmartBoot] Scene not found at saved path: {BootScenePath}. Please re-assign it."); EditorSceneManager.playModeStartScene = null; return; } // 3. ALWAYS override with the Boot Scene (fixes old Scene sticking) EditorSceneManager.playModeStartScene = bootScene; // 4. Only show Log if the open Scene is not the Boot Scene string activeScenePath = EditorSceneManager.GetActiveScene().path; if (activeScenePath != BootScenePath) { string currentSceneName = Path.GetFileNameWithoutExtension(activeScenePath); Debug.Log($"[SmartBoot] Starting from Boot Scene... (Will return context to {currentSceneName})"); } } } }