- Home /
How do I find which objects are referencing another?
If I click an object I can select its dependencies but I want to know the inverse of this. For example if I have texture how do I find all the objects that are using that texture.
I usually do this outside of Unity, on the command line. I get the asset's guid from its meta file, then search for all files containing the guid. You can make a batch/shell script to do it for you.
Answer by Gotlight · Oct 13, 2016 at 05:29 PM
For example if I have texture how do I find all the objects that are using that texture.
There is a product which allows you to search for usages (inverse to dependencies) in both Project and Scenes, e.g. it offers:
Interface for working with exact fields that are using selected asset
Search for usages of different asset types: Textures, Scenes, Scripts, Shaders, Materials, Sprites, Prefabs, Sounds...
Replacement of asset usages
Asset Store link:
Nice tool! I've got it month ago and I don't know how I'd've got before without it.
There you are. I don't often come on UA but I still manage to get your spam$$anonymous$$g :). For those of you not understanding, he does.
Answer by tnetennba · Aug 12, 2011 at 02:49 PM
This script will allow you to right click an object in the editor and will search your project and highlight the objects that reference it:
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
public class ReferenceFilter : EditorWindow
{
[MenuItem("Assets/What objects use this?", false, 20)]
private static void OnSearchForReferences()
{
string final = "";
List<UnityEngine.Object> matches = new List<UnityEngine.Object>();
int iid = Selection.activeInstanceID;
if (AssetDatabase.IsMainAsset(iid))
{
// only main assets have unique paths
string path = AssetDatabase.GetAssetPath(iid);
// strip down the name
final = System.IO.Path.GetFileNameWithoutExtension(path);
}
else
{
Debug.Log("Error Asset not found");
return;
}
// get everything
Object[] _Objects = FindObjectsOfTypeIncludingAssets(typeof(Object));
//loop through everything
foreach (Object go in _Objects)
{
// needs to be an array
Object[] g = new Object[1];
g[0] = go;
// All objects
Object[] depndencies = EditorUtility.CollectDependencies(g);
foreach (Object o in depndencies)
if (string.Compare(o.name.ToString(), final) == 0)
matches.Add(go);// add it to our list to highlight
}
Selection.objects = matches.ToArray();
matches.Clear(); // clear the list
}
}
You will need to place it in an editor folder for this to work.
Great little script -- saved me an awful head ache going through the hundreds of effect we have in our game (some of which share certain assets) and updating their texture sheet animations. Beauty.
@roberto_sc I did a long time ago now. @GrayedFox you are welcome
Nice script! although it solves the problem in the very basic way only..
Answer by Daniel-F · Apr 23, 2016 at 03:55 AM
I hacked together a version of @ricardo_arango's script which works in Unity 5.4 and has some additional functionality (optionally find references to any component in any currently-selected GameObjects, and highlight the referencing GameObject when you click the related log entry).
I realise it's not an elegant solution, but it works and I don't have time for elegance right now, so posting in case someone else finds a use for it. Tried to post it as a comment to his answer but it wouldn't submit for some reason.
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class BacktraceReference : EditorWindow {
private Component _theObject;
bool specificComponent = false;
[MenuItem("GameObject/What Objects Reference this?")]
public static void Init() {
GetWindow(typeof (BacktraceReference));
}
public void OnGUI() {
if( specificComponent = GUILayout.Toggle(specificComponent, "Match a single specific component") ) {
_theObject = EditorGUILayout.ObjectField("Component referenced : ", _theObject, typeof(Component), true) as Component;
if( _theObject == null )
return;
if( GUILayout.Button("Find Objects Referencing it") )
FindObjectsReferencing(_theObject);
}
else if( GUILayout.Button("Find Objects Referencing Selected GameObjects") )
{
GameObject[] objects = Selection.gameObjects;
if( objects==null || objects.Length < 1 ) {
GUILayout.Label("Select source object/s in Hierarchy.");
return;
}
foreach( GameObject go in objects ) {
foreach( Component c in go.GetComponents(typeof(Component)) ) {
FindObjectsReferencing(c);
}
}
}
}
private static void FindObjectsReferencing<T>(T mb) where T : Component {
var objs = Resources.FindObjectsOfTypeAll(typeof (Component)) as Component[];
if (objs == null) return;
foreach (Component obj in objs) {
FieldInfo[] fields =
obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance |
BindingFlags.Static);
foreach (FieldInfo fieldInfo in fields) {
if (FieldReferencesComponent(obj, fieldInfo, mb)) {
Debug.Log("Ref: Component " + obj.GetType() + " from Object " + obj.name +" references source component "+mb.GetType(), obj.gameObject);
}
}
}
}
private static bool FieldReferencesComponent<T>(Component obj, FieldInfo fieldInfo, T mb) where T : Component {
if (fieldInfo.FieldType.IsArray) {
var arr = fieldInfo.GetValue(obj) as Array;
foreach (object elem in arr) {
if (elem != null && mb != null && elem.GetType() == mb.GetType()) {
var o = elem as T;
if (o == mb)
return true;
}
}
}
else {
if (fieldInfo.FieldType == mb.GetType()) {
var o = fieldInfo.GetValue(obj) as T;
if (o == mb)
return true;
}
}
return false;
}
}
when i tried this it was getting an error on line 59: arr is null just do a null check:
if (arr == null) return;
worked for me after fixing that
hey thanks a lot for this. i've been looking around for a starting place to write my own on a project. i need something very tailored to a particular situation, and this is a perfect example of how to get it working.
i've been looking for exactly this type of solution, as the ones posted everywhere rely more on unity's internal editor tools. i knew right out of the gate that i was going to have to get into reflection, and i was a little afraid that i'd have to get into YA$$anonymous$$L parsing. this gets me out of that situation nicely.
thank you!
Answer by ricardo_arango · Apr 04, 2012 at 12:03 PM
This will work for all loaded objects (Not Assets in the Project):
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
public class BacktraceReference : EditorWindow {
private Class1 _theObject;
[MenuItem("GameObject/What Objects Reference this?")]
public static void Init() {
GetWindow(typeof (BacktraceReference));
}
public void OnGUI() {
_theObject = EditorGUILayout.ObjectField("Object referenced : ", _theObject, typeof (Class1), true) as Class1;
if (_theObject == null) return;
if (GUILayout.Button("Find Objects Referencing it"))
FindObjectsReferencing(_theObject);
}
private static void FindObjectsReferencing<T>(T mb) where T : Component {
var objs = Resources.FindObjectsOfTypeAll(typeof (Component)) as Component[];
if (objs == null) return;
foreach (Component obj in objs) {
FieldInfo[] fields =
obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance |
BindingFlags.Static);
foreach (FieldInfo fieldInfo in fields) {
if (FieldReferencesComponent(obj, fieldInfo, mb)) {
Debug.Log("Ref: Component " + obj.GetType() + " from Object " + obj.name);
}
}
}
}
private static bool FieldReferencesComponent<T>(Component obj, FieldInfo fieldInfo, T mb) where T : Component {
if (fieldInfo.FieldType.IsArray) {
var arr = fieldInfo.GetValue(obj) as Array;
foreach (object elem in arr) {
if (elem.GetType() == mb.GetType()) {
var o = elem as T;
if (o == mb)
return true;
}
}
}
else {
if (fieldInfo.FieldType == mb.GetType()) {
var o = fieldInfo.GetValue(obj) as T;
if (o == mb)
return true;
}
}
return false;
}
}
It's an example of a custom type of the Object you would be looking for. It could be a GameObject, Transform, Renderer, etc. Any reference type that derives from Component
Answer by ShawnFeatherly · May 21, 2018 at 06:36 PM
I made a script with similar functionality to @Daniel-F. It only handles a single scene file. Yet it handles all type of sub-references well, complex objects, arrays, etc... Tested in 2013.3.1f1 & 5.6.3f1
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
public class BacktraceReference : EditorWindow
{
/// <summary> The result </summary>
public static List<Component> ReferencingSelection = new List<Component>();
/// <summary> allComponents in the scene that will be searched to see if they contain the reference </summary>
private static Component[] allComponents;
/// <summary> Selection of gameobjects the user made </summary>
private static GameObject[] selections;
/// <summary>
/// Adds context menu to hierarchy window https://answers.unity.com/questions/22947/adding-to-the-context-menu-of-the-hierarchy-tab.html
/// </summary>
[UnityEditor.MenuItem("GameObject/Find Objects Referencing This", false, 48)]
public static void InitHierarchy()
{
selections = UnityEditor.Selection.gameObjects;
BacktraceSelection(selections);
GetWindow(typeof(BacktraceReference));
}
/// <summary>
/// Display referenced by components in window
/// </summary>
public void OnGUI()
{
if (selections == null || selections.Length < 1)
{
GUILayout.Label("Select source object/s from scene Hierarchy panel.");
return;
}
// display reference that is being checked
GUILayout.Label(string.Join(", ", selections.Where(go => go != null).Select(go => go.name).ToArray()));
// handle no references
if (ReferencingSelection == null || ReferencingSelection.Count == 0)
{
GUILayout.Label("is not referenced by any gameobjects in the scene");
return;
}
// display list of references using their component name as the label
foreach (var item in ReferencingSelection)
{
EditorGUILayout.ObjectField(item.GetType().ToString(), item, typeof(GameObject), allowSceneObjects: true);
}
}
// This script finds all objects in scene
private static Component[] GetAllActiveInScene()
{
// Use new version of Resources.FindObjectsOfTypeAll(typeof(Component)) as per https://forum.unity.com/threads/editorscript-how-to-get-all-gameobjects-in-scene.224524/
var rootObjects = UnityEngine.SceneManagement.SceneManager
.GetActiveScene()
.GetRootGameObjects();
List<Component> result = new List<Component>();
foreach (var rootObject in rootObjects)
{
result.AddRange(rootObject.GetComponentsInChildren<Component>());
}
return result.ToArray();
}
private static void BacktraceSelection(GameObject[] selections)
{
if (selections == null || selections.Length < 1)
return;
allComponents = GetAllActiveInScene();
if (allComponents == null) return;
ReferencingSelection.Clear();
foreach (GameObject selection in selections)
{
foreach (Component cOfSelection in selection.GetComponents(typeof(Component)))
{
FindObjectsReferencing(cOfSelection);
}
}
}
private static void FindObjectsReferencing<T>(T cOfSelection) where T : Component
{
foreach (Component sceneComponent in allComponents)
{
componentReferences(sceneComponent, cOfSelection);
}
}
/// <summary>
/// Determines if the component makes any references to the second "references" component in any of its inspector fields
/// </summary>
private static void componentReferences(Component component, Component references)
{
// find all fields exposed in the editor as per https://answers.unity.com/questions/1333022/how-to-get-every-public-variables-from-a-script-in.html
SerializedObject serObj = new SerializedObject(component);
SerializedProperty prop = serObj.GetIterator();
while (prop.NextVisible(true))
{
bool isObjectField = prop.propertyType == SerializedPropertyType.ObjectReference && prop.objectReferenceValue != null;
if (isObjectField && prop.objectReferenceValue == references)
{
ReferencingSelection.Add(component);
}
}
}
}
#endif
To make the editor window more useful, you can add this button to the beginning of OnGUI:
if (GUILayout.Button("Search current selection"))
{
selections = UnityEditor.Selection.gameObjects;
BacktraceSelection(selections);
}
This doesn't find inactive game objects. To fix, change GetComponentsInChildren calls to use includeInactive:
GetComponentsInChildren<Component>(includeInactive: true)
If you have lots of results, you can easily add EditorGUILayout.Begin/EndScrollView to scroll them (I used a try/finally to end without modifying the early returns). You could even try a coroutine to display EditorUtility.DisplayProgressBar and do updates in batches per frame (that's a lot of work so I haven't tried it).
You don't need to use try/finally for that, C#'s using
keyword (together with a simple wrapper class) does the same thing more cleanly.
So the class would be something like
public class EditorScrollView : System.IDisposable
{
public EditorScrollView()
{
EditorGUILayout.BeginScrollView();
}
public void Dispose()
{
EditorGUILayout.EndScrollView();
}
}
And then ins$$anonymous$$d of your try/finally you'd just have
using (new EditorScrollView())
{
// stuff in the scrollview
}
I generally do this for all the start/end paired layout functions. You never have to remember to close a section and you always know they'll close in the right order, plus the code's layout reflects that of the UI. Using lots of nested try/finally blocks for that would be far messier.
Even though it's editor-only code, I tend to avoid allocations in updates (like OnGUI).
However, I think you could change that to a struct and it would be good!
These types of references don't work:
public GameObject ref;
To include these objects referenced by GameObject ins$$anonymous$$d of Component in results, change componentReferences to look for the gameobject too:
if (isObjectField
&& (prop.objectReferenceValue == references // references the component itself
|| prop.objectReferenceValue == references.gameObject)) // references the component's owner
Your answer
Follow this Question
Related Questions
Weird problem with referencing game manager 1 Answer
Restoring Static Variables after DontDestroyOnLoad 1 Answer
Newly created scripts cannot be referenced 2 Answers
Can I access a script referenced in another script (without getcomponent)? 5 Answers
Passing reference of transform properties to coroutine animation? 1 Answer