private static void DoNodeOperation(
BuildTarget target,
NodeData currentNodeData,
ConnectionPointData currentInputPoint,
ConnectionData connectionToOutput,
SaveData saveData,
Dictionary<ConnectionData, Dictionary<string, List<Asset>>> resultDict,
Dictionary<NodeData, List<string>> cachedDict,
List<string> performedIds,
bool isActualRun,
Action<NodeException> errorHandler,
Action<NodeData, float> updateHandler
)
{
if (performedIds.Contains(currentNodeData.Id) || (currentInputPoint != null && performedIds.Contains(currentInputPoint.Id))) {
return;
}
/*
* Find connections coming into this node from parent node, and traverse recursively
*/
var connectionsToParents = saveData.Connections.FindAll(con => con.ToNodeId == currentNodeData.Id);
foreach (var c in connectionsToParents) {
var parentNode = saveData.Nodes.Find(node => node.Id == c.FromNodeId);
UnityEngine.Assertions.Assert.IsNotNull(parentNode);
// check if nodes can connect together
ConnectionData.ValidateConnection(parentNode, currentNodeData);
if( parentNode.InputPoints.Count > 0 ) {
// if node has multiple input, node is operated per input
foreach(var parentInputPoint in parentNode.InputPoints) {
DoNodeOperation(target, parentNode, parentInputPoint, c, saveData, resultDict, cachedDict, performedIds, isActualRun, errorHandler, updateHandler);
}
}
// if parent does not have input point, call with inputPoint==null
else {
DoNodeOperation(target, parentNode, null, c, saveData, resultDict, cachedDict, performedIds, isActualRun, errorHandler, updateHandler);
}
}
// mark this point as performed
if(currentInputPoint != null) {
performedIds.Add(currentInputPoint.Id);
}
// Root node does not have input point, so we are storing node id instead.
else {
performedIds.Add(currentNodeData.Id);
}
/*
* Perform node operation for this node
*/
if (updateHandler != null) {
updateHandler(currentNodeData, 0f);
}
/*
has next node, run first time.
*/
var alreadyCachedPaths = new List<string>();
if (cachedDict.ContainsKey(currentNodeData)) {
alreadyCachedPaths.AddRange(cachedDict[currentNodeData]);
}
// load already exist cache from node.
alreadyCachedPaths.AddRange(GetCachedDataByNode(target, currentNodeData));
// Grab incoming assets from result by refering connections to parents
var inputGroupAssets = new Dictionary<string, List<Asset>>();
if(currentInputPoint != null) {
// aggregates all input assets coming from current inputPoint
var connToParentsFromCurrentInput = saveData.Connections.FindAll(con => con.ToNodeConnectionPointId == currentInputPoint.Id);
foreach (var rCon in connToParentsFromCurrentInput) {
if (!resultDict.ContainsKey(rCon)) {
continue;
}
var result = resultDict[rCon];
foreach (var groupKey in result.Keys) {
if (!inputGroupAssets.ContainsKey(groupKey)) {
inputGroupAssets[groupKey] = new List<Asset>();
}
inputGroupAssets[groupKey].AddRange(result[groupKey]);
}
}
}
/*
the Action passes to NodeOperaitons.
It stores result to resultDict.
*/
Action<ConnectionData, Dictionary<string, List<Asset>>, List<string>> Output =
(ConnectionData destinationConnection, Dictionary<string, List<Asset>> outputGroupAsset, List<string> cachedItems) =>
{
if(destinationConnection != null ) {
if (!resultDict.ContainsKey(destinationConnection)) {
resultDict[destinationConnection] = new Dictionary<string, List<Asset>>();
}
/*
merge connection result by group key.
*/
foreach (var groupKey in outputGroupAsset.Keys) {
if (!resultDict[destinationConnection].ContainsKey(groupKey)) {
resultDict[destinationConnection][groupKey] = new List<Asset>();
}
resultDict[destinationConnection][groupKey].AddRange(outputGroupAsset[groupKey]);
}
}
if (isActualRun) {
if (!cachedDict.ContainsKey(currentNodeData)) {
cachedDict[currentNodeData] = new List<string>();
}
if(cachedItems != null) {
cachedDict[currentNodeData].AddRange(cachedItems);
}
}
};
try {
INodeOperation executor = CreateOperation(saveData, currentNodeData, errorHandler);
if(executor != null) {
if(isActualRun) {
executor.Run(target, currentNodeData, currentInputPoint, connectionToOutput, inputGroupAssets, alreadyCachedPaths, Output);
}
else {
executor.Setup(target, currentNodeData, currentInputPoint, connectionToOutput, inputGroupAssets, alreadyCachedPaths, Output);
}
}
} catch (NodeException e) {
errorHandler(e);
// since error occured, this node should stop running for other inputpoints. Adding node id to stop.
if(!performedIds.Contains(currentNodeData.Id)) {
performedIds.Add(currentNodeData.Id);
}
}
if (updateHandler != null) {
updateHandler(currentNodeData, 1f);
}
}