Unity编辑器扩展-引用查询

不知道大伙有没有遇到这种情况,很久以前做的项目,公司突然提需求需要改改逻辑或者什么东西,你已经忘了哪个脚本里用了这个东西。
等你理完逻辑,可能几个小时或者半天就过去了~
我就经常遇到这种需求…所以后面就整了这个扩展工具(适用于直接拖拽的引用,Transfrom.Find(“xxx”)找不到)
对着你要查询的component右键,查询引用=》就会列出哪里用了这个脚本,及调用了这个脚本里的各种函数等。
截图如下
查询设置截图
查询结果截图(方法名,关联的对象,方法参数)
在这里插入图片描述
代码如下

using Newtonsoft.Json;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

namespace YjjTool
{
    public class Yjj_ReferenceWindows : OdinMenuEditorWindow
    {
        public static Yjj_ReferenceWindows Instance
        {
            get { var window = GetWindow<Yjj_ReferenceWindows>(); window.Show(); return window; }
        }

        [Header("查询的脚本")]
        public Component script;
        [LabelText("全局查询")]
        public bool globleSearch = false;
        [Header("查询的父节点"), HideIf("globleSearch")]
        public List<Transform> searchRoots = new List<Transform>();
        [LabelText("查找组件的transfrom和Gameobject")]
        public bool transAndGameobj = true;
        [LabelText("查找组件的父节点引用")]
        public bool findParent = false;
        [LabelText("查找事件对该脚本的引用")]
        public bool findEventReference = true;
        [LabelText("查找事件参数"),ShowIf("findEventReference")]
        public bool findEventArgs = true;
        [LabelText("查找字段对该脚本的引用")]
        public bool findObjectReference = true;

        [MenuItem("Yjj/查找场景中的引用")]
        private static void Open()
        {
            GetWindow<Yjj_ReferenceWindows>().Show();
        }
        private Dictionary<string, EventReferenceInfo> dic = new Dictionary<string, EventReferenceInfo>();
        private ObjReferenceInfo obj;
        private Transform scriptTrans;
        private GameObject scriptGO;
        private Transform parentTrans;
        private GameObject parentGO;
        private ObjReferenceInfo parentReference;


