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;
- }
- }
- }
|