using System.Collections.Generic; using TyphoonGUIStyle; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; namespace TyphoonUI { [InitializeOnLoad] public class HierarchyDrawer { static HierarchyDrawer() { EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI; EditorSceneManager.activeSceneChangedInEditMode += OnSceneChanged; TyphoonUIEditorApplication.OnUIObjectOnNodesChanged += OnUIObjectOnNodesChanged; UIObject.OnInvokeAwake += AddUIObject; UIObject.OnInvokeDestroy += RemoveUIObject; } //清除缓存 private static void OnSceneChanged(Scene arg0, Scene arg1) { _monitoring.Clear(); _monitorUIObjectInstanceID.Clear(); _monitorUIObjects.Clear(); _status.Clear(); } //导出状态 private static Dictionary> _status = new Dictionary>(); //监控队列 private static HashSet _monitoring = new HashSet(); //监控UIObject private static HashSet _monitorUIObjects = new HashSet(); //监控的UIObject InstanceID private static HashSet _monitorUIObjectInstanceID = new HashSet(); private static UIObject _focusObjs = null; private static int _focusObjsInstanceID = -1; private static void OnHierarchyGUI(int instanceID, Rect selectionRect) { if (EditorApplication.isPlaying && !Preferences.Default.DrawHierarchyInPlayingMode) { return; } if (EditorApplication.isCompiling) { return; } var target = EditorUtility.InstanceIDToObject(instanceID); if (target is GameObject) { var addMonitor = _monitoring.Add(instanceID); if (addMonitor) { //添加成功,尝试获取UiObject var go = (target as GameObject); var com = go.GetComponent(); if (com != null) { AddUIObject(com); } } //绘制gui var hasUIObject = HasUIObject(instanceID); var isExport = IsExportInstanceID(instanceID, out var match); if (hasUIObject || isExport) { var isFocus = hasUIObject && (_focusObjs != null && instanceID == _focusObjsInstanceID); isFocus |= isExport && (_focusObjs != null && match.Contains(_focusObjs)); if (isFocus) { GUI.DrawTexture(selectionRect, EditorIcons.focus_hierarchy); } var rectMark = selectionRect; rectMark.width = rectMark.height; rectMark.x = selectionRect.xMax - rectMark.width; rectMark.x -= 2; if (hasUIObject && Preferences.Default.DrawUIObjectHierarchy) { if (GUI.Button(rectMark, "", Styles.Btn)) { var menu = new GenericMenu(); var obj = (target as GameObject).GetComponent(); if (_focusObjs == obj) { menu.AddItem(new GUIContent("关闭增强模式"), false, () => { _focusObjs = null; _focusObjsInstanceID = -1; }); } else { menu.AddItem(new GUIContent("开启增强模式"), false, () => { _focusObjs = obj; _focusObjsInstanceID = _focusObjs.gameObject.GetInstanceID(); }); } menu.ShowAsContext(); } if (isFocus) { GUI.DrawTexture(rectMark, EditorIcons.grid_focus); } else { GUI.DrawTexture(rectMark, EditorIcons.grid); } } if (isExport && Preferences.Default.DrawUINodeHierarchy) { if (isFocus) { GUI.DrawTexture(rectMark, EditorIcons.degree_focus); } else { GUI.DrawTexture(rectMark, EditorIcons.degree); } } } } } private static void AddUIObject(UIObject obj) { //加入UIObject监控列表 var success = _monitorUIObjects.Add(obj); if (success) { _monitorUIObjectInstanceID.Add(obj.gameObject.GetInstanceID()); //更新status var instanceIDs = obj.GetRelatedInstanceID(); foreach (var id in instanceIDs) { AddStatus(id, obj); } } } private static void RemoveUIObject(UIObject obj) { var success = _monitorUIObjects.Remove(obj); if (success) { _monitorUIObjectInstanceID.Remove(obj.gameObject.GetInstanceID()); } RemoveStatus(obj); } private static void RemoveStatus(UIObject obj) { foreach (var kv in _status) { kv.Value.Remove(obj); } } private static void AddStatus(int instanceID, UIObject obj) { if (!_status.ContainsKey(instanceID)) { _status.Add(instanceID, new HashSet()); } _status[instanceID].Add(obj); } private static bool IsExportInstanceID(int instanceId, out HashSet match) { if (_status.TryGetValue(instanceId, out match)) { return match.Count > 0; } return false; } private static bool HasUIObject(int instanceId) { return _monitorUIObjectInstanceID.Contains(instanceId); } private static void OnUIObjectOnNodesChanged(UIObject obj) { RemoveStatus(obj); var relatedInstanceID = obj.GetRelatedInstanceID(); foreach (var id in relatedInstanceID) { AddStatus(id, obj); } } } }