Files
FORT-BO/Assets/OtherAssets/DEV/FREE/SceneSwitcher/Editor/SceneSwitcherToolbar.cs
T
2026-08-04 13:47:07 +03:00

269 lines
8.5 KiB
C#

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UIElements;
using System.Reflection;
using System.Linq;
using System.IO;
using UnityEngine.SceneManagement;
[InitializeOnLoad]
public static class SceneSwitcherToolbar
{
private static string[] sceneNames = new string[0];
private static int selectedIndex = 0;
private static string lastActiveScene = "";
private static VisualElement toolbarUI;
private static float positionOffset = 180f;
private static float dropdownBoxHeight = 20f;
private static bool fetchAllScenes
{
get => EditorPrefs.GetBool("SceneSwitcher_FetchAllScenes", false);
set => EditorPrefs.SetBool("SceneSwitcher_FetchAllScenes", value);
}
static SceneSwitcherToolbar()
{
RefreshSceneList();
SelectCurrentScene();
EditorSceneManager.activeSceneChangedInEditMode += (prev, current) => UpdateSceneSelection();
EditorApplication.playModeStateChanged += OnPlayModeChanged;
EditorApplication.delayCall += AddToolbarUI;
}
static void AddToolbarUI()
{
var toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
if (toolbarType == null) return;
var toolbars = Resources.FindObjectsOfTypeAll(toolbarType);
if (toolbars.Length == 0) return;
var toolbar = toolbars[0];
var rootField = toolbarType.GetField("m_Root", BindingFlags.NonPublic | BindingFlags.Instance);
if (rootField == null) return;
var root = rootField.GetValue(toolbar) as VisualElement;
if (root == null) return;
var leftContainer = root.Q("ToolbarZoneLeftAlign");
if (leftContainer == null) return;
if (toolbarUI != null)
{
leftContainer.Remove(toolbarUI);
}
toolbarUI = new IMGUIContainer(OnGUI);
toolbarUI.style.marginLeft = positionOffset;
leftContainer.Add(toolbarUI);
}
static void OnGUI()
{
CheckAndRefreshScenes();
if (selectedIndex >= sceneNames.Length)
selectedIndex = 0;
bool isPlaying = EditorApplication.isPlaying;
GUILayout.BeginHorizontal();
// Fetch all scenes toggle button
EditorGUI.BeginDisabledGroup(isPlaying);
bool newFetchAllScenes = GUILayout.Toggle(fetchAllScenes, "All Scenes", "Button", GUILayout.Height(dropdownBoxHeight));
if (newFetchAllScenes != fetchAllScenes)
{
fetchAllScenes = newFetchAllScenes;
RefreshSceneList();
SelectCurrentScene();
}
EditorGUI.EndDisabledGroup();
// Add Scene button
EditorGUI.BeginDisabledGroup(isPlaying || fetchAllScenes);
if (GUILayout.Button("Add Scene", GUILayout.Height(dropdownBoxHeight)))
{
AddCurrentSceneToBuildSettings();
}
EditorGUI.EndDisabledGroup();
// Scene dropdown
EditorGUI.BeginDisabledGroup(isPlaying);
GUIStyle popupStyle = new GUIStyle(EditorStyles.popup)
{
fixedHeight = dropdownBoxHeight
};
int newIndex = EditorGUILayout.Popup(selectedIndex, sceneNames, popupStyle, GUILayout.Width(150), GUILayout.Height(dropdownBoxHeight));
if (newIndex != selectedIndex)
{
selectedIndex = newIndex;
LoadScene(sceneNames[selectedIndex]);
}
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();
}
static void AddCurrentSceneToBuildSettings()
{
string currentScenePath = EditorSceneManager.GetActiveScene().path;
if (string.IsNullOrEmpty(currentScenePath))
{
EditorUtility.DisplayDialog("Scene Not Saved",
"Please save the scene before adding it to Build Settings.", "OK");
return;
}
// Check if scene is already in build settings
var buildScenes = EditorBuildSettings.scenes.ToList();
bool sceneExists = buildScenes.Any(s => s.path == currentScenePath);
if (sceneExists)
{
// Enable the scene if it was disabled
var existingScene = buildScenes.Find(s => s.path == currentScenePath);
if (!existingScene.enabled)
{
existingScene.enabled = true;
EditorBuildSettings.scenes = buildScenes.ToArray();
Debug.Log($"<color=green>Scene '{Path.GetFileNameWithoutExtension(currentScenePath)}' enabled in Build Settings.</color>");
RefreshSceneList();
SelectCurrentScene();
}
else
{
Debug.Log($"Scene '{Path.GetFileNameWithoutExtension(currentScenePath)}' is already in Build Settings.");
}
}
else
{
// Add new scene to build settings
buildScenes.Add(new EditorBuildSettingsScene(currentScenePath, true));
EditorBuildSettings.scenes = buildScenes.ToArray();
Debug.Log($"<color=green>Scene '{Path.GetFileNameWithoutExtension(currentScenePath)}' added to Build Settings.</color>");
RefreshSceneList();
SelectCurrentScene();
}
}
static void RefreshSceneList()
{
if (fetchAllScenes)
{
sceneNames = Directory.GetFiles("Assets", "*.unity", SearchOption.AllDirectories)
.Select(path => Path.GetFileNameWithoutExtension(path))
.ToArray();
}
else
{
sceneNames = EditorBuildSettings.scenes
.Where(scene => scene.enabled)
.Select(scene => Path.GetFileNameWithoutExtension(scene.path))
.ToArray();
}
}
static void CheckAndRefreshScenes()
{
string[] currentScenes;
if (fetchAllScenes)
{
currentScenes = Directory.GetFiles("Assets", "*.unity", SearchOption.AllDirectories)
.Select(path => Path.GetFileNameWithoutExtension(path))
.ToArray();
}
else
{
currentScenes = EditorBuildSettings.scenes
.Where(scene => scene.enabled)
.Select(scene => Path.GetFileNameWithoutExtension(scene.path))
.ToArray();
}
if (!currentScenes.SequenceEqual(sceneNames))
{
sceneNames = currentScenes;
SelectCurrentScene();
}
}
static void SelectCurrentScene()
{
string currentScene = Path.GetFileNameWithoutExtension(EditorSceneManager.GetActiveScene().path);
int index = System.Array.IndexOf(sceneNames, currentScene);
if (index != -1)
{
selectedIndex = index;
lastActiveScene = currentScene;
}
else
{
string notInBuildName = currentScene + " (not in build index)";
sceneNames = new[] { notInBuildName }.Concat(sceneNames).ToArray();
selectedIndex = 0;
lastActiveScene = currentScene;
}
}
static void UpdateSceneSelection()
{
string currentScene = Path.GetFileNameWithoutExtension(EditorSceneManager.GetActiveScene().path);
if (currentScene != lastActiveScene)
{
lastActiveScene = currentScene;
sceneNames = sceneNames.Where(name => !name.EndsWith(" (not in build index)")).ToArray();
SelectCurrentScene();
}
}
static void LoadScene(string sceneName)
{
string scenePath;
if (fetchAllScenes)
{
scenePath = Directory.GetFiles("Assets", "*.unity", SearchOption.AllDirectories)
.FirstOrDefault(path => Path.GetFileNameWithoutExtension(path) == sceneName);
}
else
{
scenePath = EditorBuildSettings.scenes
.FirstOrDefault(scene => scene.enabled && scene.path.Contains(sceneName))?.path;
}
if (!string.IsNullOrEmpty(scenePath))
{
if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
EditorSceneManager.OpenScene(scenePath);
}
}
else
{
Debug.LogError("Scene not found: " + sceneName);
}
}
static void OnPlayModeChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.EnteredPlayMode || state == PlayModeStateChange.ExitingPlayMode)
{
EditorApplication.delayCall += () => AddToolbarUI();
}
}
}
#endif