Code to mimic "Find references in scene"

Hi, I have a feeling that this is a stupid question… but is there a simple function to programmatically get a list of references to an Asset from a given scene (or, even, within a given GameObject)?

maybe its too late but I leave the code here. Works for prefab references and for any component via component context menu

[MenuItem("CONTEXT/Component/Find references to this")]
private static void FindReferences(MenuCommand data)
{
	Object context = data.context;
	if (context)
	{
		var comp = context as Component;
		if (comp)
			FindReferencesTo(comp);
	}
}

[MenuItem("Assets/Find references to this")]
private static void FindReferencesToAsset(MenuCommand data)
{
	var selected = Selection.activeObject;
	if (selected)
		FindReferencesTo(selected);
}

private static void FindReferencesTo(Object to)
{
	var referencedBy = new List<Object>();
	var allObjects = Object.FindObjectsOfType<GameObject>();
	for (int j = 0; j < allObjects.Length; j++)
	{
		var go = allObjects[j];

		if (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance)
		{
			if (PrefabUtility.GetPrefabParent(go) == to)
			{
				Debug.Log(string.Format("referenced by {0}, {1}", go.name, go.GetType()), go);
				referencedBy.Add(go);
			}
		}

		var components = go.GetComponents<Component>();
		for (int i = 0; i < components.Length; i++)
		{
			var c = components*;*
  •  	if (!c) continue;*
    
  •  	var so = new SerializedObject(c);*
    
  •  	var sp = so.GetIterator();*
    
  •  	while (sp.NextVisible(true))*
    
  •  		if (sp.propertyType == SerializedPropertyType.ObjectReference)*
    
  •  		{*
    
  •  			if (sp.objectReferenceValue == to)*
    
  •  			{*
    
  •  				Debug.Log(string.Format("referenced by {0}, {1}", c.name, c.GetType()), c);*
    
  •  				referencedBy.Add(c.gameObject);*
    
  •  			}*
    
  •  		}*
    
  •  }*
    
  • }*

  • if (referencedBy.Any())*

  •  Selection.objects = referencedBy.ToArray();*
    
  • else Debug.Log(“no references in scene”);*
    }

Basically the opposite is easy - by calling EditorUtility.CollectReferences you can get a list of all of the things referenced by a game object - to do the inverse is more tricky.

Basically if you loop through every object in your scene and call collect references on it then add the references to a dictionary that references back to the finding object you build a reverse lookup - unfortunately the next complexity is that collecting references on a game object also collects them on the children - which means your best bet is to ensure that you start with the parents and work your way down, removing parent references when a child is added.

So what I do is this:

  • Find all of the game objects in the scene using GameObject.FindObjectsOfType(typeof(GameObject))
  • Order them by the number of parents they have (in ascending order)
  • For each one capture the dependencies using EditorUtility.CollectDependencies
  • For each dependency make an entry in a Dictionary<object, List> for the dependency and add the current game object to the list
  • For each parent of the current game object - remove it from the List.

At the end of that - given a dependency you have a list of GameObjects that reference it - the only problem is that if it is also explicitly referenced by a parent that parent won’t show up in the list.

Hi @sharsnik ! There is a solution (not the code, but with sources included) - with nice & simple GUI that will:

  • show you particular fields where your asset is used
  • let you easily replace it
  • search for usages of assets that are using your one

You can search for:

  • Asset usages in Project
  • GameObject usages in Scene
  • Component usages in Scene

Asset store link:

90270-x.jpg

Here is improved script of @ToBeGlad (thanks for nice clues, man!). Added several ergonomic enhancements and ability for search for referenced GameObjects only as Components.
Enjoy :slight_smile:

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

namespace CarrotOnFire.Assets.Editor
{
public class CarrotFindReferencesHelper : MonoBehaviour
{
[MenuItem(“CONTEXT/Component/Find References to Component”)]
private static void FindReferences(MenuCommand data)
{
Object context = data.context;
if (context)
{
var comp = context as Component;
if (comp)
FindReferencesTo(comp);
}
}

[MenuItem("GameObject/Find References to Selected", false, 0)]
public static void FindReferencesToAsset()
{
  var selected = Selection.activeObject;
  if (selected)
    FindReferencesTo(selected);
}

private static void FindReferencesTo(Object to)
{
  var referencedBy = new List<Object>();
  var allObjects = Object.FindObjectsOfType<GameObject>();
  bool toIsGameObject = to is GameObject;
  Component[] toComponents = toIsGameObject ? ((GameObject)to).GetComponents<Component>() : null;
  string toName = toIsGameObject ? to.name : string.Format("{0}.{1}", to.name, to.GetType().Name);
  for (int j = 0; j < allObjects.Length; j++)
  {
    GameObject go = allObjects[j];

    if (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance)
    {
      if (PrefabUtility.GetPrefabParent(go) == to)
      {
        Debug.Log(string.Format("referenced by {0}, {1}", go.name, go.GetType()), go);
        referencedBy.Add(go);
      }
    }

    var components = go.GetComponents<Component>();
    for (int i = 0; i < components.Length; i++)
    {
      var component = components*;*

if (!component) continue;
var so = new SerializedObject(component);
var sp = so.GetIterator();
while (sp.NextVisible(true))
{
if (sp.propertyType == SerializedPropertyType.ObjectReference)
{
if (sp.objectReferenceValue == to)
{
Debug.Log(string.Format(“‘{0}’ referenced by ‘{1}’ (Component: ‘{2}’)”, toName, component.name, component.GetType().Name), component);
referencedBy.Add(component.gameObject);
}
else if (toComponents != null)
{
bool found = false;
foreach (Component toComponent in toComponents)
{
if (sp.objectReferenceValue == toComponent)
{
found = true;
referencedBy.Add(component.gameObject);
}
}
if (found)
Debug.Log(string.Format(“‘{0}’ referenced by ‘{1}’ (Component: ‘{2}’)”, toName, component.name, component.GetType().Name), component);
}
}
}
}
}
if (referencedBy.Count > 0)
Selection.objects = referencedBy.ToArray();
else Debug.Log(string.Format(“‘{0}’: no references in scene”, toName));
}
}
}

