Instantly share code, notes, and snippets.
Created
September 2, 2023 00:48
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save koturn/a7c7d93724cefc03ca1be7520dbecf02 to your computer and use it in GitHub Desktop.
https://qiita.com/Swanman/items/279b3b679f3f96a5f925 のリフレクション結果をキャッシュするようにしたやつ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using UnityEditor; | |
namespace Koturn | |
{ | |
/// <summary> | |
/// Menu helper | |
/// </summary> | |
/// <remarks> | |
/// <seealso href="https://qiita.com/Swanman/items/279b3b679f3f96a5f925"/> | |
/// </remarks> | |
public static class MenuHelper | |
{ | |
/// <summary> | |
/// Cache of reflection result of EditorUtility.Menu.AddMenuItem(). | |
/// </summary> | |
/// <remarks> | |
/// <seealso cref="AddMenuItem"/> | |
/// <seealso cref="CreateAddMenuItemDelegate"/> | |
/// </remarks> | |
private static Action<string, string, bool, int, Action, Func<bool>> _addMenuItem; | |
/// <summary> | |
/// Cache of reflection result of EditorUtility.Menu.AddSeparator(). | |
/// </summary> | |
/// <remarks> | |
/// <seealso cref="AddSeparator"/> | |
/// <seealso cref="CreateAddSeparatorDelegate"/> | |
/// </remarks> | |
private static Action<string, int> _addSeparator; | |
/// <summary> | |
/// Cache of reflection result of EditorUtility.Menu.RemoveMenuItem(). | |
/// </summary> | |
/// <remarks> | |
/// <seealso cref="RemoveMenuItem"/> | |
/// <seealso cref="CreateRemoveMenuItemDelegate"/> | |
/// </remarks> | |
private static Action<string> _removeMenuItem; | |
/// <summary> | |
/// Cache of reflection result of EditorUtility.Internal_UpdateAllMenus(). | |
/// </summary> | |
/// <remarks> | |
/// <seealso cref="UpdateAllMenus"/> | |
/// <seealso cref="CreateUpdateAllMenusDelegate"/> | |
/// </remarks> | |
private static Action _updateAllMenus; | |
/// <summary> | |
/// Cache of reflection result about UnityEditor.ShortcutManagement.ShortcutController.RebuildShortcuts(). | |
/// </summary> | |
/// <remarks> | |
/// <seealso cref="RebuildShortcuts"/> | |
/// <seealso cref="CreateRebuildShortcutsDelegate"/> | |
/// </remarks> | |
private static Action _rebuildShortcuts; | |
/// <summary> | |
/// Add menu item. | |
/// </summary> | |
/// <param name="name">Menu name.</param> | |
/// <param name="priority">Menu priority.</param> | |
/// <param name="execute">Callback method when this menu clicked.</param> | |
/// <param name="validate">Validate method when this menu clicked.</param> | |
public static void AddMenuItem(string name, int priority, Action execute, Func<bool> validate = null) | |
{ | |
AddMenuItem(name, string.Empty, false, priority, execute, validate); | |
} | |
/// <summary> | |
/// Add menu item. | |
/// </summary> | |
/// <param name="name">Menu name.</param> | |
/// <param name="shortcut">Shortcut.</param> | |
/// <param name="priority">Menu priority.</param> | |
/// <param name="execute">Callback method when this menu clicked.</param> | |
/// <param name="validate">Validate method when this menu clicked.</param> | |
public static void AddMenuItem(string name, string shortcut, int priority, Action execute, Func<bool> validate = null) | |
{ | |
(_addMenuItem ?? (_addMenuItem = CreateAddMenuItemDelegate()))(name, shortcut ?? string.Empty, false, priority, execute, validate); | |
} | |
/// <summary> | |
/// Add menu item. | |
/// </summary> | |
/// <param name="name">Menu name.</param> | |
/// <param name="isChecked">A flag checkable or not.</param> | |
/// <param name="priority">Menu priority.</param> | |
/// <param name="execute">Callback method when this menu clicked.</param> | |
/// <param name="validate">Validate method when this menu clicked.</param> | |
public static void AddMenuItem(string name, bool isChecked, int priority, Action execute, Func<bool> validate = null) | |
{ | |
AddMenuItem(name, string.Empty, isChecked, priority, execute, validate); | |
} | |
/// <summary> | |
/// Add menu item. | |
/// </summary> | |
/// <param name="name">Menu name.</param> | |
/// <param name="shortcut">Shortcut.</param> | |
/// <param name="isChecked">A flag checkable or not.</param> | |
/// <param name="priority">Menu priority.</param> | |
/// <param name="execute">Callback method when this menu clicked.</param> | |
/// <param name="validate">Validate method when this menu clicked.</param> | |
public static void AddMenuItem(string name, string shortcut, bool isChecked, int priority, Action execute, Func<bool> validate = null) | |
{ | |
(_addMenuItem ?? (_addMenuItem = CreateAddMenuItemDelegate()))(name, shortcut ?? string.Empty, isChecked, priority, execute, validate); | |
} | |
/// <summary> | |
/// Add separator. | |
/// </summary> | |
/// <param name="name">Menu name.</param> | |
/// <param name="priority">Menu priority.</param> | |
public static void AddSeparator(string name, int priority) | |
{ | |
(_addSeparator ?? (_addSeparator = CreateAddSeparatorDelegate()))(name, priority); | |
} | |
/// <summary> | |
/// Remove menu by name. | |
/// </summary> | |
/// <param name="name">Menu name to remove.</param> | |
public static void RemoveMenuItem(string name) | |
{ | |
(_removeMenuItem ?? (_removeMenuItem = CreateRemoveMenuItemDelegate()))(name); | |
} | |
/// <summary> | |
/// Update menu items. | |
/// </summary> | |
public static void Update() | |
{ | |
UpdateAllMenus(); | |
RebuildShortcuts(); | |
} | |
/// <summary> | |
/// Update all menus, just calling UnityEditor.EditorUtility.Internal_UpdateAllMenus(). | |
/// </summary> | |
private static void UpdateAllMenus() | |
{ | |
(_updateAllMenus ?? (_updateAllMenus = CreateUpdateAllMenusDelegate()))(); | |
} | |
/// <summary> | |
/// Rebuild menu shortcuts, just calling UnityEditor.ShortcutManagement.ShortcutController.RebuildShortcuts(). | |
/// </summary> | |
private static void RebuildShortcuts() | |
{ | |
(_rebuildShortcuts ?? (_rebuildShortcuts = CreateRebuildShortcutsDelegate()))(); | |
} | |
/// <summary> | |
/// <para>Create delegate of reflection results about UnityEditor.Menu.AddMenuItem().</para> | |
/// <code>() => Menu.AddMenuItem();</code> | |
/// </summary> | |
/// <returns>Created delegate.</returns> | |
private static Action<string, string, bool, int, Action, Func<bool>> CreateAddMenuItemDelegate() | |
{ | |
// Arguments | |
var pName = Expression.Parameter(typeof(string), "name"); | |
var pShortcut = Expression.Parameter(typeof(string), "shortcut"); | |
var pIsChecked = Expression.Parameter(typeof(bool), "isChecked"); | |
var pPriority = Expression.Parameter(typeof(int), "priority"); | |
var pExecute = Expression.Parameter(typeof(Action), "execute"); | |
var pValidate = Expression.Parameter(typeof(Func<bool>), "validate"); | |
return Expression.Lambda<Action<string, string, bool, int, Action, Func<bool>>>( | |
Expression.Call( | |
typeof(Menu).GetMethod( | |
"AddMenuItem", | |
BindingFlags.Static | BindingFlags.NonPublic) | |
?? throw new InvalidOperationException("MethodInfo not found: UnityEditor.Menu.AddMenuItem"), | |
pName, | |
pShortcut, | |
pIsChecked, | |
pPriority, | |
pExecute, | |
pValidate), | |
"AddMenuItem", | |
new [] | |
{ | |
pName, | |
pShortcut, | |
pIsChecked, | |
pPriority, | |
pExecute, | |
pValidate | |
}).Compile(); | |
} | |
/// <summary> | |
/// <para>Create delegate of reflection results about UnityEditor.Menu.AddSeparator().</para> | |
/// <code> | |
/// () => Menu.AddSeparator(); | |
/// </code> | |
/// </summary> | |
/// <returns>Created delegate.</returns> | |
private static Action<string, int> CreateAddSeparatorDelegate() | |
{ | |
// Arguments | |
var pName = Expression.Parameter(typeof(string), "name"); | |
var pPriority = Expression.Parameter(typeof(int), "priority"); | |
return Expression.Lambda<Action<string, int>>( | |
Expression.Call( | |
typeof(Menu).GetMethod( | |
"AddSeparator", | |
BindingFlags.Static | BindingFlags.NonPublic) | |
?? throw new InvalidOperationException("MethodInfo not found: UnityEditor.Menu.AddSeparator"), | |
pName, | |
pPriority), | |
"AddSeparator", | |
new [] | |
{ | |
pName, | |
pPriority | |
}).Compile(); | |
} | |
/// <summary> | |
/// <para>Create delegate of reflection results about UnityEditor.Menu.RemoveMenuItem().</para> | |
/// <code> | |
/// () => Menu.RemoveMenuItem(); | |
/// </code> | |
/// </summary> | |
/// <returns>Created delegate.</returns> | |
private static Action<string> CreateRemoveMenuItemDelegate() | |
{ | |
// Arguments | |
var pName = Expression.Parameter(typeof(string), "name"); | |
return Expression.Lambda<Action<string>>( | |
Expression.Call( | |
typeof(Menu).GetMethod( | |
"RemoveMenuItem", | |
BindingFlags.Static | BindingFlags.NonPublic) | |
?? throw new InvalidOperationException("MethodInfo not found: UnityEditor.Menu.RemoveMenuItem"), | |
pName), | |
"RemoveMenuItem", | |
new [] | |
{ | |
pName, | |
}).Compile(); | |
} | |
/// <summary> | |
/// <para>Create delegate of reflection results about UnityEditor.EditorUtility.Internal_UpdateAllMenus().</para> | |
/// <code> | |
/// () => EditorUtility.Internal_UpdateAllMenus(); | |
/// </code> | |
/// </summary> | |
/// <returns>Created delegate.</returns> | |
private static Action CreateUpdateAllMenusDelegate() | |
{ | |
return Expression.Lambda<Action>( | |
Expression.Call( | |
typeof(EditorUtility).GetMethod( | |
"Internal_UpdateAllMenus", | |
BindingFlags.Static | BindingFlags.NonPublic) | |
?? throw new InvalidOperationException("MethodInfo not found: UnityEditor.EditorUtility.Internal_UpdateAllMenus")), | |
"UpdateAllMenus", | |
null).Compile(); | |
} | |
/// <summary> | |
/// <para>Create delegate of reflection results about UnityEditor.ShortcutManagement.ShortcutController.RebuildShortcuts().</para> | |
/// <code> | |
/// () => ShortcutController.instance.RebuildShortcuts(); | |
/// </code> | |
/// </summary> | |
/// <returns>Created delegate.</returns> | |
private static Action CreateRebuildShortcutsDelegate() | |
{ | |
var asm = Assembly.GetAssembly(typeof(UnityEditor.Menu)); | |
return Expression.Lambda<Action>( | |
Expression.Call( | |
Expression.Property( | |
null, // static property | |
(asm.GetType("UnityEditor.ShortcutManagement.ShortcutIntegration") | |
?? throw new InvalidOperationException("Type not found: UnityEditor.ShortcutManagement.ShortcutIntegration")).GetProperty( | |
"instance", | |
BindingFlags.Static | BindingFlags.Public) | |
?? throw new InvalidOperationException("PropertyInfo not found: UnityEditor.ShortcutManagement.ShortcutIntegration.instance")), | |
(asm.GetType("UnityEditor.ShortcutManagement.ShortcutController") | |
?? throw new InvalidOperationException("UnityEditor.ShortcutManagement.ShortcutController")).GetMethod( | |
"RebuildShortcuts", | |
BindingFlags.Instance | BindingFlags.NonPublic) | |
?? throw new InvalidOperationException("MethodInfo not found: UnityEditor.ShortcutManagement.ShortcutController.RebuildShortcuts")), | |
"RebuildShortcuts", | |
null).Compile(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment