Files
BABA_YAGA/Assets/Editor/SmartBootstrapper.cs

158 lines
6.0 KiB
C#
Raw Normal View History

2026-03-26 20:27:19 +07:00
// ===============================================================================
// 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<SmartBootstrapper>("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<SceneAsset>(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<SceneAsset>(BootScenePath);
if (bootScene == null)
{
Debug.LogWarning($"<b>[SmartBoot]</b> Scene not found at saved path: <color=yellow>{BootScenePath}</color>. 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($"<color=#00FF00><b>[SmartBoot]</b></color> Starting from Boot Scene... <i>(Will return context to {currentSceneName})</i>");
}
}
}
}