An easy to use Unity 3D library for creating illustrated Interactive Fiction games and more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

442 lines
18 KiB

// 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<Component>();
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[] { "<Value>" };
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<Variable> 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;
}
}
}