using System; using UnityEditor; using UnityEngine; namespace SepCore.Timer.Editor { [CustomEditor(typeof(TimerComponent))] public sealed class TimerComponentEditor : UnityEditor.Editor { private TimerComponent _timer; private Vector2 _scrollPosition; private bool _showDebugControls = true; private void OnEnable() { _timer = (TimerComponent)target; EditorApplication.update += Repaint; } private void OnDisable() { EditorApplication.update -= Repaint; } public override void OnInspectorGUI() { base.OnInspectorGUI(); if (!Application.isPlaying) { EditorGUILayout.HelpBox("运行时显示任务列表和调试信息", MessageType.Info); return; } DrawStatistics(); DrawDebugControls(); DrawTaskList(); } private void DrawStatistics() { TimerTaskSnapshot[] tasks = _timer.GetTaskSnapshots(); EditorGUILayout.Space(); EditorGUILayout.LabelField("统计信息", EditorStyles.boldLabel); using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { int scaledCount = 0; int unscaledCount = 0; int errorCount = 0; int infiniteCount = 0; foreach (TimerTaskSnapshot task in tasks) { if (task.TimeMode == TimerTimeMode.Scaled) scaledCount++; else unscaledCount++; if (task.HasError) errorCount++; if (task.RemainingRepeatCount < 0) infiniteCount++; } using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField("活跃任务", $"{tasks.Length}", GUILayout.Width(120)); EditorGUILayout.LabelField("Scaled", $"{scaledCount}", GUILayout.Width(80)); EditorGUILayout.LabelField("Unscaled", $"{unscaledCount}", GUILayout.Width(80)); } using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField("无限循环", $"{infiniteCount}", GUILayout.Width(120)); EditorGUILayout.LabelField("异常任务", $"{errorCount}", errorCount > 0 ? GetErrorLabelStyle() : GUIStyle.none, GUILayout.Width(80)); EditorGUILayout.LabelField("全局状态", _timer.IsPaused ? "已暂停" : "运行中", GetRichLabelStyle()); } } } private void DrawDebugControls() { EditorGUILayout.Space(); _showDebugControls = EditorGUILayout.Foldout(_showDebugControls, "调试控制", true); if (!_showDebugControls) return; using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { using (new EditorGUILayout.HorizontalScope()) { if (GUILayout.Button(_timer.IsPaused ? "恢复全部" : "暂停全部", GUILayout.Height(25))) { if (_timer.IsPaused) _timer.Resume(); else _timer.Pause(); } if (GUILayout.Button("清理全部", GUILayout.Height(25))) { if (EditorUtility.DisplayDialog("确认", "确定要清除所有定时任务吗?", "确定", "取消")) { _timer.ClearAll(); } } } } } private void DrawTaskList() { TimerTaskSnapshot[] tasks = _timer.GetTaskSnapshots(); EditorGUILayout.Space(); EditorGUILayout.LabelField($"活跃任务列表 ({tasks.Length})", EditorStyles.boldLabel); if (tasks.Length == 0) { EditorGUILayout.HelpBox("当前没有活跃的定时任务", MessageType.Info); return; } _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition); foreach (TimerTaskSnapshot task in tasks) { DrawTaskItem(task); } EditorGUILayout.EndScrollView(); } private void DrawTaskItem(TimerTaskSnapshot task) { Color originalColor = GUI.backgroundColor; if (task.HasError) GUI.backgroundColor = new Color(1f, 0.3f, 0.3f, 0.3f); using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { if (task.HasError) { EditorGUILayout.LabelField("⚠ 该任务回调曾抛出异常", GetErrorLabelStyle()); } // 头部:ID + 时间模式 + 取消按钮 using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField($"ID: #{task.Id}", GUILayout.Width(60)); string modeLabel = task.TimeMode == TimerTimeMode.Scaled ? "Scaled" : "Unscaled"; Color modeColor = task.TimeMode == TimerTimeMode.Scaled ? Color.cyan : Color.yellow; EditorGUILayout.LabelField($"{modeLabel}", GetRichLabelStyle(), GUILayout.Width(60)); string repeatLabel = task.RemainingRepeatCount < 0 ? "∞" : $"{task.RemainingRepeatCount}"; EditorGUILayout.LabelField($"剩余: {repeatLabel} 次", GUILayout.Width(80)); GUILayout.FlexibleSpace(); if (GUILayout.Button("取消", GUILayout.Width(50))) { _timer.Cancel(new TimerHandle(task.Id)); } } // 进度条 DrawProgressBar(task); // 回调信息 EditorGUILayout.LabelField("回调:", task.CallbackMethod, EditorStyles.miniLabel); // 归属对象(可点击 Ping) using (new EditorGUILayout.HorizontalScope()) { EditorGUILayout.LabelField("归属:", GUILayout.Width(40)); if (task.Owner is UnityEngine.Object unityObject && unityObject != null) { if (GUILayout.Button(unityObject.name, EditorStyles.linkLabel)) { EditorGUIUtility.PingObject(unityObject); Selection.activeObject = unityObject; } } else if (task.Owner != null) { EditorGUILayout.LabelField(task.Owner.ToString(), EditorStyles.miniLabel); } else { EditorGUILayout.LabelField("(无归属对象)", EditorStyles.miniLabel); } } } GUI.backgroundColor = originalColor; EditorGUILayout.Space(2); } private void DrawProgressBar(TimerTaskSnapshot task) { float progress; string label; if (task.Interval <= 0f || task.RemainingRepeatCount == 1) { // 一次性任务:显示延迟进度 float totalTime = Mathf.Max(task.Interval, task.RemainingTime); progress = totalTime > 0f ? 1f - (task.RemainingTime / totalTime) : 1f; label = $"剩余 {task.RemainingTime:F2}s (一次性)"; } else if (task.RemainingRepeatCount < 0) { // 无限循环:显示当前周期进度 progress = 1f - (task.RemainingTime / task.Interval); label = $"剩余 {task.RemainingTime:F2}s (无限循环)"; } else { // 有限循环:显示当前周期进度 progress = 1f - (task.RemainingTime / task.Interval); label = $"剩余 {task.RemainingTime:F2}s (周期进度)"; } Rect rect = EditorGUILayout.GetControlRect(false, 18); EditorGUI.ProgressBar(rect, Mathf.Clamp01(progress), label); } private static GUIStyle GetRichLabelStyle() { GUIStyle style = new GUIStyle(EditorStyles.label); style.richText = true; return style; } private static GUIStyle GetErrorLabelStyle() { GUIStyle style = new GUIStyle(EditorStyles.label); style.normal.textColor = Color.red; style.fontStyle = FontStyle.Bold; return style; } } }