Pascal Serrarens 17741d862a First commit
2022-01-12 10:50:57 +01:00

650 lines
27 KiB
C#

using System;
using System.Reflection;
using UnityEngine;
namespace Passer {
/// <summary>
/// A function which can be called
/// </summary>
[Serializable]
public partial class FunctionCall {
/// <summary>
/// The target GameObject on which the function should be called.
/// </summary>
public GameObject targetGameObject;
/// <summary>
/// The name of the method to call on the GameObject
/// </summary>
/// The format of this string is &lt;fully qualified component type&gt;.&lt;function name&gt;
public string methodName;
public FunctionCall() { }
/// <summary>
/// Creates a new FunctionCall
/// </summary>
/// <param name="targetGameObject">The GameObject on which the functioncall is executed</param>
/// <param name="methodName">The full method name: component/methodName</param>
public FunctionCall(GameObject targetGameObject, string methodName) {
this.targetGameObject = targetGameObject;
this.methodName = methodName;
}
protected INetworkObject networkObject;
protected Delegate targetDelegate;
protected delegate void Method();
protected delegate void MethodBool(bool value);
protected delegate void MethodFloat(float value);
protected delegate void MethodInt(int value);
protected delegate void MethodVector3(Vector3 value);
protected delegate void MethodGameObject(GameObject value);
protected delegate void MethodRigidbody(Rigidbody value);
// For animation parameter calls
protected delegate void MethodStringBool(string s, bool value);
protected delegate void MethodStringFloat(string s, float value);
protected delegate void MethodStringInt(string s, int value);
public enum ParameterType {
Void,
Float,
Int,
Bool,
Vector3,
GameObject,
Rigidbody,
String,
}
public static Type ToSystemType(ParameterType parameterType) {
switch (parameterType) {
default:
case ParameterType.Void:
return typeof(void);
case ParameterType.Bool:
return typeof(bool);
case ParameterType.Int:
return typeof(int);
case ParameterType.Float:
return typeof(float);
case ParameterType.Vector3:
return typeof(Vector3);
case ParameterType.GameObject:
return typeof(GameObject);
case ParameterType.Rigidbody:
return typeof(Rigidbody);
case ParameterType.String:
return typeof(string);
}
}
/// <summary>
/// Function Parameter
/// </summary>
[Serializable]
public class Parameter {
/// <summary>
/// The parameter value comes from the event
/// </summary>
/// When false one of the constant values is used, based on the type of the parameter
public bool fromEvent = false;
/// <summary>
/// For future use...
/// </summary>
public string localProperty;
/// <summary>
/// The type of the parameter
/// </summary>
/// May be converted to a System.Type later...
public ParameterType type;
/// <summary>
/// The constant float value when the parameter type is float and fromEvent is false.
/// </summary>
public float floatConstant;
/// <summary>
/// The constant integer value when the parameter type is int and fromEvent is false.
/// </summary>
public int intConstant;
/// <summary>
/// The constant boolean value when the parameter type is bool and fromEvent is false.
/// </summary>
public bool boolConstant;
/// <summary>
/// The constant string value when the parameter type is string and fromEvent is false.
/// </summary>
public string stringConstant;
/// <summary>
/// The constant Vector3 value when the parameter type is Vector3 and fromEvent is false.
/// </summary>
public Vector3 vector3Constant;
/// <summary>
/// The constant GameObject value when the parameter type is GameObject and fromEvent is false.
/// </summary>
public GameObject gameObjectConstant;
/// <summary>
/// The constant Rigidbody value when the parameter type is Rigidbody and fromEvent is false.
/// </summary>
public Rigidbody rigidbodyConstant;
}
/// <summary>
/// For future use...
/// </summary>
public Parameter[] parameters;
/// <summary>
/// Adds a new Parameter to the function call
/// </summary>
/// <returns>The new Parameter</returns>
public Parameter AddParameter() {
if (parameters == null || parameters.Length == 0)
parameters = new Parameter[1];
parameters[parameters.Length - 1] = new Parameter();
return parameters[parameters.Length - 1];
}
public static void Execute(GameObject target, string methodName) {
UnityEngine.Object component = GetComponent(target, methodName);
Method method = CreateMethod(component, methodName);
method();
}
/// <summary>
/// For future use...
/// </summary>
public enum Networking {
No,
Yes
}
/// <summary>
/// Execute the void function call
/// </summary>
/// <param name="networking">For future use...</param>
public virtual void Execute(Networking networking = Networking.No) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
if (targetDelegate is Method) {
((Method)targetDelegate)();
ExecuteRemote();
}
else if (targetDelegate is MethodBool) {
((MethodBool)targetDelegate)(parameters[0].boolConstant);
ExecuteRemote(parameters[0].boolConstant);
}
else if (targetDelegate is MethodInt)
((MethodInt)targetDelegate)(parameters[0].intConstant);
else if (targetDelegate is MethodFloat)
((MethodFloat)targetDelegate)(parameters[0].floatConstant);
else if (targetDelegate is MethodGameObject) {
((MethodGameObject)targetDelegate)(parameters[0].gameObjectConstant);
}
else if (targetDelegate is MethodVector3)
((MethodVector3)targetDelegate)(parameters[0].vector3Constant);
else if (targetDelegate is MethodRigidbody)
((MethodRigidbody)targetDelegate)(parameters[0].rigidbodyConstant);
}
private void ExecuteRemote() {
if (NetworkObject.connected == false)
return;
if (networkObject == null)
networkObject = NetworkObject.GetINetworkObject(this);
if (networkObject != null)
networkObject.RPC(this);
}
private void ExecuteRemote(bool value) {
if (NetworkObject.connected == false)
return;
if (networkObject == null)
networkObject = NetworkObject.GetINetworkObject(this);
if (networkObject != null)
networkObject.RPC(this, value);
}
private void ExecuteRemote(float value) {
if (NetworkObject.connected == false)
return;
if (networkObject == null)
networkObject = NetworkObject.GetINetworkObject(this);
if (networkObject != null)
networkObject.RPC(this, value);
}
public static void Execute(GameObject target, string methodName, bool boolValue) {
UnityEngine.Object component = GetComponent(target, methodName);
MethodBool method = CreateMethodBool(component, methodName);
method(boolValue);
}
public static void Execute(GameObject target, string methodName, float floatValue) {
UnityEngine.Object component = GetComponent(target, methodName);
MethodFloat method = CreateMethodFloat(component, methodName);
method(floatValue);
}
/// <summary>
/// Execute a function call with a boolean parameter
/// </summary>
/// <param name="value">The boolean value to pass to the function</param>
/// <param name="networking">For future use...</param>
public void Execute(bool value, Networking networking = Networking.No) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodBool)targetDelegate)(value);
ExecuteRemote(value);
}
/// <summary>
/// Call the function with an integer parameter
/// </summary>
/// <param name="value">The integer value to pass to the function</param>
public void Execute(int value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodInt)targetDelegate)(value);
}
/// <summary>
/// Call the function with a float parameter
/// </summary>
/// <param name="value">The float value to pass to the function</param>
public virtual void Execute(float value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodFloat)targetDelegate)(value);
}
/// <summary>
/// Call the function with a Vector3 parameter
/// </summary>
/// <param name="value">The Vector3 value to pass to the function</param>
public void Execute(Vector3 value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodVector3)targetDelegate)(value);
}
/// <summary>
/// Call the funtion with a GameObject parameter
/// </summary>
/// <param name="value">The GameObject value to pass to the function</param>
public void Execute(GameObject value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodGameObject)targetDelegate)(value);
}
/// <summary>
/// Call the function with a Rigidbody parameter
/// </summary>
/// <param name="value">The Rigidbody value to pass to the function </param>
protected void Execute(Rigidbody value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodRigidbody)targetDelegate)(value);
}
/// <summary>
/// Call the function with a string and a boolean parameter
/// </summary>
/// <param name="s">The string value to pass to the function as the first parameter</param>
/// <param name="value">The boolean value to pass to the function as the second parameter</param>
public void ExecuteString(string s, bool value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodStringBool)targetDelegate)(s, value);
}
/// <summary>
/// Call the function with a string and a float parameter
/// </summary>
/// <param name="s">The string value to pass to the function as the first parameter</param>
/// <param name="value">The float value to pass to the function as the second parameter</param>
public void ExecuteString(string s, float value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodStringFloat)targetDelegate)(s, value);
}
/// <summary>
/// Call the function with a string and a integer parameter
/// </summary>
/// <param name="s">The string value to pass to the function as the first parameter</param>
/// <param name="value">The integer value to pass to the function as the second parameter</param>
public void ExecuteString(string s, int value) {
if (targetDelegate == null) {
GetTargetMethod();
if (targetDelegate == null)
return;
}
((MethodStringInt)targetDelegate)(s, value);
}
protected virtual void GetTargetMethod() {
if (targetGameObject == null)
return;
string localMethodName;
if (methodName != null && methodName.Length > 21 &&
methodName.Substring(0, 21).Equals("SetAnimatorParameter/")) {
CreateAnimationParameterMethod(targetGameObject, methodName);
if (targetDelegate != null)
return;
}
UnityEngine.Object targetComponent = GetComponent(targetGameObject, methodName, out localMethodName);
if (targetComponent == null)
return;
if (targetComponent is Script) {
Script script = (Script)targetComponent;
targetDelegate = (Method)(() => script.Execute());
return;
}
if (parameters == null || parameters.Length == 0) {
targetDelegate = CreateMethod(targetGameObject, methodName);
return;
}
switch (parameters[0].type) {
case ParameterType.Void:
targetDelegate = CreateMethod(targetGameObject, methodName);
break;
case ParameterType.Bool:
CreateTargetMethod(targetComponent, localMethodName, parameters[0].fromEvent, parameters[0].boolConstant);
break;
case ParameterType.Int:
CreateTargetMethod(targetComponent, localMethodName, parameters[0].fromEvent, parameters[0].intConstant);
break;
case ParameterType.Float:
CreateTargetMethod(targetComponent, localMethodName, parameters[0].fromEvent, parameters[0].floatConstant);
break;
case ParameterType.String:
CreateTargetMethodString(targetComponent, localMethodName, parameters[0].fromEvent, parameters[0].stringConstant);
break;
case ParameterType.Vector3:
CreateTargetMethod(targetComponent, localMethodName, parameters[0].fromEvent, parameters[0].vector3Constant);
break;
case ParameterType.GameObject:
CreateTargetMethod(targetComponent, localMethodName, parameters[0].fromEvent, parameters[0].gameObjectConstant);
break;
case ParameterType.Rigidbody:
CreateTargetMethod(targetComponent, localMethodName, parameters[0].fromEvent, parameters[0].rigidbodyConstant);
break;
default:
return;
}
}
protected static UnityEngine.Object GetComponent(GameObject target, string fullMethodName) {
string methodName;
return GetComponent(target, fullMethodName, out methodName);
}
protected static UnityEngine.Object GetComponent(GameObject target, string fullMethodName, out string methodName) {
methodName = fullMethodName;
string componentName = "";
int slashPos = methodName.LastIndexOf("/");
if (slashPos >= 0) {
methodName = methodName.Substring(slashPos + 1);
componentName = fullMethodName.Substring(0, slashPos);
}
if (componentName == "")
return null;
if (componentName == "UnityEngine.GameObject")
return target;
if (componentName == "Script") {
Script[] scriptComponents = target.GetComponents<Script>();
for (int i =0; i < scriptComponents.Length; i++) {
if (scriptComponents[i].scriptName == methodName)
return scriptComponents[i];
}
return null;
}
UnityEngine.Object component = target.GetComponent(componentName);
if (component != null)
return component;
if (componentName.StartsWith("UnityEngine."))
componentName = componentName.Substring(12);
return target.GetComponent(componentName);
}
/// <summary>
/// Gets the GameObject for the Object.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static GameObject GetGameObject(UnityEngine.Object obj) {
if (obj is GameObject)
return (GameObject)obj;
else if (obj is Component)
return ((Component)obj).gameObject;
else
return null;
}
protected void CreateAnimationParameterMethod(GameObject target, string fullMethodName) {
////string parameterName = fullMethodName.Substring(21);
//Humanoid.HumanoidControl humanoid = target.GetComponent<Humanoid.HumanoidControl>();
//if (humanoid == null)
// return;
//Type targetType = typeof(Humanoid.HumanoidControl);
//MethodInfo methodInfo;
//switch (parameters[0].type) {
// case ParameterType.Bool:
// methodInfo = targetType.GetMethod("SetAnimationParameterBool", new Type[] { typeof(string), typeof(bool) });
// if (methodInfo != null)
// targetDelegate = (MethodStringBool)Delegate.CreateDelegate(typeof(MethodStringBool), humanoid, methodInfo);
// break;
// case ParameterType.Float:
// methodInfo = targetType.GetMethod("SetAnimationParameterFloat", new Type[] { typeof(string), typeof(float) });
// if (methodInfo != null)
// targetDelegate = (MethodStringFloat)Delegate.CreateDelegate(typeof(MethodStringFloat), humanoid, methodInfo);
// break;
// case ParameterType.Int:
// methodInfo = targetType.GetMethod("SetAnimationParameterInt", new Type[] { typeof(string), typeof(int) });
// if (methodInfo != null)
// targetDelegate = (MethodStringInt)Delegate.CreateDelegate(typeof(MethodStringInt), humanoid, methodInfo);
// break;
// case ParameterType.Void:
// methodInfo = targetType.GetMethod("SetAnimationParameterTrigger", new Type[] { typeof(string) });
// if (methodInfo != null)
// targetDelegate = (MethodString)Delegate.CreateDelegate(typeof(MethodString), humanoid, methodInfo);
// break;
//}
}
protected static Method CreateMethod(GameObject target, string fullMethodName) {
string methodName;
UnityEngine.Object component = GetComponent(target, fullMethodName, out methodName);
if (component == null)
return null;
Method method = CreateMethod(component, methodName);
return method;
}
protected static Method CreateMethod(UnityEngine.Object target, string methodName) {
if (target is Script) {
Script script = (Script)target;
Method targetMethod = () => script.Execute();
return targetMethod;
}
else {
Type targetComponentType = target.GetType();
MethodInfo methodInfo = targetComponentType.GetMethod(methodName, new Type[] { });
if (methodInfo == null)
return null;
Method targetMethod = (Method)Delegate.CreateDelegate(typeof(Method), target, methodInfo);
return targetMethod;
}
}
protected static MethodBool CreateMethod(GameObject target, string fullMethodName, bool boolConstant) {
string methodName;
UnityEngine.Object component = GetComponent(target, fullMethodName, out methodName);
MethodBool method = CreateMethodBool(component, methodName);
return method;
}
protected static MethodBool CreateMethodBool(UnityEngine.Object target, string methodName) {
if (target is Script) {
// Scripts do not yet support parameters
return null;
}
else {
Type targetComponentType = target.GetType();
MethodInfo methodInfo = targetComponentType.GetMethod(methodName, new Type[] { });
if (methodInfo == null)
return null;
MethodBool targetMethod = (MethodBool)Delegate.CreateDelegate(typeof(MethodBool), target, methodInfo);
return targetMethod;
}
}
protected static MethodFloat CreateMethodFloat(UnityEngine.Object target, string methodName) {
if (target is Script) {
// Scripts do not yet support parameters
return null;
}
else {
Type targetComponentType = target.GetType();
MethodInfo methodInfo = targetComponentType.GetMethod(methodName, new Type[] { });
if (methodInfo == null)
return null;
MethodFloat targetMethod = (MethodFloat)Delegate.CreateDelegate(typeof(MethodFloat), target, methodInfo);
return targetMethod;
}
}
protected void CreateTargetMethod(UnityEngine.Object target, string methodName, bool fromEvent, bool boolConstant) {
Type targetType = target.GetType();
MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(bool) });
if (methodInfo == null)
return;
MethodBool intDelegate = (MethodBool)Delegate.CreateDelegate(typeof(MethodBool), target, methodInfo);
if (fromEvent)
targetDelegate = intDelegate;
else
targetDelegate = (MethodBool)(_ => intDelegate(boolConstant));
}
protected void CreateTargetMethod(UnityEngine.Object target, string methodName, bool fromEvent, int intConstant) {
Type targetType = target.GetType();
MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(int) });
if (methodInfo == null)
return;
MethodInt intDelegate = (MethodInt)Delegate.CreateDelegate(typeof(MethodInt), target, methodInfo);
if (fromEvent)
targetDelegate = intDelegate;
else
targetDelegate = (MethodInt)(_ => intDelegate(intConstant));
}
protected void CreateTargetMethod(UnityEngine.Object target, string methodName, bool fromEvent, float floatConstant) {
Type targetType = target.GetType();
MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(float) });
if (methodInfo == null)
return;
MethodFloat floatDelegate = (MethodFloat)Delegate.CreateDelegate(typeof(MethodFloat), target, methodInfo);
if (fromEvent)
targetDelegate = floatDelegate;
else
targetDelegate = (MethodFloat)(_ => floatDelegate(floatConstant));
}
protected void CreateTargetMethod(UnityEngine.Object target, string methodName, bool fromEvent, Vector3 vectorConstant) {
Type targetType = target.GetType();
MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(Vector3) });
if (methodInfo == null)
return;
MethodVector3 vector3Delegate = (MethodVector3)Delegate.CreateDelegate(typeof(MethodVector3), target, methodInfo);
if (fromEvent)
targetDelegate = vector3Delegate;
else
targetDelegate = (MethodVector3)(_ => vector3Delegate(vectorConstant));
}
// This is the example for the other target method creation.
// When it has a constant parameter, a void method is created and used which is the most efficient
protected void CreateTargetMethod(UnityEngine.Object target, string methodName, bool fromEvent, GameObject gameObjectConstant) {
Type targetType = target.GetType();
MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(GameObject) });
if (methodInfo == null)
return;
MethodGameObject gameObjectDelegate = (MethodGameObject)Delegate.CreateDelegate(typeof(MethodGameObject), target, methodInfo);
if (fromEvent)
targetDelegate = gameObjectDelegate;
else
targetDelegate = (MethodGameObject)(_ => gameObjectDelegate(gameObjectConstant));
}
protected void CreateTargetMethod(UnityEngine.Object target, string methodName, bool fromEvent, Rigidbody rigidbodyConstant) {
Type targetType = target.GetType();
MethodInfo methodInfo = targetType.GetMethod(methodName, new Type[] { typeof(Rigidbody) });
if (methodInfo == null)
return;
MethodRigidbody rigidbodyDelegate = (MethodRigidbody)Delegate.CreateDelegate(typeof(MethodRigidbody), target, methodInfo);
if (fromEvent)
targetDelegate = rigidbodyDelegate;
else
targetDelegate = (MethodRigidbody)(_ => rigidbodyDelegate(rigidbodyConstant));
}
}
}