popcorn/ReferenceViewer/Editor/ReferenceViewer.cs

370 lines
15 KiB
C#
Raw Normal View History

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<Item> items = new List<Item>();
private Vector2 pos = Vector2.zero;
private int selectedFilter;
static Dictionary<string, List<GUIContent>> sceneReference = new Dictionary<string, List<GUIContent>>();
static Dictionary<string, bool> foldouts = new Dictionary<string, bool>();
[MenuItem("Window/ReferenceViewer")]
private static void Open()
{
GetWindow<ReferenceViewer>();
}
[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<Item>();
var guids = new List<string>();
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<GUIContent, string>(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<GUIContent, string>(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<Item, string>(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<ReferenceViewer>();
window.selectedFilter = 0;
window.Results(items);
}
private void Results(List<Item> 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<GUIContent> 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<T>(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<GUIContent> referencedGUIContents = new List<GUIContent>();
public List<GUIContent> referenceGUIContents = new List<GUIContent>();
}
}
}