📏
Unity(Editor)/ MenuItemの一覧を取得する
先日、ドラッグアンドドロップでファイル作成できるユーティリティを作っていた際、
"Assets/Create"の一覧とか取得できないかなと思って調べたんですが、探した限りpublicなものは見つからず…
GitHubの検索機能を使ってUnityCsReferenceを探してみると
Menuクラスにinternalとして「GetMenuItems」という関数を見つけました。[1]
メニューのパスからその中にある全部のMenuItemを一覧で取得できます。
最悪なことに、構造体がinternalなのでめんどくさい!
コード
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEditor;
static class MenuItemInternals
{
public struct MenuItemInfo
{
public string Path { get; set; }
public bool IsSeparator { get; set; }
public int Priority { get; set; }
}
public static IEnumerable<MenuItemInfo> GetMenuItems(string menuPath, bool includeSeparators, bool localized)
{
if (s_GetMenuItems?.Invoke(null, new object[] { menuPath, includeSeparators, localized })
is not Array result)
{
Debug.LogError("(Editor) It could not get menu items. Please check the Unity version!");
return Enumerable.Empty<MenuItemInfo>();
}
return result.Cast<object>().Select(e =>
{
return new MenuItemInfo
{
Path = s_ScriptingMenuItem_path?.GetValue(e) as string,
IsSeparator = s_ScriptingMenuItem_isSeparator?.GetValue(e) as bool? ?? false,
Priority = s_ScriptingMenuItem_priority?.GetValue(e) as int? ?? 0
};
});
}
private readonly static MethodInfo s_GetMenuItems;
private readonly static PropertyInfo s_ScriptingMenuItem_path;
private readonly static PropertyInfo s_ScriptingMenuItem_priority;
private readonly static PropertyInfo s_ScriptingMenuItem_isSeparator;
static MenuItemInternals()
{
var eapm = Array.Empty<ParameterModifier>();
var eat = Array.Empty<Type>();
s_GetMenuItems = typeof(Menu).GetMethod("GetMenuItems", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[] { typeof(string), typeof(bool), typeof(bool) }, eapm);
if (s_GetMenuItems == null) Debug.LogError("(Editor) s_GetMenuItems == null");
var scriptingMenuItemType = Type.GetType("UnityEditor.ScriptingMenuItem, UnityEditor.CoreModule");
if (scriptingMenuItemType == null) Debug.LogError("(Editor) scriptingMenuItemType == null");
s_ScriptingMenuItem_path = scriptingMenuItemType?.GetProperty("path", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null, typeof(string), eat, eapm);
if (s_ScriptingMenuItem_path == null) Debug.LogError("(Editor) s_ScriptingMenuItem_path == null");
s_ScriptingMenuItem_isSeparator = scriptingMenuItemType?.GetProperty("isSeparator", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null, typeof(bool), eat, eapm);
if (s_ScriptingMenuItem_isSeparator == null) Debug.LogError("(Editor) s_ScriptingMenuItem_isSeparator == null");
s_ScriptingMenuItem_priority = scriptingMenuItemType?.GetProperty("priority", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance, null, typeof(int), eat, eapm);
if (s_ScriptingMenuItem_priority == null) Debug.LogError("(Editor) s_ScriptingMenuItem_priority == null");
}
}
使用例
foreach (var menuItem in MenuItemInternals.UnityEditor_Menu_GetMenuItems(
menuPath: "Assets/Create",
includeSeparators: true,
localized: false
))
{
Debug.Log($"'{menuItem.Path}': {menuItem.Priority}");
}
出力
2021.3.25f(Personal)での、3D/built-inプロジェクトのデフォルトの場合の出力です。
'Assets/Create/Folder': 18
'Assets/Create/C# Script': 81
'Assets/Create/2D': 81
'Assets/Create/2D/Physics Material 2D': 12
'Assets/Create/Visual Scripting': 81
'Assets/Create/Visual Scripting/State Graph': 81
'Assets/Create/Visual Scripting/Script Graph': 81
'Assets/Create/Shader': 83
'Assets/Create/Shader/Standard Surface Shader': 83
'Assets/Create/Shader/Unlit Shader': 84
'Assets/Create/Shader/Image Effect Shader': 85
'Assets/Create/Shader/Compute Shader': 90
'Assets/Create/Shader/Ray Tracing Shader': 93
'Assets/Create/Shader Variant Collection': 83
'Assets/Create/Testing': 83
'Assets/Create/Testing/Tests Assembly Folder': 83
'Assets/Create/Testing/C# Test Script': 83
'Assets/Create/Playables': 87
'Assets/Create/Playables/Playable Behaviour C# Script': 87
'Assets/Create/Playables/Playable Asset C# Script': 88
'Assets/Create/Assembly Definition': 91
'Assets/Create/Assembly Definition Reference': 93
'Assets/Create/Text': 105
'Assets/Create/Text/Font Asset': 100
'Assets/Create/Text/Font Asset Variant': 105
'Assets/Create/Text/Sprite Asset': 150
'Assets/Create/Text/Text StyleSheet': 200
'Assets/Create/Text/Color Gradient': 250
'Assets/Create/TextMeshPro': 105
'Assets/Create/TextMeshPro/Font Asset': 100
'Assets/Create/TextMeshPro/Font Asset Variant': 105
'Assets/Create/TextMeshPro/Sprite Asset': 110
'Assets/Create/TextMeshPro/Color Gradient': 115
'Assets/Create/TextMeshPro/Style Sheet': 120
'Assets/Create/Scene': 201
'Assets/Create/Scene Template': 201
'Assets/Create/Scene Template From Scene': 201
'Assets/Create/Scene Template Pipeline': 202
'Assets/Create/Prefab': 202
'Assets/Create/Prefab Variant': 203
'Assets/Create/Audio Mixer': 215
'Assets/Create/Material': 301
'Assets/Create/Lens Flare': 303
'Assets/Create/Render Texture': 304
'Assets/Create/Lightmap Parameters': 305
'Assets/Create/Lighting Settings': 306
'Assets/Create/Custom Render Texture': 307
'Assets/Create/Animator Controller': 401
'Assets/Create/Animation': 402
'Assets/Create/Animator Override Controller': 403
'Assets/Create/Avatar Mask': 404
'Assets/Create/Timeline': 450
'Assets/Create/Signal': 451
'Assets/Create/Physic Material': 501
'Assets/Create/GUI Skin': 601
'Assets/Create/Custom Font': 602
'Assets/Create/Legacy': 701
'Assets/Create/Legacy/Cubemap': 701
'Assets/Create/UI Toolkit': 701
'Assets/Create/UI Toolkit/Style Sheet': 603
'Assets/Create/UI Toolkit/TSS Theme File': 604
'Assets/Create/UI Toolkit/Default Runtime Theme File': 605
'Assets/Create/UI Toolkit/UI Document': 610
'Assets/Create/UI Toolkit/Panel Settings Asset': 701
'Assets/Create/UI Toolkit/Editor Window': 701
'Assets/Create/UI Toolkit/Text Settings': 1000
'Assets/Create/Search': 1000
'Assets/Create/Search/Assets Index': 1000
'Assets/Create/Search/Prefabs Index': 1000
'Assets/Create/Search/Scenes Index': 1000
'Assets/Create/Brush': 1000
'Assets/Create/Terrain Layer': 1000
パラメータについて
「includeSeparators」がtrueだと、
2D/
2D/A
2D/B
みたいなときに、「2D」自体も含めて返します。そのとき「2D」はIsSeparatorがtrueになる
。「2D」のpriority知りたいときとかはtrueにするといいみたいです。(たぶん)
「localized」というのもあって普通にうれしい。
Discussion