Skip to content

Commit 2d69127

Browse files
committed
Added an API to factorise CustomPortBehavior by type
1 parent 63863dc commit 2d69127

File tree

2 files changed

+90
-4
lines changed

2 files changed

+90
-4
lines changed

Assets/com.alelievr.NodeGraphProcessor/Runtime/Elements/BaseNode.cs

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace GraphProcessor
1010
{
1111
public delegate IEnumerable< PortData > CustomPortBehaviorDelegate(List< SerializableEdge > edges);
12+
public delegate IEnumerable< PortData > CustomPortTypeBehaviorDelegate(string fieldName, string displayName, object value);
1213

1314
[Serializable]
1415
public abstract class BaseNode
@@ -105,6 +106,9 @@ public abstract class BaseNode
105106
[NonSerialized]
106107
internal Dictionary< string, NodeFieldInformation > nodeFields = new Dictionary< string, NodeFieldInformation >();
107108

109+
[NonSerialized]
110+
internal Dictionary< Type, CustomPortTypeBehaviorDelegate> customPortTypeBehaviorMap = new Dictionary<Type, CustomPortTypeBehaviorDelegate>();
111+
108112
[NonSerialized]
109113
List< string > messages = new List< string >();
110114

@@ -186,12 +190,53 @@ public static BaseNode CreateFromType(Type nodeType, Vector2 position)
186190
public void Initialize(BaseGraph graph)
187191
{
188192
this.graph = graph;
193+
InitializeCustomPortTypeMethods();
189194

190195
ExceptionToLog.Call(() => Enable());
191196

192197
InitializePorts();
193198
}
194199

200+
void InitializeCustomPortTypeMethods()
201+
{
202+
// var methods = GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
203+
204+
// if (GetType().Name.Contains("Distance"))
205+
// Debug.Log(GetType().GetMethod("GetTypeFromTextureDim", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy));
206+
207+
MethodInfo[] methods = new MethodInfo[0];
208+
Type baseType = GetType();
209+
while (true)
210+
{
211+
methods = baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);
212+
foreach (var method in methods)
213+
{
214+
var typeBehaviors = method.GetCustomAttributes<CustomPortTypeBehavior>().ToArray();
215+
216+
if (typeBehaviors.Length == 0)
217+
continue;
218+
219+
CustomPortTypeBehaviorDelegate deleg = null;
220+
try
221+
{
222+
deleg = Delegate.CreateDelegate(typeof(CustomPortTypeBehaviorDelegate), this, method) as CustomPortTypeBehaviorDelegate;
223+
} catch (Exception e)
224+
{
225+
Debug.LogError(e);
226+
Debug.LogError($"Cannot convert method {method} to a delegate of type {typeof(CustomPortTypeBehaviorDelegate)}");
227+
}
228+
229+
foreach (var typeBehavior in typeBehaviors)
230+
customPortTypeBehaviorMap[typeBehavior.type] = deleg;
231+
}
232+
233+
// Try to also find private methods in the base class
234+
baseType = baseType.BaseType;
235+
if (baseType == null)
236+
break;
237+
}
238+
}
239+
195240
/// <summary>
196241
/// Use this function to initialize anything related to ports generation in your node
197242
/// This will allow the node creation menu to correctly recognize ports that can be connected between nodes
@@ -202,7 +247,7 @@ public virtual void InitializePorts()
202247
{
203248
var nodeField = nodeFieldKP.Value;
204249

205-
if (nodeField.behavior != null)
250+
if (HasCustomBehavior(nodeField))
206251
{
207252
UpdatePortsForField(nodeField.fieldName);
208253
}
@@ -262,7 +307,7 @@ public bool UpdatePortsForFieldLocal(string fieldName)
262307

263308
var fieldInfo = nodeFields[fieldName];
264309

265-
if (fieldInfo.behavior == null)
310+
if (!HasCustomBehavior(fieldInfo))
266311
return false;
267312

268313
List< string > finalPorts = new List< string >();
@@ -274,7 +319,20 @@ public bool UpdatePortsForFieldLocal(string fieldName)
274319
// Gather all edges connected to these fields:
275320
var edges = nodePorts.SelectMany(n => n.GetEdges()).ToList();
276321

277-
foreach (var portData in fieldInfo.behavior(edges))
322+
if (fieldInfo.behavior != null)
323+
{
324+
foreach (var portData in fieldInfo.behavior(edges))
325+
AddPortData(portData);
326+
}
327+
else
328+
{
329+
var customPortTypeBehavior = customPortTypeBehaviorMap[fieldInfo.info.FieldType];
330+
331+
foreach (var portData in customPortTypeBehavior(fieldName, fieldInfo.name, fieldInfo.info.GetValue(this)))
332+
AddPortData(portData);
333+
}
334+
335+
void AddPortData(PortData portData)
278336
{
279337
var port = nodePorts.FirstOrDefault(n => n.portData.identifier == portData.identifier);
280338
// Guard using the port identifier so we don't duplicate identifiers
@@ -335,6 +393,17 @@ public bool UpdatePortsForFieldLocal(string fieldName)
335393
return changed;
336394
}
337395

396+
bool HasCustomBehavior(NodeFieldInformation info)
397+
{
398+
if (info.behavior != null)
399+
return true;
400+
401+
if (customPortTypeBehaviorMap.ContainsKey(info.info.FieldType))
402+
return true;
403+
404+
return false;
405+
}
406+
338407
/// <summary>
339408
/// Update the ports related to one C# property field and all connected nodes in the graph
340409
/// </summary>
@@ -372,7 +441,7 @@ public bool UpdatePortsForField(string fieldName)
372441
foreach(var edge in port.GetEdges())
373442
{
374443
var edgeNode = (node.IsFieldInput(field)) ? edge.outputNode : edge.inputNode;
375-
var fieldsWithBehavior = edgeNode.nodeFields.Values.Where(f => f.behavior != null).Select(f => f.fieldName).ToList();
444+
var fieldsWithBehavior = edgeNode.nodeFields.Values.Where(f => HasCustomBehavior(f)).Select(f => f.fieldName).ToList();
376445
fieldsToUpdate.Push(new PortUpdate{fieldNames = fieldsWithBehavior, node = edgeNode});
377446
}
378447
}

Assets/com.alelievr.NodeGraphProcessor/Runtime/Graph/Attributes.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,23 @@ public CustomPortBehaviorAttribute(string fieldName)
157157
}
158158
}
159159

160+
/// <summary>
161+
/// Allow to bind a method to generate a specific set of ports based on a field type in a node
162+
/// </summary>
163+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
164+
public class CustomPortTypeBehavior : Attribute
165+
{
166+
/// <summary>
167+
/// Target type
168+
/// </summary>
169+
public Type type;
170+
171+
public CustomPortTypeBehavior(Type type)
172+
{
173+
this.type = type;
174+
}
175+
}
176+
160177
/// <summary>
161178
/// Allow you to have a custom view for your stack nodes
162179
/// </summary>

0 commit comments

Comments
 (0)