Advertisement
ccoddes

Edited ReferenceFinder (Fixed ScriptableObjects)

Jun 16th, 2022
224
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.72 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEditor;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. /// To use, stick this under a folder named "Editor", then right click an object/script in the project window and click "Find References"
  7. /// @edit ccoddes - Fixed searching for ScriptableObject referencers
  8. /// @author Marudice
  9. /// https://marudice.hatenablog.jp/entry/2020/01/13/123407
  10. /// original source by Dave Lloyd- www.powerhoof.com
  11. /// https://www.powerhoof.com/find-object-references-in-unity/
  12. /// https://pastebin.com/AXAcUTMH
  13.  
  14. /// <summary>
  15. /// Reference finder - Finds prefabs and scene that reference an object in unity
  16. /// </summary>
  17. public class ReferenceFinder : EditorWindow
  18. {
  19.     Vector2 m_scrollPosition = Vector2.zero;
  20.     List<GameObject>      m_refPrefabs        = new List<GameObject>();
  21.     List<SceneAsset>      m_refScenes     = new List<SceneAsset>();
  22.     List<ScriptableObject>    m_refScriptables    = new List<ScriptableObject>();
  23.     List<string> m_paths = null;
  24.     bool m_ignoreInnerReference = true;
  25.     Object[] m_toFindObjects = null;
  26.  
  27.     Object[] m_toFindObjectsAfterLayout = null;
  28.  
  29.  
  30.     [MenuItem("Assets/Find References", false, 39)]
  31.     static void FindObjectReferences()
  32.     {
  33.         //Show existing window instance. If one doesn't exist, make one.
  34.         ReferenceFinder window = EditorWindow.GetWindow<ReferenceFinder>(true, "Find References", true);
  35.         if( Selection.objects.Length > 1)
  36.         {
  37.             window.FindObjectReferencesAll(Selection.objects);
  38.         }
  39.         else
  40.         {
  41.             window.FindObjectReferences(Selection.activeObject);
  42.         }
  43.     }
  44.  
  45.     void OnGUI()
  46.     {
  47.         GUILayout.Space(5);
  48.         m_scrollPosition = EditorGUILayout.BeginScrollView(m_scrollPosition);
  49.  
  50.         GUILayout.BeginHorizontal();
  51.         m_ignoreInnerReference = GUILayout.Toggle(m_ignoreInnerReference, "Ignore inner reference");
  52.         GUILayout.EndHorizontal();
  53.  
  54.         GUILayout.BeginHorizontal();
  55.         if (GUILayout.Button("Clear", EditorStyles.miniButton))
  56.         {
  57.             m_refPrefabs.Clear();
  58.             m_refScenes.Clear();
  59.             m_refScriptables.Clear();
  60.             m_toFindObjects = null;
  61.         }
  62.         GUILayout.EndHorizontal();
  63.  
  64.         GUILayout.Space(15);
  65.  
  66.         if ( m_toFindObjects != null)
  67.         {
  68.             GUILayout.BeginHorizontal();
  69.             if ( m_toFindObjects.Length == 1)
  70.             {
  71.                 LayoutObjectButton(m_toFindObjects[0]);
  72.                 GUILayout.Label($" is referenced by...");
  73.             }
  74.             else
  75.             {
  76.                 GUILayout.Label($"{m_toFindObjects.Length} items");
  77.                 if (GUILayout.Button("\u25B6", EditorStyles.miniButtonRight, GUILayout.MaxWidth(20)))
  78.                 {
  79.                     m_toFindObjectsAfterLayout = m_toFindObjects;
  80.                 }
  81.                 GUILayout.Label($"are referenced by...");
  82.             }
  83.             GUILayout.EndHorizontal();
  84.         }
  85.  
  86.         LayoutGroup(m_refPrefabs, "prefabs");
  87.         LayoutGroup(m_refScriptables, "scriptables");
  88.         LayoutGroup(m_refScenes, "scenes");
  89.  
  90.         EditorGUILayout.EndScrollView();
  91.  
  92.         if (m_toFindObjectsAfterLayout != null)
  93.         {
  94.             FindObjectReferencesAll(m_toFindObjectsAfterLayout);
  95.             m_toFindObjectsAfterLayout = null;
  96.         }
  97.     }
  98.  
  99.     void LayoutGroup<T>(List<T> references, string footer) where T: Object
  100.     {
  101.         GUILayout.Space(5);
  102.  
  103.         GUILayout.BeginHorizontal();
  104.         GUILayout.Label($" {references.Count} {footer}");
  105.         GUILayout.EndHorizontal();
  106.  
  107.         GUILayout.Space(5);
  108.  
  109.         for (int i = references.Count - 1; i >= 0; --i)
  110.         {
  111.             LayoutItem(i, references[i]);
  112.         }
  113.     }
  114.  
  115.     void LayoutItem(int i, UnityEngine.Object obj)
  116.     {
  117.         if (obj != null)
  118.         {
  119.             GUILayout.BeginHorizontal();
  120.             LayoutObjectButton(obj);
  121.             GUILayout.EndHorizontal();
  122.         }
  123.     }
  124.  
  125.     private void LayoutObjectButton(Object obj)
  126.     {
  127.         GUIStyle style = EditorStyles.miniButtonLeft;
  128.         style.alignment = TextAnchor.MiddleLeft;
  129.  
  130.         if (GUILayout.Button(obj.name, style))
  131.         {
  132.             Selection.activeObject = obj;
  133.             EditorGUIUtility.PingObject(obj);
  134.         }
  135.  
  136.         // Use "right arrow" unicode character
  137.         if (GUILayout.Button("\u25B6", EditorStyles.miniButtonRight, GUILayout.MaxWidth(20)))
  138.         {
  139.             var objs = new Object[1];
  140.             objs[0] = obj;
  141.             m_toFindObjectsAfterLayout = objs;
  142.         }
  143.     }
  144.  
  145.     /// Finds references to passed objects and puts them in m_references
  146.     void FindObjectReferencesAll(Object[] toFindObjects)
  147.     {
  148.         EditorUtility.DisplayProgressBar("Searching", "Generating file paths", 0.0f);
  149.  
  150.         m_toFindObjects = toFindObjects;
  151.  
  152.         // Get all prefabs in the project
  153.         //
  154.         if (m_paths == null)
  155.         {
  156.             m_paths = new List<string>();
  157.             GetFilePaths("Assets", ref m_paths, ".prefab", ".unity", ".asset");
  158.         }
  159.  
  160.         float progressBarPos = 0;
  161.         int numPaths = m_paths.Count;
  162.         int hundredthIteration = Mathf.Max(1, numPaths / 100); // So we only update progress bar 100 times, not for every item
  163.  
  164.         //string toFindName = AssetDatabase.GetAssetPath(toFind);
  165.         //toFindName = System.IO.Path.GetFileNameWithoutExtension(toFindName);
  166.         Object[] tmpArray = new Object[1];
  167.         m_refPrefabs.Clear();
  168.         m_refScriptables.Clear();
  169.         m_refScenes.Clear();
  170.  
  171.         //
  172.         // Loop through all files, and add any that have the selected object in it's list of dependencies
  173.         //
  174.         for (int i = 0; i < numPaths; ++i)
  175.         {
  176.             tmpArray[0] = AssetDatabase.LoadMainAssetAtPath(m_paths[i]);
  177.             foreach(Object toFind in toFindObjects)
  178.             {
  179.                 if (tmpArray != null && tmpArray.Length > 0 && tmpArray[0] != toFind) // Don't add self
  180.                 {
  181.                     Object[] dependencies = EditorUtility.CollectDependencies(tmpArray);
  182.                     if (System.Array.Exists(dependencies, item => item == toFind))
  183.                     {
  184.                         // Don't add if another of the dependencies is already in there
  185.                         if (tmpArray[0] is GameObject)
  186.                         {
  187.                             m_refPrefabs.Add(tmpArray[0] as GameObject);
  188.                         }
  189.                         else if (tmpArray[0] is SceneAsset)
  190.                         {
  191.                             m_refScenes.Add(tmpArray[0] as SceneAsset);
  192.                         }
  193.                         else if (tmpArray[0] is ScriptableObject)
  194.                         {
  195.                             m_refScriptables.Add(tmpArray[0] as ScriptableObject);
  196.                         }
  197.                         else
  198.                         {
  199.                             Debug.LogErrorFormat($"Unexpected. found object [{tmpArray[0]}] is {tmpArray[0].GetType()}");
  200.                         }
  201.                     }
  202.  
  203.                 }
  204.             }
  205.             if (i % hundredthIteration == 0)
  206.             {
  207.                 progressBarPos += 0.01f;
  208.                 EditorUtility.DisplayProgressBar("Searching", "Searching dependencies", progressBarPos);
  209.             }
  210.         }
  211.  
  212.  
  213.         if (m_ignoreInnerReference)
  214.         {
  215.             EditorUtility.DisplayProgressBar("Searching", "Removing inner prefab references", 0);
  216.             RemoveInnerReferences(ref m_refPrefabs,           m_refPrefabs, m_refScriptables);
  217.             EditorUtility.DisplayProgressBar("Searching", "Removing inner scriptable references", 1.0f/3.0f);
  218.             RemoveInnerReferences(ref m_refScriptables,       m_refPrefabs, m_refScriptables);
  219.             EditorUtility.DisplayProgressBar("Searching", "Removing inner scene references", 2.0f / 3.0f);
  220.             RemoveInnerReferences(ref m_refScenes,            m_refPrefabs, m_refScriptables);
  221.             EditorUtility.DisplayProgressBar("Searching", "Removing inner references", 1);
  222.         }
  223.         EditorUtility.ClearProgressBar();
  224.     }
  225.  
  226.     /// Finds references to passed objects and puts them in m_references
  227.     void FindObjectReferences(Object toFind)
  228.     {
  229.         Object[] toFindObjects = new Object[1];
  230.         toFindObjects[0] = toFind;
  231.         FindObjectReferencesAll(toFindObjects);
  232.     }
  233.  
  234.     private static void RemoveInnerReferences<T>(ref List<T> check_references
  235.         , List<GameObject> prefab_references
  236.         , List<ScriptableObject> scriptable_references
  237.         )
  238.         where T : Object
  239.     {
  240.         //
  241.         // Go through the references, get dependencies of each and remove any that have another dependency on the match list. We only want direct dependencies.
  242.         //
  243.         Object[] tmpArray = new Object[1];
  244.         for (int i = check_references.Count - 1; i >= 0; i--)
  245.         {
  246.             tmpArray[0] = check_references[i];
  247.             Object[] dependencies = EditorUtility.CollectDependencies(tmpArray);
  248.  
  249.             bool shouldRemove = false;
  250.  
  251.             for (int j = 0; j < dependencies.Length && shouldRemove == false; ++j)
  252.             {
  253.                 Object dependency = dependencies[j];
  254.                 shouldRemove =
  255.                     (prefab_references.Find(item => item == dependency && item != tmpArray[0]) != null) ||
  256.                     (scriptable_references.Find(item => item == dependency && item != tmpArray[0]) != null);
  257.             }
  258.  
  259.             if (shouldRemove)
  260.                 check_references.RemoveAt(i);
  261.         }
  262.     }
  263.  
  264.     /// Recursively find all file paths with particular extention in a directory
  265.     static void GetFilePaths(string startingDirectory, ref List<string> paths, params string[] extensions)
  266.     {
  267.         try
  268.         {
  269.             // Add any file paths with the correct extention
  270.             string[] files = Directory.GetFiles(startingDirectory);
  271.             for (int i = 0; i < files.Length; ++i)
  272.             {
  273.                 string file = files[i];
  274.                 foreach(var extension in extensions)
  275.                 {
  276.                     if (file.EndsWith(extension))
  277.                     {
  278.                         paths.Add(file);
  279.                         break;
  280.                     }
  281.                 }
  282.             }
  283.  
  284.             // Recurse for all directories
  285.             string[] directories = Directory.GetDirectories(startingDirectory);
  286.             for (int i = 0; i < directories.Length; ++i)
  287.             {
  288.                 GetFilePaths(directories[i], ref paths, extensions);
  289.             }
  290.         }
  291.         catch (System.Exception excpt)
  292.         {
  293.             Debug.LogError(excpt.Message);
  294.         }
  295.     }
  296.  
  297. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement