查找某个资源的引用 || 查找资源在场景中的引用

SearchReferenceInSceneEditorWindow.cs

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;

namespace act.editor.ui
{
    public class SearchReferenceInSceneEditorWindow : EditorWindow
    {
        [SerializeField] public List<Object> objectList = new List<Object>();
        
        private SerializedObject serializedObject;
        private SerializedProperty objListProperty;
        
        private HashSet<Object> tempObjects;

        [MenuItem("Rex/@UI_System/检测资源是否在场景中被引用",   false,48160001)]
        static void SearchRefrence()
        {
            var window = (SearchReferenceInSceneEditorWindow)EditorWindow.GetWindow(typeof(SearchReferenceInSceneEditorWindow), false, "检测资源的场景引用", true);
            window.Show();
        }

        private void OnEnable()
        {
	        serializedObject = new SerializedObject(this);
	        objListProperty = serializedObject.FindProperty("objectList");
	        if (tempObjects == null)
	        {
		        tempObjects = new HashSet<Object>();
	        }
        }

        private void OnGUI()
        {
	        EditorGUILayout.PropertyField(objListProperty, true);

	        if (GUILayout.Button("检测"))
	        {
		        tempObjects.Clear();
		        for (int i = 0; i < objectList.Count; i++)
		        {
			        var targetObject = objectList[i];
			        if (targetObject != null)
			        {
				        var assetPath = AssetDatabase.GetAssetPath(targetObject);
				        if (targetObject is DefaultAsset && AssetDatabase.IsValidFolder(assetPath))
				        {
					        //选中了文件夹
					        var assets = AssetDatabase.FindAssets($"", new[] { assetPath });
					        foreach (var guid in assets)
					        {
						        var asset = AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GUIDToAssetPath(guid));
						        tempObjects.Add(asset);
					        }
				        }
				        else
				        {
					        tempObjects.Add(targetObject);
				        }
			        }
		        }

		        if (tempObjects.Count > 0)
		        {
			        FindReferencesTo(tempObjects);
		        }
	        }
        }

        private static void FindReferencesTo(HashSet<Object> toFindObjects)
		{
			var referencedBy = new List<UnityEngine.Object>();
			var allObjects = FindAllSceneGameObjects();
			for (int j = 0; j < allObjects.Count; j++)
			{
				GameObject go = allObjects[j];
				if (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance)
				{
					if (toFindObjects.Contains(PrefabUtility.GetPrefabParent(go)))
					{
						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[i];
					if (!component)
						continue;
					var so = new SerializedObject(component);
					var sp = so.GetIterator();
					while (sp.NextVisible(true))
					{
						var name = sp.displayName;
						if (sp.propertyType == SerializedPropertyType.ObjectReference)
						{
							var target = sp.objectReferenceValue;
							if (target != null)
							{
								var spType = target.GetType();
								string toName = string.Format("{0}.{1}", target.name, target.GetType().Name);
								string log = string.Format("'{0}' referenced by '{1}' (Component: '{2}')", toName, component.name, component.GetType().Name);
								if (toFindObjects.Contains(target))
								{
									Debug.Log(log, component);
									referencedBy.Add(component.gameObject);
								}
								else if (target is Sprite sprite)
								{
									if (toFindObjects.Contains(sprite.texture))
									{
										Debug.Log(log, component);
										referencedBy.Add(component.gameObject);
									}
								}
								else if (target is Material material)
								{
									
								}
							}
						}
					}
				}
			}
			if (referencedBy.Count > 0)
				Selection.objects = referencedBy.ToArray();
			else
				Debug.Log(string.Format("no references in scene"));
		}

        public static List<GameObject> FindAllSceneGameObjects()
		{
			List<GameObject> results = new List<GameObject>();
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				var scene = SceneManager.GetSceneAt(i);
				if (scene.isLoaded)
				{
					var rootGameObjects = scene.GetRootGameObjects();
					for (int j = 0; j < rootGameObjects.Length; j++)
					{
						var transforms = rootGameObjects[j].GetComponentsInChildren<Transform>(true);
						foreach (var transform in transforms)
						{
							results.Add(transform.gameObject);
						}
					}
				}
			}
			
			//为了查找 DontDestroyOnLoad 场景中的物体,需要先 DontDestroyOnLoad 一个 GameObject,才能获取它的 Scene
			var go = new GameObject();
			DontDestroyOnLoad(go);
			Scene dontDestroyScene = go.scene;
			DestroyImmediate(go);
			var extraRootGameObjects = dontDestroyScene.GetRootGameObjects();
			for (int j = 0; j < extraRootGameObjects.Length; j++)
			{
				var transforms = extraRootGameObjects[j].GetComponentsInChildren<Transform>(true);
				foreach (var transform in transforms)
				{
					results.Add(transform.gameObject);
				}
			}
			return results;
		}
        
    }
}

