Files
2026-06-17 20:44:53 +03:00

177 lines
5.2 KiB
C#

#if UNITY_EDITOR
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.SceneManagement;
[InitializeOnLoad]
public static class PlaySpeedToolbar
{
private const string ToolbarElementName = "PlaySpeedToolbar";
private const double ToolbarCheckInterval = 0.25;
private static readonly float[] Speeds = { 1f, 2f, 4f };
private static VisualElement toolbarElement;
private static double nextToolbarCheckTime;
static PlaySpeedToolbar()
{
EditorApplication.update += OnEditorUpdate;
EditorApplication.playModeStateChanged += OnPlayModeChanged;
EditorApplication.delayCall += AddToolbarUI;
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
}
private static void OnAfterAssemblyReload()
{
EditorApplication.delayCall += AddToolbarUI;
}
private static void OnPlayModeChanged(PlayModeStateChange state)
{
if (state == PlayModeStateChange.EnteredEditMode)
Time.timeScale = 1f;
EditorApplication.delayCall += AddToolbarUI;
}
private static void OnEditorUpdate()
{
EnsureToolbarExists();
}
private static void EnsureToolbarExists()
{
if (EditorApplication.timeSinceStartup < nextToolbarCheckTime)
return;
nextToolbarCheckTime = EditorApplication.timeSinceStartup + ToolbarCheckInterval;
var toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
if (toolbarType == null)
return;
var toolbars = Resources.FindObjectsOfTypeAll(toolbarType);
if (toolbars == null || toolbars.Length == 0)
return;
foreach (var toolbar in toolbars)
{
TryInjectIntoToolbar(toolbarType, toolbar);
}
}
private static void AddToolbarUI()
{
var toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar");
if (toolbarType == null)
return;
var toolbars = Resources.FindObjectsOfTypeAll(toolbarType);
if (toolbars == null || toolbars.Length == 0)
return;
foreach (var toolbar in toolbars)
{
TryInjectIntoToolbar(toolbarType, toolbar);
}
}
private static void TryInjectIntoToolbar(Type toolbarType, UnityEngine.Object toolbar)
{
var rootField = toolbarType.GetField("m_Root", BindingFlags.NonPublic | BindingFlags.Instance);
if (rootField == null)
return;
if (rootField.GetValue(toolbar) is not VisualElement root)
return;
// Центр тулбара, рядом с play/pause/stop
var middleContainer = root.Q("ToolbarZonePlayMode");
if (middleContainer == null)
return;
var existing = middleContainer.Q<IMGUIContainer>(ToolbarElementName);
if (existing != null)
{
toolbarElement = existing;
return;
}
var newElement = new IMGUIContainer(DrawGUI);
newElement.name = ToolbarElementName;
newElement.style.flexGrow = 0;
newElement.style.flexShrink = 0;
newElement.style.marginLeft = 6;
newElement.style.marginRight = 2;
newElement.style.minWidth = 118;
newElement.style.maxWidth = 140;
middleContainer.Add(newElement);
toolbarElement = newElement;
}
private static void DrawGUI()
{
GUILayout.BeginHorizontal();
// Bootstrap toggle
bool bootstrapEnabled = SceneBootstrapLoader.Enabled;
Color oldBg = GUI.backgroundColor;
if (bootstrapEnabled)
GUI.backgroundColor = new Color(0.72f, 0.84f, 1f);
if (GUILayout.Button(
new GUIContent("B", bootstrapEnabled ? "Bootstrap: ON" : "Bootstrap: OFF"),
EditorStyles.miniButtonLeft,
GUILayout.Width(24),
GUILayout.Height(18)))
{
SceneBootstrapLoader.Enabled = !SceneBootstrapLoader.Enabled;
if (!SceneBootstrapLoader.Enabled)
EditorSceneManager.playModeStartScene = null;
}
GUI.backgroundColor = oldBg;
bool isPlaying = EditorApplication.isPlaying;
EditorGUI.BeginDisabledGroup(!isPlaying);
for (int i = 0; i < Speeds.Length; i++)
{
float speed = Speeds[i];
bool selected = Mathf.Approximately(Time.timeScale, speed);
GUIStyle buttonStyle;
if (i == Speeds.Length - 1)
buttonStyle = EditorStyles.miniButtonRight;
else
buttonStyle = EditorStyles.miniButtonMid;
oldBg = GUI.backgroundColor;
if (selected)
GUI.backgroundColor = new Color(0.72f, 0.84f, 1f);
if (GUILayout.Button(
new GUIContent($"{speed:0}x", $"Set Time.timeScale = {speed}"),
buttonStyle,
GUILayout.Width(24),
GUILayout.Height(18)))
{
Time.timeScale = speed;
}
GUI.backgroundColor = oldBg;
}
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();
}
}
#endif