// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus). // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) using UnityEngine; using System.Collections; using UnityEditor; using System.Linq; using System.Reflection; using System; using System.Collections.Generic; namespace Fungus.EditorUtils { [CustomEditor(typeof(InvokeMethod))] public class InvokeMethodEditor : CommandEditor { InvokeMethod targetMethod; public override void DrawCommandGUI() { base.DrawCommandGUI(); targetMethod = target as InvokeMethod; if (targetMethod == null || targetMethod.TargetObject == null) return; SerializedObject objSerializedTarget = new SerializedObject(targetMethod); string component = ShowComponents(objSerializedTarget, targetMethod.TargetObject); // show component methods if selected if (!string.IsNullOrEmpty(component)) { var method = ShowMethods(objSerializedTarget, targetMethod.TargetObject, component); // show method parameters if selected if (method != null) { objSerializedTarget.ApplyModifiedProperties(); ShowParameters(objSerializedTarget, targetMethod.TargetObject, method); ShowReturnValue(objSerializedTarget, method); } } } private string ShowComponents(SerializedObject objTarget, GameObject gameObject) { var targetComponentAssemblyName = objTarget.FindProperty("targetComponentAssemblyName"); var targetComponentFullname = objTarget.FindProperty("targetComponentFullname"); var targetComponentText = objTarget.FindProperty("targetComponentText"); var objComponents = gameObject.GetComponents(); var objTypesAssemblynames = (from objComp in objComponents select objComp.GetType().AssemblyQualifiedName).ToList(); var objTypesName = (from objComp in objComponents select objComp.GetType().Name).ToList(); int index = objTypesAssemblynames.IndexOf(targetComponentAssemblyName.stringValue); index = EditorGUILayout.Popup("Target Component", index, objTypesName.ToArray()); if (index != -1) { targetComponentAssemblyName.stringValue = objTypesAssemblynames[index]; targetComponentFullname.stringValue = objComponents.GetType().FullName; targetComponentText.stringValue = objTypesName[index]; } else { targetComponentAssemblyName.stringValue = null; } objTarget.ApplyModifiedProperties(); return targetComponentAssemblyName.stringValue; } private MethodInfo ShowMethods(SerializedObject objTarget, GameObject gameObject, string component) { MethodInfo result = null; var targetMethodProp = objTarget.FindProperty("targetMethod"); var targetMethodTextProp = objTarget.FindProperty("targetMethodText"); var methodParametersProp = objTarget.FindProperty("methodParameters"); var showInheritedProp = objTarget.FindProperty("showInherited"); var saveReturnValueProp = objTarget.FindProperty("saveReturnValue"); var returnValueKeyProp = objTarget.FindProperty("returnValueVariableKey"); var objComponent = gameObject.GetComponent(ReflectionHelper.GetType(component)); var bindingFlags = BindingFlags.Default | BindingFlags.Public | BindingFlags.Instance; if (!showInheritedProp.boolValue) { bindingFlags |= BindingFlags.DeclaredOnly; } if (objComponent != null) { var objMethods = objComponent.GetType().GetMethods(bindingFlags); var methods = (from objMethod in objMethods where !objMethod.IsSpecialName select objMethod).ToList(); // filter out the getter/setter methods var methodText = (from objMethod in methods select objMethod.Name + FormatParameters(objMethod.GetParameters()) + ": " + objMethod.ReturnType.Name).ToList(); int index = methodText.IndexOf(targetMethodTextProp.stringValue); index = EditorGUILayout.Popup("Target Method", index, methodText.ToArray()); EditorGUILayout.PropertyField(showInheritedProp); if (index != -1) { if (targetMethodTextProp.stringValue != methodText[index]) { // reset methodParametersProp.ClearArray(); methodParametersProp.arraySize = methods[index].GetParameters().Length; saveReturnValueProp.boolValue = false; returnValueKeyProp.stringValue = null; } targetMethodTextProp.stringValue = methodText[index]; targetMethodProp.stringValue = methods[index].Name; result = methods[index]; } else { targetMethodTextProp.stringValue = null; targetMethodProp.stringValue = null; } objTarget.ApplyModifiedProperties(); } return result; } private void ShowParameters(SerializedObject objTarget, GameObject gameObject, MethodInfo method) { var methodParametersProp = objTarget.FindProperty("methodParameters"); var objParams = method.GetParameters(); if (objParams.Length > 0) { GUILayout.Space(20); EditorGUILayout.LabelField("Parameters", EditorStyles.boldLabel); EditorGUILayout.BeginVertical(EditorStyles.helpBox); for (int i = 0; i < objParams.Length; i++) { var objParam = objParams[i]; GUILayout.BeginHorizontal(); string labelFormat = string.Format("{0}: {1}", objParam.ParameterType.Name, objParam.Name); var objItemProp = methodParametersProp.GetArrayElementAtIndex(i); var serObjValueProp = objItemProp.FindPropertyRelative("objValue"); var serVariableKeyProp = objItemProp.FindPropertyRelative("variableKey"); var serValueTypeAssemblynameProp = serObjValueProp.FindPropertyRelative("typeAssemblyname"); var serValueTypeFullnameProp = serObjValueProp.FindPropertyRelative("typeFullname"); serValueTypeAssemblynameProp.stringValue = objParam.ParameterType.AssemblyQualifiedName; serValueTypeFullnameProp.stringValue = objParam.ParameterType.FullName; bool isDrawn = true; if (string.IsNullOrEmpty(serVariableKeyProp.stringValue)) { isDrawn = DrawTypedPropertyInput(labelFormat, serObjValueProp, objParam.ParameterType); } if (isDrawn) { var vars = GetFungusVariablesByType(targetMethod.GetFlowchart().Variables, objParam.ParameterType); var values = new string[] { "" }; var displayValue = values.Concat(vars).ToList(); int index = displayValue.IndexOf(serVariableKeyProp.stringValue); if (index == -1) { index = 0; } if (string.IsNullOrEmpty(serVariableKeyProp.stringValue)) { index = EditorGUILayout.Popup(index, displayValue.ToArray(), GUILayout.MaxWidth(80)); } else { index = EditorGUILayout.Popup(labelFormat, index, displayValue.ToArray()); } if (index > 0) { serVariableKeyProp.stringValue = displayValue[index]; } else { serVariableKeyProp.stringValue = null; } } else { var style = EditorStyles.label; var prevColor = style.normal.textColor; style.normal.textColor = Color.red; EditorGUILayout.LabelField(new GUIContent(objParam.ParameterType.Name + " cannot be drawn, don´t use this method in the flowchart."), style); style.normal.textColor = prevColor; } GUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); objTarget.ApplyModifiedProperties(); } } private void ShowReturnValue(SerializedObject objTarget, MethodInfo method) { var saveReturnValueProp = objTarget.FindProperty("saveReturnValue"); var returnValueKeyProp = objTarget.FindProperty("returnValueVariableKey"); var returnValueTypeProp = objTarget.FindProperty("returnValueType"); var callModeProp = objTarget.FindProperty("callMode"); returnValueTypeProp.stringValue = method.ReturnType.FullName; if (method.ReturnType == typeof(IEnumerator)) { GUILayout.Space(20); EditorGUILayout.PropertyField(callModeProp); } else if (method.ReturnType != typeof(void)) { GUILayout.Space(20); EditorGUILayout.LabelField("Return Value", EditorStyles.boldLabel); EditorGUILayout.BeginVertical(EditorStyles.helpBox); saveReturnValueProp.boolValue = EditorGUILayout.Toggle("Save return value", saveReturnValueProp.boolValue); if (saveReturnValueProp.boolValue) { var vars = GetFungusVariablesByType(targetMethod.GetFlowchart().Variables, method.ReturnType).ToList(); int index = vars.IndexOf(returnValueKeyProp.stringValue); index = EditorGUILayout.Popup(method.ReturnType.Name, index, vars.ToArray()); if (index != -1) { returnValueKeyProp.stringValue = vars[index]; } } EditorGUILayout.EndVertical(); } else { saveReturnValueProp.boolValue = false; } objTarget.ApplyModifiedProperties(); } private bool DrawTypedPropertyInput(string label, SerializedProperty objProperty, Type type) { SerializedProperty objectValue = null; if (type == typeof(int)) { objectValue = objProperty.FindPropertyRelative("intValue"); objectValue.intValue = EditorGUILayout.IntField(new GUIContent(label), objectValue.intValue); return true; } else if (type == typeof(bool)) { objectValue = objProperty.FindPropertyRelative("boolValue"); objectValue.boolValue = EditorGUILayout.Toggle(new GUIContent(label), objectValue.boolValue); return true; } else if (type == typeof(float)) { objectValue = objProperty.FindPropertyRelative("floatValue"); objectValue.floatValue = EditorGUILayout.FloatField(new GUIContent(label), objectValue.floatValue); return true; } else if (type == typeof(string)) { objectValue = objProperty.FindPropertyRelative("stringValue"); objectValue.stringValue = EditorGUILayout.TextField(new GUIContent(label), objectValue.stringValue); return true; } else if (type == typeof(Color)) { objectValue = objProperty.FindPropertyRelative("colorValue"); objectValue.colorValue = EditorGUILayout.ColorField(new GUIContent(label), objectValue.colorValue); return true; } else if (type == typeof(UnityEngine.GameObject)) { objectValue = objProperty.FindPropertyRelative("gameObjectValue"); objectValue.objectReferenceValue = EditorGUILayout.ObjectField(new GUIContent(label), objectValue.objectReferenceValue, typeof(UnityEngine.GameObject), true); return true; } else if (type == typeof(UnityEngine.Material)) { objectValue = objProperty.FindPropertyRelative("materialValue"); objectValue.objectReferenceValue = EditorGUILayout.ObjectField(new GUIContent(label), objectValue.objectReferenceValue, typeof(UnityEngine.Material), true); return true; } else if (type == typeof(UnityEngine.Sprite)) { objectValue = objProperty.FindPropertyRelative("spriteValue"); objectValue.objectReferenceValue = EditorGUILayout.ObjectField(new GUIContent(label), objectValue.objectReferenceValue, typeof(UnityEngine.Sprite), true); return true; } else if (type == typeof(UnityEngine.Texture)) { objectValue = objProperty.FindPropertyRelative("textureValue"); objectValue.objectReferenceValue = EditorGUILayout.ObjectField(new GUIContent(label), objectValue.objectReferenceValue, typeof(UnityEngine.Texture), true); return true; } else if (type == typeof(UnityEngine.Vector2)) { objectValue = objProperty.FindPropertyRelative("vector2Value"); objectValue.vector2Value = EditorGUILayout.Vector2Field(new GUIContent(label), objectValue.vector2Value); return true; } else if (type == typeof(UnityEngine.Vector3)) { objectValue = objProperty.FindPropertyRelative("vector3Value"); objectValue.vector3Value = EditorGUILayout.Vector3Field(new GUIContent(label), objectValue.vector3Value); return true; } else if (type.IsSubclassOf(typeof(UnityEngine.Object))) { objectValue = objProperty.FindPropertyRelative("objectValue"); objectValue.objectReferenceValue = EditorGUILayout.ObjectField(new GUIContent(label), objectValue.objectReferenceValue, type, true); return true; } else if (type.IsEnum) { var enumNames = Enum.GetNames(type); objectValue = objProperty.FindPropertyRelative("intValue"); objectValue.intValue = EditorGUILayout.Popup(label, objectValue.intValue, enumNames); return true; } return false; } private string[] GetFungusVariablesByType(List variables, Type type) { string[] result = new string[0]; if (type == typeof(int)) { result = (from v in variables where v.GetType() == typeof(IntegerVariable) select v.Key).ToArray(); } else if (type == typeof(bool)) { result = (from v in variables where v.GetType() == typeof(BooleanVariable) select v.Key).ToArray(); } else if (type == typeof(float)) { result = (from v in variables where v.GetType() == typeof(FloatVariable) select v.Key).ToArray(); } else if (type == typeof(string)) { result = (from v in variables where v.GetType() == typeof(StringVariable) select v.Key).ToArray(); } else if (type == typeof(Color)) { result = (from v in variables where v.GetType() == typeof(ColorVariable) select v.Key).ToArray(); } else if (type == typeof(UnityEngine.GameObject)) { result = (from v in variables where v.GetType() == typeof(GameObjectVariable) select v.Key).ToArray(); } else if (type == typeof(UnityEngine.Material)) { result = (from v in variables where v.GetType() == typeof(MaterialVariable) select v.Key).ToArray(); } else if (type == typeof(UnityEngine.Sprite)) { result = (from v in variables where v.GetType() == typeof(SpriteVariable) select v.Key).ToArray(); } else if (type == typeof(UnityEngine.Texture)) { result = (from v in variables where v.GetType() == typeof(TextureVariable) select v.Key).ToArray(); } else if (type == typeof(UnityEngine.Vector2)) { result = (from v in variables where v.GetType() == typeof(Vector2Variable) select v.Key).ToArray(); } else if (type == typeof(UnityEngine.Vector3)) { result = (from v in variables where v.GetType() == typeof(Vector3Variable) select v.Key).ToArray(); } else if (type.IsSubclassOf(typeof(UnityEngine.Object))) { result = (from v in variables where v.GetType() == typeof(ObjectVariable) select v.Key).ToArray(); } return result; } private string FormatParameters(ParameterInfo[] paramInfo) { string result = " ("; for (int i = 0; i < paramInfo.Length; i++) { var pi = paramInfo[i]; result += pi.ParameterType.Name; // " arg" + (i + 1); if (i < paramInfo.Length - 1) { result += ", "; } } return result + ")"; } private object GetDefaultValue(Type t) { if (t.IsValueType) return Activator.CreateInstance(t); return null; } } }