private static IEnumerable <Command> ScanAttributes() { var commands = new List <Command>(); foreach (var mi in TypeCache.GetMethodsWithAttribute <CommandHandlerAttribute>()) { if (!(Delegate.CreateDelegate(typeof(CommandHandler), mi) is CommandHandler callback)) { continue; } foreach (var attr in mi.GetCustomAttributes <CommandHandlerAttribute>()) { if (commands.Any(c => c.id == attr.id)) { Debug.LogWarning($"There is already a command with the ID {attr.id}. " + "Commands need to have a unique ID, i.e. \"Unity/Category/Command_42\"."); continue; } commands.Add(new Command { id = attr.id, label = attr.label ?? attr.id, hint = attr.hint, handler = callback, managed = true }); } } return(commands); }
private static void ExtractMenuItemsFromAttributes() { s_MenuItemsPerMode = new Dictionary <string, MenuItemsTree <MenuItemScriptCommand> >(); s_MenuItemsDefaultMode = new Dictionary <string, MenuItemScriptCommand>(); var menuItems = TypeCache.GetMethodsWithAttribute <MenuItem>(); // Order the menu items to start with Unity menus before projects menus. That way if there is a duplicate, the project one is flagged as duplicate foreach (var methodInfo in menuItems.OrderBy(m => !Utility.FastStartsWith(m.DeclaringType.Assembly.FullName, "UnityEditor", "unityeditor"))) { if (!ValidateMethodForMenuCommand(methodInfo)) { continue; } foreach (var attribute in methodInfo.GetCustomAttributes(typeof(MenuItem), false)) { string menuName = SanitizeMenuItemName(((MenuItem)attribute).menuItem); string[] editorModes = ((MenuItem)attribute).editorModes; foreach (var editorMode in editorModes) { if (editorMode == k_DefaultModeId) { if (s_MenuItemsDefaultMode.TryGetValue(menuName, out var menuItem)) { menuItem.Update((MenuItem)attribute, methodInfo); } else { s_MenuItemsDefaultMode.Add(menuName, MenuItemScriptCommand.Initialize(menuName, (MenuItem)attribute, methodInfo)); } } else { if (s_MenuItemsPerMode.TryGetValue(editorMode, out var menuItemsPerMode)) { MenuItemScriptCommand menuItem = menuItemsPerMode.FindItem(menuName); if (menuItem == null) { menuItemsPerMode.AddChildSearch(MenuItemScriptCommand.Initialize(menuName, (MenuItem)attribute, methodInfo)); } else { menuItem.Update((MenuItem)attribute, methodInfo); } } else { var newMenusPerMode = new MenuItemsTree <MenuItemScriptCommand>(); newMenusPerMode.AddChildSearch(MenuItemScriptCommand.Initialize(menuName, (MenuItem)attribute, methodInfo)); s_MenuItemsPerMode.Add(editorMode, newMenusPerMode); } } } } } CleanUpInvalidMenuItems(); }
static MethodInfo GetCustomSelectorHandlerForAttribute(Attribute attribute) { var methodsWithHandler = TypeCache.GetMethodsWithAttribute(typeof(ObjectSelectorHandlerAttribute)); foreach (var methodWithHandler in methodsWithHandler) { var selectorHandlerAttributes = methodWithHandler.GetCustomAttributes(typeof(ObjectSelectorHandlerAttribute), false).OfType <ObjectSelectorHandlerAttribute>(); foreach (var selectorHandlerAttribute in selectorHandlerAttributes) { if (selectorHandlerAttribute.attributeType == attribute.GetType()) { return(methodWithHandler); } } } return(null); }
private static void ProcessInitializeOnLoadMethodAttributes() { bool reportTimes = (bool)Debug.GetDiagnosticSwitch("EnableDomainReloadTimings").value; foreach (var method in TypeCache.GetMethodsWithAttribute <InitializeOnLoadMethodAttribute>()) { using (new EditorPerformanceMarker($"InitializeOnLoad {method.DeclaringType?.Name}.{method.Name}", method.DeclaringType).Auto()) using (_profilerMarkerProcessInitializeOnLoadMethodAttributes.Auto(reportTimes, () => $"{method.DeclaringType?.FullName}::{method.Name}")) { try { method.Invoke(null, null); } catch (Exception x) { Debug.LogError(x); } } } }
// Invokes the menu item in the specified path. public static bool ExecuteMenuItem(string menuItemPath) { var sanitizedPath = MenuService.SanitizeMenuItemName(menuItemPath); var isDefaultMode = ModeService.currentId == ModeService.k_DefaultModeId; var result = ExecuteMenuItemInternal(sanitizedPath, isDefaultMode); if (result) { return(result); } if (!isDefaultMode) { var menuItems = TypeCache.GetMethodsWithAttribute <MenuItem>(); foreach (var item in menuItems) { MenuItem itemData = (MenuItem)item.GetCustomAttributes(typeof(MenuItem), false)[0]; if (!itemData.validate && itemData.menuItem == sanitizedPath) { if (item.GetParameters().Length == 0) { item.Invoke(null, new object[0]); return(true); } else if (item.GetParameters()[0].ParameterType == typeof(MenuCommand)) { item.Invoke(null, new[] { new MenuCommand(null) }); return(true); } break; } } Debug.LogError($"ExecuteMenuItem failed because there is no menu named '{menuItemPath}'"); } return(false); }
internal static void DrawHint(Rect hintTriggerRect, Vector2 mousePosition, AssetReference assetReference) { if (!hintTriggerRect.Contains(mousePosition) || !GUIClip.visibleRect.Contains(mousePosition)) { return; } string assetPath = AssetDatabase.GUIDToAssetPath(assetReference.guid); var assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath); if (assetType == null) //this means the object or its base script has been deleted and is "Missing" { return; } var hintGenerators = TypeCache.GetMethodsWithAttribute <DynamicHintGeneratorAttribute>(); if (assetType.IsSubclassOf(typeof(ScriptableObject))) { DynamicHintContent hint = GetDynamicHintContentOf(hintGenerators, assetType, assetPath); if (hint != null) { DrawMouseTooltip(hint, hintTriggerRect); } return; } if (assetType == typeof(GameObject)) { /* GameObjects can have multiple components with custom tooltips * so for now we'll just display the first one. * If needed, we could: * 1) Implement a "priority system" (like OrderedCallbacks) * 2) Display one big tooltip made up with all elements from custom tooltip */ GameObject assetGameObject = (GetLoadedObjectFromInstanceID(assetReference.instanceID) as GameObject); if (!assetGameObject) { /* this seems to happen non-deterministically at project startup depending of what the user is hovering when the editor opens, * or while the user is scrolling a list of objects and hovers one of them casually, even if the object hovered is actually a * GameObject. * */ return; } foreach (var component in assetGameObject.GetComponents <Component>()) { if (component == null) { continue; } //this means its script has been deleted and is "Missing" DynamicHintContent hint = GetDynamicHintContentOf(hintGenerators, component.GetType(), string.Empty, component); if (hint == null) { continue; } DrawMouseTooltip(hint, hintTriggerRect); return; } } }