I would personally try and stay away from iterating the scene objects, this can get expensive quickly. This is a O(n) operation on your selected object. I don’t know if you’re talking about a child object.

Instead implement a design that allows you to store the objects you need in a list and find what you need in that list. Just attach this to each of your objects you need a reference for.

#LogicComponent.cs
List<GameObject> ListOfChildren = new List<GameObject>();
void LogicComponent{
    if (transform.parent != null)
        transform.parent.GetComponent<LogicComponent>().ListOfChildren .Add(this.GameObject)
}

If you want to have the result IN CODE, I am not sure.

BUT if you want to replicate right click + find references, then read on (it can be a huge timesaver).

When you right click + Find References (or right click + F for faster), unity inputs a search string in the scene hierarchy like this ::

ref:L_FG_Assets_Pack1.0/L_FG_Assets_Pack_Lite/Perfabs/Plant/Plant05_b.prefab

You can replicate that functionality by using a script to manually input text in unity’s filter.

You can use the attached script with the following hotkeys ::

Select a project item and then,

  • Ctrl+F :: Searches the scene for name

  • Alt+Shift+F :: Searches the scene by reference (what the OP wanted)link text

    [using System.Reflection;
    using UnityEditor;
    using UnityEngine;

    namespace TGP
    {
    public static class FindReferences
    {
    [MenuItem(“Tools/Toggle Inspector Lock %f”)] // Ctrl + F
    public static void SetSearchFilter_CurrentItem_Name()
    {
    // Grab the selected item
    UnityEngine.Object obj = Selection.activeObject;
    if (obj == null) return;

             SetSearchFilter(obj.name, HierarchyFilterMode.All);
         }
    
         [MenuItem("Tools/Toggle Inspector Lock #&f")] // Ctrl + Shift + F
         public static void SetSearchFilter_CurrentItem_References()
         {
             // Grab the selected item 
             UnityEngine.Object obj = Selection.activeObject;
             if (obj == null) return;
    
             string path = AssetDatabase.GetAssetPath(obj);
    
             // Trim the beginning, otherwise it doesn't work
             path = path.Remove(0, "Assets/".Length);
    
             string searchTerm = "ref: " + path;
             SetSearchFilter(searchTerm, HierarchyFilterMode.All);
         }
    
         // Original from https://stackoverflow.com/questions/29575964/setting-a-hierarchy-filter-via-script, switched to enums
         public static void SetSearchFilter(string filter, HierarchyFilterMode filterMode)
         {
    
             SearchableEditorWindow[] windows = (SearchableEditorWindow[])Resources.FindObjectsOfTypeAll(typeof(SearchableEditorWindow));
             SearchableEditorWindow hierarchy = null;
             foreach (SearchableEditorWindow window in windows)
             {
    
                 if (window.GetType().ToString() == "UnityEditor.SceneHierarchyWindow")
                 {
    
                     hierarchy = window;
                     break;
                 }
             }
    
             if (hierarchy == null)
                 return;
    
             MethodInfo setSearchType = typeof(SearchableEditorWindow).GetMethod("SetSearchFilter", BindingFlags.NonPublic | BindingFlags.Instance);
             object[] parameters = new object[] { filter, (int)filterMode, false };
    
             setSearchType.Invoke(hierarchy, parameters);
         }
    
         /*
         public const int FILTERMODE_ALL = 0;
         public const int FILTERMODE_NAME = 1;
         public const int FILTERMODE_TYPE = 2;
         */
         public enum HierarchyFilterMode { All = 0, Name = 1, Type = 2 }
     }
    

    }][2]

@sharsnik

There is not a simple funciton to find all references to an asset, but there is a tool which can do this.

Check it out here: Unity Asset Store - The Best Assets for Game Making