| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 | using System;using UnityEngine;using System.Collections.Generic;using System.Reflection;using System.Linq.Expressions;namespace GraphProcessor{	public delegate void CustomPortIODelegate(BaseNode node, List< SerializableEdge > edges, NodePort outputPort = null);	public static class CustomPortIO	{		class PortIOPerField : Dictionary< string, CustomPortIODelegate > {}		class PortIOPerNode : Dictionary< Type, PortIOPerField > {}		static Dictionary< Type, List< Type > >	assignableTypes = new Dictionary< Type, List< Type > >();		static PortIOPerNode					customIOPortMethods = new PortIOPerNode();		static CustomPortIO()		{			LoadCustomPortMethods();		}		static void LoadCustomPortMethods()		{			BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;			foreach (var type in AppDomain.CurrentDomain.GetAllTypes())			{				if (type.IsAbstract || type.ContainsGenericParameters)					continue ;				if (!(type.IsSubclassOf(typeof(BaseNode))))					continue ;				var methods = type.GetMethods(bindingFlags);				foreach (var method in methods)				{					var portInputAttr = method.GetCustomAttribute< CustomPortInputAttribute >();					var portOutputAttr = method.GetCustomAttribute< CustomPortOutputAttribute >();					if (portInputAttr == null && portOutputAttr == null)						continue ;										var p = method.GetParameters();					bool nodePortSignature = false;					// Check if the function can take a NodePort in optional param					if (p.Length == 2 && p[1].ParameterType == typeof(NodePort))						nodePortSignature = true;					CustomPortIODelegate deleg;#if ENABLE_IL2CPP					// IL2CPP doesn't support expression builders					if (nodePortSignature)					{						deleg = new CustomPortIODelegate((node, edges, port) => {							Debug.Log(port);							method.Invoke(node, new object[]{ edges, port});						});					}					else					{						deleg = new CustomPortIODelegate((node, edges, port) => {							method.Invoke(node, new object[]{ edges });						});					}#else					var p1 = Expression.Parameter(typeof(BaseNode), "node");					var p2 = Expression.Parameter(typeof(List< SerializableEdge >), "edges");					var p3 = Expression.Parameter(typeof(NodePort), "port");					MethodCallExpression ex;					if (nodePortSignature)						ex = Expression.Call(Expression.Convert(p1, type), method, p2, p3);					else						ex = Expression.Call(Expression.Convert(p1, type), method, p2);					deleg = Expression.Lambda< CustomPortIODelegate >(ex, p1, p2, p3).Compile();#endif					if (deleg == null)					{						Debug.LogWarning("Can't use custom IO port function " + method + ": The method have to respect this format: " + typeof(CustomPortIODelegate));						continue ;					}					string fieldName = (portInputAttr == null) ? portOutputAttr.fieldName : portInputAttr.fieldName;					Type customType = (portInputAttr == null) ? portOutputAttr.outputType : portInputAttr.inputType;					Type fieldType = type.GetField(fieldName, bindingFlags).FieldType;					AddCustomIOMethod(type, fieldName, deleg);					AddAssignableTypes(customType, fieldType);					AddAssignableTypes(fieldType, customType);				}			}		}		public static CustomPortIODelegate GetCustomPortMethod(Type nodeType, string fieldName)		{			PortIOPerField			portIOPerField;			CustomPortIODelegate	deleg;			customIOPortMethods.TryGetValue(nodeType, out portIOPerField);			if (portIOPerField == null)				return null;			portIOPerField.TryGetValue(fieldName, out deleg);			return deleg;		}		static void AddCustomIOMethod(Type nodeType, string fieldName, CustomPortIODelegate deleg)		{			if (!customIOPortMethods.ContainsKey(nodeType))				customIOPortMethods[nodeType] = new PortIOPerField();			customIOPortMethods[nodeType][fieldName] = deleg;		}		static void AddAssignableTypes(Type fromType, Type toType)		{			if (!assignableTypes.ContainsKey(fromType))				assignableTypes[fromType] = new List< Type >();			assignableTypes[fromType].Add(toType);		}		public static bool IsAssignable(Type input, Type output)		{			if (assignableTypes.ContainsKey(input))				return assignableTypes[input].Contains(output);			return false;		}	}}
 |