Finished first EA Version #1

Merged
Nicola merged 110 commits from dev into main 2026-05-19 20:01:13 +02:00
9 changed files with 116 additions and 15 deletions
Showing only changes of commit 672628ee13 - Show all commits
+1 -1
View File
@@ -1,6 +1,6 @@
[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]
offset_right = 158.0
+2 -2
View File
@@ -19,12 +19,12 @@ public class ForNode : ProgramNode
{
amountExecuted = 0;
}
return isConditionFulfilled ? NodeResult.CONDITIONFALSE : NodeResult.SUCCESS;
return isConditionFulfilled ? NodeResult.SUCCESS : NodeResult.CONDITIONFALSE;
}
private bool DetermineCondition()
{
return amountExecuted < amount;
return amountExecuted >= amount;
}
public override ProgramNode Duplicate()
+8
View File
@@ -5,6 +5,7 @@ public abstract class ProgramNode
{
public ProgramNode nextNode;
public ProgramNode NegativeNode;
public string EditorNodeId;
public string DisplayText;
public string TooltipText;
public string lastExecutionMessage;
@@ -13,6 +14,13 @@ public abstract class ProgramNode
public abstract ProgramNode Duplicate();
public abstract string Save();
public ProgramNode DuplicateForRuntime(string editorNodeId)
{
ProgramNode duplicate = Duplicate();
duplicate.EditorNodeId = editorNodeId;
return duplicate;
}
public virtual void SetNextNode(
List<Godot.Collections.Dictionary> connections,
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 MaintenanceLossPerSecond = 0.025f;
private bool isExecuting = false;
public bool isExecuting = false;
public ProgramNode programStartNode;
public ProgramNode currentNode;
public string currentProgram;
public string currentMessage = "";
@@ -103,6 +104,7 @@ public partial class Robot : Node3D
if (nodes.Count <= 0) return;
isExecuting = true;
programStartNode = nodes[0];
currentNode = nodes[0];
currentMessage = "";
}
@@ -110,6 +112,7 @@ public partial class Robot : Node3D
public void StopExecution(string message)
{
isExecuting = false;
programStartNode = null;
currentNode = null;
currentMessage = message;
}
+16
View File
@@ -35,6 +35,7 @@ public partial class TestRunner : Node
Run("If node evaluates inventory comparisons", TestIfNodeEvaluatesInventoryComparisons);
Run("While node reports false conditions", TestWhileNodeReportsFalseConditions);
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("Split node connections restore both branches", TestSplitNodeConnectionsRestoreBothBranches);
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");
}
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()
{
StartNode node = new StartNode();
+58 -2
View File
@@ -15,6 +15,7 @@ public partial class CodingWindow : PanelContainer
public System.Collections.Generic.Dictionary<ProgramNode, PackedScene> DSLNodes;
public NodeDisplay selectedNode;
public NodeDisplay highlightedNode;
public override void _Ready()
{
@@ -41,6 +42,58 @@ public partial class CodingWindow : PanelContainer
editorWindow.RemoveChild(selectedNode);
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)
@@ -133,6 +186,7 @@ public partial class CodingWindow : PanelContainer
public void ClearWindow()
{
ClearHighlightedNode();
DisconnectAllNodes();
RemoveEditorNodes();
scriptName.Text = "";
@@ -210,16 +264,18 @@ public partial class CodingWindow : PanelContainer
public void LoadTemporaryProgram()
{
if (robot == null) return;
if (robot.currentNode == null) return;
ProgramNode rootNode = robot.programStartNode ?? robot.currentNode;
if (rootNode == null) return;
RunningProgramGraphBuilder builder = new RunningProgramGraphBuilder(
DSLNodes,
AddLoadedNode,
ConnectNodes
);
builder.Load(robot.currentNode);
builder.Load(rootNode);
scriptName.Text = robot.currentProgram ?? "";
UpdateCurrentNode();
}
public void DeleteProgram()
+9
View File
@@ -4,6 +4,7 @@ using Godot;
public partial class NodeDisplay : GraphNode
{
public ProgramNode node;
private bool isHighlighted = false;
public override void _Ready()
{
@@ -48,6 +49,14 @@ public partial class NodeDisplay : GraphNode
public virtual void ReadParameters() { }
public void SetHighlighted(bool highlighted)
{
if (isHighlighted == highlighted) return;
isHighlighted = highlighted;
SelfModulate = highlighted ? UIStyle.GetWarningColor() : Colors.White;
}
public HBoxContainer GetValueContainer()
{
return GetNode<HBoxContainer>("./Values");
@@ -40,6 +40,10 @@ public class RunningProgramGraphBuilder
dslNodes
);
if (nodeDisplay == null) return null;
if (programNode.EditorNodeId != null && programNode.EditorNodeId.Length > 0)
{
nodeDisplay.Name = programNode.EditorNodeId;
}
addNode(nodeDisplay);
loadedNodes.Add(programNode, nodeDisplay);
+12 -7
View File
@@ -5,7 +5,7 @@ using System.Collections.Generic;
public class ScriptGraphCompiler
{
private readonly GraphEdit editorWindow;
private System.Collections.Generic.Dictionary<StringName, ProgramNode> availableNodes;
private System.Collections.Generic.Dictionary<StringName, ProgramNode> runtimeNodes;
public ScriptGraphCompiler(GraphEdit editorWindow)
{
@@ -22,7 +22,7 @@ public class ScriptGraphCompiler
return new List<ProgramNode>();
}
BuildAvailableNodeLookup();
BuildRuntimeNodeLookup();
return BuildScriptOrder(
startNode,
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++)
{
@@ -40,7 +40,10 @@ public class ScriptGraphCompiler
if (nodeDisplay == null) continue;
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 (visitedNodes.Contains(node.Name)) return program;
if (!runtimeNodes.ContainsKey(node.Name)) return program;
visitedNodes.Add(node.Name);
program.Add(node.node);
ProgramNode runtimeNode = runtimeNodes[node.Name];
program.Add(runtimeNode);
List<Dictionary> nextConnections = GetOutgoingConnections(node);
if (nextConnections.Count <= 0) return program;
node.node.SetNextNode(nextConnections, availableNodes);
runtimeNode.SetNextNode(nextConnections, runtimeNodes);
foreach (Dictionary connection in nextConnections)
{
NodeDisplay nextNode = editorWindow.GetNodeOrNull<NodeDisplay>(