using Godot; using Godot.Collections; using System.Collections.Generic; public class ScriptGraphCompiler { private readonly GraphEdit editorWindow; private System.Collections.Generic.Dictionary availableNodes; public ScriptGraphCompiler(GraphEdit editorWindow) { this.editorWindow = editorWindow; } public List BuildProgram(out string errorMessage) { errorMessage = ""; NodeDisplay startNode = FindStartNode(); if (startNode == null) { errorMessage = "(FAILED) Script needs exactly one Start node"; return new List(); } BuildAvailableNodeLookup(); return BuildScriptOrder( startNode, new List(), new HashSet() ); } private void BuildAvailableNodeLookup() { availableNodes = new System.Collections.Generic.Dictionary(); for (int i = 0; i < editorWindow.GetChildCount(); i++) { NodeDisplay nodeDisplay = editorWindow.GetChild(i) as NodeDisplay; if (nodeDisplay == null) continue; nodeDisplay.ReadParameters(); availableNodes.Add(nodeDisplay.Name, nodeDisplay.node); } } private List BuildScriptOrder( NodeDisplay node, List program, HashSet visitedNodes ) { if (node == null) return program; if (visitedNodes.Contains(node.Name)) return program; visitedNodes.Add(node.Name); program.Add(node.node); List nextConnections = GetOutgoingConnections(node); if (nextConnections.Count <= 0) return program; node.node.SetNextNode(nextConnections, availableNodes); foreach (Dictionary connection in nextConnections) { NodeDisplay nextNode = editorWindow.GetNodeOrNull( new NodePath(connection["to_node"].AsStringName()) ); program = BuildScriptOrder( nextNode, program, visitedNodes ); } return program; } private List GetOutgoingConnections(NodeDisplay node) { List result = new List(); Array connections = editorWindow.GetConnectionListFromNode(node.Name); for (int i = 0; i < connections.Count; i++) { if (connections[i]["from_node"].AsStringName() == node.Name) { result.Add(connections[i]); } } return result; } private NodeDisplay FindStartNode() { NodeDisplay startNode = null; for (int i = 0; i < editorWindow.GetChildCount(); i++) { NodeDisplay nodeDisplay = editorWindow.GetChild(i) as NodeDisplay; if (nodeDisplay == null) continue; if (nodeDisplay.node is not StartNode) continue; if (startNode != null) return null; startNode = nodeDisplay; } return startNode; } }