SearchRefrenceEditorWindow.cs

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.IO;

namespace act.editor.ui
{
    public class SearchRefrenceEditorWindow : EditorWindow
    {
        /// <summary>
        /// 查找引用
        /// </summary>
        [MenuItem("Rex/@UI_System/检测资源是否被引用 %p",   false,48160000)]
        static void SearchRefrence()
        {
            SearchRefrenceEditorWindow window = (SearchRefrenceEditorWindow)EditorWindow.GetWindow(typeof(SearchRefrenceEditorWindow), false, "检测资源是否被引用窗口", true);
            window.Show();
        }
        
        [MenuItem("Assets/UI_System/检测资源是否被引用",false,30)]
        static void ResolveMaterialReference()
        {

            szSelectAsset = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
            assetPath = "Assets/ResourceRex/UI";
            
            SearchRefrence();

        }

        public static void ResolveMaterialReference(Object obj, string path)
        {
            szSelectAsset = new Object[1] { obj };
            assetPath     = path;
            SearchRefrence();
        }


        private SerializedObject serializedObject;
        private SerializedProperty serializedProperty;

        public static string assetPath = "Assets/ResourceRex";
        [SerializeField]
        public  List<Object> searchObject = new List<Object>();
        private static Object[] szSelectAsset;
        private Dictionary<Object, List<Object>> result = new Dictionary<Object, List<Object>>();
        private Dictionary<string, Object> guidList = new Dictionary<string, Object>();
        private Vector3 scrollViewPosProject = Vector2.zero;

        private GUIStyle style = new GUIStyle();


        void OnEnable()
        {
            serializedObject = new SerializedObject(this);
            serializedProperty = serializedObject.FindProperty("searchObject");
            
            //style.fontSize = 12;
            style.normal.textColor = Color.white;
            style.alignment = TextAnchor.MiddleLeft;
            
            
            if (!szSelectAsset.IsNullOrEmpty())
            {
                foreach (var obj in szSelectAsset)
                {
                    // 忽略文件夹
                    if (obj is DefaultAsset fDefaultAsset)
                    {
                        continue;
                    }

                    searchObject.Add(obj);
                }
                szSelectAsset .Clear();
                serializedObject.ApplyModifiedProperties();
            }
        }


        private void OnGUI()
        {
            
            serializedObject.Update();

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.BeginVertical();
            assetPath = EditorGUILayout.TextField("被检测目录: ", assetPath/*, GUILayout.Width(500)*/);
            EditorGUILayout.PropertyField(serializedProperty, true);


            if (GUILayout.Button("开始检测", /*GUILayout.Width(500),*/GUILayout.Height(30)))
            {
                guidList.Clear();
                result.Clear();

                foreach (var obj in searchObject)
                {
                    string objPath = AssetDatabase.GetAssetPath(obj);
                    string assetGuid = AssetDatabase.AssetPathToGUID(objPath);
                    guidList[assetGuid] = obj;
                }


                //只检查prefab
                string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { assetPath });

                int length = guids.Length;
                for (int i = 0; i < length; i++)
                {
                    string filePath = AssetDatabase.GUIDToAssetPath(guids[i]);
                    bool cancel = EditorUtility.DisplayCancelableProgressBar($"Checking... [{i}/{length}]", $"..{filePath.Replace(assetPath, "")}", (float)i / length);
                    if (cancel) break;
                    //检查是否包含guid
                    string content = File.ReadAllText(filePath);
                    foreach (var guid in guidList)
                    {
                        if (content.Contains(guid.Key))
                        {
                            Object fileObject = AssetDatabase.LoadAssetAtPath(filePath, typeof(Object));
                            if (!result.ContainsKey(guid.Value))
                            {
                                result[guid.Value] = new List<Object>();
                            }
                            result[guid.Value].Add(fileObject);
                        }
                        else
                        {
                            if (!result.ContainsKey(guid.Value))
                            {
                                result[guid.Value] = new List<Object>();
                            }
                        }
                    }
                }

                EditorUtility.ClearProgressBar();
            }

