// =============================================================================== // 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 foundPaths = new List(); 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("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(path); EditorGUIUtility.PingObject(obj); Selection.activeObject = obj; } EditorGUILayout.EndHorizontal(); } } }