Skip to content

Instantly share code, notes, and snippets.

@ffyhlkain
Last active October 18, 2023 00:54
Show Gist options
  • Star 52 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save ffyhlkain/2111681c1df404108837ffa5f71e0f68 to your computer and use it in GitHub Desktop.
Save ffyhlkain/2111681c1df404108837ffa5f71e0f68 to your computer and use it in GitHub Desktop.
A reference finder for assets in a #Unity3d project.
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;
namespace FoundationEditor.Editor.ReferenceFinder
{
public class ReferenceFinder : EditorWindow
{
private string guidToFind = string.Empty;
private string replacementGuid = string.Empty;
private Object searchedObject;
private Dictionary<Object, int> referenceObjects = new Dictionary<Object, int>();
private Vector2 scrollPosition;
private Stopwatch searchTimer = new Stopwatch();
[MenuItem("Window/Reference Finder")]
static void Init()
{
GetWindow(typeof(ReferenceFinder), false, "Reference Finder");
}
void OnGUI()
{
if (EditorSettings.serializationMode == SerializationMode.ForceText)
{
DisplayMainMenu();
if (GUILayout.Button("Search"))
{
searchTimer.Reset();
searchTimer.Start();
referenceObjects.Clear();
var pathToAsset = AssetDatabase.GUIDToAssetPath(guidToFind);
if (!string.IsNullOrEmpty(pathToAsset))
{
searchedObject = AssetDatabase.LoadAssetAtPath<Object>(pathToAsset);
var allPathToAssetsList = new List<string>();
var allPrefabs = Directory.GetFiles(Application.dataPath, "*.prefab", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allPrefabs);
var allMaterials = Directory.GetFiles(Application.dataPath, "*.mat", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allMaterials);
var allScenes = Directory.GetFiles(Application.dataPath, "*.unity", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allScenes);
var allControllers = Directory.GetFiles(Application.dataPath, "*.controller", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allControllers);
var allVfxGraphs = Directory.GetFiles(Application.dataPath, "*.vfx", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allVfxGraphs);
var allShaderGraphs = Directory.GetFiles(Application.dataPath, "*.shadergraph", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allShaderGraphs);
string assetPath;
for (int i = 0; i < allPathToAssetsList.Count; i++)
{
assetPath = allPathToAssetsList[i];
var text = File.ReadAllText(assetPath);
var lines = text.Split('\n');
for (int j = 0; j < lines.Length; j++)
{
var line = lines[j];
if (line.Contains("guid:"))
{
if (line.Contains(guidToFind))
{
var pathToReferenceAsset = assetPath.Replace(Application.dataPath, string.Empty);
pathToReferenceAsset = pathToReferenceAsset.Replace(".meta", string.Empty);
var path = "Assets" + pathToReferenceAsset;
path = path.Replace(@"\", "/"); // fix OSX/Windows path
var asset = AssetDatabase.LoadAssetAtPath<Object>(path);
if (asset != null)
{
if (!referenceObjects.ContainsKey(asset))
{
referenceObjects.Add(asset, 0);
}
referenceObjects[asset]++;
}
else
{
Debug.LogError(path + " could not be loaded");
}
}
}
}
}
searchTimer.Stop();
//Debug.Log("Search took " + searchTimer.Elapsed);
}
else
{
Debug.LogError("no asset found for GUID: " + guidToFind);
}
}
if (referenceObjects.Count > 0 && GUILayout.Button("Replace"))
{
ReplaceGuids(referenceObjects, guidToFind, replacementGuid);
}
DisplayReferenceObjectList(referenceObjects);
}
else
{
DisplaySerializationWarning();
}
}
private void ReplaceGuids(Dictionary<Object, int> referenceObjects, string guidToFind, string replacementGuid)
{
foreach (var referenceObject in referenceObjects.Keys)
{
var assetPath = AssetDatabase.GetAssetPath(referenceObject);
var text = File.ReadAllText(assetPath);
var newText = text.Replace(guidToFind, replacementGuid);
Debug.Log("Overwriting file data of: " + referenceObject.name + "\n\nOld:\n" + text + "\n\nNew:\n" + newText);
File.WriteAllText(assetPath, newText);
}
AssetDatabase.Refresh(ImportAssetOptions.Default);
}
private void DisplaySerializationWarning()
{
GUILayout.Label("The Reference Finder relies on readable meta files (visible text serialization).\nPlease change your serialization mode in \"Edit/Project Settings/Editor/Version Control\"\n to \"Visisble Meta Files\" and \"Asset Serialization\" to \"Force Text\".");
}
private void DisplayReferenceObjectList(Dictionary<Object, int> referenceObjectsDictionary)
{
GUILayout.Label("Reference by: " + referenceObjectsDictionary.Count + " assets. (Last search duration: " + searchTimer.Elapsed + ")");
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
foreach (var referenceObject in referenceObjectsDictionary)
{
var referencingObject = referenceObject.Key;
var referenceCount = referenceObject.Value;
EditorGUILayout.ObjectField(referencingObject.name + " (" + referenceCount + ")", referencingObject, typeof(Object), false);
}
EditorGUILayout.EndScrollView();
}
private void DisplayMainMenu()
{
EditorGUILayout.BeginHorizontal();
searchedObject = EditorGUILayout.ObjectField(searchedObject != null ? searchedObject.name : "Drag & Drop Asset", searchedObject, typeof(Object), false);
if (GUILayout.Button("Get GUID") && searchedObject != null)
{
var pathToAsset = AssetDatabase.GetAssetPath(searchedObject);
guidToFind = AssetDatabase.AssetPathToGUID(pathToAsset);
}
EditorGUILayout.EndHorizontal();
var newGuidToFind = EditorGUILayout.TextField("GUID", guidToFind);
if (!guidToFind.Equals(newGuidToFind))
guidToFind = newGuidToFind;
if (referenceObjects != null && referenceObjects.Count > 0)
{
var newReplacementGuid = EditorGUILayout.TextField("Replacement", replacementGuid);
if (!replacementGuid.Equals(newReplacementGuid))
replacementGuid = newReplacementGuid;
}
}
}
}
@ffyhlkain
Copy link
Author

ffyhlkain commented Apr 10, 2017

Finding references to your assets

Ever wondered where (or if at all) one of your assets is used in your project? Me too, so I wrote this little helper to find references in prefabs, scenes and materials for assets.

Usage

Open the window from the Windows menu. Then simply drag & drop your asset from the Project View into the finder field.

dropdown

Press on "Get GUID" to get the GUID of your asset and press "Search".

reference_search

Note: The script will attempt a brute force search through all your assets in the project, reading through prefabs, scenes, materials and meta files to find the references. This could (though in my larger projects, it didn't took more than some seconds) take a lot of time, so I added a duration display to the output.

The script will only display the assets referencing your asset and how many times it is referenced! If you want to know on which GameObjects your asset is referenced in a scene, open the displayed scene and use the "Find references in scene" feature.

references_in_scene

How it works

Put the script into an "Editor" folder in your project (e.g. "Assets/Editor") to make it work,

The script needs visible meta files in text format, as it takes the GUID of your object from its meta file, then searches through all scenes, prefabs and materials (if you need more, its pretty easy to add) if the GUID is referenced anywhere else.

If you need to know what the GUID is, better take a look into the docs of Unity (pretty spare, but check the link):

Feedback

Wrote the script mostly for me own (or our artists) needs. If you have questions, suggestions, find bugs or just want to get in touch, you can follow me on Twitter @ffyhlkain.

@LucasTejero3DIQ
Copy link

I Added the material support, thank you for this

var allMaterials = Directory.GetFiles(Application.dataPath, "*.mat", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allMaterials);

@AgentOttsel
Copy link

AgentOttsel commented Jun 22, 2021

This is a pretty useful tool! Thanks for sharing it!

You can also add support for searching in ScriptableObjects by adding this to the OnGUI function after the other AddRange() calls:

var allAssets = Directory.GetFiles(Application.dataPath, "*.asset", SearchOption.AllDirectories);
allPathToAssetsList.AddRange(allAssets);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment