Unityのプロジェクト内で、Componentや自作クラスの参照を見つけるEditor拡張をちょっと良くしました
これはなに?
以前作った、
kakovail.info
こちら、右クリックでサクッと探したいな、と思ったり、リロードの問題があったりしたので、リファクタがてら書き直していました。
使い方と変わったところ
前回に追加して、Projectビューからお好きなスクリプトを右クリック→メニューから選択でも調べられるようになりました。(Assets/KEditorExtensions/から)
Sceneロードでのバグも消しました。
非アクティブなSceneの対処はちょっと保留です。
コード
// Copyright (c) 2021 Hiroyuki Kako
// This software is released under the MIT License, see LICENSE.
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
public class ReferenceFinder : EditorWindow
{
private static string _targetComponentName;
private static List<GameObject> _foundAssets = new List<GameObject>();
private static IEnumerable<Type> _cashedComponents;
private static Dictionary<string, List<Type>> _typeDict;
private static bool _isFirstTime = true;
static MonoScript[] _monoScripts;
private Vector2 _currentScrollPosition;
[InitializeOnLoadMethod]
private static void InitializeEvent()
{
EditorSceneManager.sceneClosing += OnClosing;
}
private static void OnClosing(Scene scene, bool removingScene)
{
if (!HasOpenInstances<ReferenceFinder>())
return;
GetWindow<ReferenceFinder>().Close();
}
[MenuItem("KEditorExtensions/Reference/ReferenceFinder")]
private static void Open()
{
_cashedComponents = GetAllTypes();
GetWindow<ReferenceFinder>("Components Reference Finder.");
}
[MenuItem("Assets/KEditorExtensions/Find references in active scene and all prefabs")]
private static void FindWithRightClick()
{
var name = Selection.activeObject;
_cashedComponents = GetAllTypes();
GetWindow<ReferenceFinder>("Components Reference Finder.");
_targetComponentName = name.name;
SearchObjects();
}
private void OnGUI()
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Never change Scene before reset this window");
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("This window can search active scene objects and all prefabs");
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
_targetComponentName = EditorGUILayout.TextField("Target Component Name: ", _targetComponentName);
EditorGUILayout.EndHorizontal();
if (_foundAssets.Count > 0)
{
_currentScrollPosition = EditorGUILayout.BeginScrollView(_currentScrollPosition);
foreach (var asset in _foundAssets)
{
EditorGUILayout.ObjectField(asset.name, asset, typeof(GameObject), false);
}
EditorGUILayout.EndScrollView();
}
if (GUILayout.Button("Search"))
{
SearchObjects();
}
}
private static void SearchObjects()
{
_foundAssets.Clear();
var guids = AssetDatabase.FindAssets("t:GameObject", null);
foreach (var guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var loadAsset = AssetDatabase.LoadAssetAtPath<GameObject>(path);
var typeCash = GetType(_targetComponentName) ?? null;
if (typeCash == null)
{
Debug.Log("No Type Found.");
return;
}
var tmp = loadAsset.GetComponentsInChildren(GetType(_targetComponentName) ?? null);
foreach (var kari in tmp)
{
_foundAssets.Add(kari.gameObject);
}
}
var allObj = GetObjectsInAllScene();
foreach (var obj in allObj)
{
var typeCash = GetType(_targetComponentName) ?? null;
var tmp = obj.GetComponentsInChildren(GetType(_targetComponentName) ?? null);
if (typeCash == null)
{
Debug.Log("No Type Found.");
return;
}
foreach (var kari in tmp)
{
_foundAssets.Add(kari.gameObject);
}
}
}
/// <summary>
/// All script files that exist in the project
/// </summary>
static MonoScript[] MonoScripts
{
get
{
return _monoScripts ?? (_monoScripts = Resources.FindObjectsOfTypeAll<MonoScript>().ToArray());
}
}
/// <summary>
/// Getting the type from the class name
/// </summary>
private static Type GetType(string className)
{
if (_typeDict == null)
{
_typeDict = new Dictionary<string, List<Type>>();
foreach (var type in _cashedComponents)
{
if (!_typeDict.ContainsKey(type.Name))
{
_typeDict.Add(type.Name, new List<Type>());
}
_typeDict[type.Name].Add(type);
}
}
// If the class exists, show it in the list
if (_typeDict.ContainsKey(className))
{
return _typeDict[className][0];
}
else
{
// If the class doesn't exist, get it just in case, and run again.
if (_isFirstTime)
{
Debug.Log("Not found. ReScanning...");
_cashedComponents = GetAllTypes();
_isFirstTime = false;
GetType(className);
}
_isFirstTime = true;
return null;
}
}
/// <summary>
/// Get all class
/// </summary>
private static IEnumerable<Type> GetAllTypes()
{
var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(asm => asm.GetTypes()).Where(type => type != null && !string.IsNullOrEmpty(type.Namespace)).Where(type => type.Namespace.Contains("UnityEngine"));
var localTypes = MonoScripts.Where(script => script != null).Select(script => script.GetClass()).Where(classType => classType != null).Where(classType => classType.Module.Name == "Assembly-CSharp.dll");
return types.Concat(localTypes).Distinct();
}
private static GameObject[] GetObjectsInAllScene(bool includeInactive = true)
{
var sceneNumber = SceneManager.sceneCount;
IEnumerable<GameObject> resultObjects = (GameObject[])Enumerable.Empty<GameObject>();
for (int i = 0; i < sceneNumber; i++)
{
var obj = SceneManager.GetSceneAt(i).GetRootGameObjects();
resultObjects = resultObjects.Concat(obj);
}
return resultObjects.ToArray();
}
}
#endif