Skip to content

Instantly share code, notes, and snippets.

@tsubaki
Last active May 30, 2018 02:40
Show Gist options
  • Save tsubaki/713af9c003a16ea71aaa to your computer and use it in GitHub Desktop.
Save tsubaki/713af9c003a16ea71aaa to your computer and use it in GitHub Desktop.
シーン内のコード群から特定のコードを見つける
///
/// ReferenceExplorer
///
/// Copyright (c) 2014 Tatsuhiko Yamamura
/// Released under the MIT license
// / http://opensource.org/licenses/mit-license.php
///
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace ReferenceExplorer
{
/// <summary>
/// シーン全体の情報を格納する
/// </summary>
public class SceneData
{
/// <summary>
/// Initializes the <see cref="ReferenceExplorer.SceneData"/> class.
/// </summary>
static SceneData()
{
EditorApplication.update += ()=>{
frameCount ++;
};
IsSelected = false;
IsRegex = false;
}
/// <summary>
/// 検索範囲を選択中のオブジェクトに限定する
/// </summary>
public static bool IsSelected{ get; set;}
/// <summary>
/// 検索に正規表現を使用する
/// </summary>
public static bool IsRegex{get; set;}
/// <summary>
/// 検索に使用する全てのMonobehaviour
/// </summary>
static List<MonoBehaviour> allMonobehaviourList = new List<MonoBehaviour> ();
/// <summary>
/// シーン内の全オブジェクト
/// </summary>
static List<GameObject> allGameObjectList = new List<GameObject>();
/// <summary>
/// エディタのフレームカウント
/// </summary>
public static long frameCount { get; private set;}
/// <summary>
/// 更新フレーム。frameCountと一致しなければ更新しない等の用途
/// </summary>
static long monobehaviourLastUpdateFrame = 0, gameobjectLastUpdateFrame = 0;
/// <summary>
/// シーンにある全てのGameObject。isSelectedにチェックがある場合は選択中のオブジェクトを取得する
/// </summary>
/// <value>GameObject一覧</value>
public static List<GameObject> SelectedObjects {
get {
if (IsSelected) {
return new List<GameObject>(Selection.gameObjects);
} else {
return AllObjects;
}
}
}
/// <summary>
/// シーン内の全コンポーネントを取得する。isSelectedにチェックがある場合は選択中のオブジェクトのコンポーネントを取得する
/// </summary>
/// <value>Monobehaviour一覧</value>
public static List<MonoBehaviour> SelectedMonobehaviours
{
get{
var monobehaviourList = new List<MonoBehaviour> ();
if (IsSelected) {
foreach (var obj in Selection.gameObjects) {
monobehaviourList.AddRange ( AllComponents.FindAll (item => item.gameObject == obj));
}
return monobehaviourList;
} else {
return AllComponents;
}
}
}
/// <summary>
/// Gets all objects.
/// </summary>
/// <value>All objects.</value>
public static List<GameObject> AllObjects
{
get{
if (frameCount != gameobjectLastUpdateFrame) {
UpdateAllObjectList ();
gameobjectLastUpdateFrame = frameCount;
}
return new List<GameObject>(allGameObjectList);
}
}
/// <summary>
/// Gets all component.
/// </summary>
/// <value>All component.</value>
public static List<MonoBehaviour> AllComponents
{
get{
if (monobehaviourLastUpdateFrame != frameCount) {
UpdateAllMonobehaviourList ();
monobehaviourLastUpdateFrame = frameCount;
}
return new List<MonoBehaviour> (allMonobehaviourList);
}
}
/// <summary>
///Component一覧を更新する
/// </summary>
static void UpdateAllMonobehaviourList ()
{
allMonobehaviourList.Clear ();
allMonobehaviourList.AddRange (GetComponentsInList<MonoBehaviour> (AllObjects));
}
/// <summary>
/// GameObject一覧(deactive含む)を更新する
/// </summary>
static void UpdateAllObjectList()
{
allGameObjectList.Clear ();
foreach (GameObject obj in (GameObject[])Resources.FindObjectsOfTypeAll (typeof(GameObject))) {
if (obj.hideFlags == HideFlags.NotEditable || obj.hideFlags == HideFlags.HideAndDontSave)
continue;
if (Application.isEditor) {
string sAssetPath = AssetDatabase.GetAssetPath (obj.transform.root.gameObject);
if (!string.IsNullOrEmpty (sAssetPath))
continue;
}
allGameObjectList.Add (obj);
}
}
public static IEnumerable<T> GetComponentsInList<T> (IEnumerable<GameObject> gameObjects ) where T : Component
{
var componentList = new List<T> ();
foreach (var obj in gameObjects) {
var component = obj.GetComponent<T> ();
if (component != null) {
componentList.Add (component);
}
}
return componentList;
}
/// <summary>
/// searchの内容がInputに含まれることを確認する。isRegexにチェックを入れると正規表現で検索する
/// </summary>
/// <param name="input">インプット</param>
/// <param name="search">検索キーワード</param>
public static bool Match(string input, string search)
{
if (string.IsNullOrEmpty (input))
return false;
if (IsRegex) {
var match = Regex.Match (input, search);
return match.Success;
} else {
var result = input.IndexOf (search);
return (result != 0 && result != -1);
}
}
/// <summary>
/// ユニークなMonobehaviourを継承したコンポーネント一覧を取得する
/// </summary>
/// <returns>検索するオブジェクト一覧</returns>
/// <param name="objects">Monobehaviour一覧</param>
public static List<MonoBehaviour> GetUniqueMonobehaviour (IEnumerable<GameObject> objects)
{
var uniqueMonobehaviourList = new List<MonoBehaviour> ();
foreach (var obj in objects) {
foreach (var monobehaviour in obj.GetComponents<MonoBehaviour>()) {
if (!uniqueMonobehaviourList.Exists (item => item.GetType () == monobehaviour.GetType ())) {
uniqueMonobehaviourList.Add (monobehaviour);
}
}
}
return uniqueMonobehaviourList;
}
}
}
///
/// ReferenceExplorer
///
/// Copyright (c) 2014 Tatsuhiko Yamamura
/// Released under the MIT license
// / http://opensource.org/licenses/mit-license.php
///
#pragma warning disable 0618
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace ReferenceExplorer
{
/// <summary>
/// シーン内のクラス群を特定キーワードで検索するエディタウィンドウ
/// </summary>
public class SearchCodeInSceneWindow : EditorWindow
{
/// <summary>
/// 検索する文字列
/// </summary>
protected string searchText = string.Empty;
/// <summary>
/// 検索キーワードにヒットしたMonobehaviour一覧
/// </summary>
List<CodeObject> ExistCodeObjectList = new List<CodeObject> ();
/// <summary>
/// 選択中のMonobehaviour
/// </summary>
int current = 0;
/// <summary>
/// ウィンドウを開く
/// </summary>
[MenuItem ("Window/ReferenceExplorer/SearchCode")]
static void Open ()
{
SearchCodeInSceneWindow.GetWindow<SearchCodeInSceneWindow> ("code search");
}
/// <summary>
/// ContainCodeObjectを更新する
/// </summary>
void UpdateContainCodeObjectList ()
{
ExistCodeObjectList.Clear ();
var uniqueMonobehaviour = SceneData.GetUniqueMonobehaviour (SceneData.SelectedObjects);
foreach (var monobehaviour in uniqueMonobehaviour) {
var monoscript = MonoScript.FromMonoBehaviour (monobehaviour);
bool isMatch = false;
List<string> lines = new List<string> ();
foreach (var line in monoscript.text.Split( new string[]{ Environment.NewLine }, StringSplitOptions.None )) {
if (!SceneData.Match (line, searchText))
continue;
lines.Add (line);
isMatch = true;
}
if (isMatch) {
ExistCodeObjectList.Add (new CodeObject () {
componentType = monobehaviour.GetType (),
monoscript = monoscript,
lines = lines.ToArray(),
});
}
}
}
#region GUI
/// <summary>
/// スクロールビューの座標
/// </summary>
Vector2 componentScroll, textScroll;
/// <summary>
/// サーチバーの表示を行う。OnGUIで使用する想定
/// </summary>
void SearchBar ()
{
EditorGUILayout.BeginHorizontal ();
EditorGUI.BeginChangeCheck ();
SceneData.IsSelected = GUILayout.Toggle (SceneData.IsSelected, "Selection", EditorStyles.toolbarButton , GUILayout.Width (60));
SceneData.IsRegex = GUILayout.Toggle (SceneData.IsRegex, "Regex", EditorStyles.toolbarButton , GUILayout.Width (40));
searchText = GUILayout.TextField (searchText, GUILayout.Width( Screen.width - 110));
if (EditorGUI.EndChangeCheck ()) {
UpdateContainCodeObjectList ();
}
EditorGUILayout.EndHorizontal ();
}
/// <summary>
/// コンポーネントの一覧を表示する。OnGUIで使用する想定
/// </summary>
void ContentView ()
{
var containCodeObjects = ExistCodeObjectList.ToArray ();
componentScroll = EditorGUILayout.BeginScrollView (componentScroll);
for (int i = 0; i < containCodeObjects.Length; i++) {
var containCodeObject = containCodeObjects[i];
EditorGUILayout.BeginHorizontal ();
EditorGUI.BeginChangeCheck ();
EditorGUILayout.Toggle (i == current, EditorStyles.radioButton, GUILayout.Width(14) );
if (EditorGUI.EndChangeCheck ()) {
current = i;
}
EditorGUILayout.ObjectField (containCodeObject.monoscript, typeof(MonoScript));
EditorGUILayout.EndHorizontal ();
if (i == current) {
GUILayout.Space (4);
var components = SceneData.SelectedMonobehaviours.FindAll (item => item.GetType () == containCodeObject.componentType);
EditorGUI.indentLevel = 2;
foreach (var obj in components) {
EditorGUILayout.ObjectField (obj.gameObject, typeof(GameObject));
}
GUILayout.Space (4);
EditorGUI.indentLevel = 0;
}
}
EditorGUILayout.EndScrollView ();
}
/// <summary>
/// 選択中のコンポーネントの検索結果を表示する。OnGUIで使用する想定
/// </summary>
void CodeLineView()
{
if (ExistCodeObjectList.Count <= current)
return;
var currentContainCodeObject = ExistCodeObjectList [current];
var textHeight = (currentContainCodeObject.lines.Length + 1) * 18;
var windowHeight = Mathf.Min (100, textHeight);
GUILayout.BeginArea( new Rect(0, Screen.height - 120, Screen.width, 100));
textScroll = EditorGUILayout.BeginScrollView (textScroll);
EditorGUILayout.BeginVertical ("box", GUILayout.Height(windowHeight));
foreach (var line in currentContainCodeObject.lines) {
EditorGUILayout.BeginHorizontal ("box");
EditorGUILayout.LabelField (line);
EditorGUILayout.EndHorizontal ();
}
EditorGUILayout.EndVertical ();
EditorGUILayout.EndScrollView ();
GUILayout.EndArea ();
}
#endregion
#region EditorWindowCallback
/// <summary>
/// Unity Callback OnGUI
/// </summary>
void OnGUI ()
{
SearchBar ();
ContentView ();
CodeLineView ();
}
/// <summary>
/// Unity Callback OnGUI
/// </summary>
void OnSelectionChange ()
{
if (!SceneData.IsSelected)
return;
UpdateContainCodeObjectList ();
Repaint ();
}
#endregion
/// <summary>
/// 検索して見つかったコンポーネントを格納する
/// </summary>
class CodeObject
{
/// <summary> Monobehaviourのタイプ </summary>
public Type componentType;
/// <summary> Monobehaviourのコード </summary>
public MonoScript monoscript;
/// <summary> 一致したライン </summary>
public string[] lines;
}
}
}
@tsubaki
Copy link
Author

tsubaki commented Nov 24, 2014

機能

image

シーン内のコードを検索し、合致するコード及びアタッチされているオブジェクトを一覧表示します。

使用方法

Window > ReferenceExplorer > SearchCodeで開きます。

SelectionがONの時は、選択中のオブジェクト群から検索します。
RegexがONの時は、検索キーワードに正規表現を使用します。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment