popcorn/ReferenceViewer/Editor/ReferenceViewer.cs

370 lines
15 KiB
C#
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>();
}
}
}