How can I find what objects are using another object?

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:

using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class ReferenceFilter : EditorWindow
{
    private static ReferenceFilter _referenceFilter;
    public static Object Sel = Selection.activeObject;

    static readonly List<Object> Matches = new List<Object>();
    static readonly List<Object> SceneList = new List<Object>();
    static readonly List<Object> InCurrentScene = new List<Object>();

    bool _objectFoldout = false;
    bool _sceneFoldout = false;
    private bool _projectFoldout = false;
    private static bool _noReferencesFound = false;

    [MenuItem("Unity Support Tools/Project/What objects use this?")]
    private static void LaunchReferenceFilterWindow()
    {
        // make sure the scene files are available to search
        PreLoadScenes();
        _referenceFilter = GetWindow<ReferenceFilter>();
    }

    private static void ClearResults()
    {
        Matches.Clear();
        InCurrentScene.Clear();
        SceneList.Clear();
        _noReferencesFound = false;
    }

    private static bool AreListsEmpty()
    {
        return Matches.Count + InCurrentScene.Count + SceneList.Count == 0;
    }

    void OnGUI()
    {
        if (GUILayout.Button("Search"))
            OnSearchForReferences();
        if (GUILayout.Button("Clear Search Results"))
            ClearResults();

        Sel = EditorGUILayout.ObjectField("Selection", Sel, typeof(Object), false, GUILayout.ExpandWidth(true));

        // avoids null reference exception spam
        string selectionName = Sel != null ? Sel.name : "";

        _objectFoldout = EditorGUILayout.Foldout(_objectFoldout, "Objects in the current scene referencing " + selectionName);
        if (_objectFoldout)
        {
            EditorGUIUtility.LookLikeControls(0, _referenceFilter.position.width);
            foreach (var match in Matches)
                EditorGUILayout.ObjectField("", match, typeof(Object), false, GUILayout.ExpandWidth(true));
        }
        
        _projectFoldout = EditorGUILayout.Foldout(_projectFoldout, "Objects in Project that reference " + selectionName);
        if (_projectFoldout)
        {
            EditorGUIUtility.LookLikeControls(0, _referenceFilter.position.width);
            foreach (var match in InCurrentScene)
                EditorGUILayout.ObjectField("", match, typeof(Object), false, GUILayout.ExpandWidth(true));
        }

        _sceneFoldout = EditorGUILayout.Foldout(_sceneFoldout, "Scenes that contain objects referencing " + selectionName);
        if (_sceneFoldout)
        {
            EditorGUIUtility.LookLikeControls(0, _referenceFilter.position.width);
            foreach (var scene in SceneList)
                EditorGUILayout.ObjectField("", scene, typeof(Object), false, GUILayout.ExpandWidth(true));
        }

       if (_noReferencesFound)
        EditorGUILayout.LabelField("", selectionName + " is not referenced by anything in this project");
        
        Repaint();
    }

    void Update()
    {
        Repaint();
    }

    static void PreLoadScenes()
    {
        // we need to find the scene files and select them so that they will appear in the AssetDatabase
        // unity will only add the scene to the assetdatabase once it has been clicked on
        var files = System.IO.Directory.GetFiles(Application.dataPath, "*.unity", System.IO.SearchOption.AllDirectories);
        var l = Application.dataPath.Length;
        foreach (var s in files)
        {
            string temp = s.Remove(0, l);
            temp = temp.Insert(0, "Assets");
            temp = temp.Replace("\\", "/");
            AssetDatabase.LoadAssetAtPath(temp, typeof(Object));
        }
    }

    private static bool GetCurrentSelection(out string _object)
    {
        if (AssetDatabase.Contains(Sel))
        {
            int iid = Sel.GetInstanceID();
            if (AssetDatabase.IsMainAsset(iid))
            {
                _object = System.IO.Path.GetFileNameWithoutExtension(AssetDatabase.GetAssetPath(iid));
                return true;
            }
        }
        _object = "";
        return false;
    }

    private static string GetCurrentScene()
    {
        return System.IO.Path.GetFileNameWithoutExtension(EditorApplication.currentScene);
    }

    private static void AddReferencesToList(Object _currentObject, string _ref, Object[] _dependencyList, List<Object> _listToAddTo)
    {
        foreach (Object dependency in _dependencyList)
            if (string.Compare(dependency.name, _ref) == 0  string.Compare(dependency.name , "HandlesGO") != 0)
            {
                // check for game objects and dont include child objects as they generate duplicates for each component
                var gameobject = _currentObject as GameObject;
                if (gameobject != null  gameobject.transform.parent == null  gameobject != Selection.activeObject  !Matches.Contains(_currentObject))
                    _listToAddTo.Add(_currentObject); // add it to our list to highlight

                //add scene files(DefaultAsset) 
                if (_currentObject.ToString().Contains("DefaultAsset")  !SceneList.Contains(_currentObject))
                    SceneList.Add(_currentObject);

                // check for materials as they are not game objects
                var mat = _currentObject as Material;
                if (mat != null  mat != Selection.activeObject)
                    _listToAddTo.Add(_currentObject); // add it to our list to highlight
            }
    }

    private static void OnSearchForReferences()
    {
        // make sure scene files that have been added since the window was luanched are included
        PreLoadScenes();
        ClearResults();
        string final;
        bool cancel = false;

        if (!GetCurrentSelection(out final))
        {
            Debug.Log("Asset is not contained in the AssetDatabase. It is likely that this object is only present in the current scene");
            return;
        }

        // get everything
        Object[] allObjects = Resources.FindObjectsOfTypeAll(typeof(Object));

        var noOfObjects = allObjects.Length;
        var searchedSoFar = 0;

        //loop through everything
        foreach (Object obj in allObjects)
        {
            // hack fix
            if (obj.name == "HandlesGO") continue;
            // All objects
            Object[] dependencies = EditorUtility.CollectDependencies(new[] { obj });
            AddReferencesToList(obj, final, dependencies, Matches);

            // progress bar logic
            searchedSoFar++;
           cancel = EditorUtility.DisplayCancelableProgressBar("Searching all references", "Completed: "  + ((searchedSoFar / (float)noOfObjects))*100.0f + "%" ,searchedSoFar/(float) noOfObjects);
           if (cancel)
           {
               ClearResults();
               _noReferencesFound = true;
               EditorUtility.ClearProgressBar();
               return;
           }
        }

        searchedSoFar = 0;
        foreach (var scene in SceneList)
        {
            noOfObjects = SceneList.Count;
            //get the objects that are scene dependencies
            Object[] dependencies = EditorUtility.CollectDependencies(new[] { scene });
            foreach (var dependency in dependencies.Where(dependency => Matches.Contains(dependency)))
            {
                InCurrentScene.Add(dependency);
                Matches.Remove(dependency);
            }
            EditorUtility.DisplayProgressBar("Gathering referenced scenes", "Completed: " + ((searchedSoFar / (float)noOfObjects)) * 100.0f + "%", searchedSoFar / (float)noOfObjects);
        }

        Selection.objects = Matches.ToArray();
        EditorUtility.ClearProgressBar();
        _noReferencesFound = AreListsEmpty();
    }
}

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:

Wow. Cool. Should post this in Unify. Thanks for the share though. :smile:

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.

Quick update to this before it goes on the Asset store as soon as I get a chance. Free of course.