using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
namespace AdvancedInspector
{
///
/// This class represent an event, and allows the Inspector to bind it to another method.
/// Arguments can be sent to the invoked method from a static field, internal from the code invoking, or from another method returned value.
///
[Serializable, AdvancedInspector]
public class ActionBinding : ICopiable
{
[SerializeField]
private string[] internalParameters = new string[0];
[SerializeField]
private GameObject gameObject;
[Inspect]
public GameObject GameObject
{
get { return gameObject; }
set
{
if (gameObject != value)
{
gameObject = value;
Component = null;
}
}
}
[SerializeField]
private Component component;
[Inspect, Restrict("GetComponents")]
public Component Component
{
get { return component; }
set
{
if (component != value)
{
component = value;
Method = null;
}
}
}
private IList GetComponents()
{
List components = new List();
if (gameObject == null)
return components;
foreach (Component component in gameObject.GetComponents(typeof(Component)))
components.Add(new DescriptorPair(component, new DescriptorAttribute(component.GetType().Name, "")));
return components;
}
[SerializeField]
private string method;
[Inspect, Restrict("GetMethods", RestrictDisplay.Toolbox)]
public MethodInfo Method
{
get { return GetMethodInfo(); }
set
{
if (value == null)
{
parameters = new BindingParameter[0];
method = "";
return;
}
MethodInfo info = GetMethodInfo();
if (info != value)
{
method = value.Name;
ParameterInfo[] param = value.GetParameters();
parameters = new BindingParameter[param.Length];
for (int i = 0; i < param.Length; i++)
{
parameters[i] = new BindingParameter(internalParameters.Length > i);
parameters[i].Type = param[i].ParameterType;
if (internalParameters.Length > i)
parameters[i].binding = BindingParameter.BindingType.Internal;
}
}
}
}
private IList GetMethods()
{
List methods = new List();
if (gameObject == null || component == null)
return methods;
foreach (MethodInfo info in component.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy))
{
if (info.IsGenericMethod || info.IsConstructor || info.IsFinal || info.IsSpecialName || info.DeclaringType == typeof(object) || info.DeclaringType == typeof(Component))
continue;
if (!IsMethodValid(info))
continue;
ParameterInfo[] param = info.GetParameters();
methods.Add(new DescriptorPair(info, new DescriptorAttribute(GetParamNames(info.Name, param), "")));
}
foreach (PropertyInfo info in component.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy))
{
if (!info.CanWrite || info.DeclaringType == typeof(object) || info.DeclaringType == typeof(UnityEngine.Object) || info.DeclaringType == typeof(Component))
continue;
MethodInfo method = info.GetSetMethod();
if (method == null || !IsMethodValid(method))
continue;
ParameterInfo[] param = method.GetParameters();
methods.Add(new DescriptorPair(method, new DescriptorAttribute(GetParamNames(info.Name, param), "")));
}
return methods;
}
private bool IsMethodValid(MethodInfo info)
{
ParameterInfo[] param = info.GetParameters();
bool valid = true;
for (int i = 0; i < param.Length; i++)
{
if (!BindingParameter.IsValidType(param[i].ParameterType))
{
valid = false;
break;
}
if (internalParameters.Length > i)
{
Type type = Type.GetType(internalParameters[i]);
if (!type.IsAssignableFrom(param[i].ParameterType))
{
valid = false;
break;
}
}
}
return valid;
}
private string GetParamNames(string name, ParameterInfo[] param)
{
string paramName = name + " (";
for (int i = 0; i < param.Length; i++)
{
paramName += param[i].ParameterType.Name;
if (i < param.Length - 1)
paramName += ", ";
}
paramName += ")";
return paramName;
}
private MethodInfo GetMethodInfo()
{
if (gameObject == null || component == null || string.IsNullOrEmpty(method))
return null;
Type[] types = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
types[i] = parameters[i].Type;
return component.GetType().GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, types, null);
}
[Inspect, Collection(0, false), SerializeField]
private BindingParameter[] parameters = new BindingParameter[0];
public event ActionEventHandler OnInvoke;
///
/// Parameter-less method constructor.
///
public ActionBinding() { }
///
/// The array of types is the method definition.
/// Method with the wrong parameters are not selectable.
///
public ActionBinding(Type[] types)
{
internalParameters = new string[types.Length];
for (int i = 0; i < types.Length; i++)
internalParameters[i] = types[i].AssemblyQualifiedName;
}
///
/// Invoke the method.
/// Be careful to pass the proper type as args, otherwise they will be ignored.
/// Args are only retained if the parameter is flagged as internal.
///
public void Invoke(params object[] args)
{
if (gameObject == null || component == null || string.IsNullOrEmpty(method))
return;
MethodInfo info = GetMethodInfo();
if (info == null)
return;
object[] values = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
if (args.Length > i && parameters[i].binding == BindingParameter.BindingType.Internal)
values[i] = args[i];
else
values[i] = parameters[i].Value;
}
info.Invoke(component, values);
if (OnInvoke != null)
OnInvoke(this, values);
}
public override string ToString()
{
string supplied = "(";
for (int i = 0; i < internalParameters.Length; i++)
{
supplied += Type.GetType(internalParameters[i]).Name;
if (i < internalParameters.Length - 1)
supplied += ", ";
}
supplied += ")";
if (component != null)
return component.GetType().Name + " : " + method + " : " + supplied;
else
return supplied;
}
public bool Copiable(object destination)
{
ActionBinding action = destination as ActionBinding;
if (action == null)
return false;
if (action.internalParameters.Length != internalParameters.Length)
return false;
for (int i = 0; i < internalParameters.Length; i++)
if (internalParameters[i] != action.internalParameters[i])
return false;
return true;
}
///
/// The binding parameter define how each of the argument of the invoked method is handled.
///
[Serializable, AdvancedInspector]
public class BindingParameter : ICopy, ICopiable
{
[Inspect(-1), Restrict("RestrictBinding")]
public BindingType binding;
private IList RestrictBinding()
{
List