        [Button]
        public  void Search()
        {
            //Debug.Log(typeof(CenterEvent).IsSubclassOf(typeof(UnityEventBase)));
            var removes = searchRoots.Where(x => x == null).ToArray();
            foreach (var remove in removes)
            {
                searchRoots.Remove(remove);
            }
            if (searchRoots.Count == 0 && !globleSearch)
            {
                if (EditorUtility.DisplayDialog("空查询", "当前没有添加查询的父节点,是否需要开启全局查询", "开启", "取消"))
                {
                    globleSearch = true;
                }
                else
                {
                    return;
                }
            }
            if (script == null) return;
            if (transAndGameobj)
            {
                scriptTrans = script.transform;
                scriptGO = script.gameObject;
            }
            dic.Clear();
            List<Task> tasks = new List<Task>();
            if (findObjectReference)
            {
                obj = new ObjReferenceInfo
                {
                    objName = script.GetType().Name,
                    goName = script.gameObject.name
                };
            }
            if (findParent)
            {
                parentReference = new ObjReferenceInfo();
                parentTrans = script.transform.parent;
                if (parentTrans != null)
                {
                    parentGO = parentTrans.gameObject;
                    parentReference.objName = parentGO.name;
                }
            }
            var transforms = new List<Transform>();
            if (globleSearch)
            {
                for (int i = 0; i < SceneManager.sceneCount; i++)
                {
                    transforms = Resources.FindObjectsOfTypeAll<Transform>()
                     .Where(x => !EditorUtility.IsPersistent(x.root.gameObject) && !(x.gameObject.hideFlags == HideFlags.HideAndDontSave || x.gameObject.hideFlags == HideFlags.NotEditable) && x.gameObject.scene.isLoaded)
                     .ToList();
                }
            }
            else
            {
                foreach (Transform t in searchRoots)
                {
                    if (t == null) continue;
                    transforms.AddRange(t.GetComponentsInChildren<Transform>());
                }
            }

            int length = transforms.Count;
            for (int i = 0; i < length; i++)
            {
                var arr = transforms[i].GetComponents<Component>();
                EditorUtility.DisplayProgressBar("搜索进度", $"{i + 1}/{length}", (i + 1f) / length);
                for (int k = 0; k < arr.Length; k++)
                {
                    var c = arr[k];
                    if(c == null)
                    {
                        continue;
                    }
                    var goName = script.gameObject.name;
                    tasks.Add(Task.Run(() =>
                    {
                        try
                        {
                            Find(c, goName);
                        }
                        catch(Exception e)
                        {
                            Debug.LogException(e);
                        }
                    }));
                }
            }
            Task.WaitAll(tasks.ToArray());
            EditorUtility.ClearProgressBar();
            if (MenuTree == null)
            {
                ForceMenuTreeRebuild();
            }
            MenuTree.MenuItems.Clear();
            MenuTree.Add("查询设置", this);
            int menuIndex = 0;
            foreach (var key in dic.Keys)
            {
                dic.TryGetValue(key, out var data);
                MenuTree.Add(key, data);
                menuIndex++;
            }
            if (findParent && parentReference.list.Count > 0)
            {
                MenuTree.Add("父节点引用", parentReference);
                menuIndex++;
            }
            if (findObjectReference && obj.list.Count > 0)
            {
                MenuTree.Add("组件引用", obj);
                menuIndex++;
            }
            MenuTree.MenuItems[menuIndex].Select();
            GC.Collect();
        }
        private EventReferenceInfo GetInfo(string str,string goName)
        {
            if (dic.TryGetValue(str, out var info))
            {

            }
            else
            {
                info = new EventReferenceInfo
                {
                    eventName = str,
                    goName = goName,
                };
                dic.Add(str, info);
            }
            return info;
        }
        private void Find(Component com, string goName)
        {
            var tp = com.GetType();
            var fileds = tp.GetFields();
            foreach (var field in fileds)
            {
                var value = field.GetValue(com);
                #region 查找事件
                if (findEventReference)
                {
                    var baseType = typeof(UnityEventBase);
                    if (field.FieldType.IsSubclassOf(baseType))
                    {
                        UnityEventBase ue = field.GetValue(com) as UnityEventBase;
                        int length = ue.GetPersistentEventCount();
                        List<string> objs = new List<string>();
                        if (length > 0 && findEventArgs)
                        {
                            //持久化事件
                            var fieldInfo = baseType.GetField("m_PersistentCalls", BindingFlags.NonPublic | BindingFlags.Instance);
                            var m_PersistentCalls = fieldInfo.GetValue(ue);
                            fieldInfo = fieldInfo.FieldType.GetField("m_Calls", BindingFlags.NonPublic | BindingFlags.Instance);
                            var calls = fieldInfo.GetValue(m_PersistentCalls);
                            var list = calls as IEnumerable<object>;
                            foreach (var item in list)
                            {
                                var itemType = item.GetType();
                                var mode = itemType.GetField("m_Mode", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(item).ToString();
                                var argumentsType = itemType.GetField("m_Arguments", BindingFlags.NonPublic | BindingFlags.Instance);
                                var arguments = argumentsType.GetValue(item);
                                //foreach(var f in arguments.GetType().GetFields( BindingFlags.NonPublic | BindingFlags.Instance))
                                //{
                                //    Debug.Log(f);
                                //}
                                FieldInfo resultInfo = null;
                                if (mode == "String")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_StringArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Bool")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_BoolArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Float")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_FloatArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Int")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_IntArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Object")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_ObjectArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                    var result = resultInfo.GetValue(arguments);
                                    string temp = null;
                                    if (result == null)
                                    {
                                        temp = "Null";
                                    }
                                    else
                                    {
                                        temp = resultInfo.FieldType.ToString();
                                    }
                                    objs.Add(temp);
                                    continue;
                                }
                                objs.Add(resultInfo == null ? null : resultInfo.GetValue(arguments).ToString());
                            }
                        }
                        for (int i = 0; i < length; i++)
                        {
                            var target = ue.GetPersistentTarget(i);
                            if (target == script)
                            {
                                var method = ue.GetPersistentMethodName(i);
                                var info = GetInfo(method, goName);
                                //var methedinfo = UnityEventBase.GetValidMethodInfo(target, method, Type.EmptyTypes);
                                info.Add(field, com, objs.Count > i ? objs[i] : null);
                            }
                            else if (transAndGameobj && (target == scriptTrans || target == scriptGO))
                            {
                                 var method = ue.GetPersistentMethodName(i);
                                 var info = GetInfo(method, goName);
                                 info.Add(field, com, objs.Count > i ? objs[i] : null);
                            }
                        }
                    }
                }
                #endregion
                //查找字段
                if (findObjectReference)
                {

                    var st = script.GetType();
                    #region 查找该组件的transform和gameobject
                    if (transAndGameobj)
                    {
                        if(st != typeof(RectTransform) && value == (object)scriptTrans)
                        {
                            obj.Add(field, com);
                        }
                        if (value == (object)scriptGO)
                        {
                            obj.Add(field, com);
                        }
                        if (typeof(System.Collections.IList).IsAssignableFrom(field.FieldType))
                        {
                            var arr = field.FieldType.GenericTypeArguments;
                            if (arr.Length == 1 && (arr[0] == typeof(Transform) || arr[0] == typeof(GameObject)))
                            {
                                var list = value as IList;
                                foreach (var l in list)
                                {
                                    if (l == (object)scriptTrans || (object)scriptGO == l)
                                    {
                                        obj.Add(field, com);
                                    }
                                }
                            }
                        }

                    }
                    #endregion
                    if ((object)value == script)
                    {
                        obj.Add(field, com);
                    }
                    #region 查找list属性是否包含该类型
                    if (typeof(IList).IsAssignableFrom(field.FieldType))
                    {
                        var arr = field.FieldType.GenericTypeArguments;
                        if (arr.Length == 1 && (arr[0] == st))
                        {
                            var list = value as IList;
                            foreach (var l in list)
                            {
                                if (l == (object)script)
                                {
                                    obj.Add(field, com);
                                }
                            }
                        }
                    }
                    #endregion
                }
                #region 查找父物体
                if (findParent && parentTrans != null)
                {
                    if (value == (object)parentTrans || value == (object)parentGO)
                    {
                        parentReference.Add(field, com);
                    }
                    if (typeof(System.Collections.IList).IsAssignableFrom(field.FieldType))
                    {
                        var arr = field.FieldType.GenericTypeArguments;
                        if (arr.Length == 1 && (arr[0] == typeof(Transform) || arr[0] == typeof(GameObject)))
                        {
                            var list = value as IList;
                            foreach (var l in list)
                            {
                                if (l == (object)parentTrans || (object)parentGO == l)
                                {
                                    parentReference.Add(field, com);
                                }
                            }
                        }
                    }
                }
            }
            #endregion
            var propers = tp.GetProperties();
            foreach (PropertyInfo property in propers)
            {
                #region 查找事件

                if (findEventReference)
                {
                    var baseType = typeof(UnityEventBase);
                    if (property.PropertyType.IsSubclassOf(baseType))
                    {
                        UnityEventBase ue = property.GetValue(com) as UnityEventBase;
                        int length = ue.GetPersistentEventCount();
                        List<string> objs = new List<string>();
                        if (length > 0 && findEventArgs)
                        {
                            //持久化事件
                            var fieldInfo = baseType.GetField("m_PersistentCalls", BindingFlags.NonPublic | BindingFlags.Instance);
                            var m_PersistentCalls = fieldInfo.GetValue(ue);
                            fieldInfo = fieldInfo.FieldType.GetField("m_Calls", BindingFlags.NonPublic | BindingFlags.Instance);
                            var calls = fieldInfo.GetValue(m_PersistentCalls);
                            var list = calls as IEnumerable<object>;
                            foreach(var item in list)
                            {
                                var itemType = item.GetType();
                                var mode = itemType.GetField("m_Mode", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(item).ToString();
                                var argumentsType = itemType.GetField("m_Arguments", BindingFlags.NonPublic | BindingFlags.Instance);
                                var arguments = argumentsType.GetValue(item);
                                //foreach(var f in arguments.GetType().GetFields( BindingFlags.NonPublic | BindingFlags.Instance))
                                //{
                                //    Debug.Log(f);
                                //}
                                FieldInfo resultInfo = null;
                                if (mode == "String")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_StringArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Bool")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_BoolArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Float")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_FloatArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Int")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_IntArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                }
                                else if (mode == "Object")
                                {
                                    resultInfo = argumentsType.FieldType.GetField("m_ObjectArgument", BindingFlags.NonPublic | BindingFlags.Instance);
                                    var result = resultInfo.GetValue(arguments);
                                    string temp = null;
                                    if(result == null)
                                    {
                                        temp = "Null";
                                    }
                                    else
                                    {
                                        temp = resultInfo.FieldType.ToString();
                                    }
                                    objs.Add(temp);
                                    continue;
                                }
                                objs.Add(resultInfo == null?null:resultInfo.GetValue(arguments).ToString());
                            }
                        }

                        for (int i = 0; i < length; i++)
                        {
                            var target = ue.GetPersistentTarget(i);
                            if (target == script)
                            {
                                var method = ue.GetPersistentMethodName(i);
                                EventReferenceInfo info = GetInfo(method, goName);
                                info.Add(property, com, objs.Count > i ? objs[i] : null);
                            }else if (transAndGameobj && (target == scriptTrans || target == scriptGO))
                            {
                                var method = ue.GetPersistentMethodName(i);
                                var info = GetInfo(method, goName);
                                info.Add(property, com, objs.Count > i ? objs[i] : null);
                            }
                        }
 
                    }
                }
                #endregion
            }
        }

        protected override OdinMenuTree BuildMenuTree()
        {
            if(MenuTree == null)
            {
                var tree = new OdinMenuTree();
                tree.Add("查询设置", this);
                return tree;
            }
            else
            {
                return MenuTree;
            }
        }
        #region 数据
        public class EventReferenceInfo
        {
            [HideInInspector]
            public string eventName;
            [HideInInspector]
            public string goName;

            [Title("@eventName", TitleAlignment = TitleAlignments.Centered, HorizontalLine = true, Bold = true, Subtitle = "@goName"), HideLabel]
            [TableList(AlwaysExpanded = true, CellPadding = 5, HideToolbar = true, ShowIndexLabels = false, IsReadOnly = true)]
            public List<ReferenceDetail> list = new List<ReferenceDetail>();

            //[LabelText("引用情况"), HorizontalGroup("use")]
            //public List<string> useInfos = new List<string>();
            //[LabelText("有引用该方法的物体"), HorizontalGroup("use")]
            //public List<Component> gos = new List<Component>();

            public void Add(MemberInfo field, Component com,string args,string details = null)
            {
                var attribute = field.GetCustomAttributes(typeof(LabelTextAttribute), true);
                if (attribute.Length > 0)
                {
                    list.Add(new ReferenceDetail(field.Name, com,args, (attribute[0] as LabelTextAttribute).Text));
                }
                else
                {
                    list.Add(new ReferenceDetail(field.Name, com,args,null));
                }
            }
        }
        public class ObjReferenceInfo
        {
            [HideInInspector]
            public string objName;
            [HideInInspector]
            public string goName;
            [Title("@objName",TitleAlignment = TitleAlignments.Centered,HorizontalLine = true,Bold =true,Subtitle ="@goName")]
            [HideLabel]
            [TableList(AlwaysExpanded = true,CellPadding = 5,HideToolbar =true,ShowIndexLabels =false,IsReadOnly =true)]
            public List<ReferenceDetail> list = new List<ReferenceDetail>();
            public void Add(FieldInfo field, Component com)
            {
                var attribute = field.GetCustomAttributes(typeof(LabelTextAttribute), true);
                if (attribute.Length > 0)
                {
                    //  obj.useInfos.Add((attribute[0] as LabelTextAttribute).Text);
                   list.Add(new ReferenceDetail( field.Name, com, (attribute[0] as LabelTextAttribute).Text));
                }
                else
                {
                    //  obj.useInfos.Add(field.Name);
                    list.Add(new ReferenceDetail(field.Name, com));
                }
            }
        }
        [System.Serializable]
        public class ReferenceDetail
        {
            [VerticalGroup("属性名"),HideLabel, ShowIf("@string.IsNullOrEmpty(descript)")]
            public string fieldName;

            [VerticalGroup("属性名"),HideLabel,HideIf("@string.IsNullOrEmpty(descript)")]
            public string descript;

            public Component component;

            [ShowIf("@args!=null")]
            public string args = null;

            [Button("打开脚本"),TableColumnWidth(200,resizable:false),ButtonGroup("操作")]
            private async void Open()
            {
                var type = component.GetType();
                var str = AssetDatabase.FindAssets($"{type.Name}")[0];
                var path = AssetDatabase.GUIDToAssetPath(str);
                var target = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
                var resultPath = PathUtility.GetFullPath(path);
                int i = 0;
                await Task.Run(() =>
                {
                    using (StreamReader sr = new StreamReader(resultPath))
                    {
                        string line;
                        var targetInfo = fieldName;
                        while ((line = sr.ReadLine()) != null)
                        {
                            if (Regex.IsMatch(line, $"\\b{targetInfo}\\b"))
                            {
                                break;
                            }
                            i++;
                        }
                    }
                });
                AssetDatabase.OpenAsset(target, i + 1);
            }
            [Button("打开面板"),ButtonGroup("操作")]
            private void Modefine()
            {
                var window = OdinEditorWindow.InspectObject(component);
                //var rect = window.position;
                //window.position = new Rect(rect.position, new Vector2(rect.width, 1600));
                window.position = GUIHelper.GetEditorWindowRect().AlignCenter(450,680);
            }
            public ReferenceDetail(string f,Component c,string dec = "")
            {
                fieldName = f;component = c;descript = dec;
            }
            public ReferenceDetail(string f, Component c,string obj,string dec = null)
            {
                
                fieldName = f; component = c;args = obj; descript = dec;
            }
        }
        #endregion
        [MenuItem("CONTEXT/Component/查找引用", priority = 1000)]
        private static void FindObj(MenuCommand command)
        {
            var window = Instance;
            window.script = (Component)command.context;
            window.Search();
        }

    }
}


需要odin插件,应该复制粘贴就能使用了,记得点赞哦!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值