-
Notifications
You must be signed in to change notification settings - Fork 425
Expand file tree
/
Copy pathCustomPortIO.cs
More file actions
138 lines (111 loc) · 4.15 KB
/
CustomPortIO.cs
File metadata and controls
138 lines (111 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
string fieldName = (portInputAttr == null) ? portOutputAttr.fieldName : portInputAttr.fieldName;
Type customType = (portInputAttr == null) ? portOutputAttr.outputType : portInputAttr.inputType;
var field = type.GetField(fieldName, bindingFlags);
if (field == null)
{
Debug.LogWarning("Can't use custom IO port function '" + method.Name + "' of class '" + type.Name + "': No field named " + fieldName + " found");
continue ;
}
Type fieldType = field.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;
}
}
}