            if (result.Count > 0)
            {

                string resultStr = "------------------------------------检 测 结 果------------------------------------";
                //float forwardWidth = (position.width - resultStr.Length) / 2;
                //EditorGUILayout.BeginHorizontal();
                //EditorGUILayout.LabelField("", GUILayout.Width(forwardWidth));
                EditorGUILayout.TextArea(resultStr, style);
                scrollViewPosProject = EditorGUILayout.BeginScrollView(scrollViewPosProject);
                foreach (var objs in result)
                {
                    EditorGUILayout.Space();

                    bool addDelete = objs.Value.Count <= 0;
                    if (addDelete) EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.ObjectField("资源名称:", objs.Key, typeof(Object), true/*, GUILayout.Width(480)*/);
                    if (addDelete)
                    {
                        if (GUILayout.Button("删除", GUILayout.Width(60)))
                        {
                            if (EditorUtility.DisplayDialog("警告", $"是否要删除文件{objs.Key}", "确定", "取消"))
                            {
                                string path = AssetDatabase.GetAssetPath(objs.Key);
                                AssetDatabase.DeleteAsset(path);

                                // 这里还可以再完善下,删除文件后的UI,显示的一下问题

                                AssetDatabase.Refresh();
                            }
                        }
                        if (GUILayout.Button("复制资源名称", GUILayout.Width(60)))
                        {
                            TextEditor textEditor = new TextEditor();
                            textEditor.text = objs.Key.name;
                            textEditor.SelectAll();
                            textEditor.Copy();
                            Debug.LogError($"[{objs.Key.name}] 已复制到剪切板");
                        }
                        EditorGUILayout.EndHorizontal();
                    }
                    else
                    {
                        if (GUILayout.Button("批量替换", GUILayout.Width(500),GUILayout.Height(20)))
                        {
                            if (EditorUtility.DisplayDialog("批量", $"确认是否批将更换{objs.Key}资源更换为其他资源", "确定", "取消"))
                            {
                                BatchReplaceReferencesEditorWindow.szReplaceAsset = objs.Key;
                                BatchReplaceReferencesEditorWindow.szSelectAsset = new List<Object>(objs.Value);
                                BatchReplaceReferencesEditorWindow.OpenWindow();
                            } 
                        }
                    }

                    foreach (var obj in objs.Value)
                    {
                        EditorGUILayout.ObjectField(obj, typeof(Object), true/*, GUILayout.Width(430)*/);
                    }

                }
                EditorGUILayout.EndScrollView();
                EditorGUILayout.Space();
                EditorGUILayout.BeginHorizontal();



                if (GUILayout.Button("清理检测结果", GUILayout.Width(position.width / 2)))
                {
                    result.Clear();
                    guidList.Clear();
                    searchObject.Clear();
                }
                if (GUILayout.Button("保存检测结果", GUILayout.Width(position.width / 2)))
                {
                    string savePath = Application.persistentDataPath +
                                      $"/图片引用{System.DateTime.Now.Month}-{System.DateTime.Now.Day}-{System.DateTime.Now.Hour}-{System.DateTime.Now.Minute}.txt";
                    List<string> names = new List<string>();
                    foreach (var objs in result)
                    {
                        names.Add($"资源名称:\t{objs.Key.name}");
                        foreach (var obj in objs.Value)
                        {
                            names.Add($"名称:{obj.name}\n路径:{AssetDatabase.GetAssetPath(obj)}");
                        }
                        names.Add("");
                    }
                    names.Add($"\n文件路径:{savePath}");
                    File.WriteAllLines(savePath, names);
                    System.Diagnostics.Process.Start(savePath);
                    Debug.Log($"引用资源名称保存至:{savePath}");
                    System.Diagnostics.Process.Start("explorer.exe", Application.persistentDataPath);  

                }
                EditorGUILayout.EndHorizontal();

            }
            EditorGUILayout.EndVertical();
        }
    }
}