using HutongGames.PlayMaker.Actions; using HutongGames.PlayMakerEditor; using UnityEditor; using UnityEngine; using System; using System.Collections; using System.Reflection; using HutongGames.PlayMaker; namespace HutongGames.PlayMakerEditor { /// /// TODO: /// Keep parameters when changing method signature? /// Copy/paste parameter values? /// Ability to add custom menu item to Action Settings menu? /// [CustomActionEditor(typeof(HutongGames.PlayMaker.Actions.CallMethod))] public class CallMethodEditor : CustomActionEditor { private CallMethod callMethod; private Type cachedType; private string cachedTypeName; private MethodInfo cachedMethod; private string cachedMethodSignature; private ParameterInfo[] cachedParameters; private GUIContent[] cachedParameterLabels; private GUIContent cachedReturnLabel; private object[] parameterAttributes; private object[] returnAttributes; private string methodSignature; private bool initialized; public override void OnEnable() { //Debug.Log("OnEnable"); Initialize(); } private void Initialize() { if (initialized) return; UpdateCache(); parameterAttributes = new object[] { new HideTypeFilter() }; returnAttributes = new object[] { new UIHintAttribute(UIHint.Variable), new HideTypeFilter() }; methodSignature = GetMethodSignatureFromSettings(); //Debug.Log(methodSignature); var method = TypeHelpers.FindMethod(cachedType, methodSignature); InitMethod(method); initialized = true; } private void UpdateCache() { callMethod = target as CallMethod; if (callMethod != null) { if (callMethod.parameters == null) { callMethod.parameters = new FsmVar[0]; } if (callMethod.methodName == null) { callMethod.methodName = new FsmString(); } if (callMethod.behaviour != null) { cachedType = callMethod.behaviour.ObjectType; cachedTypeName = cachedType != null ? cachedType.FullName : ""; //Debug.Log(cachedTypeName); } else { //Debug.Log("callMethod.behaviour == null"); } } } private void CheckCache() { if (callMethod.behaviour != null) { if (cachedType != callMethod.behaviour.ObjectType) { ClearCache(); UpdateCache(); return; } // NOTE: Temp fix. Permanent fix in VariableEditor.cs in 1.8.3 if (callMethod.behaviour.Value != null && callMethod.behaviour.Value.GetType() != callMethod.behaviour.ObjectType) { callMethod.behaviour.ObjectType = callMethod.behaviour.Value.GetType(); ClearCache(); UpdateCache(); } // NOTE: Temp fix. Permanent fix in VariableEditor.cs in 1.8.3 if ((!callMethod.behaviour.UseVariable && callMethod.behaviour.Value == null) || callMethod.behaviour.IsNone) { var component = callMethod.behaviour.Value as Component; if (component == null) { callMethod.behaviour.ObjectType = typeof (Component); callMethod.methodName = ""; ClearCache(); UpdateCache(); } } /* // User Reset the action if (!callMethod.behaviour.UseVariable && callMethod.behaviour.Value == null && !string.IsNullOrEmpty(cachedTypeName)) { ClearCache(); }*/ } } public override bool OnGUI() { if (callMethod.manualUI) { return DrawDefaultInspector(); } EditField("behaviour"); FsmEditorGUILayout.ReadonlyTextField(cachedTypeName); CheckCache(); EditorGUILayout.BeginHorizontal(); FsmEditorGUILayout.PrefixLabel("Method"); var buttonRect = GUILayoutUtility.GetRect(GUIContent.none, EditorStyles.popup); var methodName = callMethod.methodName != null ? callMethod.methodName.Value : ""; if (GUI.Button(buttonRect, methodName, EditorStyles.popup)) { TypeHelpers.GenerateMethodMenu(cachedType, SelectMethod).DropDown(buttonRect); } EditorGUILayout.EndHorizontal(); FsmEditorGUILayout.ReadonlyTextField(cachedMethodSignature); //EditorGUI.indentLevel++; if (cachedParameters != null && cachedParameters.Length > 0) { GUILayout.Label("Parameters", EditorStyles.boldLabel); for (int i = 0; i < cachedParameters.Length; i++) { //GUILayout.Label(callMethod.parameters[i].RealType.ToString()); callMethod.parameters[i] = FsmEditor.ActionEditor.EditFsmVar(cachedParameterLabels[i], callMethod.parameters[i], parameterAttributes); } } if (cachedMethod != null && cachedMethod.ReturnType != typeof (void)) { GUILayout.Label("Return", EditorStyles.boldLabel); callMethod.storeResult = FsmEditor.ActionEditor.EditFsmVar(cachedReturnLabel, callMethod.storeResult, returnAttributes); } //EditorGUI.indentLevel--; FsmEditorGUILayout.LightDivider(); EditField("everyFrame"); FsmEditorGUILayout.LightDivider(); EditField("manualUI"); if (GUI.changed) { UpdateCache(); } return GUI.changed; } // NOTE: This should match format generated by TypeHelpers. private string GetMethodSignatureFromSettings() { if (callMethod.methodName == null || callMethod.parameters == null || callMethod.storeResult == null) return ""; return TypeHelpers.GetMethodSignature(callMethod.methodName.Value, callMethod.parameters, callMethod.storeResult); } private void ClearCache() { //Debug.Log("ClearCache"); cachedMethod = null; cachedMethodSignature = null; cachedParameters = null; cachedParameterLabels = null; } private void InitMethod(MethodInfo method) { if (method == null) { //Debug.Log("InitMethod: None"); // TODO: select none ClearCache(); } else { //Debug.Log("InitMethod: " + method.Name); cachedMethod = method; cachedMethodSignature = TypeHelpers.GetMethodSignature(method); cachedParameters = method.GetParameters(); cachedParameterLabels = new GUIContent[cachedParameters.Length]; callMethod.methodName.Value = method.Name; for (int i = 0; i < cachedParameters.Length; i++) { var parameter = cachedParameters[i]; cachedParameterLabels[i] = new GUIContent(Labels.NicifyVariableName(parameter.Name)); } cachedReturnLabel = new GUIContent("Store Result", Labels.GetTypeTooltip(method.ReturnType)); } } private void SelectMethod(object userdata) { var method = userdata as MethodInfo; if (method == null) { //Debug.Log("Select Method: None"); // TODO: select none ClearCache(); } else { //Debug.Log("Select Method: " + method.Name); InitMethod(method); callMethod.parameters = new FsmVar[cachedParameters.Length]; for (int i = 0; i < cachedParameters.Length; i++) { callMethod.parameters[i] = new FsmVar(cachedParameters[i].ParameterType); } callMethod.storeResult = new FsmVar(method.ReturnType); FsmEditor.SaveActions(); } } } }