ET8.1

Open Init 快速打开Init场景
Run Init 快速运行Init场景 结束运行后 会自动回到点击这个按钮的场景
其他版本看着改看着改private const string ScenePath = “Assets/Scenes/Init.unity”;
脚本放到Assets/Scripts/Editor下
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UIElements;
namespace ET
{
[InitializeOnLoad]
static class ToolbarInitButton
{
private const string ScenePath = "Assets/Scenes/Init.unity";
private const string ContainerName = "InitSceneButtonContainer";
private const string PrevSceneKey = "ToolbarInitButton_PreviousScene";
static ToolbarInitButton()
{
EditorApplication.delayCall += AddButtonToToolbar;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
private static void AddButtonToToolbar()
{
var toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
if (toolbarType == null) return;
var toolbars = Resources.FindObjectsOfTypeAll(toolbarType);
if (toolbars == null || toolbars.Length == 0)
{
EditorApplication.delayCall += AddButtonToToolbar;
return;
}
foreach (var tb in toolbars)
{
var root = GetRootVisualElement(tb, toolbarType);
if (root == null) continue;
if (root.Q(ContainerName) != null) continue;
// IMGUIContainer 内根据 EditorApplication.isPlaying 禁用按钮
var container = new IMGUIContainer(() =>
{
GUILayout.BeginVertical();
GUILayout.FlexibleSpace();
GUILayout.BeginHorizontal();
bool prevEnabled = GUI.enabled;
GUI.enabled = !EditorApplication.isPlaying; // 如果正在运行则禁用按钮
if (GUILayout.Button("Open Init", EditorStyles.toolbarButton, GUILayout.Width(100)))
{
OpenInitScene();
}
GUILayout.Space(5);
if (GUILayout.Button("Run Init", EditorStyles.toolbarButton, GUILayout.Width(100)))
{
RunInitScene();
}
GUI.enabled = prevEnabled; // 恢复之前的 GUI.enabled
GUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
GUILayout.EndVertical();
})
{
name = ContainerName
};
container.style.height = 22;
container.style.minHeight = 22;
container.style.marginLeft = 4;
container.style.marginRight = 4;
container.style.alignSelf = Align.Center;
// 尝试找到 Play 按钮并插入到其之前
VisualElement playElement = null;
try
{
playElement = root.Query<VisualElement>().Where(e =>
string.Equals(e.tooltip, "Play", StringComparison.OrdinalIgnoreCase) ||
string.Equals(e.tooltip, "播放", StringComparison.OrdinalIgnoreCase) ||
(e.name != null && e.name.IndexOf("play", StringComparison.OrdinalIgnoreCase) >= 0)).First();
}
catch
{
playElement = null;
}
if (playElement != null && playElement.parent != null)
{
var parent = playElement.parent;
int idx = parent.IndexOf(playElement);
parent.Insert(idx, container);
}
else
{
var leftZone = root.Q("ToolbarZoneLeftAlign") ?? root.Q("ToolbarZoneLeft") ?? root.Q("LeftAlignToolbarZone");
if (leftZone != null)
leftZone.Add(container);
else
{
container.style.position = Position.Absolute;
container.style.left = 60;
container.style.top = 3;
root.Add(container);
}
}
(tb as EditorWindow)?.Repaint();
}
}
private static VisualElement GetRootVisualElement(object toolbarInstance, Type toolbarType)
{
var prop = toolbarType.GetProperty("rootVisualElement", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (prop != null)
{
var val = prop.GetValue(toolbarInstance) as VisualElement;
if (val != null) return val;
}
var fieldNames = new[] { "m_Root", "m_RootVisualElement", "m_VisualTree" };
foreach (var name in fieldNames)
{
var field = toolbarType.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (field == null) continue;
var val = field.GetValue(toolbarInstance) as VisualElement;
if (val != null) return val;
}
return null;
}
private static void OpenInitScene()
{
if (!File.Exists(ScenePath))
{
EditorUtility.DisplayDialog("打开场景失败", $"未找到场景:`{ScenePath}`", "确定");
return;
}
if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
EditorSceneManager.OpenScene(ScenePath);
}
}
private static void RunInitScene()
{
if (!File.Exists(ScenePath))
{
EditorUtility.DisplayDialog("运行场景失败", $"未找到场景:`{ScenePath}`", "确定");
return;
}
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) return;
var prev = EditorSceneManager.GetActiveScene().path;
if (string.IsNullOrEmpty(prev))
{
EditorUtility.DisplayDialog("运行场景失败", "当前场景未保存,请先保存场景再运行。", "确定");
return;
}
EditorPrefs.SetString(PrevSceneKey, prev);
// 确保订阅播放状态变化
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
EditorSceneManager.OpenScene(ScenePath);
EditorApplication.delayCall += () =>
{
if (!EditorApplication.isPlaying) EditorApplication.isPlaying = true;
};
}
private static void OnPlayModeStateChanged(PlayModeStateChange state)
{
// 当从播放模式返回到编辑模式时恢复之前记录的场景
if (state == PlayModeStateChange.EnteredEditMode)
{
if (EditorPrefs.HasKey(PrevSceneKey))
{
var prev = EditorPrefs.GetString(PrevSceneKey, "");
EditorPrefs.DeleteKey(PrevSceneKey);
if (!string.IsNullOrEmpty(prev) && File.Exists(prev))
{
EditorApplication.delayCall += () =>
{
if (prev != ScenePath)
{
EditorSceneManager.OpenScene(prev);
}
};
}
else if (!string.IsNullOrEmpty(prev))
{
EditorUtility.DisplayDialog("恢复场景失败", $"未找到之前的场景:`{prev}`", "确定");
}
}
// 取消订阅恢复逻辑,避免重复
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
}
// 每次播放状态变化都重绘工具栏,确保按钮启用/禁用状态刷新
RepaintToolbars();
}
private static void RepaintToolbars()
{
var toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
if (toolbarType == null) return;
var toolbars = Resources.FindObjectsOfTypeAll(toolbarType);
if (toolbars == null) return;
foreach (var tb in toolbars)
{
(tb as EditorWindow)?.Repaint();
}
}
}
}