// (c) copyright Hutong Games, LLC 2010-2012. All rights reserved. using System; using System.Reflection; using UnityEngine; using System.Collections.Generic; namespace HutongGames.PlayMaker.Actions { [ActionCategory(ActionCategory.ScriptControl)] [Tooltip("Call a static method in a class.")] public class CallStaticMethod : FsmStateAction { [Tooltip("Full path to the class that contains the static method.")] public FsmString className; [Tooltip("The static method to call.")] public FsmString methodName; [Tooltip("Method parameters. NOTE: these must match the method's signature!")] public FsmVar[] parameters; [ActionSection("Store Result")] [UIHint(UIHint.Variable)] [Tooltip("Store the result of the method call.")] public FsmVar storeResult; [Tooltip("Repeat every frame.")] public bool everyFrame; private Type cachedType; private string cachedClassName; private string cachedMethodName; private MethodInfo cachedMethodInfo; private ParameterInfo[] cachedParameterInfo; private object[] parametersArray; private string errorString; public override void OnEnter() { parametersArray = new object[parameters.Length]; DoMethodCall(); if (!everyFrame) { Finish(); } } public override void OnUpdate() { DoMethodCall(); } private void DoMethodCall() { if (className == null || string.IsNullOrEmpty(className.Value)) { Finish(); return; } if (cachedClassName != className.Value || cachedMethodName != methodName.Value) { errorString = string.Empty; if(!DoCache()) { Debug.LogError(errorString); Finish(); return; } } object result = null; if (cachedParameterInfo.Length == 0) { result = cachedMethodInfo.Invoke(null, null); } else { for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; parameter.UpdateValue(); parametersArray[i] = parameter.GetValue(); } result = cachedMethodInfo.Invoke(null, parametersArray); } storeResult.SetValue(result); } private bool DoCache() { cachedType = ReflectionUtils.GetGlobalType(className.Value); if (cachedType == null) { errorString += "Class is invalid: " + className.Value + "\n"; Finish(); return false; } cachedClassName = className.Value; #if NETFX_CORE cachedMethodInfo = cachedType.GetTypeInfo().GetDeclaredMethod(methodName.Value); #else var types = new List( capacity: parameters.Length ); foreach ( var each in parameters ) { types.Add( each.RealType ); } cachedMethodInfo = cachedType.GetMethod(methodName.Value, types.ToArray()); #endif if (cachedMethodInfo == null) { errorString += "Invalid Method Name or Parameters: " + methodName.Value +"\n"; Finish(); return false; } cachedMethodName = methodName.Value; cachedParameterInfo = cachedMethodInfo.GetParameters(); return true; } public override string ErrorCheck() { errorString = string.Empty; DoCache(); if (!string.IsNullOrEmpty(errorString)) { return errorString; } if (parameters.Length != cachedParameterInfo.Length) { return "Parameter count does not match method.\nMethod has " + cachedParameterInfo.Length + " parameters.\nYou specified " +parameters.Length + " paramaters."; } for (var i = 0; i < parameters.Length; i++) { var p = parameters[i]; var paramType = p.RealType; var paramInfoType = cachedParameterInfo[i].ParameterType; if (!ReferenceEquals(paramType, paramInfoType )) { return "Parameters do not match method signature.\nParameter " + (i + 1) + " (" + paramType + ") should be of type: " + paramInfoType; } } if (ReferenceEquals(cachedMethodInfo.ReturnType, typeof(void))) { if (!string.IsNullOrEmpty(storeResult.variableName)) { return "Method does not have return.\nSpecify 'none' in Store Result."; } } else if (!ReferenceEquals(cachedMethodInfo.ReturnType,storeResult.RealType)) { return "Store Result is of the wrong type.\nIt should be of type: " + cachedMethodInfo.ReturnType; } return string.Empty; } } }