【Unity】アタッチ可能なすべてのコンポーネントのTypeを取得する

方針

エディタの「AddComponent」のプログラムを参考に、アタッチ可能な(ゲームオブジェクトに付けられる)すべてのコンポーネントを取得したいと思います。

参考

UnityのAddComponentについて調べてみた - Qiita
AddComponentできるのはMonoBehaviourクラスを継承しているコンポーネントだけ。MonoBehaviourはBehaviourクラス->Componentクラス->Unity…

コード

using UnityEngine;
using System.Collections.Generic;
using System;
using UnityEditor;
using System.Text.RegularExpressions;
using System.Reflection;

internal static class Sample
{

    [MenuItem("Tools/LogAllComponents")]
    private static void LogAllComponents()
    {
        foreach(var type in GetComponentTypes())
        {
            Debug.Log(type);
        }
    }

    private static List<Type> GetComponentTypes()
    {
        var types = new List<Type>();

        //すべてのコンポーネントのIDを取得する
        var idArray = Unsupported.GetSubmenusCommands("Component");
        //数字だけの文字列を表す正規表現
        var regex = new Regex("^\\d+$");

        foreach (var commandString in idArray)
        {
            Type type = null;

            //UnityEngineのクラス以外
            if (commandString.StartsWith("SCRIPT"))
            {
                //インスタンスIDから型を取得する
                var instanceID = int.Parse(commandString.Substring(6));
                var obj = EditorUtility.InstanceIDToObject(instanceID);
                var monoScript = obj as MonoScript;
                type = monoScript.GetClass();
            }
            //UnityEngineのクラス
            else if (regex.IsMatch(commandString))
            {
                //クラスIDから型を取得する
                var classID = int.Parse(commandString);
                type = GetTypeByClassID(classID);
            }

            if (type != null)
            {
                types.Add(type);
            }
        }

        return types;
    }

    private static Type GetTypeByClassID(int classID)
    {
        //"UnityType"クラスを取得する(internalなクラスである)
        //以下のURLからプログラムが見れる
        //https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Editor/Mono/TypeSystem/UnityType.cs
        var unityType = Assembly.GetAssembly(typeof(MonoScript)).GetType("UnityEditor.UnityType") ;

        //"FindTypeByPersistentTypeID"メソッドよりClassIDからUnityTypeを取得する
        var classObject = unityType.InvokeMember("FindTypeByPersistentTypeID", BindingFlags.InvokeMethod, null, null, new object[] { classID });
        if (classObject == null)
        {
            return null;
        }

        //実際の型の名前は"name"プロパティから取得できる
        var name = unityType.GetProperty("name").GetValue(classObject) as string;

        //すべてのアセンブリから名前が一致する型を探す
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var type in assembly.GetTypes())
            {
                if (name == type.Name)
                {
                    return type;
                }
            }
        }

        return null;
    }
}

実行結果

UnityEngine.MeshFilter
UnityEngine.TextMesh
UnityEngine.MeshRenderer
UnityEngine.SkinnedMeshRenderer
<以下略>

留意点

この方法はエディタ専用です。ランタイムでは動きません。

参考

https://gist.github.com/hecres/f594add4b38493fcf2f17317f3c88d32

※上のリンクのプログラムはスペルミスがあるので注意。
× “FindTypeByP re sistentTypeID”
〇 “FindTypeByP er sistentTypeID”

UnityのAddComponentについて調べてみた - Qiita
AddComponentできるのはMonoBehaviourクラスを継承しているコンポーネントだけ。MonoBehaviourはBehaviourクラス->Componentクラス->Unity…

コメント

タイトルとURLをコピーしました