public override void OnGUI(Rect position, SerializedProperty serCallBaseProperty, GUIContent label) { // Indent label label.text = " " + label.text; GUI.Box(position, "", (GUIStyle)"flow overlay box"); position.y += 4; // Using BeginProperty / EndProperty on the parent property means that // prefab override logic works on the entire property. EditorGUI.BeginProperty(position, label, serCallBaseProperty); // Draw label Rect pos = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); Rect targetRect = new Rect(pos.x, pos.y, pos.width, EditorGUIUtility.singleLineHeight); // Get target SerializedProperty targetProp = serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase._target)); object target = targetProp.objectReferenceValue; // Get UdId SerializedProperty UdiDProp = serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase.UDIDObject)); if (target != null) { if (string.IsNullOrEmpty(UdiDProp.stringValue)) { UdiDProp.stringValue = target.GetHashCode().ToString(); serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase.dirty)).boolValue = true; serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase.dirtyChecker)).boolValue = false; serCallBaseProperty.serializedObject.ApplyModifiedProperties(); serCallBaseProperty.serializedObject.Update(); return; } } else { UdiDProp.stringValue = null; } SerializedSystemFunc.Hidden.Arg argsTemplateTouse = new SerializedSystemFunc.Hidden.Arg(); if (IpropGenerator != null) { if (!IpropGenerator.GetType().FullName.EndsWith(serCallBaseProperty.type)) { IpropGenerator = null; } } if (IpropGenerator == null) { // UnityEngine.Debug.LogWarning(" Working For : " + serCallBaseProperty.type); var typesFromAssymbly = (from type in typeof(SerializedSystemFunc.Hidden.SerializableCallbackBase).Assembly.GetTypes() where type.FullName.EndsWith(serCallBaseProperty.type) select type); if (typesFromAssymbly != null && typesFromAssymbly.Count() > 0) { foreach (var item in typesFromAssymbly) { IpropGenerator = ((SerializedSystemFunc.Hidden.SerializableCallbackBase)System.Activator.CreateInstance(item)); break; } } } argsTemplateTouse = IpropGenerator.GenTemplateArg(); EditorGUI.PropertyField(targetRect, targetProp, GUIContent.none); if (target != null) { // Get method name SerializedProperty methodProp = serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase._methodName)); string methodName = methodProp.stringValue; // Get args SerializedProperty argProps = serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase._args)); Type[] argTypes = GetArgTypes(argProps, argsTemplateTouse); // Get active method MethodInfo activeMethod = GetMethod(target, methodName, argTypes); GUIContent methodlabel = new GUIContent("n/a"); if (activeMethod != null) { methodlabel = new GUIContent(PrettifyMethod(activeMethod)); } else if (!string.IsNullOrEmpty(methodName)) { methodlabel = new GUIContent("Missing (" + PrettifyMethod(methodName, argTypes) + ")"); } Rect methodRect = new Rect(position.x, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width, EditorGUIUtility.singleLineHeight); // Method select button pos = EditorGUI.PrefixLabel(methodRect, GUIUtility.GetControlID(FocusType.Passive), new GUIContent(" Method")); // dynamic ? "Method (dynamic)" : "Method" if (EditorGUI.DropdownButton(pos, methodlabel, FocusType.Keyboard)) { MethodSelector(serCallBaseProperty, argsTemplateTouse, IpropGenerator); } } else { // Target is null! Rect helpBoxRect = new Rect(position.x + 8, targetRect.max.y + EditorGUIUtility.standardVerticalSpacing, position.width - 16, EditorGUIUtility.singleLineHeight); string msg = "Call not set. Execution will be slower."; EditorGUI.LabelField(helpBoxRect, new GUIContent(msg, msg), "helpBox"); } // Set indent back to what it was EditorGUI.EndProperty(); }
private static void MethodSelector(SerializedProperty serCallBaseProperty, SerializedSystemFunc.Hidden.Arg argsTemplateToUse, SerializedSystemFunc.Hidden.SerializableCallbackBase coreProp) { // Return type constraint Type returnType = null; // Arg type constraint Type[] argTypes = new Type[0]; // Get return type and argument constraints string stringValueTypedName = serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase._typeName)).stringValue; Type MainTypeToLook = Type.GetType(stringValueTypedName, false); Type[] genericTypes = null; if (MainTypeToLook != null) { genericTypes = MainTypeToLook.BaseType.GetGenericArguments(); } if (genericTypes != null && genericTypes.Length > 0) { // The last generic argument is the return type returnType = genericTypes[genericTypes.Length - 1]; if (genericTypes.Length > 1) { argTypes = new Type[genericTypes.Length - 1]; Array.Copy(genericTypes, argTypes, genericTypes.Length - 1); } } Type[] typesConstraintsParams = coreProp.GetConstraints(); SerializedProperty targetProp = serCallBaseProperty.FindPropertyRelative(nameof(SerializedSystemFunc.Hidden.SerializableCallbackBase._target)); List <MenuItem> dynamicItems = new List <MenuItem>(); List <MenuItem> staticItems = new List <MenuItem>(); List <Object> targets = new List <Object>() { targetProp.objectReferenceValue }; if (targets[0] is Component) { targets = (targets[0] as Component).gameObject.GetComponents <Component>().ToList <Object>(); targets.Add((targetProp.objectReferenceValue as Component).gameObject); } else if (targets[0] is GameObject) { targets = (targets[0] as GameObject).GetComponents <Component>().ToList <Object>(); targets.Add(targetProp.objectReferenceValue as GameObject); } for (int c = 0; c < targets.Count; c++) { UnityEngine.Object t = targets[c]; MethodInfo[] methods = targets[c].GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); for (int i = 0; i < methods.Length; i++) { MethodInfo method = methods[i]; // Skip methods with wrong return type if (returnType != null && method.ReturnType != returnType) { continue; } // Skip methods with null return type if (method.ReturnType == typeof(void)) { continue; } // Skip generic methods if (method.IsGenericMethod) { continue; } Type[] parms = method.GetParameters().Select(x => x.ParameterType).ToArray(); // Skip methods with more than 4 args if (parms.Length > 4) { continue; } // Skip methods with unsupported args if (parms.Any(x => !argsTemplateToUse.IsSupported(x))) { continue; } // Skip when parameters are defined if (typesConstraintsParams != null && typesConstraintsParams.Length > 0 && !parms.Any(x => CheckIfPassing(x, typesConstraintsParams))) { continue; } // Skip methods with wrong constrained args if (argTypes.Length > 0 && !Enumerable.SequenceEqual(argTypes, parms)) { continue; } // dynamicItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, // methods[i].Name, // () => SetMethod(serCallBaseProperty, t, method, true))); string methodPrettyName = PrettifyMethod(methods[i]); staticItems.Add(new MenuItem(targets[c].GetType().Name + "/" + methods[i].DeclaringType.Name, methodPrettyName, () => SetMethod(serCallBaseProperty, t, method))); } } // Construct and display context menu GenericMenu menu = new GenericMenu(); if (dynamicItems.Count > 0) { string[] paths = dynamicItems.GroupBy(x => x.path).Select(x => x.First().path).ToArray(); foreach (string path in paths) { menu.AddItem(new GUIContent(path + "/Dynamic " + PrettifyTypes(argTypes)), false, null); } for (int i = 0; i < dynamicItems.Count; i++) { menu.AddItem(dynamicItems[i].label, false, dynamicItems[i].action); } foreach (string path in paths) { menu.AddItem(new GUIContent(path + "/ "), false, null); menu.AddItem(new GUIContent(path + "/Static parameters"), false, null); } } for (int i = 0; i < staticItems.Count; i++) { menu.AddItem(staticItems[i].label, false, staticItems[i].action); } if (menu.GetItemCount() == 0) { menu.AddDisabledItem(new GUIContent("No methods with return type '" + GetSimplePrettyTypeName(returnType) + "'")); } menu.ShowAsContext(); }