PONOS Advent Calendar 2021の9日目の記事です。
昨日は@nissy_gpさんの「YouTubeの英語の動画はどう見たほうが間違えないのか」でした。
はじめに
先日、「Debug.Log()の全文をファイル出力し、で省略された内容をすぐに確認できるようにする」という記事を投稿しました。
この調査を進める中でUnityエディタ内のクラスにアクセスする機会があり、やり方について知っておくとエディタを拡張する際に便利かと思いましたので、共有いたします。
確認環境はUnity 2019.4.32f1
です。
Unityエディタの中を見る方法
通常、Unityエディタ内で使用されているクラス(例えば、Consoleを始めとした各ウインドウの制御など)は、利用することができません。
ですが、クラスの定義が判明していれば、C#のリフレクションの機能を使ってクラスを利用することができます。
では、Unityエディタ内のクラスの定義はどこで確認したら良いでしょうか。
実はUnity公式から実際に運用されているC#のコードが公開されています。
(確認する際は、自身が使用しているUnityのバージョンに合わせてブランチまたはタグを切り替えてください)
GitHub - Unity-Technologies/UnityCsReference: Unity C# reference source code.
ライセンスは以下が適用されています。(対象コードは参照にのみ利用できます)
Unity Reference-Only License (“License”) - Unity
このリポジトリのコードを読むことで、Unityエディタ内にどういったクラスが定義されているのかを知ることができます。
サンプル
さて、ではUnityエディタ内のクラスを利用するサンプルとして、**「Consoleウインドウのフィルター欄に『PONOS』文字列を設定する」**機能を実装してみます。
型を取得する
まずは、リフレクションの処理を用いてConsoleWindow
の型を取得してみましょう。
Consoleウインドウの処理はConsolwWindow
クラスに実装されています。
UnityCsReference/ConsoleWindow.cs at 2019.4 · Unity-Technologies/UnityCsReference · GitHub
System.Refrection.Assembly
クラスを利用してConsoleWindow
が含まれるエディタ用のアセンブリオブジェクトを取得し、その中から対象となる型情報を取得しています。
// エディタ用のアセンブリを取得。
var assembly = typeof(Editor).Assembly;
// Consoleウインドウの型情報を取得。
var consoleWindowType = assembly.GetType("UnityEditor.ConsoleWindow");
メソッド情報を取得する
次に、フィルター欄に文字列を設定するためのメソッドConsoleWindow.SetFilter()
を実行するために必要な、メソッド情報MethodInfo
を探します。
メソッド情報を探すときは対象のメソッド名が必要となります。
また、対象となるメソッドの定義に応じて、適切にBindingFlags
で検索方法を指定する必要があります。
今回対象となるSetFilter()
メソッドは以下のように定義されているため、BindingFlags
はBindingFlags.Instance | BindingFlags.NonPublic
を指定します。
private void SetFilter(string filteringText)
※その他のBindingFlags
の値は以下を参考にしてください。
BindingFlags 列挙型 (System.Reflection) | Microsoft Docs
以上を踏まえて、メソッド情報を取得するためのコードは以下のようになります。
// SetFilter()メソッドの情報を取得する。
// フラグとして「インスタンスメンバである」「パブリックアクセス以外のメンバを含める」を渡しておく。
var bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic;
var setFilterMethodInfo = consoleWindowType.GetMethod("SetFilter", bindingAttr);
メソッドを実行する
最後にメソッド情報を元に、処理を実行します。
MethodInfo
から処理を実行する際は、「メソッドを実行させるオブジェクト」を渡す必要があります。
ConsoleWindow
オブジェクトはEditorApplication.GetWindow()
から取得が可能です。
// メソッドの実行対象となるConsoleウインドウのオブジェクトを取得。
var consoleWindow = EditorWindow.GetWindow(consoleWindowType);
// メソッド情報を元に、対象のオブジェクトに対してメソッドを実行する。
setFilterMethodInfo.Invoke(consoleWindow, new object[] { "PONOS" });
コード全文
説明は以上です。コードの全文は以下のようになります。
using System.Reflection;
using UnityEditor;
/// <summary>
/// Consoleウインドウのフィルター欄に文字列を設定するクラス。
/// </summary>
public static class ConsoleFilterSetter
{
/// <summary>
/// Consoleウインドウのフィルター欄に「PONOS」を設定する。
/// </summary>
[MenuItem("Console Filter/Set \"PONOS\"")]
public static void SetPONOS()
{
// エディタ用のアセンブリを取得。
var assembly = typeof(Editor).Assembly;
// Consoleウインドウの型情報を取得。
var consoleWindowType = assembly.GetType("UnityEditor.ConsoleWindow");
// SetFilter()メソッドの情報を取得する。
// フラグとして「インスタンスメソッド」「パブリックでない」を渡しておく。
var bindingAttr = BindingFlags.Instance | BindingFlags.NonPublic;
var setFilterMethodInfo = consoleWindowType.GetMethod("SetFilter", bindingAttr);
// メソッドの実行対象となるConsoleウインドウのオブジェクトを取得。
var consoleWindow = EditorWindow.GetWindow(consoleWindowType);
// メソッド情報を元に、対象のオブジェクトに対してメソッドを実行する。
setFilterMethodInfo.Invoke(consoleWindow, new object[] { "PONOS" });
}
}
実行結果は以下です。
まとめ
UnityCsReference
リポジトリを見ることでUnityエディタ内の処理を追うことができるので、Unityに対する理解を一層深めることができると思います!
明日は@nisei275さんです!