using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using UnityEngine; using UnityEditor; using System.IO; using System.Linq; using Object = UnityEngine.Object; namespace ReferenceViewer { public class ReferenceViewer : EditorWindow { private List items = new List(); private Vector2 pos = Vector2.zero; private int selectedFilter; static Dictionary> sceneReference = new Dictionary>(); static Dictionary foldouts = new Dictionary(); [MenuItem("Window/ReferenceViewer")] private static void Open() { GetWindow(); } [MenuItem("Assets/Find References In Project", true)] private static bool FindValidate() { return Selection.objects.Length != 0; } [MenuItem("Assets/Find References In Project")] private static void Find() { sceneReference.Clear(); var path = "build/ReferenceViewer/data.dat"; var selectedObjects = Selection.objects; Action find = () => { var data = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(path)[0] as Data; Find(data, selectedObjects); }; if (File.Exists(path)) { find(); } else { if (EditorUtility.DisplayDialog("必要なデータがありません", "データを作成します。\nデータ作成に時間がかかりますがよろしいですか?", "はい", "いいえ")) { Creator.Build(find); } } } private static void Find(Data data, params Object[] selectedObjects) { var items = new List(); var guids = new List(); foreach (var selectedObject in selectedObjects) { var guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(selectedObject)); if (AssetDatabase.IsSubAsset(selectedObject)) { var item = new Item { searchedGUIContent = GetGUIContent(selectedObject), type = selectedObject.GetType() }; foreach (var assetData in data.assetData) { foreach (var subAssetData in assetData.subAssets) { var type = Assembly.Load("UnityEngine.dll").GetType(subAssetData.typeName); if (subAssetData.guid == guid && type == selectedObject.GetType()) { item.referencedGUIContents.Add(GetGUIContent(assetData.guid)); } } } item.referencedGUIContents = item.referencedGUIContents.Distinct( new CompareSelector(i => i.tooltip)) .ToList(); items.Add(item); } else { guids.Add(guid); foreach (var assetData in data.assetData.Where(assetData => guid == assetData.guid)) { foreach (var subAssetData in assetData.subAssets) { var type = Assembly.Load("UnityEngine.dll").GetType(subAssetData.typeName); var tex = AssetPreview.GetMiniTypeThumbnail(type); var item = items.FirstOrDefault( _item => _item.searchedGUIContent.tooltip == GetGUIContent(selectedObject).tooltip); if (item == null) { item = new Item {searchedGUIContent = GetGUIContent(selectedObject)}; items.Add(item); } item.type = type; item.referenceGUIContents.Add(new GUIContent(subAssetData.name, tex, AssetDatabase.GUIDToAssetPath(subAssetData.guid))); item.referenceGUIContents = item.referenceGUIContents.Distinct( new CompareSelector(i => i.text)) .ToList(); } } } } items.AddRange(guids .Select(guid => new { type = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), typeof(Object)).GetType(), searched = GetGUIContent(guid), referenced = data.assetData.Where(assetData => assetData.reference.Contains(guid)) .Select(assetData => GetGUIContent(assetData.guid)) .Where(c => c != null) .Where(c => c.image && guid != AssetDatabase.AssetPathToGUID(c.tooltip)) .OrderBy(c => c.image.name) .ToList(), reference = data.assetData.Find(item => item.guid == guid) .reference.Where(g => g != guid) .Select(g => GetGUIContent(g)) .Where(c => c != null) .Where(c => c.image) .OrderBy(c => c.image.name) .ToList() }) .Where(item => (item.referenced.Count != 0 || item.reference.Count != 0) && item.searched.image) .OrderBy(item => item.searched.image.name) .Select(item => new Item { type = item.type, searchedGUIContent = item.searched, referencedGUIContents = item.referenced, referenceGUIContents = item.reference }) .ToList()); items.Distinct(new CompareSelector(i => i.searchedGUIContent.tooltip)); foreach (var item in items) { foreach (var i in item.referencedGUIContents) { if (Path.GetExtension(i.tooltip) == ".unity") { var d = data.assetData.Find(asset => asset.assetPath == i.tooltip).sceneData; var key = item.searchedGUIContent.tooltip + " - " + i.tooltip; if (sceneReference.ContainsKey(key)) { sceneReference[key] .AddRange(d.Select(s => new GUIContent(s.name, AssetDatabase.GUIDToAssetPath(s.guid))) .ToList()); } else { sceneReference.Add(key, d.Select(s => new GUIContent(s.name, AssetDatabase.GUIDToAssetPath(s.guid))).ToList()); } } } } var window = GetWindow(); window.selectedFilter = 0; window.Results(items); } private void Results(List items) { this.items = items; } private void OnGUI() { EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Update", EditorStyles.toolbarButton)) { Creator.Build(); EditorGUIUtility.ExitGUI(); } EditorGUI.BeginChangeCheck(); var types = items.Select(item => item.type).ToArray(); var display = types.Select(t => t.Name).ToArray(); for (var i = 0; i < display.Length; i++) { switch (display[i]) { case "Object": display[i] = "Scene"; break; case "GameObject": display[i] = "Prefab"; break; } } ArrayUtility.Insert(ref display, 0, "All"); var selected = EditorGUILayout.Popup(selectedFilter, display, EditorStyles.toolbarPopup); if (EditorGUI.EndChangeCheck()) { selectedFilter = selected; } EditorGUILayout.EndHorizontal(); if (items.Count == 0) return; pos = EditorGUILayout.BeginScrollView(pos); var groupBy = items.GroupBy(item => item.searchedGUIContent.tooltip); foreach (var group in groupBy) { var enumerator = @group.GetEnumerator(); var item = new Item(); while (enumerator.MoveNext()) { item.type = enumerator.Current.type; item.searchedGUIContent = enumerator.Current.searchedGUIContent; item.referenceGUIContents.AddRange(enumerator.Current.referenceGUIContents); item.referencedGUIContents.AddRange(enumerator.Current.referencedGUIContents); } if (selectedFilter != 0 && item.type != types[selectedFilter - 1]) { continue; } EditorGUILayout.BeginHorizontal("box", GUILayout.Width(position.width * 0.96f)); DrawGUIContents(item.searchedGUIContent, item.referenceGUIContents); var iconSize = EditorGUIUtility.GetIconSize(); EditorGUIUtility.SetIconSize(Vector2.one * 32); GUILayout.Label(item.searchedGUIContent, GUILayout.Width(position.width * 0.3f), GUILayout.ExpandWidth(false)); EditorGUIUtility.SetIconSize(iconSize); PingObjectIfOnMouseDown(item.searchedGUIContent.tooltip); DrawGUIContents(item.searchedGUIContent, item.referencedGUIContents); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); } EditorGUILayout.EndScrollView(); } private void DrawGUIContents(GUIContent searched, List contents) { if (contents.Count != 0) { EditorGUILayout.BeginVertical(GUILayout.Width(position.width * 0.3f)); foreach (var content in contents) { if (IsScene(content)) { var key = searched.tooltip + " - " + content.tooltip; if (!foldouts.ContainsKey(key)) { foldouts.Add(key, false); } foldouts[key] = EditorGUILayout.Foldout(foldouts[key], content); if (foldouts[key]) { if (sceneReference.ContainsKey(key)) { EditorGUI.indentLevel++; foreach (var sceneData in sceneReference[key]) { if (searched.tooltip == sceneData.tooltip) EditorGUILayout.LabelField(sceneData, EditorStyles.miniLabel, GUILayout.Width(position.width * 0.3f), GUILayout.ExpandWidth(true)); } EditorGUI.indentLevel--; } } } else { EditorGUILayout.LabelField(content, GUILayout.Width(position.width * 0.3f), GUILayout.ExpandWidth(true)); } PingObjectIfOnMouseDown(content.tooltip); } EditorGUILayout.EndVertical(); } else { GUILayout.Space(position.width * 0.3f + 16); } } private static bool IsScene(GUIContent content) { return Path.GetExtension(content.tooltip) == ".unity"; } private static void PingObjectIfOnMouseDown(string path) { if (Event.current.type != EventType.MouseDown) return; if (!GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) return; var obj = AssetDatabase.LoadAssetAtPath(path, typeof(Object)); Selection.activeObject = obj; EditorGUIUtility.PingObject(obj); } private static GUIContent GetGUIContent(string guidOrAssetPath) { var assetPath = File.Exists(guidOrAssetPath) ? guidOrAssetPath : AssetDatabase.GUIDToAssetPath(guidOrAssetPath); var asset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Object)); return asset ? GetGUIContent(asset) : null; } private static GUIContent GetGUIContent(Object obj) { if (!obj) return new GUIContent(); return new GUIContent(EditorGUIUtility.ObjectContent(obj, obj.GetType())) { tooltip = AssetDatabase.GetAssetPath(obj) }; } private static T ByteArrayToObject(byte[] arrBytes) { T obj; using (var memStream = new MemoryStream()) { var binForm = new BinaryFormatter(); memStream.Write(arrBytes, 0, arrBytes.Length); memStream.Seek(0, SeekOrigin.Begin); obj = (T) binForm.Deserialize(memStream); } return obj; } private class Item { public Type type; public GUIContent searchedGUIContent; public List referencedGUIContents = new List(); public List referenceGUIContents = new List(); } } }