161 lines
5.6 KiB
C#
161 lines
5.6 KiB
C#
|
|
// ===============================================================================
|
||
|
|
// ReferenceFinderTool - Deep Dependency Analysis for Unity Assets
|
||
|
|
//
|
||
|
|
// Creator: Scove
|
||
|
|
// Last Updated: 2024-05-08
|
||
|
|
// Version: 2.0
|
||
|
|
//
|
||
|
|
// Purpose:
|
||
|
|
// Finds every asset in the project that references the selected item by
|
||
|
|
// scanning GUIDs inside Unity's YAML-based files (Scenes, Prefabs, Materials, etc.).
|
||
|
|
//
|
||
|
|
// Key Features:
|
||
|
|
// 1. Interactive Result List: Click any result to highlight the asset in Project window.
|
||
|
|
// 2. Wide Scope: Scans all text-based assets (Mat, PhysMat, Controller, Asset, etc.).
|
||
|
|
// 3. Optimized Search: Faster file reading and progress bar with Cancel support.
|
||
|
|
// 4. Clean UI: Integrated as a professional Editor Window.
|
||
|
|
//
|
||
|
|
// How to Use:
|
||
|
|
// 1. Right-click any asset in the Project window.
|
||
|
|
// 2. Select "Find References (Deep Scan)".
|
||
|
|
// 3. View the results in the pop-up window.
|
||
|
|
// ===============================================================================
|
||
|
|
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEngine;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
|
||
|
|
namespace Editor
|
||
|
|
{
|
||
|
|
public class ReferenceFinderTool : EditorWindow
|
||
|
|
{
|
||
|
|
private static List<string> foundPaths = new List<string>();
|
||
|
|
private static string targetAssetName = "";
|
||
|
|
private static string targetAssetGUID = "";
|
||
|
|
private Vector2 scrollPosition;
|
||
|
|
|
||
|
|
[MenuItem("Assets/Find References (Deep Scan)", false, 25)]
|
||
|
|
public static void FindReferences()
|
||
|
|
{
|
||
|
|
Object selected = Selection.activeObject;
|
||
|
|
if (selected == null) return;
|
||
|
|
|
||
|
|
string path = AssetDatabase.GetAssetPath(selected);
|
||
|
|
targetAssetGUID = AssetDatabase.AssetPathToGUID(path);
|
||
|
|
targetAssetName = selected.name;
|
||
|
|
|
||
|
|
if (string.IsNullOrEmpty(targetAssetGUID)) return;
|
||
|
|
|
||
|
|
PerformDeepScan();
|
||
|
|
|
||
|
|
// Open the results window
|
||
|
|
ReferenceFinderTool window = GetWindow<ReferenceFinderTool>("Reference Finder");
|
||
|
|
window.minSize = new Vector2(400, 300);
|
||
|
|
window.Show();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void PerformDeepScan()
|
||
|
|
{
|
||
|
|
foundPaths.Clear();
|
||
|
|
|
||
|
|
// We look for all assets that are usually saved in Text/YAML format
|
||
|
|
// Added: Materials, Animators, ScriptableObjects, etc.
|
||
|
|
string[] allGuids = AssetDatabase.FindAssets("t:Prefab t:Scene t:Material t:PhysicMaterial t:RuntimeAnimatorController t:ScriptableObject t:AnimatorOverrideController");
|
||
|
|
|
||
|
|
int total = allGuids.Length;
|
||
|
|
|
||
|
|
for (int i = 0; i < total; i++)
|
||
|
|
{
|
||
|
|
string assetPath = AssetDatabase.GUIDToAssetPath(allGuids[i]);
|
||
|
|
|
||
|
|
// Update Progress Bar
|
||
|
|
bool isCanceled = EditorUtility.DisplayCancelableProgressBar(
|
||
|
|
"Searching References",
|
||
|
|
$"Scanning: {Path.GetFileName(assetPath)}",
|
||
|
|
(float)i / total);
|
||
|
|
|
||
|
|
if (isCanceled) break;
|
||
|
|
|
||
|
|
// Check if the asset file contains the Target GUID
|
||
|
|
if (FileContainsGUID(assetPath, targetAssetGUID))
|
||
|
|
{
|
||
|
|
foundPaths.Add(assetPath);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorUtility.ClearProgressBar();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static bool FileContainsGUID(string path, string guid)
|
||
|
|
{
|
||
|
|
if (!File.Exists(path)) return false;
|
||
|
|
|
||
|
|
// Using StreamReader is faster than File.ReadAllText for very large files
|
||
|
|
using (StreamReader reader = new StreamReader(path))
|
||
|
|
{
|
||
|
|
string line;
|
||
|
|
while ((line = reader.ReadLine()) != null)
|
||
|
|
{
|
||
|
|
if (line.Contains(guid)) return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnGUI()
|
||
|
|
{
|
||
|
|
GUILayout.Label($"References for: {targetAssetName}", EditorStyles.boldLabel);
|
||
|
|
EditorGUILayout.LabelField($"GUID: {targetAssetGUID}", EditorStyles.miniLabel);
|
||
|
|
EditorGUILayout.Space();
|
||
|
|
|
||
|
|
if (foundPaths.Count == 0)
|
||
|
|
{
|
||
|
|
EditorGUILayout.HelpBox("No references found. Note: Ensure 'Asset Serialization' is set to 'Force Text' in Project Settings.", MessageType.Info);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
GUILayout.Label($"Found {foundPaths.Count} items:", EditorStyles.label);
|
||
|
|
|
||
|
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||
|
|
|
||
|
|
for (int i = 0; i < foundPaths.Count; i++)
|
||
|
|
{
|
||
|
|
DrawResultItem(foundPaths[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorGUILayout.EndScrollView();
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorGUILayout.Space();
|
||
|
|
if (GUILayout.Button("Rescan", GUILayout.Height(30)))
|
||
|
|
{
|
||
|
|
PerformDeepScan();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DrawResultItem(string path)
|
||
|
|
{
|
||
|
|
EditorGUILayout.BeginHorizontal("box");
|
||
|
|
|
||
|
|
// Get the asset icon
|
||
|
|
Texture icon = AssetDatabase.GetCachedIcon(path);
|
||
|
|
GUILayout.Label(icon, GUILayout.Width(16), GUILayout.Height(16));
|
||
|
|
|
||
|
|
// Display path
|
||
|
|
GUILayout.Label(path, EditorStyles.wordWrappedLabel);
|
||
|
|
|
||
|
|
GUILayout.FlexibleSpace();
|
||
|
|
|
||
|
|
// Ping Button
|
||
|
|
if (GUILayout.Button("Ping", GUILayout.Width(50)))
|
||
|
|
{
|
||
|
|
Object obj = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||
|
|
EditorGUIUtility.PingObject(obj);
|
||
|
|
Selection.activeObject = obj;
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorGUILayout.EndHorizontal();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|