Search Unity

How can I find what objects are using another object?

Discussion in 'Editor & General Support' started by markharkness, Aug 12, 2011.

  1. markharkness

    markharkness

    Unity Technologies

    Joined:
    Nov 2, 2010
    Posts:
    176
    As a request that had came in through the support channel someone asked if this would be possible. So I set about writing this lovely little script:

    Code (csharp):
    1. using System.Linq;
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Collections.Generic;
    5.  
    6. public class ReferenceFilter : EditorWindow
    7. {
    8.     private static ReferenceFilter _referenceFilter;
    9.     public static Object Sel = Selection.activeObject;
    10.  
    11.     static readonly List<Object> Matches = new List<Object>();
    12.     static readonly List<Object> SceneList = new List<Object>();
    13.     static readonly List<Object> InCurrentScene = new List<Object>();
    14.  
    15.     bool _objectFoldout = false;
    16.     bool _sceneFoldout = false;
    17.     private bool _projectFoldout = false;
    18.     private static bool _noReferencesFound = false;
    19.  
    20.     [MenuItem("Unity Support Tools/Project/What objects use this?")]
    21.     private static void LaunchReferenceFilterWindow()
    22.     {
    23.         // make sure the scene files are available to search
    24.         PreLoadScenes();
    25.         _referenceFilter = GetWindow<ReferenceFilter>();
    26.     }
    27.  
    28.     private static void ClearResults()
    29.     {
    30.         Matches.Clear();
    31.         InCurrentScene.Clear();
    32.         SceneList.Clear();
    33.         _noReferencesFound = false;
    34.     }
    35.  
    36.     private static bool AreListsEmpty()
    37.     {
    38.         return Matches.Count + InCurrentScene.Count + SceneList.Count == 0;
    39.     }
    40.  
    41.     void OnGUI()
    42.     {
    43.         if (GUILayout.Button("Search"))
    44.             OnSearchForReferences();
    45.         if (GUILayout.Button("Clear Search Results"))
    46.             ClearResults();
    47.  
    48.         Sel = EditorGUILayout.ObjectField("Selection", Sel, typeof(Object), false, GUILayout.ExpandWidth(true));
    49.  
    50.         // avoids null reference exception spam
    51.         string selectionName = Sel != null ? Sel.name : "";
    52.  
    53.         _objectFoldout = EditorGUILayout.Foldout(_objectFoldout, "Objects in the current scene referencing " + selectionName);
    54.         if (_objectFoldout)
    55.         {
    56.             EditorGUIUtility.LookLikeControls(0, _referenceFilter.position.width);
    57.             foreach (var match in Matches)
    58.                 EditorGUILayout.ObjectField("", match, typeof(Object), false, GUILayout.ExpandWidth(true));
    59.         }
    60.        
    61.         _projectFoldout = EditorGUILayout.Foldout(_projectFoldout, "Objects in Project that reference " + selectionName);
    62.         if (_projectFoldout)
    63.         {
    64.             EditorGUIUtility.LookLikeControls(0, _referenceFilter.position.width);
    65.             foreach (var match in InCurrentScene)
    66.                 EditorGUILayout.ObjectField("", match, typeof(Object), false, GUILayout.ExpandWidth(true));
    67.         }
    68.  
    69.         _sceneFoldout = EditorGUILayout.Foldout(_sceneFoldout, "Scenes that contain objects referencing " + selectionName);
    70.         if (_sceneFoldout)
    71.         {
    72.             EditorGUIUtility.LookLikeControls(0, _referenceFilter.position.width);
    73.             foreach (var scene in SceneList)
    74.                 EditorGUILayout.ObjectField("", scene, typeof(Object), false, GUILayout.ExpandWidth(true));
    75.         }
    76.  
    77.        if (_noReferencesFound)
    78.         EditorGUILayout.LabelField("", selectionName + " is not referenced by anything in this project");
    79.        
    80.         Repaint();
    81.     }
    82.  
    83.     void Update()
    84.     {
    85.         Repaint();
    86.     }
    87.  
    88.     static void PreLoadScenes()
    89.     {
    90.         // we need to find the scene files and select them so that they will appear in the AssetDatabase
    91.         // unity will only add the scene to the assetdatabase once it has been clicked on
    92.         var files = System.IO.Directory.GetFiles(Application.dataPath, "*.unity", System.IO.SearchOption.AllDirectories);
    93.         var l = Application.dataPath.Length;
    94.         foreach (var s in files)
    95.         {
    96.             string temp = s.Remove(0, l);
    97.             temp = temp.Insert(0, "Assets");
    98.             temp = temp.Replace("\\", "/");
    99.             AssetDatabase.LoadAssetAtPath(temp, typeof(Object));
    100.         }
    101.     }
    102.  
    103.     private static bool GetCurrentSelection(out string _object)
    104.     {
    105.         if (AssetDatabase.Contains(Sel))
    106.         {
    107.             int iid = Sel.GetInstanceID();
    108.             if (AssetDatabase.IsMainAsset(iid))
    109.             {
    110.                 _object = System.IO.Path.GetFileNameWithoutExtension(AssetDatabase.GetAssetPath(iid));
    111.                 return true;
    112.             }
    113.         }
    114.         _object = "";
    115.         return false;
    116.     }
    117.  
    118.     private static string GetCurrentScene()
    119.     {
    120.         return System.IO.Path.GetFileNameWithoutExtension(EditorApplication.currentScene);
    121.     }
    122.  
    123.     private static void AddReferencesToList(Object _currentObject, string _ref, Object[] _dependencyList, List<Object> _listToAddTo)
    124.     {
    125.         foreach (Object dependency in _dependencyList)
    126.             if (string.Compare(dependency.name, _ref) == 0  string.Compare(dependency.name , "HandlesGO") != 0)
    127.             {
    128.                 // check for game objects and dont include child objects as they generate duplicates for each component
    129.                 var gameobject = _currentObject as GameObject;
    130.                 if (gameobject != null  gameobject.transform.parent == null  gameobject != Selection.activeObject  !Matches.Contains(_currentObject))
    131.                     _listToAddTo.Add(_currentObject); // add it to our list to highlight
    132.  
    133.                 //add scene files(DefaultAsset)
    134.                 if (_currentObject.ToString().Contains("DefaultAsset")  !SceneList.Contains(_currentObject))
    135.                     SceneList.Add(_currentObject);
    136.  
    137.                 // check for materials as they are not game objects
    138.                 var mat = _currentObject as Material;
    139.                 if (mat != null  mat != Selection.activeObject)
    140.                     _listToAddTo.Add(_currentObject); // add it to our list to highlight
    141.             }
    142.     }
    143.  
    144.     private static void OnSearchForReferences()
    145.     {
    146.         // make sure scene files that have been added since the window was luanched are included
    147.         PreLoadScenes();
    148.         ClearResults();
    149.         string final;
    150.         bool cancel = false;
    151.  
    152.         if (!GetCurrentSelection(out final))
    153.         {
    154.             Debug.Log("Asset is not contained in the AssetDatabase. It is likely that this object is only present in the current scene");
    155.             return;
    156.         }
    157.  
    158.         // get everything
    159.         Object[] allObjects = Resources.FindObjectsOfTypeAll(typeof(Object));
    160.  
    161.         var noOfObjects = allObjects.Length;
    162.         var searchedSoFar = 0;
    163.  
    164.         //loop through everything
    165.         foreach (Object obj in allObjects)
    166.         {
    167.             // hack fix
    168.             if (obj.name == "HandlesGO") continue;
    169.             // All objects
    170.             Object[] dependencies = EditorUtility.CollectDependencies(new[] { obj });
    171.             AddReferencesToList(obj, final, dependencies, Matches);
    172.  
    173.             // progress bar logic
    174.             searchedSoFar++;
    175.            cancel = EditorUtility.DisplayCancelableProgressBar("Searching all references", "Completed: "  + ((searchedSoFar / (float)noOfObjects))*100.0f + "%" ,searchedSoFar/(float) noOfObjects);
    176.            if (cancel)
    177.            {
    178.                ClearResults();
    179.                _noReferencesFound = true;
    180.                EditorUtility.ClearProgressBar();
    181.                return;
    182.            }
    183.         }
    184.  
    185.         searchedSoFar = 0;
    186.         foreach (var scene in SceneList)
    187.         {
    188.             noOfObjects = SceneList.Count;
    189.             //get the objects that are scene dependencies
    190.             Object[] dependencies = EditorUtility.CollectDependencies(new[] { scene });
    191.             foreach (var dependency in dependencies.Where(dependency => Matches.Contains(dependency)))
    192.             {
    193.                 InCurrentScene.Add(dependency);
    194.                 Matches.Remove(dependency);
    195.             }
    196.             EditorUtility.DisplayProgressBar("Gathering referenced scenes", "Completed: " + ((searchedSoFar / (float)noOfObjects)) * 100.0f + "%", searchedSoFar / (float)noOfObjects);
    197.         }
    198.  
    199.         Selection.objects = Matches.ToArray();
    200.         EditorUtility.ClearProgressBar();
    201.         _noReferencesFound = AreListsEmpty();
    202.     }
    203. }
    204.  
    205.  
    This is an Editor script so you will need to remember to put it into and Editor folder in your project window.

    To use it simply right click any object in your project tab and it will search everything in your project and your scenes and highlight it for you.
    I will try and give it a bit more ZAZZ at some point but for now the basic functionality is on there.

    I should add any input on this is more welcome, I'm sure someone will come along and tell me that there is an even better way to do it. any changes that are made I will try and keep this first post updated with them.

    If you find this useful please up vote it on answers:
    http://answers.unity3d.com/questions/155746/how-do-i-find-which-objects-are-referencing-anothe.html
     
    Last edited: Sep 16, 2011
  2. zine92

    zine92

    Joined:
    Nov 13, 2010
    Posts:
    1,347
    Wow. Cool. Should post this in Unify. Thanks for the share though. :D
     
  3. markharkness

    markharkness

    Unity Technologies

    Joined:
    Nov 2, 2010
    Posts:
    176
    Yeah I'll get it around as much as possible.
    I'll put it up on the asset store eventually once I've added progress bar and some GUI repaint to grey out everything that is not highlighted in the actual scene.
     
  4. markharkness

    markharkness

    Unity Technologies

    Joined:
    Nov 2, 2010
    Posts:
    176
    Quick update to this before it goes on the Asset store as soon as I get a chance. Free of course.