77using UnityEngine . SceneManagement ;
88using UnityEditor . SceneManagement ;
99using UnityMCP . Editor . Helpers ;
10+ using System . Reflection ;
1011
1112namespace UnityMCP . Editor . Commands
1213{
@@ -398,5 +399,107 @@ private static GameObject CreateDirectionalLight()
398399 light . shadows = LightShadows . Soft ;
399400 return obj ;
400401 }
402+
403+ /// <summary>
404+ /// Executes a context menu method on a component of a game object
405+ /// </summary>
406+ public static object ExecuteContextMenuItem ( JObject @params )
407+ {
408+ string objectName = ( string ) @params [ "object_name" ] ?? throw new Exception ( "Parameter 'object_name' is required." ) ;
409+ string componentName = ( string ) @params [ "component" ] ?? throw new Exception ( "Parameter 'component' is required." ) ;
410+ string contextMenuItemName = ( string ) @params [ "context_menu_item" ] ?? throw new Exception ( "Parameter 'context_menu_item' is required." ) ;
411+
412+ // Find the game object
413+ var obj = GameObject . Find ( objectName ) ?? throw new Exception ( $ "Object '{ objectName } ' not found.") ;
414+
415+ // Find the component type
416+ Type componentType = FindTypeInLoadedAssemblies ( componentName ) ??
417+ throw new Exception ( $ "Component type '{ componentName } ' not found.") ;
418+
419+ // Get the component from the game object
420+ var component = obj . GetComponent ( componentType ) ??
421+ throw new Exception ( $ "Component '{ componentName } ' not found on object '{ objectName } '.") ;
422+
423+ // Find methods with ContextMenu attribute matching the context menu item name
424+ var methods = componentType . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance )
425+ . Where ( m => m . GetCustomAttributes ( typeof ( ContextMenuItemAttribute ) , true ) . Any ( ) ||
426+ m . GetCustomAttributes ( typeof ( ContextMenu ) , true )
427+ . Cast < ContextMenu > ( )
428+ . Any ( attr => attr . menuItem == contextMenuItemName ) )
429+ . ToList ( ) ;
430+
431+ // If no methods with ContextMenuItemAttribute are found, look for methods with name matching the context menu item
432+ if ( methods . Count == 0 )
433+ {
434+ methods = componentType . GetMethods ( BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance )
435+ . Where ( m => m . Name == contextMenuItemName )
436+ . ToList ( ) ;
437+ }
438+
439+ if ( methods . Count == 0 )
440+ throw new Exception ( $ "No context menu method '{ contextMenuItemName } ' found on component '{ componentName } '.") ;
441+
442+ // If multiple methods match, use the first one and log a warning
443+ if ( methods . Count > 1 )
444+ {
445+ Debug . LogWarning ( $ "Found multiple methods for context menu item '{ contextMenuItemName } ' on component '{ componentName } '. Using the first one.") ;
446+ }
447+
448+ var method = methods [ 0 ] ;
449+
450+ // Execute the method
451+ try
452+ {
453+ method . Invoke ( component , null ) ;
454+ return new
455+ {
456+ success = true ,
457+ message = $ "Successfully executed context menu item '{ contextMenuItemName } ' on component '{ componentName } ' of object '{ objectName } '."
458+ } ;
459+ }
460+ catch ( Exception ex )
461+ {
462+ throw new Exception ( $ "Error executing context menu item: { ex . Message } ") ;
463+ }
464+ }
465+
466+ // Add this helper method to find types across all loaded assemblies
467+ private static Type FindTypeInLoadedAssemblies ( string typeName )
468+ {
469+ // First try standard approach
470+ Type type = Type . GetType ( typeName ) ;
471+ if ( type != null )
472+ return type ;
473+
474+ type = Type . GetType ( $ "UnityEngine.{ typeName } ") ;
475+ if ( type != null )
476+ return type ;
477+
478+ // Then search all loaded assemblies
479+ foreach ( var assembly in AppDomain . CurrentDomain . GetAssemblies ( ) )
480+ {
481+ // Try with the simple name
482+ type = assembly . GetType ( typeName ) ;
483+ if ( type != null )
484+ return type ;
485+
486+ // Try with the fully qualified name (assembly.GetTypes() can be expensive, so we do this last)
487+ var types = assembly . GetTypes ( ) . Where ( t => t . Name == typeName ) . ToArray ( ) ;
488+
489+ if ( types . Length > 0 )
490+ {
491+ // If we found multiple types with the same name, log a warning
492+ if ( types . Length > 1 )
493+ {
494+ Debug . LogWarning (
495+ $ "Found multiple types named '{ typeName } '. Using the first one: { types [ 0 ] . FullName } "
496+ ) ;
497+ }
498+ return types [ 0 ] ;
499+ }
500+ }
501+
502+ return null ;
503+ }
401504 }
402505}
0 commit comments