Advertisement
Bunny83

MulticastDelegateDebugger.cs

Oct 24th, 2020
280
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.91 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEditor;
  4. using System.Reflection;
  5. using System.Text;
  6.  
  7. namespace B83.UnityEditorTools.MDDebugger
  8. {
  9.     public class AnalysedObject
  10.     {
  11.         public static HashSet<object> m_ObjectSet = new HashSet<object>();
  12.  
  13.         public AnalysedObject parent = null;
  14.         public FieldInfo fieldInfo;
  15.         public object obj;
  16.         public System.Type type;
  17.         public List<DelegateMember> members = new List<DelegateMember>();
  18.         public List<AnalysedObject> children = new List<AnalysedObject>();
  19.         public AnalysedObject(object aObj, AnalysedObject aParent = null, FieldInfo aFieldInfo = null)
  20.         {
  21.             obj = aObj;
  22.             parent = aParent;
  23.             fieldInfo = aFieldInfo;
  24.         }
  25.         public bool Analyse(BindingFlags aFlags)
  26.         {
  27.             type = obj.GetType();
  28.             if (m_ObjectSet.Contains(obj))
  29.                 return false;
  30.             else
  31.                 m_ObjectSet.Add(obj);
  32.             var fields = type.GetFields(aFlags);
  33.             bool hasContent = false;
  34.             foreach (var field in fields)
  35.             {
  36.                 if (typeof(System.Delegate).IsAssignableFrom(field.FieldType))
  37.                 {
  38.                     var dm = new DelegateMember(this, field);
  39.                     members.Add(dm);
  40.                     hasContent = true;
  41.                 }
  42.                 else if (field.FieldType.IsClass)
  43.                 {
  44.                     var val = field.GetValue(obj);
  45.                     if (val == null)
  46.                         continue;
  47.                     var tmp = new AnalysedObject(val, this, field);
  48.                     if (tmp.Analyse(aFlags))
  49.                     {
  50.                         hasContent = true;
  51.                         children.Add(tmp);
  52.                     }
  53.                 }
  54.             }
  55.             return hasContent;
  56.         }
  57.         public void Draw()
  58.         {
  59.             GUILayout.BeginHorizontal();
  60.             GUILayout.Space(20);
  61.             GUILayout.BeginVertical();
  62.             GUILayout.BeginHorizontal();
  63.             if (fieldInfo != null && fieldInfo.IsStatic)
  64.                 GUILayout.Label("static field: " + fieldInfo.Name);
  65.             else if (fieldInfo != null)
  66.                 GUILayout.Label("field: " + fieldInfo.Name);
  67.  
  68.             GUILayout.Label(" type: " + TypeName.FixGenericTypeNames(type));
  69.             if (typeof(MonoBehaviour).IsAssignableFrom(type))
  70.                 GUILayout.Label(" : MonoBehaviour");
  71.             if (obj != null && obj is UnityEngine.Object uObj)
  72.                 EditorGUILayout.ObjectField(uObj, uObj.GetType(), true);
  73.             GUILayout.FlexibleSpace();
  74.             GUILayout.EndHorizontal();
  75.             foreach (var d in members)
  76.             {
  77.                 d.DrawReferences();
  78.             }
  79.  
  80.  
  81.             GUILayout.BeginVertical("box");
  82.             foreach (var ch in children)
  83.             {
  84.                 ch.Draw();
  85.             }
  86.             GUILayout.EndVertical();
  87.  
  88.             GUILayout.EndVertical();
  89.             GUILayout.EndHorizontal();
  90.  
  91.         }
  92.     }
  93.     public class DelegateMember
  94.     {
  95.         public AnalysedObject parent;
  96.         public FieldInfo fieldInfo;
  97.         public List<MethodReference> references = new List<MethodReference>();
  98.         public DelegateMember(AnalysedObject aParent, FieldInfo aFieldInfo)
  99.         {
  100.             parent = aParent;
  101.             fieldInfo = aFieldInfo;
  102.             if (parent.obj == null)
  103.                 return;
  104.             var obj = (System.Delegate)fieldInfo.GetValue(parent.obj);
  105.             if (obj == null)
  106.                 return;
  107.             var list = obj.GetInvocationList();
  108.             foreach(var d in list)
  109.             {
  110.                 references.Add(new MethodReference {
  111.                     methodInfo = d.Method,
  112.                     obj = d.Target
  113.                 });
  114.             }
  115.         }
  116.         public void DrawReferences()
  117.         {
  118.             GUILayout.BeginHorizontal();
  119.             GUILayout.Space(20);
  120.             GUILayout.BeginVertical();
  121.             GUILayout.BeginHorizontal();
  122.             if (fieldInfo.IsStatic)
  123.                 GUILayout.Label("static field: " + fieldInfo.Name);
  124.             else
  125.                 GUILayout.Label("field: " + fieldInfo.Name);
  126.             GUILayout.Label(" type: " + TypeName.FixGenericTypeNames(fieldInfo.FieldType));
  127.             GUILayout.FlexibleSpace();
  128.             GUILayout.EndHorizontal();
  129.             foreach (var r in references)
  130.             {
  131.                 GUILayout.BeginHorizontal();
  132.  
  133.                 GUILayout.Space(20);
  134.                 GUILayout.Label("ref: " + r.methodInfo.Name+" @ " + TypeName.FixGenericTypeNames(r.methodInfo.ReflectedType));
  135.                 if (r.obj != null && r.obj is UnityEngine.Object target)
  136.                     EditorGUILayout.ObjectField(target, target.GetType(), true);
  137.                 GUILayout.FlexibleSpace();
  138.                 GUILayout.EndHorizontal();
  139.             }
  140.             GUILayout.EndVertical();
  141.             GUILayout.EndHorizontal();
  142.         }
  143.     }
  144.  
  145.     public class MethodReference
  146.     {
  147.         public MemberInfo methodInfo;
  148.         public object obj = null;
  149.     }
  150.  
  151.     public class TypeName
  152.     {
  153.         public static void GenericTypeArguments(System.Type aType, StringBuilder aSB)
  154.         {
  155.             var name = aType.Name;
  156.             if (!aType.IsGenericType)
  157.             {
  158.                 aSB.Append(name);
  159.                 return;
  160.             }
  161.             name = name.Substring(0, aType.Name.IndexOf('`'));
  162.             aSB.Append(name).Append("<");
  163.             foreach (var p in aType.GenericTypeArguments)
  164.             {
  165.                 GenericTypeArguments(p, aSB);
  166.             }
  167.             aSB.Append(">");
  168.         }
  169.         public static string FixGenericTypeNames(System.Type aType)
  170.         {
  171.             var sb = new StringBuilder();
  172.             GenericTypeArguments(aType, sb);
  173.             return sb.ToString();
  174.         }
  175.     }
  176.  
  177.     public class MulticastDelegateDebugger : EditorWindow
  178.     {
  179.         BindingFlags m_BindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
  180.         List<AnalysedObject> m_Objs = new List<AnalysedObject>();
  181.         Vector2 scrollPos;
  182.         [MenuItem("Tools/B83/MulticastDelegateDebugger")]
  183.         public static void Init()
  184.         {
  185.             GetWindow<MulticastDelegateDebugger>();
  186.         }
  187.  
  188.         private void OnEnable()
  189.         {
  190.             titleContent = new GUIContent("MD Debugger");
  191.             UpdateView();
  192.             EditorApplication.playModeStateChanged += OnPlaymodeChanged;
  193.         }
  194.         private void OnDisable()
  195.         {
  196.             EditorApplication.playModeStateChanged -= OnPlaymodeChanged;
  197.         }
  198.  
  199.         private void OnPlaymodeChanged(PlayModeStateChange aState)
  200.         {
  201.             UpdateView();
  202.         }
  203.  
  204.         private void OnSelectionChange()
  205.         {
  206.             UpdateView();
  207.         }
  208.  
  209.         private void UpdateView()
  210.         {
  211.             Analyse(Selection.gameObjects);
  212.             Repaint();
  213.         }
  214.         void Analyse(GameObject[] aObjs)
  215.         {
  216.             m_Objs.Clear();
  217.             AnalysedObject.m_ObjectSet.Clear();
  218.             if (aObjs == null || aObjs.Length == 0)
  219.                 return;
  220.             foreach (var go in aObjs)
  221.             {
  222.                 foreach (var mb in go.GetComponents<MonoBehaviour>())
  223.                 {
  224.                     if (mb == null)
  225.                         continue;
  226.                     var analysedObject = new AnalysedObject(mb);
  227.                     if (analysedObject.Analyse(m_BindingFlags))
  228.                         m_Objs.Add(analysedObject);
  229.                 }
  230.             }
  231.         }
  232.         void BindFlagsButton(string aName, BindingFlags aFlag)
  233.         {
  234.             bool active = (m_BindingFlags & aFlag) != 0;
  235.             if (GUILayout.Toggle(active, aName, "Button"))
  236.                 m_BindingFlags |= aFlag;
  237.             else
  238.                 m_BindingFlags &= ~aFlag;
  239.         }
  240.         void DrawBindingFlagSelection()
  241.         {
  242.             var oldFlags = m_BindingFlags;
  243.             GUILayout.BeginHorizontal();
  244.             BindFlagsButton("public", BindingFlags.Public);
  245.             BindFlagsButton("private", BindingFlags.NonPublic);
  246.             BindFlagsButton("instance", BindingFlags.Instance);
  247.             BindFlagsButton("static", BindingFlags.Static);
  248.             GUILayout.EndHorizontal();
  249.             if (oldFlags != m_BindingFlags)
  250.                 UpdateView();
  251.         }
  252.  
  253.         void OnGUI()
  254.         {
  255.             DrawBindingFlagSelection();
  256.             scrollPos = GUILayout.BeginScrollView(scrollPos);
  257.             foreach(var o in m_Objs)
  258.             {
  259.                 GUILayout.BeginVertical("box");
  260.                 o.Draw();
  261.                 GUILayout.EndVertical();
  262.             }
  263.             GUILayout.EndScrollView();
  264.         }
  265.     }
  266. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement