using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; using Object = UnityEngine.Object; namespace TEngine { /// /// 调试器模块。 /// [DisallowMultipleComponent] public sealed partial class Debugger : MonoBehaviour { private static Debugger _instance; public static Debugger Instance => _instance; /// /// 默认调试器漂浮框大小。 /// internal static readonly Rect DefaultIconRect = new Rect(10f, 10f, 60f, 60f); /// /// 默认调试器窗口大小。 /// internal static readonly Rect DefaultWindowRect = new Rect(10f, 10f, 640f, 480f); /// /// 默认调试器窗口缩放比例。 /// internal static readonly float DefaultWindowScale = 1.5f; private static TextEditor s_TextEditor = null; private IDebuggerModule _debuggerModule = null; private readonly Rect _dragRect = new Rect(0f, 0f, float.MaxValue, 25f); private Rect _iconRect = DefaultIconRect; private Rect _windowRect = DefaultWindowRect; private float _windowScale = DefaultWindowScale; [SerializeField] private GUISkin skin = null; [SerializeField] private DebuggerActiveWindowType activeWindow = DebuggerActiveWindowType.AlwaysOpen; public DebuggerActiveWindowType ActiveWindowType => activeWindow; [SerializeField] private bool _showFullWindow = false; [SerializeField] private ConsoleWindow _consoleWindow = new ConsoleWindow(); private SystemInformationWindow _systemInformationWindow = new SystemInformationWindow(); private EnvironmentInformationWindow _environmentInformationWindow = new EnvironmentInformationWindow(); private ScreenInformationWindow _screenInformationWindow = new ScreenInformationWindow(); private GraphicsInformationWindow _graphicsInformationWindow = new GraphicsInformationWindow(); private InputSummaryInformationWindow _inputSummaryInformationWindow = new InputSummaryInformationWindow(); private InputTouchInformationWindow _inputTouchInformationWindow = new InputTouchInformationWindow(); private InputLocationInformationWindow _inputLocationInformationWindow = new InputLocationInformationWindow(); private InputAccelerationInformationWindow _inputAccelerationInformationWindow = new InputAccelerationInformationWindow(); private InputGyroscopeInformationWindow _inputGyroscopeInformationWindow = new InputGyroscopeInformationWindow(); private InputCompassInformationWindow _inputCompassInformationWindow = new InputCompassInformationWindow(); private PathInformationWindow _pathInformationWindow = new PathInformationWindow(); private SceneInformationWindow _sceneInformationWindow = new SceneInformationWindow(); private TimeInformationWindow _timeInformationWindow = new TimeInformationWindow(); private QualityInformationWindow _qualityInformationWindow = new QualityInformationWindow(); private ProfilerInformationWindow _profilerInformationWindow = new ProfilerInformationWindow(); private RuntimeMemorySummaryWindow _runtimeMemorySummaryWindow = new RuntimeMemorySummaryWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryAllInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryTextureInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryMeshInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryMaterialInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryShaderInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryAnimationClipInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryAudioClipInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryFontInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryTextAssetInformationWindow = new RuntimeMemoryInformationWindow(); private RuntimeMemoryInformationWindow _runtimeMemoryScriptableObjectInformationWindow = new RuntimeMemoryInformationWindow(); private MemoryPoolPoolInformationWindow _memoryPoolPoolInformationWindow = new MemoryPoolPoolInformationWindow(); private SettingsWindow _settingsWindow = new SettingsWindow(); private FpsCounter _fpsCounter = null; /// /// 获取或设置调试器窗口是否激活。 /// public bool ActiveWindow { get => _debuggerModule.ActiveWindow; set { _debuggerModule.ActiveWindow = value; enabled = value; } } /// /// 获取或设置是否显示完整调试器界面。 /// public bool ShowFullWindow { get => _showFullWindow; set { if (_eventSystem != null) { _eventSystem.SetActive(!value); } _showFullWindow = value; } } /// /// 获取或设置调试器漂浮框大小。 /// public Rect IconRect { get => _iconRect; set => _iconRect = value; } /// /// 获取或设置调试器窗口大小。 /// public Rect WindowRect { get => _windowRect; set => _windowRect = value; } /// /// 获取或设置调试器窗口缩放比例。 /// public float WindowScale { get => _windowScale; set => _windowScale = value; } private GameObject _eventSystem; /// /// 游戏框架模块初始化。 /// void Awake() { _instance = this; s_TextEditor = new TextEditor(); _instance.gameObject.name = $"[{nameof(Debugger)}]"; _eventSystem = GameObject.Find("UIRoot/EventSystem"); } private void OnDestroy() { PlayerPrefs.Save(); } private void Initialize() { _debuggerModule = ModuleSystem.GetModule(); if (_debuggerModule == null) { Log.Fatal("Debugger manager is invalid."); return; } _fpsCounter = new FpsCounter(0.5f); var lastIconX = PlayerPrefs.GetFloat("Debugger.Icon.X", DefaultIconRect.x); var lastIconY = PlayerPrefs.GetFloat("Debugger.Icon.Y", DefaultIconRect.y); var lastWindowX = PlayerPrefs.GetFloat("Debugger.Window.X", DefaultWindowRect.x); var lastWindowY = PlayerPrefs.GetFloat("Debugger.Window.Y", DefaultWindowRect.y); var lastWindowWidth = PlayerPrefs.GetFloat("Debugger.Window.Width", DefaultWindowRect.width); var lastWindowHeight = PlayerPrefs.GetFloat("Debugger.Window.Height", DefaultWindowRect.height); _windowScale = PlayerPrefs.GetFloat("Debugger.Window.Scale", DefaultWindowScale); _windowRect = new Rect(lastIconX, lastIconY, DefaultIconRect.width, DefaultIconRect.height); _windowRect = new Rect(lastWindowX, lastWindowY, lastWindowWidth, lastWindowHeight); } private void Start() { Initialize(); RegisterDebuggerWindow("Console", _consoleWindow); RegisterDebuggerWindow("Information/System", _systemInformationWindow); RegisterDebuggerWindow("Information/Environment", _environmentInformationWindow); RegisterDebuggerWindow("Information/Screen", _screenInformationWindow); RegisterDebuggerWindow("Information/Graphics", _graphicsInformationWindow); RegisterDebuggerWindow("Information/Input/Summary", _inputSummaryInformationWindow); RegisterDebuggerWindow("Information/Input/Touch", _inputTouchInformationWindow); RegisterDebuggerWindow("Information/Input/Location", _inputLocationInformationWindow); RegisterDebuggerWindow("Information/Input/Acceleration", _inputAccelerationInformationWindow); RegisterDebuggerWindow("Information/Input/Gyroscope", _inputGyroscopeInformationWindow); RegisterDebuggerWindow("Information/Input/Compass", _inputCompassInformationWindow); RegisterDebuggerWindow("Information/Other/Scene", _sceneInformationWindow); RegisterDebuggerWindow("Information/Other/Path", _pathInformationWindow); RegisterDebuggerWindow("Information/Other/Time", _timeInformationWindow); RegisterDebuggerWindow("Information/Other/Quality", _qualityInformationWindow); RegisterDebuggerWindow("Profiler/Summary", _profilerInformationWindow); RegisterDebuggerWindow("Profiler/Memory/Summary", _runtimeMemorySummaryWindow); RegisterDebuggerWindow("Profiler/Memory/All", _runtimeMemoryAllInformationWindow); RegisterDebuggerWindow("Profiler/Memory/Texture", _runtimeMemoryTextureInformationWindow); RegisterDebuggerWindow("Profiler/Memory/Mesh", _runtimeMemoryMeshInformationWindow); RegisterDebuggerWindow("Profiler/Memory/Material", _runtimeMemoryMaterialInformationWindow); RegisterDebuggerWindow("Profiler/Memory/Shader", _runtimeMemoryShaderInformationWindow); RegisterDebuggerWindow("Profiler/Memory/AnimationClip", _runtimeMemoryAnimationClipInformationWindow); RegisterDebuggerWindow("Profiler/Memory/AudioClip", _runtimeMemoryAudioClipInformationWindow); RegisterDebuggerWindow("Profiler/Memory/Font", _runtimeMemoryFontInformationWindow); RegisterDebuggerWindow("Profiler/Memory/TextAsset", _runtimeMemoryTextAssetInformationWindow); RegisterDebuggerWindow("Profiler/Memory/ScriptableObject", _runtimeMemoryScriptableObjectInformationWindow); RegisterDebuggerWindow("Profiler/Reference Pool", _memoryPoolPoolInformationWindow); RegisterDebuggerWindow("Other/Settings", _settingsWindow); switch (activeWindow) { case DebuggerActiveWindowType.AlwaysOpen: ActiveWindow = true; break; case DebuggerActiveWindowType.OnlyOpenWhenDevelopment: ActiveWindow = Debug.isDebugBuild; break; case DebuggerActiveWindowType.OnlyOpenInEditor: ActiveWindow = Application.isEditor; break; default: ActiveWindow = false; break; } } private void Update() { _fpsCounter.Update(Time.deltaTime, Time.unscaledDeltaTime); } private void OnGUI() { if (_debuggerModule == null || !_debuggerModule.ActiveWindow) { return; } GUISkin cachedGuiSkin = GUI.skin; Matrix4x4 cachedMatrix = GUI.matrix; GUI.skin = skin; GUI.matrix = Matrix4x4.Scale(new Vector3(_windowScale, _windowScale, 1f)); if (_showFullWindow) { _windowRect = GUILayout.Window(0, _windowRect, DrawWindow, "DEBUGGER"); } else { _iconRect = GUILayout.Window(0, _iconRect, DrawDebuggerWindowIcon, "DEBUGGER"); } GUI.matrix = cachedMatrix; GUI.skin = cachedGuiSkin; } /// /// 注册调试器窗口。 /// /// 调试器窗口路径。 /// 要注册的调试器窗口。 /// 初始化调试器窗口参数。 public void RegisterDebuggerWindow(string path, IDebuggerWindow debuggerWindow, params object[] args) { _debuggerModule.RegisterDebuggerWindow(path, debuggerWindow, args); } /// /// 解除注册调试器窗口。 /// /// 调试器窗口路径。 /// 是否解除注册调试器窗口成功。 public bool UnregisterDebuggerWindow(string path) { return _debuggerModule.UnregisterDebuggerWindow(path); } /// /// 获取调试器窗口。 /// /// 调试器窗口路径。 /// 要获取的调试器窗口。 public IDebuggerWindow GetDebuggerWindow(string path) { return _debuggerModule.GetDebuggerWindow(path); } /// /// 选中调试器窗口。 /// /// 调试器窗口路径。 /// 是否成功选中调试器窗口。 public bool SelectDebuggerWindow(string path) { return _debuggerModule.SelectDebuggerWindow(path); } /// /// 还原调试器窗口布局。 /// public void ResetLayout() { IconRect = DefaultIconRect; WindowRect = DefaultWindowRect; WindowScale = DefaultWindowScale; } /// /// 获取记录的所有日志。 /// /// 要获取的日志。 public void GetRecentLogs(List results) { _consoleWindow.GetRecentLogs(results); } /// /// 获取记录的最近日志。 /// /// 要获取的日志。 /// 要获取最近日志的数量。 public void GetRecentLogs(List results, int count) { _consoleWindow.GetRecentLogs(results, count); } private void DrawWindow(int windowId) { GUI.DragWindow(_dragRect); DrawDebuggerWindowGroup(_debuggerModule.DebuggerWindowRoot); } private void DrawDebuggerWindowGroup(IDebuggerWindowGroup debuggerWindowGroup) { if (debuggerWindowGroup == null) { return; } List names = new List(); string[] debuggerWindowNames = debuggerWindowGroup.GetDebuggerWindowNames(); for (int i = 0; i < debuggerWindowNames.Length; i++) { names.Add(Utility.Text.Format("{0}", debuggerWindowNames[i])); } if (debuggerWindowGroup == _debuggerModule.DebuggerWindowRoot) { names.Add("Close"); } int toolbarIndex = GUILayout.Toolbar(debuggerWindowGroup.SelectedIndex, names.ToArray(), GUILayout.Height(30f), GUILayout.MaxWidth(Screen.width)); if (toolbarIndex >= debuggerWindowGroup.DebuggerWindowCount) { ShowFullWindow = false; return; } if (debuggerWindowGroup.SelectedWindow == null) { return; } if (debuggerWindowGroup.SelectedIndex != toolbarIndex) { debuggerWindowGroup.SelectedWindow.OnLeave(); debuggerWindowGroup.SelectedIndex = toolbarIndex; debuggerWindowGroup.SelectedWindow.OnEnter(); } IDebuggerWindowGroup subDebuggerWindowGroup = debuggerWindowGroup.SelectedWindow as IDebuggerWindowGroup; if (subDebuggerWindowGroup != null) { DrawDebuggerWindowGroup(subDebuggerWindowGroup); } debuggerWindowGroup?.SelectedWindow?.OnDraw(); } private void DrawDebuggerWindowIcon(int windowId) { GUI.DragWindow(_dragRect); GUILayout.Space(5); Color32 color = Color.white; _consoleWindow.RefreshCount(); if (_consoleWindow.FatalCount > 0) { color = _consoleWindow.GetLogStringColor(LogType.Exception); } else if (_consoleWindow.ErrorCount > 0) { color = _consoleWindow.GetLogStringColor(LogType.Error); } else if (_consoleWindow.WarningCount > 0) { color = _consoleWindow.GetLogStringColor(LogType.Warning); } else { color = _consoleWindow.GetLogStringColor(LogType.Log); } string title = Utility.Text.Format("FPS: {4:F2}", color.r, color.g, color.b, color.a, _fpsCounter.CurrentFps); if (GUILayout.Button(title, GUILayout.Width(100f), GUILayout.Height(40f))) { ShowFullWindow = true; } } private static void CopyToClipboard(string content) { s_TextEditor.text = content; s_TextEditor.OnFocus(); s_TextEditor.Copy(); s_TextEditor.text = string.Empty; } } }