/**
* Perform Run or Setup from parent of given terminal node recursively.
*/
private static void DoNodeOperation(
string nodeId,
List <NodeData> allNodes,
List <ConnectionData> allConnections,
Dictionary <string, Dictionary <string, List <Asset> > > resultDict,
Dictionary <string, List <string> > cachedDict,
List <string> usedConnectionIds,
bool isActualRun,
Action <string, float> updateHandler = null
)
{
var relatedNodes = allNodes.Where(relation => relation.nodeId == nodeId).ToList();
if (!relatedNodes.Any())
{
return;
}
var currentNodeData = relatedNodes[0];
if (currentNodeData.IsAlreadyDone())
{
return;
}
var nodeName = currentNodeData.nodeName;
var nodeKind = currentNodeData.nodeKind;
/*
* Perform prarent node recursively from this node
*/
foreach (var connectionToParent in currentNodeData.connectionToParents)
{
var parentNodeId = connectionToParent.fromNodeId;
var usedConnectionId = connectionToParent.connectionId;
if (usedConnectionIds.Contains(usedConnectionId))
{
throw new NodeException("connection loop detected.", parentNodeId);
}
usedConnectionIds.Add(usedConnectionId);
var parentNode = allNodes.Where(node => node.nodeId == parentNodeId).ToList();
if (!parentNode.Any())
{
return;
}
var parentNodeKind = parentNode[0].nodeKind;
// check node kind order.
SystemDataValidator.ValidateAssertNodeOrder(parentNodeKind, nodeKind);
DoNodeOperation(parentNodeId, allNodes, allConnections, resultDict, cachedDict, usedConnectionIds, isActualRun, updateHandler);
}
/*
* Perform node operation for this node
*/
// connections Ids from this node to child nodes. non-ordered.
// actual running order depends on order of Node's OutputPoint order.
var nonOrderedConnectionsFromThisNodeToChildNode = allConnections
.Where(con => con.fromNodeId == nodeId)
.ToList();
var orderedNodeOutputPointIds = allNodes.Where(node => node.nodeId == nodeId).SelectMany(node => node.outputPointIds).ToList();
/*
* get connection ids which is orderd by node's outputPoint-order.
*/
var orderedConnectionIds = new List <string>(nonOrderedConnectionsFromThisNodeToChildNode.Count);
foreach (var orderedNodeOutputPointId in orderedNodeOutputPointIds)
{
foreach (var nonOrderedConnectionFromThisNodeToChildNode in nonOrderedConnectionsFromThisNodeToChildNode)
{
var nonOrderedConnectionOutputPointId = nonOrderedConnectionFromThisNodeToChildNode.fromNodeOutputPointId;
if (orderedNodeOutputPointId == nonOrderedConnectionOutputPointId)
{
orderedConnectionIds.Add(nonOrderedConnectionFromThisNodeToChildNode.connectionId);
continue;
}
}
}
/*
* FilterNode and BundlizerNode uses specific multiple output connections.
* ExportNode does not have output.
* but all other nodes has only one output connection and uses first connection.
*/
var firstConnectionIdFromThisNodeToChildNode = string.Empty;
if (orderedConnectionIds.Any())
{
firstConnectionIdFromThisNodeToChildNode = orderedConnectionIds[0];
}
if (updateHandler != null)
{
updateHandler(nodeId, 0f);
}
/*
* has next node, run first time.
*/
var alreadyCachedPaths = new List <string>();
if (cachedDict.ContainsKey(nodeId))
{
alreadyCachedPaths.AddRange(cachedDict[nodeId]);
}
/*
* load already exist cache from node.
*/
alreadyCachedPaths.AddRange(GetCachedDataByNodeKind(nodeKind, nodeId));
var inputParentResults = new Dictionary <string, List <Asset> >();
var receivingConnectionIds = allConnections
.Where(con => con.toNodeId == nodeId)
.Select(con => con.connectionId)
.ToList();
foreach (var connecionId in receivingConnectionIds)
{
if (!resultDict.ContainsKey(connecionId))
{
continue;
}
var result = resultDict[connecionId];
foreach (var groupKey in result.Keys)
{
if (!inputParentResults.ContainsKey(groupKey))
{
inputParentResults[groupKey] = new List <Asset>();
}
inputParentResults[groupKey].AddRange(result[groupKey]);
}
}
/*
* the Action passes to NodeOperaitons.
* It stores result to resultDict.
*/
Action <string, string, Dictionary <string, List <Asset> >, List <string> > Output =
(string dataSourceNodeId, string targetConnectionId, Dictionary <string, List <Asset> > result, List <string> justCached) =>
{
var targetConnectionIds = allConnections
.Where(con => con.connectionId == targetConnectionId)
.Select(con => con.connectionId)
.ToList();
if (!targetConnectionIds.Any())
{
// if next connection does not exist, no results for next.
// save results to resultDict with this endpoint node's id.
resultDict[dataSourceNodeId] = new Dictionary <string, List <Asset> >();
foreach (var groupKey in result.Keys)
{
if (!resultDict[dataSourceNodeId].ContainsKey(groupKey))
{
resultDict[dataSourceNodeId][groupKey] = new List <Asset>();
}
resultDict[dataSourceNodeId][groupKey].AddRange(result[groupKey]);
}
return;
}
if (!resultDict.ContainsKey(targetConnectionId))
{
resultDict[targetConnectionId] = new Dictionary <string, List <Asset> >();
}
/*
* merge connection result by group key.
*/
foreach (var groupKey in result.Keys)
{
if (!resultDict[targetConnectionId].ContainsKey(groupKey))
{
resultDict[targetConnectionId][groupKey] = new List <Asset>();
}
resultDict[targetConnectionId][groupKey].AddRange(result[groupKey]);
}
if (isActualRun)
{
if (!cachedDict.ContainsKey(nodeId))
{
cachedDict[nodeId] = new List <string>();
}
cachedDict[nodeId].AddRange(justCached);
}
};
try {
if (isActualRun)
{
switch (nodeKind)
{
/*
* Scripts
*/
case AssetBundleGraphSettings.NodeKind.FILTER_SCRIPT: {
var scriptClassName = currentNodeData.scriptClassName;
var executor = SystemDataUtility.CreateNodeOperationInstance <FilterBase>(scriptClassName, nodeId);
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.PREFABRICATOR_SCRIPT: {
var scriptClassName = currentNodeData.scriptClassName;
var executor = SystemDataUtility.CreateNodeOperationInstance <PrefabricatorBase>(scriptClassName, nodeId);
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
/*
* GUIs
*/
case AssetBundleGraphSettings.NodeKind.LOADER_GUI: {
var currentLoadFilePath = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.loadFilePath);
var executor = new IntegratedGUILoader(FileUtility.GetPathWithAssetsPath(currentLoadFilePath));
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.FILTER_GUI: {
/*
* Filter requires "outputPoint ordered exist connection Id and Fake connection Id" for
* exhausting assets by keyword and type correctly.
*
* outputPoint which has connection can through assets by keyword and keytype,
* also outputPoint which doesn't have connection should take assets by keyword and keytype.
*/
var orderedConnectionIdsAndFakeConnectionIds = new string[orderedNodeOutputPointIds.Count];
for (var i = 0; i < orderedNodeOutputPointIds.Count; i++)
{
var orderedNodeOutputPointId = orderedNodeOutputPointIds[i];
foreach (var nonOrderedConnectionFromThisNodeToChildNode in nonOrderedConnectionsFromThisNodeToChildNode)
{
var connectionOutputPointId = nonOrderedConnectionFromThisNodeToChildNode.fromNodeOutputPointId;
if (orderedNodeOutputPointId == connectionOutputPointId)
{
orderedConnectionIdsAndFakeConnectionIds[i] = nonOrderedConnectionFromThisNodeToChildNode.connectionId;
break;
}
else
{
orderedConnectionIdsAndFakeConnectionIds[i] = AssetBundleGraphSettings.FILTER_FAKE_CONNECTION_ID;
}
}
}
var executor = new IntegratedGUIFilter(orderedConnectionIdsAndFakeConnectionIds, currentNodeData.containsKeywords, currentNodeData.containsKeytypes);
executor.Run(nodeName, nodeId, string.Empty, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.IMPORTSETTING_GUI: {
var executor = new IntegratedGUIImportSetting();
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.MODIFIER_GUI: {
var specificScriptClass = currentNodeData.scriptClassName;
var executor = new IntegratedGUIModifier(specificScriptClass, SystemDataUtility.GetCurrentPlatformShortName());
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.GROUPING_GUI: {
var executor = new IntegratedGUIGrouping(SystemDataUtility.GetCurrentPlatformValue(currentNodeData.groupingKeyword));
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.PREFABRICATOR_GUI: {
var scriptClassName = currentNodeData.scriptClassName;
if (string.IsNullOrEmpty(scriptClassName))
{
Debug.LogError(nodeName + ": Classname is empty. Set valid classname. Configure valid script name from editor.");
break;
}
var executor = SystemDataUtility.CreateNodeOperationInstance <PrefabricatorBase>(scriptClassName, nodeId);
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.BUNDLIZER_GUI: {
/*
* Bundlizer requires assetOutputConnectionId and additional resourceOutputConnectionId.
* both-connected, or both-not-connected, or one of them is connected. 4 patterns exists.
*
* Bundler Node's outputPoint [0] is always the point for assetOutputConnectionId.
* Bundler Node's outputPoint [1] is always the point for resourceOutputConnectionId.
*
* if one of these outputPoint don't have connection, use Fake connection id for correct output.
*
*
* unorderedConnectionId \
* ----> orderedConnectionIdsAndFakeConnectionIds.
* orderedOutputPointId /
*/
var orderedConnectionIdsAndFakeConnectionIds = new string[orderedNodeOutputPointIds.Count];
for (var i = 0; i < orderedNodeOutputPointIds.Count; i++)
{
var orderedNodeOutputPointId = orderedNodeOutputPointIds[i];
foreach (var nonOrderedConnectionFromThisNodeToChildNode in nonOrderedConnectionsFromThisNodeToChildNode)
{
var connectionOutputPointId = nonOrderedConnectionFromThisNodeToChildNode.fromNodeOutputPointId;
if (orderedNodeOutputPointId == connectionOutputPointId)
{
orderedConnectionIdsAndFakeConnectionIds[i] = nonOrderedConnectionFromThisNodeToChildNode.connectionId;
break;
}
else
{
orderedConnectionIdsAndFakeConnectionIds[i] = AssetBundleGraphSettings.BUNDLIZER_FAKE_CONNECTION_ID;
}
}
}
var bundleNameTemplate = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.bundleNameTemplate);
/*
* TODO: variants needs to be execute Setup/Run as many times as its variants
*/
var executor = new IntegratedGUIBundlizer(bundleNameTemplate, orderedConnectionIdsAndFakeConnectionIds[0], currentNodeData.variants);
executor.Run(nodeName, nodeId, string.Empty, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.BUNDLEBUILDER_GUI: {
var bundleOptions = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.enabledBundleOptions);
var executor = new IntegratedGUIBundleBuilder(bundleOptions, allNodes.Select(nodeData => nodeData.nodeId).ToList());
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.EXPORTER_GUI: {
var exportTo = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.exportFilePath);
var executor = new IntegratedGUIExporter(FileUtility.GetPathWithProjectPath(exportTo));
executor.Run(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
default: {
Debug.LogError(nodeName + " is defined as unknown kind of node. value:" + nodeKind);
break;
}
}
}
else
{
switch (nodeKind)
{
/*
* Scripts
*/
case AssetBundleGraphSettings.NodeKind.FILTER_SCRIPT: {
var scriptClassName = currentNodeData.scriptClassName;
var executor = SystemDataUtility.CreateNodeOperationInstance <FilterBase>(scriptClassName, nodeId);
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.PREFABRICATOR_SCRIPT: {
var scriptClassName = currentNodeData.scriptClassName;
var executor = SystemDataUtility.CreateNodeOperationInstance <PrefabricatorBase>(scriptClassName, nodeId);
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
/*
* GUIs
*/
case AssetBundleGraphSettings.NodeKind.LOADER_GUI: {
var currentLoadFilePath = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.loadFilePath);
var executor = new IntegratedGUILoader(FileUtility.GetPathWithAssetsPath(currentLoadFilePath));
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.FILTER_GUI: {
/*
* Filter requires "outputPoint ordered exist connection Id and Fake connection Id" for
* exhausting assets by keyword and type correctly.
*
* outputPoint which has connection can through assets by keyword and keytype,
* also outputPoint which doesn't have connection should take assets by keyword and keytype.
*/
var orderedConnectionIdsAndFakeConnectionIds = new string[orderedNodeOutputPointIds.Count];
for (var i = 0; i < orderedNodeOutputPointIds.Count; i++)
{
var orderedNodeOutputPointId = orderedNodeOutputPointIds[i];
foreach (var nonOrderedConnectionFromThisNodeToChildNode in nonOrderedConnectionsFromThisNodeToChildNode)
{
var connectionOutputPointId = nonOrderedConnectionFromThisNodeToChildNode.fromNodeOutputPointId;
if (orderedNodeOutputPointId == connectionOutputPointId)
{
orderedConnectionIdsAndFakeConnectionIds[i] = nonOrderedConnectionFromThisNodeToChildNode.connectionId;
break;
}
else
{
orderedConnectionIdsAndFakeConnectionIds[i] = AssetBundleGraphSettings.FILTER_FAKE_CONNECTION_ID;
}
}
}
var executor = new IntegratedGUIFilter(orderedConnectionIdsAndFakeConnectionIds, currentNodeData.containsKeywords, currentNodeData.containsKeytypes);
executor.Setup(nodeName, nodeId, string.Empty, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.IMPORTSETTING_GUI: {
var executor = new IntegratedGUIImportSetting();
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.MODIFIER_GUI: {
var specificScriptClass = currentNodeData.scriptClassName;
var executor = new IntegratedGUIModifier(specificScriptClass, SystemDataUtility.GetCurrentPlatformShortName());
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.GROUPING_GUI: {
var executor = new IntegratedGUIGrouping(SystemDataUtility.GetCurrentPlatformValue(currentNodeData.groupingKeyword));
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.PREFABRICATOR_GUI: {
var scriptClassName = currentNodeData.scriptClassName;
if (string.IsNullOrEmpty(scriptClassName))
{
AssetBundleGraphEditorWindow.AddNodeException(new NodeException(nodeName + ": Classname is empty. Set valid classname.", nodeId));
break;
}
try {
var executor = SystemDataUtility.CreateNodeOperationInstance <PrefabricatorBase>(scriptClassName, nodeId);
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
} catch (NodeException e) {
AssetBundleGraphEditorWindow.AddNodeException(e);
break;
}
break;
}
case AssetBundleGraphSettings.NodeKind.BUNDLIZER_GUI: {
/*
* Bundlizer requires assetOutputConnectionId and additional resourceOutputConnectionId.
* both-connected, or both-not-connected, or one of them is connected. 4 patterns exists.
*
* Bundler Node's outputPoint [0] is always the point for assetOutputConnectionId.
* Bundler Node's outputPoint [1] is always the point for resourceOutputConnectionId.
*
* if one of these outputPoint don't have connection, use Fake connection id for correct output.
*
*
* unorderedConnectionId \
* ----> orderedConnectionIdsAndFakeConnectionIds.
* orderedOutputPointId /
*/
var orderedConnectionIdsAndFakeConnectionIds = new string[orderedNodeOutputPointIds.Count];
for (var i = 0; i < orderedNodeOutputPointIds.Count; i++)
{
var orderedNodeOutputPointId = orderedNodeOutputPointIds[i];
foreach (var nonOrderedConnectionFromThisNodeToChildNode in nonOrderedConnectionsFromThisNodeToChildNode)
{
var connectionOutputPointId = nonOrderedConnectionFromThisNodeToChildNode.fromNodeOutputPointId;
if (orderedNodeOutputPointId == connectionOutputPointId)
{
orderedConnectionIdsAndFakeConnectionIds[i] = nonOrderedConnectionFromThisNodeToChildNode.connectionId;
break;
}
else
{
orderedConnectionIdsAndFakeConnectionIds[i] = AssetBundleGraphSettings.BUNDLIZER_FAKE_CONNECTION_ID;
}
}
}
var bundleNameTemplate = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.bundleNameTemplate);
/*
* TODO: variants needs to be execute Setup/Run as many times as its variants
*/
var executor = new IntegratedGUIBundlizer(bundleNameTemplate, orderedConnectionIdsAndFakeConnectionIds[0], currentNodeData.variants);
executor.Setup(nodeName, nodeId, string.Empty, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.BUNDLEBUILDER_GUI: {
var bundleOptions = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.enabledBundleOptions);
var executor = new IntegratedGUIBundleBuilder(bundleOptions, allNodes.Select(nodeData => nodeData.nodeId).ToList());
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
case AssetBundleGraphSettings.NodeKind.EXPORTER_GUI: {
var exportTo = SystemDataUtility.GetCurrentPlatformValue(currentNodeData.exportFilePath);
var executor = new IntegratedGUIExporter(FileUtility.GetPathWithProjectPath(exportTo));
executor.Setup(nodeName, nodeId, firstConnectionIdFromThisNodeToChildNode, inputParentResults, alreadyCachedPaths, Output);
break;
}
default: {
Debug.LogError(nodeName + " is defined as unknown kind of node. value:" + nodeKind);
break;
}
}
}
} catch (NodeException e) {
AssetBundleGraphEditorWindow.AddNodeException(e);
//Debug.LogError("error occured:\"" + e.reason + "\", please check information on node.");
return;
//throw new AssetBundleGraphException(nodeName + ": " + e.reason);
}
currentNodeData.Done();
if (updateHandler != null)
{
updateHandler(nodeId, 1f);
}
}