Added node highlight, fixed temporary load to include start node as well, fixed For-Condition

This commit is contained in:
2026-05-14 21:37:26 +02:00
parent eee59b6385
commit 672628ee13
9 changed files with 116 additions and 15 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[gd_scene format=3 uid="uid://cinn18bl736rk"] [gd_scene format=3 uid="uid://cinn18bl736rk"]
[ext_resource type="Script" path="res://Scripts/UI/DSL/NodeDisplays/CraftNodeDisplay.cs" id="1_qemp1"] [ext_resource type="Script" uid="uid://bfosue8mejnr5" path="res://Scripts/UI/DSL/NodeDisplays/CraftNodeDisplay.cs" id="1_qemp1"]
[node name="Craft" type="GraphNode" unique_id=908155742] [node name="Craft" type="GraphNode" unique_id=908155742]
offset_right = 158.0 offset_right = 158.0
+2 -2
View File
@@ -19,12 +19,12 @@ public class ForNode : ProgramNode
{ {
amountExecuted = 0; amountExecuted = 0;
} }
return isConditionFulfilled ? NodeResult.CONDITIONFALSE : NodeResult.SUCCESS; return isConditionFulfilled ? NodeResult.SUCCESS : NodeResult.CONDITIONFALSE;
} }
private bool DetermineCondition() private bool DetermineCondition()
{ {
return amountExecuted < amount; return amountExecuted >= amount;
} }
public override ProgramNode Duplicate() public override ProgramNode Duplicate()
+8
View File
@@ -5,6 +5,7 @@ public abstract class ProgramNode
{ {
public ProgramNode nextNode; public ProgramNode nextNode;
public ProgramNode NegativeNode; public ProgramNode NegativeNode;
public string EditorNodeId;
public string DisplayText; public string DisplayText;
public string TooltipText; public string TooltipText;
public string lastExecutionMessage; public string lastExecutionMessage;
@@ -13,6 +14,13 @@ public abstract class ProgramNode
public abstract ProgramNode Duplicate(); public abstract ProgramNode Duplicate();
public abstract string Save(); public abstract string Save();
public ProgramNode DuplicateForRuntime(string editorNodeId)
{
ProgramNode duplicate = Duplicate();
duplicate.EditorNodeId = editorNodeId;
return duplicate;
}
public virtual void SetNextNode( public virtual void SetNextNode(
List<Godot.Collections.Dictionary> connections, List<Godot.Collections.Dictionary> connections,
Dictionary<StringName, ProgramNode> availableNodes Dictionary<StringName, ProgramNode> availableNodes
+4 -1
View File
@@ -11,8 +11,9 @@ public partial class Robot : Node3D
private const float CooldownTarget = 35f; private const float CooldownTarget = 35f;
private const float MaintenanceLossPerSecond = 0.025f; private const float MaintenanceLossPerSecond = 0.025f;
private bool isExecuting = false; public bool isExecuting = false;
public ProgramNode programStartNode;
public ProgramNode currentNode; public ProgramNode currentNode;
public string currentProgram; public string currentProgram;
public string currentMessage = ""; public string currentMessage = "";
@@ -103,6 +104,7 @@ public partial class Robot : Node3D
if (nodes.Count <= 0) return; if (nodes.Count <= 0) return;
isExecuting = true; isExecuting = true;
programStartNode = nodes[0];
currentNode = nodes[0]; currentNode = nodes[0];
currentMessage = ""; currentMessage = "";
} }
@@ -110,6 +112,7 @@ public partial class Robot : Node3D
public void StopExecution(string message) public void StopExecution(string message)
{ {
isExecuting = false; isExecuting = false;
programStartNode = null;
currentNode = null; currentNode = null;
currentMessage = message; currentMessage = message;
} }
+16
View File
@@ -35,6 +35,7 @@ public partial class TestRunner : Node
Run("If node evaluates inventory comparisons", TestIfNodeEvaluatesInventoryComparisons); Run("If node evaluates inventory comparisons", TestIfNodeEvaluatesInventoryComparisons);
Run("While node reports false conditions", TestWhileNodeReportsFalseConditions); Run("While node reports false conditions", TestWhileNodeReportsFalseConditions);
Run("For node stops after configured amount", TestForNodeStopsAfterConfiguredAmount); Run("For node stops after configured amount", TestForNodeStopsAfterConfiguredAmount);
Run("Runtime node keeps editor id without sharing state", TestRuntimeNodeKeepsEditorIdWithoutSharingState);
Run("Start node succeeds immediately", TestStartNodeSucceedsImmediately); Run("Start node succeeds immediately", TestStartNodeSucceedsImmediately);
Run("Split node connections restore both branches", TestSplitNodeConnectionsRestoreBothBranches); Run("Split node connections restore both branches", TestSplitNodeConnectionsRestoreBothBranches);
Run("Linear node connection restores next node", TestLinearNodeConnectionRestoresNextNode); Run("Linear node connection restores next node", TestLinearNodeConnectionRestoresNextNode);
@@ -479,6 +480,21 @@ public partial class TestRunner : Node
AssertEqual(NodeResult.SUCCESS, node.Execute(null, 0), "loop finished"); AssertEqual(NodeResult.SUCCESS, node.Execute(null, 0), "loop finished");
} }
private void TestRuntimeNodeKeepsEditorIdWithoutSharingState()
{
MoveNode editorNode = new MoveNode
{
targetPosition = new Vector3I(1, 0, 1)
};
ProgramNode runtimeNode = editorNode.DuplicateForRuntime("MoveNode42");
MoveNode runtimeMoveNode = runtimeNode as MoveNode;
AssertFalse(ReferenceEquals(editorNode, runtimeNode), "runtime node should be a copy");
AssertEqual("MoveNode42", runtimeNode.EditorNodeId, "runtime node editor id");
AssertEqual(editorNode.targetPosition, runtimeMoveNode.targetPosition, "runtime node parameters");
}
private void TestStartNodeSucceedsImmediately() private void TestStartNodeSucceedsImmediately()
{ {
StartNode node = new StartNode(); StartNode node = new StartNode();
+60 -4
View File
@@ -15,6 +15,7 @@ public partial class CodingWindow : PanelContainer
public System.Collections.Generic.Dictionary<ProgramNode, PackedScene> DSLNodes; public System.Collections.Generic.Dictionary<ProgramNode, PackedScene> DSLNodes;
public NodeDisplay selectedNode; public NodeDisplay selectedNode;
public NodeDisplay highlightedNode;
public override void _Ready() public override void _Ready()
{ {
@@ -30,7 +31,7 @@ public partial class CodingWindow : PanelContainer
} }
} }
public override void _Process(double delta) public override void _Process(double delta)
{ {
if (Input.IsActionJustPressed("delete_node")) if (Input.IsActionJustPressed("delete_node"))
{ {
@@ -41,11 +42,63 @@ public partial class CodingWindow : PanelContainer
editorWindow.RemoveChild(selectedNode); editorWindow.RemoveChild(selectedNode);
selectedNode.QueueFree(); selectedNode.QueueFree();
} }
if (robot != null && Visible && robot.isExecuting)
{
UpdateCurrentNode();
}
}
private void UpdateCurrentNode()
{
if (robot.currentNode == null)
{
ClearHighlightedNode();
return;
}
if (highlightedNode != null)
{
if (IsCurrentRuntimeNode(highlightedNode))
{
return;
}
ClearHighlightedNode();
}
foreach (Node child in editorWindow.GetChildren())
{
NodeDisplay nodeDisplay = child as NodeDisplay;
if (nodeDisplay == null) continue;
if (IsCurrentRuntimeNode(nodeDisplay))
{
nodeDisplay.SetHighlighted(true);
highlightedNode = nodeDisplay;
break;
}
}
}
private bool IsCurrentRuntimeNode(NodeDisplay nodeDisplay)
{
return robot.currentNode.EditorNodeId != null
&& robot.currentNode.EditorNodeId.Length > 0
&& nodeDisplay.Name.ToString() == robot.currentNode.EditorNodeId;
}
private void ClearHighlightedNode()
{
if (highlightedNode == null) return;
highlightedNode.SetHighlighted(false);
highlightedNode = null;
} }
public void OnMapToggled(bool toggledOn) public void OnMapToggled(bool toggledOn)
{ {
if(robot == null) return; if (robot == null) return;
robot.showOnMap = toggledOn; robot.showOnMap = toggledOn;
} }
@@ -133,6 +186,7 @@ public partial class CodingWindow : PanelContainer
public void ClearWindow() public void ClearWindow()
{ {
ClearHighlightedNode();
DisconnectAllNodes(); DisconnectAllNodes();
RemoveEditorNodes(); RemoveEditorNodes();
scriptName.Text = ""; scriptName.Text = "";
@@ -210,16 +264,18 @@ public partial class CodingWindow : PanelContainer
public void LoadTemporaryProgram() public void LoadTemporaryProgram()
{ {
if (robot == null) return; if (robot == null) return;
if (robot.currentNode == null) return; ProgramNode rootNode = robot.programStartNode ?? robot.currentNode;
if (rootNode == null) return;
RunningProgramGraphBuilder builder = new RunningProgramGraphBuilder( RunningProgramGraphBuilder builder = new RunningProgramGraphBuilder(
DSLNodes, DSLNodes,
AddLoadedNode, AddLoadedNode,
ConnectNodes ConnectNodes
); );
builder.Load(robot.currentNode); builder.Load(rootNode);
scriptName.Text = robot.currentProgram ?? ""; scriptName.Text = robot.currentProgram ?? "";
UpdateCurrentNode();
} }
public void DeleteProgram() public void DeleteProgram()
+9
View File
@@ -4,6 +4,7 @@ using Godot;
public partial class NodeDisplay : GraphNode public partial class NodeDisplay : GraphNode
{ {
public ProgramNode node; public ProgramNode node;
private bool isHighlighted = false;
public override void _Ready() public override void _Ready()
{ {
@@ -48,6 +49,14 @@ public partial class NodeDisplay : GraphNode
public virtual void ReadParameters() { } public virtual void ReadParameters() { }
public void SetHighlighted(bool highlighted)
{
if (isHighlighted == highlighted) return;
isHighlighted = highlighted;
SelfModulate = highlighted ? UIStyle.GetWarningColor() : Colors.White;
}
public HBoxContainer GetValueContainer() public HBoxContainer GetValueContainer()
{ {
return GetNode<HBoxContainer>("./Values"); return GetNode<HBoxContainer>("./Values");
@@ -40,6 +40,10 @@ public class RunningProgramGraphBuilder
dslNodes dslNodes
); );
if (nodeDisplay == null) return null; if (nodeDisplay == null) return null;
if (programNode.EditorNodeId != null && programNode.EditorNodeId.Length > 0)
{
nodeDisplay.Name = programNode.EditorNodeId;
}
addNode(nodeDisplay); addNode(nodeDisplay);
loadedNodes.Add(programNode, nodeDisplay); loadedNodes.Add(programNode, nodeDisplay);
+12 -7
View File
@@ -5,7 +5,7 @@ using System.Collections.Generic;
public class ScriptGraphCompiler public class ScriptGraphCompiler
{ {
private readonly GraphEdit editorWindow; private readonly GraphEdit editorWindow;
private System.Collections.Generic.Dictionary<StringName, ProgramNode> availableNodes; private System.Collections.Generic.Dictionary<StringName, ProgramNode> runtimeNodes;
public ScriptGraphCompiler(GraphEdit editorWindow) public ScriptGraphCompiler(GraphEdit editorWindow)
{ {
@@ -22,7 +22,7 @@ public class ScriptGraphCompiler
return new List<ProgramNode>(); return new List<ProgramNode>();
} }
BuildAvailableNodeLookup(); BuildRuntimeNodeLookup();
return BuildScriptOrder( return BuildScriptOrder(
startNode, startNode,
new List<ProgramNode>(), new List<ProgramNode>(),
@@ -30,9 +30,9 @@ public class ScriptGraphCompiler
); );
} }
private void BuildAvailableNodeLookup() private void BuildRuntimeNodeLookup()
{ {
availableNodes = new System.Collections.Generic.Dictionary<StringName, ProgramNode>(); runtimeNodes = new System.Collections.Generic.Dictionary<StringName, ProgramNode>();
for (int i = 0; i < editorWindow.GetChildCount(); i++) for (int i = 0; i < editorWindow.GetChildCount(); i++)
{ {
@@ -40,7 +40,10 @@ public class ScriptGraphCompiler
if (nodeDisplay == null) continue; if (nodeDisplay == null) continue;
nodeDisplay.ReadParameters(); nodeDisplay.ReadParameters();
availableNodes.Add(nodeDisplay.Name, nodeDisplay.node); runtimeNodes.Add(
nodeDisplay.Name,
nodeDisplay.node.DuplicateForRuntime(nodeDisplay.Name.ToString())
);
} }
} }
@@ -52,14 +55,16 @@ public class ScriptGraphCompiler
{ {
if (node == null) return program; if (node == null) return program;
if (visitedNodes.Contains(node.Name)) return program; if (visitedNodes.Contains(node.Name)) return program;
if (!runtimeNodes.ContainsKey(node.Name)) return program;
visitedNodes.Add(node.Name); visitedNodes.Add(node.Name);
program.Add(node.node); ProgramNode runtimeNode = runtimeNodes[node.Name];
program.Add(runtimeNode);
List<Dictionary> nextConnections = GetOutgoingConnections(node); List<Dictionary> nextConnections = GetOutgoingConnections(node);
if (nextConnections.Count <= 0) return program; if (nextConnections.Count <= 0) return program;
node.node.SetNextNode(nextConnections, availableNodes); runtimeNode.SetNextNode(nextConnections, runtimeNodes);
foreach (Dictionary connection in nextConnections) foreach (Dictionary connection in nextConnections)
{ {
NodeDisplay nextNode = editorWindow.GetNodeOrNull<NodeDisplay>( NodeDisplay nextNode = editorWindow.GetNodeOrNull<NodeDisplay>(