using System; using System.Collections.Generic; using System.Linq; namespace UnityEngine.Graphing { public class SlotConfigurationException : Exception { public SlotConfigurationException(string message) : base(message) {} } public static class NodeUtils { public static void SlotConfigurationExceptionIfBadConfiguration(INode node, IEnumerable expectedInputSlots, IEnumerable expectedOutputSlots) { var missingSlots = new List(); var inputSlots = expectedInputSlots as IList ?? expectedInputSlots.ToList(); missingSlots.AddRange(inputSlots.Except(node.GetInputSlots().Select(x => x.id))); var outputSlots = expectedOutputSlots as IList ?? expectedOutputSlots.ToList(); missingSlots.AddRange(outputSlots.Except(node.GetOutputSlots().Select(x => x.id))); if (missingSlots.Count == 0) return; var toPrint = missingSlots.Select(x => x.ToString()); throw new SlotConfigurationException(string.Format("Missing slots {0} on node {1}", string.Join(", ", toPrint.ToArray()), node)); } public static IEnumerable GetAllEdges(INode node) { var result = new List(); var validSlots = ListPool.Get(); validSlots.AddRange(node.GetInputSlots()); for (int index = 0; index < validSlots.Count; index++) { var inputSlot = validSlots[index]; result.AddRange(node.owner.GetEdges(inputSlot.slotReference)); } validSlots.Clear(); validSlots.AddRange(node.GetOutputSlots()); for (int index = 0; index < validSlots.Count; index++) { var outputSlot = validSlots[index]; result.AddRange(node.owner.GetEdges(outputSlot.slotReference)); } ListPool.Release(validSlots); return result; } // CollectNodesNodeFeedsInto looks at the current node and calculates // which child nodes it depends on for it's calculation. // Results are returned depth first so by processing each node in // order you can generate a valid code block. public enum IncludeSelf { Include, Exclude } public static void DepthFirstCollectNodesFromNode(List nodeList, INode node, int? slotId = null, IncludeSelf includeSelf = IncludeSelf.Include) { DepthFirstCollectNodesFromNodeSlotList(nodeList, node, slotId.HasValue ? new List() { slotId.Value } : null, includeSelf); } public static void DepthFirstCollectNodesFromNodeSlotList(List nodeList, INode node, List slotId = null, IncludeSelf includeSelf = IncludeSelf.Include) { // no where to start if (node == null) return; // allready added this node if (nodeList.Contains(node)) return; // if we have a slot passed in but can not find it on the node abort if (slotId != null && node.GetInputSlots().All(x => !slotId.Contains(x.id))) return; var validSlots = ListPool.Get(); if (slotId != null) slotId.ForEach(x => validSlots.Add(x)); else validSlots.AddRange(node.GetInputSlots().Select(x => x.id)); foreach (var slot in validSlots) { foreach (var edge in node.owner.GetEdges(node.GetSlotReference(slot))) { var outputNode = node.owner.GetNodeFromGuid(edge.outputSlot.nodeGuid); DepthFirstCollectNodesFromNodeSlotList(nodeList, outputNode); } } if (includeSelf == IncludeSelf.Include) nodeList.Add(node); ListPool.Release(validSlots); } public static void CollectNodesNodeFeedsInto(List nodeList, INode node, IncludeSelf includeSelf = IncludeSelf.Include) { if (node == null) return; if (nodeList.Contains(node)) return; foreach (var slot in node.GetOutputSlots()) { foreach (var edge in node.owner.GetEdges(slot.slotReference)) { var inputNode = node.owner.GetNodeFromGuid(edge.inputSlot.nodeGuid); CollectNodesNodeFeedsInto(nodeList, inputNode); } } if (includeSelf == IncludeSelf.Include) nodeList.Add(node); } } }