Finished first EA Version #1
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene format=3 uid="uid://co7op7et6is8p"]
|
[gd_scene format=3 uid="uid://co7op7et6is8p"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Scripts/UI/DSL/NodeDisplays/ForNodeDisplay.cs" id="1_xshi5"]
|
[ext_resource type="Script" uid="uid://gptqyjv5swwc" path="res://Scripts/UI/DSL/NodeDisplays/ForNodeDisplay.cs" id="1_xshi5"]
|
||||||
|
|
||||||
[node name="For" type="GraphNode" unique_id=1235671673]
|
[node name="For" type="GraphNode" unique_id=1235671673]
|
||||||
offset_right = 229.0
|
offset_right = 229.0
|
||||||
@@ -16,7 +16,7 @@ slot/0/right_type = 0
|
|||||||
slot/0/right_color = Color(1, 1, 1, 1)
|
slot/0/right_color = Color(1, 1, 1, 1)
|
||||||
slot/0/right_icon = null
|
slot/0/right_icon = null
|
||||||
slot/0/draw_stylebox = true
|
slot/0/draw_stylebox = true
|
||||||
slot/1/left_enabled = true
|
slot/1/left_enabled = false
|
||||||
slot/1/left_type = 0
|
slot/1/left_type = 0
|
||||||
slot/1/left_color = Color(1, 1, 1, 1)
|
slot/1/left_color = Color(1, 1, 1, 1)
|
||||||
slot/1/left_icon = null
|
slot/1/left_icon = null
|
||||||
@@ -61,7 +61,7 @@ vertical_alignment = 1
|
|||||||
|
|
||||||
[node name="RichTextLabel" type="RichTextLabel" parent="." unique_id=1677882951]
|
[node name="RichTextLabel" type="RichTextLabel" parent="." unique_id=1677882951]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Until"
|
text = "Afterwards"
|
||||||
fit_content = true
|
fit_content = true
|
||||||
autowrap_mode = 0
|
autowrap_mode = 0
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene format=3 uid="uid://ctmad6foidkvp"]
|
[gd_scene format=3 uid="uid://ctmad6foidkvp"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Scripts/UI/DSL/NodeDisplays/IfNodeDisplay.cs" id="1_ygi5c"]
|
[ext_resource type="Script" uid="uid://cngxwfcrim746" path="res://Scripts/UI/DSL/NodeDisplays/IfNodeDisplay.cs" id="1_ygi5c"]
|
||||||
|
|
||||||
[node name="If" type="GraphNode" unique_id=821127877]
|
[node name="If" type="GraphNode" unique_id=821127877]
|
||||||
offset_right = 468.0
|
offset_right = 468.0
|
||||||
@@ -16,7 +16,7 @@ slot/0/right_type = 0
|
|||||||
slot/0/right_color = Color(1, 1, 1, 1)
|
slot/0/right_color = Color(1, 1, 1, 1)
|
||||||
slot/0/right_icon = null
|
slot/0/right_icon = null
|
||||||
slot/0/draw_stylebox = true
|
slot/0/draw_stylebox = true
|
||||||
slot/1/left_enabled = true
|
slot/1/left_enabled = false
|
||||||
slot/1/left_type = 0
|
slot/1/left_type = 0
|
||||||
slot/1/left_color = Color(1, 1, 1, 1)
|
slot/1/left_color = Color(1, 1, 1, 1)
|
||||||
slot/1/left_icon = null
|
slot/1/left_icon = null
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
[gd_scene format=3 uid="uid://b1y4r3s7ukmfw"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://Scripts/UI/DSL/NodeDisplays/StartNodeDisplay.cs" id="1_start"]
|
||||||
|
|
||||||
|
[node name="Start" type="GraphNode" unique_id=2100000001]
|
||||||
|
offset_right = 65.0
|
||||||
|
offset_bottom = 55.0
|
||||||
|
title = "Start"
|
||||||
|
slot/0/left_enabled = false
|
||||||
|
slot/0/left_type = 0
|
||||||
|
slot/0/left_color = Color(1, 1, 1, 1)
|
||||||
|
slot/0/left_icon = null
|
||||||
|
slot/0/right_enabled = true
|
||||||
|
slot/0/right_type = 0
|
||||||
|
slot/0/right_color = Color(1, 1, 1, 1)
|
||||||
|
slot/0/right_icon = null
|
||||||
|
slot/0/draw_stylebox = true
|
||||||
|
script = ExtResource("1_start")
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="." unique_id=2100000002]
|
||||||
|
layout_mode = 2
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene format=3 uid="uid://bwiaqvl0d4x8v"]
|
[gd_scene format=3 uid="uid://bwiaqvl0d4x8v"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://Scripts/UI/DSL/NodeDisplays/WhileNodeDisplay.cs" id="1_q0rc7"]
|
[ext_resource type="Script" uid="uid://d3npiur46icru" path="res://Scripts/UI/DSL/NodeDisplays/WhileNodeDisplay.cs" id="1_q0rc7"]
|
||||||
|
|
||||||
[node name="While" type="GraphNode" unique_id=2040226700]
|
[node name="While" type="GraphNode" unique_id=2040226700]
|
||||||
offset_right = 499.0
|
offset_right = 499.0
|
||||||
@@ -16,7 +16,7 @@ slot/0/right_type = 0
|
|||||||
slot/0/right_color = Color(1, 1, 1, 1)
|
slot/0/right_color = Color(1, 1, 1, 1)
|
||||||
slot/0/right_icon = null
|
slot/0/right_icon = null
|
||||||
slot/0/draw_stylebox = true
|
slot/0/draw_stylebox = true
|
||||||
slot/1/left_enabled = true
|
slot/1/left_enabled = false
|
||||||
slot/1/left_type = 0
|
slot/1/left_type = 0
|
||||||
slot/1/left_color = Color(1, 1, 1, 1)
|
slot/1/left_color = Color(1, 1, 1, 1)
|
||||||
slot/1/left_icon = null
|
slot/1/left_icon = null
|
||||||
@@ -82,7 +82,7 @@ vertical_alignment = 1
|
|||||||
|
|
||||||
[node name="RichTextLabel" type="RichTextLabel" parent="." unique_id=1571031910]
|
[node name="RichTextLabel" type="RichTextLabel" parent="." unique_id=1571031910]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Until"
|
text = "Afterwards"
|
||||||
fit_content = true
|
fit_content = true
|
||||||
autowrap_mode = 0
|
autowrap_mode = 0
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public partial class ResourceLoader
|
|||||||
{
|
{
|
||||||
Dictionary<ProgramNode, PackedScene> nodes = new Dictionary<ProgramNode, PackedScene>()
|
Dictionary<ProgramNode, PackedScene> nodes = new Dictionary<ProgramNode, PackedScene>()
|
||||||
{
|
{
|
||||||
|
{ new StartNode(), GD.Load<PackedScene>("res://Prefabs/DSL/StartNode.tscn") },
|
||||||
{ new MoveNode(), GD.Load<PackedScene>("res://Prefabs/DSL/MoveNode.tscn") },
|
{ new MoveNode(), GD.Load<PackedScene>("res://Prefabs/DSL/MoveNode.tscn") },
|
||||||
{ new HarvestNode(), GD.Load<PackedScene>("res://Prefabs/DSL/HarvestNode.tscn") },
|
{ new HarvestNode(), GD.Load<PackedScene>("res://Prefabs/DSL/HarvestNode.tscn") },
|
||||||
{ new CraftNode(), GD.Load<PackedScene>("res://Prefabs/DSL/CraftNode.tscn") },
|
{ new CraftNode(), GD.Load<PackedScene>("res://Prefabs/DSL/CraftNode.tscn") },
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class ForNode : ProgramNode
|
public class ForNode : ProgramNode
|
||||||
{
|
{
|
||||||
@@ -34,4 +35,27 @@ public class ForNode : ProgramNode
|
|||||||
{
|
{
|
||||||
return $"Name: {DisplayText}, AmountExecuted: {amountExecuted}, Amount: {amount}";
|
return $"Name: {DisplayText}, AmountExecuted: {amountExecuted}, Amount: {amount}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetNextNode(
|
||||||
|
List<Godot.Collections.Dictionary> connections,
|
||||||
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
nextNode = null;
|
||||||
|
NegativeNode = null;
|
||||||
|
|
||||||
|
foreach (Godot.Collections.Dictionary connection in connections)
|
||||||
|
{
|
||||||
|
int port = (int)connection["from_port"];
|
||||||
|
ProgramNode connectedNode = GetConnectedNode(connection, availableNodes);
|
||||||
|
if (port == 0)
|
||||||
|
{
|
||||||
|
nextNode = connectedNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NegativeNode = connectedNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class IfNode : ProgramNode
|
public class IfNode : ProgramNode
|
||||||
{
|
{
|
||||||
@@ -56,4 +57,27 @@ public class IfNode : ProgramNode
|
|||||||
{
|
{
|
||||||
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetNextNode(
|
||||||
|
List<Godot.Collections.Dictionary> connections,
|
||||||
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
nextNode = null;
|
||||||
|
NegativeNode = null;
|
||||||
|
|
||||||
|
foreach (Godot.Collections.Dictionary connection in connections)
|
||||||
|
{
|
||||||
|
int port = (int)connection["from_port"];
|
||||||
|
ProgramNode connectedNode = GetConnectedNode(connection, availableNodes);
|
||||||
|
if (port == 0)
|
||||||
|
{
|
||||||
|
nextNode = connectedNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NegativeNode = connectedNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ public class MoveNode : ProgramNode
|
|||||||
pathPoints.Remove(pathPoints[0]);
|
pathPoints.Remove(pathPoints[0]);
|
||||||
if (pathPoints.Count <= 0)
|
if (pathPoints.Count <= 0)
|
||||||
{
|
{
|
||||||
|
pathPoints = null;
|
||||||
lastExecutionMessage = "";
|
lastExecutionMessage = "";
|
||||||
return NodeResult.SUCCESS;
|
return NodeResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,37 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public abstract class ProgramNode
|
public abstract class ProgramNode
|
||||||
{
|
{
|
||||||
public ProgramNode nextNode;
|
public ProgramNode nextNode;
|
||||||
public ProgramNode previousNode;
|
public ProgramNode NegativeNode;
|
||||||
public string DisplayText;
|
public string DisplayText;
|
||||||
public string lastExecutionMessage;
|
public string lastExecutionMessage;
|
||||||
|
|
||||||
public abstract NodeResult Execute(Robot robot, double delta);
|
public abstract NodeResult Execute(Robot robot, double delta);
|
||||||
public abstract ProgramNode Duplicate();
|
public abstract ProgramNode Duplicate();
|
||||||
public abstract string Save();
|
public abstract string Save();
|
||||||
|
|
||||||
|
public virtual void SetNextNode(
|
||||||
|
List<Godot.Collections.Dictionary> connections,
|
||||||
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
nextNode = null;
|
||||||
|
|
||||||
|
if (connections.Count <= 0) return;
|
||||||
|
|
||||||
|
nextNode = GetConnectedNode(connections[0], availableNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ProgramNode GetConnectedNode(
|
||||||
|
Godot.Collections.Dictionary connection,
|
||||||
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
StringName nodeName = connection["to_node"].AsStringName();
|
||||||
|
if (!availableNodes.ContainsKey(nodeName)) return null;
|
||||||
|
|
||||||
|
return availableNodes[nodeName];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
public class StartNode : ProgramNode
|
||||||
|
{
|
||||||
|
public StartNode()
|
||||||
|
{
|
||||||
|
DisplayText = "Start";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override NodeResult Execute(Robot robot, double delta)
|
||||||
|
{
|
||||||
|
return NodeResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ProgramNode Duplicate()
|
||||||
|
{
|
||||||
|
StartNode duplicate = new StartNode();
|
||||||
|
return duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Save()
|
||||||
|
{
|
||||||
|
return $"Name: {DisplayText}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d3kyu2j3nxjsh
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public class WhileNode : ProgramNode
|
public class WhileNode : ProgramNode
|
||||||
{
|
{
|
||||||
@@ -57,4 +58,27 @@ public class WhileNode : ProgramNode
|
|||||||
{
|
{
|
||||||
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
return $"Name: {DisplayText}, Item: {(selectedItem == null ? "Empty" : selectedItem.data.Id)}, Comparator: {comparator}, Amount: {amount}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void SetNextNode(
|
||||||
|
List<Godot.Collections.Dictionary> connections,
|
||||||
|
Dictionary<StringName, ProgramNode> availableNodes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
nextNode = null;
|
||||||
|
NegativeNode = null;
|
||||||
|
|
||||||
|
foreach (Godot.Collections.Dictionary connection in connections)
|
||||||
|
{
|
||||||
|
int port = (int)connection["from_port"];
|
||||||
|
ProgramNode connectedNode = GetConnectedNode(connection, availableNodes);
|
||||||
|
if (port == 0)
|
||||||
|
{
|
||||||
|
nextNode = connectedNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NegativeNode = connectedNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,26 +35,11 @@ public partial class Robot : Node3D
|
|||||||
{
|
{
|
||||||
if (CanExecute(delta))
|
if (CanExecute(delta))
|
||||||
{
|
{
|
||||||
|
GD.Print(currentNode.DisplayText);
|
||||||
switch (currentNode.Execute(this, delta))
|
switch (currentNode.Execute(this, delta))
|
||||||
{
|
{
|
||||||
case NodeResult.SUCCESS:
|
case NodeResult.SUCCESS:
|
||||||
if (currentNode.DisplayText == "Until")
|
currentNode = currentNode.nextNode;
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
currentNode = currentNode.previousNode;
|
|
||||||
if (currentNode == null)
|
|
||||||
{
|
|
||||||
isExecuting = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (currentNode.DisplayText == "For" || currentNode.DisplayText == "While") break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentNode = currentNode.nextNode;
|
|
||||||
}
|
|
||||||
if (currentNode == null)
|
if (currentNode == null)
|
||||||
{
|
{
|
||||||
isExecuting = false;
|
isExecuting = false;
|
||||||
@@ -70,33 +55,10 @@ public partial class Robot : Node3D
|
|||||||
currentMessage = "";
|
currentMessage = "";
|
||||||
break;
|
break;
|
||||||
case NodeResult.CONDITIONFALSE:
|
case NodeResult.CONDITIONFALSE:
|
||||||
string sourceNode = currentNode.DisplayText;
|
currentNode = currentNode.NegativeNode;
|
||||||
while (true)
|
if (currentNode == null)
|
||||||
{
|
{
|
||||||
currentNode = currentNode.nextNode;
|
isExecuting = false;
|
||||||
if (currentNode == null)
|
|
||||||
{
|
|
||||||
isExecuting = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (sourceNode == "If")
|
|
||||||
{
|
|
||||||
if (currentNode.DisplayText == "If" || currentNode.DisplayText == "Else") break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (currentNode.DisplayText == "While" || currentNode.DisplayText == "For" || currentNode.DisplayText == "Until")
|
|
||||||
{
|
|
||||||
if (currentNode.nextNode == null)
|
|
||||||
{
|
|
||||||
isExecuting = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
currentNode = currentNode.nextNode;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -133,6 +95,13 @@ public partial class Robot : Node3D
|
|||||||
currentMessage = "";
|
currentMessage = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void StopExecution(string message)
|
||||||
|
{
|
||||||
|
isExecuting = false;
|
||||||
|
currentNode = null;
|
||||||
|
currentMessage = message;
|
||||||
|
}
|
||||||
|
|
||||||
public float GetMovementSpeed()
|
public float GetMovementSpeed()
|
||||||
{
|
{
|
||||||
return GameData.robotStats.GetMovementSpeed(GameData.robotSpeed)
|
return GameData.robotStats.GetMovementSpeed(GameData.robotSpeed)
|
||||||
|
|||||||
@@ -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("Start node succeeds immediately", TestStartNodeSucceedsImmediately);
|
||||||
Run("Paused world does not drain survival", TestPausedWorldDoesNotDrainSurvival);
|
Run("Paused world does not drain survival", TestPausedWorldDoesNotDrainSurvival);
|
||||||
Run("Open gate hides gate content", TestOpenGateHidesGateContent);
|
Run("Open gate hides gate content", TestOpenGateHidesGateContent);
|
||||||
Run("Layer generation succeeds above threshold", TestLayerGenerationSuccessRate);
|
Run("Layer generation succeeds above threshold", TestLayerGenerationSuccessRate);
|
||||||
@@ -476,6 +477,14 @@ public partial class TestRunner : Node
|
|||||||
AssertEqual(NodeResult.CONDITIONFALSE, node.Execute(null, 0), "loop finished");
|
AssertEqual(NodeResult.CONDITIONFALSE, node.Execute(null, 0), "loop finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TestStartNodeSucceedsImmediately()
|
||||||
|
{
|
||||||
|
StartNode node = new StartNode();
|
||||||
|
|
||||||
|
AssertEqual(NodeResult.SUCCESS, node.Execute(null, 0), "start should succeed");
|
||||||
|
AssertEqual("Name: Start", node.Save(), "start save");
|
||||||
|
}
|
||||||
|
|
||||||
private void TestPausedWorldDoesNotDrainSurvival()
|
private void TestPausedWorldDoesNotDrainSurvival()
|
||||||
{
|
{
|
||||||
GameData.isPaused = true;
|
GameData.isPaused = true;
|
||||||
@@ -549,6 +558,18 @@ public partial class TestRunner : Node
|
|||||||
AssertTrue(GameData.availableItems.ContainsKey("water"), "water item loaded");
|
AssertTrue(GameData.availableItems.ContainsKey("water"), "water item loaded");
|
||||||
AssertTrue(GameData.availableResearch.ContainsKey("basics"), "basics research loaded");
|
AssertTrue(GameData.availableResearch.ContainsKey("basics"), "basics research loaded");
|
||||||
AssertTrue(GameData.availableResearch.ContainsKey("iron_robotics"), "iron robotics research loaded");
|
AssertTrue(GameData.availableResearch.ContainsKey("iron_robotics"), "iron robotics research loaded");
|
||||||
|
|
||||||
|
Dictionary<ProgramNode, PackedScene> dslNodes = ResourceLoader.LoadDSLNodes();
|
||||||
|
bool hasStartNode = false;
|
||||||
|
foreach (ProgramNode node in dslNodes.Keys)
|
||||||
|
{
|
||||||
|
if (node is StartNode)
|
||||||
|
{
|
||||||
|
hasStartNode = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssertTrue(hasStartNode, "start node prefab loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Layer CreateTestLayer(int level, string collapsedMesh)
|
private Layer CreateTestLayer(int level, string collapsedMesh)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public partial class CodingWindow : PanelContainer
|
|||||||
[Export] LineEdit nameInput;
|
[Export] LineEdit nameInput;
|
||||||
|
|
||||||
public System.Collections.Generic.Dictionary<ProgramNode, PackedScene> DSLNodes;
|
public System.Collections.Generic.Dictionary<ProgramNode, PackedScene> DSLNodes;
|
||||||
|
private System.Collections.Generic.Dictionary<StringName, ProgramNode> availableNodes;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
@@ -83,10 +84,19 @@ public partial class CodingWindow : PanelContainer
|
|||||||
private void AddEditorNode(ProgramNode node)
|
private void AddEditorNode(ProgramNode node)
|
||||||
{
|
{
|
||||||
NodeDisplay editorDisplay = DSLNodes[node].Instantiate<NodeDisplay>();
|
NodeDisplay editorDisplay = DSLNodes[node].Instantiate<NodeDisplay>();
|
||||||
|
editorDisplay.PositionOffset = (editorWindow.ScrollOffset + editorWindow.Size / 2) / editorWindow.Zoom - editorDisplay.Size / 2;
|
||||||
editorWindow.AddChild(editorDisplay);
|
editorWindow.AddChild(editorDisplay);
|
||||||
RegisterEditorNode(editorDisplay);
|
RegisterEditorNode(editorDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MoveNodeToVisibleGraphCenter(NodeDisplay nodeDisplay)
|
||||||
|
{
|
||||||
|
Vector2 visibleCenter = editorWindow.ScrollOffset
|
||||||
|
+ editorWindow.Size / (2f * editorWindow.Zoom);
|
||||||
|
|
||||||
|
nodeDisplay.PositionOffset = visibleCenter - nodeDisplay.Size / (2f * editorWindow.Zoom);
|
||||||
|
}
|
||||||
|
|
||||||
private void RegisterEditorNode(NodeDisplay editorDisplay)
|
private void RegisterEditorNode(NodeDisplay editorDisplay)
|
||||||
{
|
{
|
||||||
editorDisplay.OnDeleteNode += () =>
|
editorDisplay.OnDeleteNode += () =>
|
||||||
@@ -121,7 +131,25 @@ public partial class CodingWindow : PanelContainer
|
|||||||
|
|
||||||
public void CompileProgram()
|
public void CompileProgram()
|
||||||
{
|
{
|
||||||
List<ProgramNode> nodes = new List<ProgramNode>();
|
if (robot == null) return;
|
||||||
|
|
||||||
|
NodeDisplay startNode = FindStartNode();
|
||||||
|
if (startNode == null)
|
||||||
|
{
|
||||||
|
robot.StopExecution("(FAILED) Script needs exactly one Start node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
availableNodes = BuildAvailableNodeLookup();
|
||||||
|
List<ProgramNode> nodes = BuildScriptOrder(startNode, new List<ProgramNode>());
|
||||||
|
if (nodes.Count > 0) robot.SetupExecution(nodes);
|
||||||
|
robot.currentProgram = scriptName.Text.Length <= 0 ? $"Script{availableScripts.ItemCount}" : scriptName.Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private System.Collections.Generic.Dictionary<StringName, ProgramNode> BuildAvailableNodeLookup()
|
||||||
|
{
|
||||||
|
System.Collections.Generic.Dictionary<StringName, ProgramNode> availableNodes =
|
||||||
|
new System.Collections.Generic.Dictionary<StringName, ProgramNode>();
|
||||||
|
|
||||||
for (int i = 0; i < editorWindow.GetChildCount(); i++)
|
for (int i = 0; i < editorWindow.GetChildCount(); i++)
|
||||||
{
|
{
|
||||||
@@ -129,22 +157,56 @@ public partial class CodingWindow : PanelContainer
|
|||||||
if (nodeDisplay == null) continue;
|
if (nodeDisplay == null) continue;
|
||||||
|
|
||||||
nodeDisplay.ReadParameters();
|
nodeDisplay.ReadParameters();
|
||||||
ProgramNode executableNode = nodeDisplay.node.Duplicate();
|
availableNodes.Add(nodeDisplay.Name, nodeDisplay.node);
|
||||||
nodes.Add(executableNode);
|
|
||||||
|
|
||||||
if (nodes.Count > 1)
|
|
||||||
{
|
|
||||||
nodes[nodes.Count - 2].nextNode = executableNode;
|
|
||||||
}
|
|
||||||
if (nodes.Count > 1)
|
|
||||||
{
|
|
||||||
executableNode.previousNode = nodes[nodes.Count - 2];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (robot == null) return;
|
return availableNodes;
|
||||||
if (nodes.Count > 0) robot.SetupExecution(nodes);
|
}
|
||||||
robot.currentProgram = scriptName.Text.Length <= 0 ? $"Script{availableScripts.ItemCount}" : scriptName.Text;
|
|
||||||
|
private List<ProgramNode> BuildScriptOrder(NodeDisplay node, List<ProgramNode> program)
|
||||||
|
{
|
||||||
|
program.Add(node.node);
|
||||||
|
if (editorWindow.GetConnectionListFromNode(node.Name).Count <= 0) return program;
|
||||||
|
List<Dictionary> nextConnections = CheckNodeConnections(node);
|
||||||
|
if (nextConnections.Count <= 0) return program;
|
||||||
|
node.node.SetNextNode(nextConnections, availableNodes);
|
||||||
|
foreach (Dictionary connection in nextConnections)
|
||||||
|
{
|
||||||
|
program = BuildScriptOrder(
|
||||||
|
editorWindow.GetNode<NodeDisplay>(new NodePath(connection["to_node"].AsStringName())),
|
||||||
|
program
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Dictionary> CheckNodeConnections(NodeDisplay node)
|
||||||
|
{
|
||||||
|
List<Dictionary> result = new List<Dictionary>();
|
||||||
|
Array<Dictionary> 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRobot(Robot robot)
|
public void SetRobot(Robot robot)
|
||||||
@@ -177,14 +239,8 @@ public partial class CodingWindow : PanelContainer
|
|||||||
if (robot == null) return;
|
if (robot == null) return;
|
||||||
if (robot.currentNode == null) return;
|
if (robot.currentNode == null) return;
|
||||||
|
|
||||||
ProgramNode firstNode = robot.currentNode;
|
|
||||||
while (firstNode.previousNode != null)
|
|
||||||
{
|
|
||||||
firstNode = firstNode.previousNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashSet<ProgramNode> loadedNodes = new HashSet<ProgramNode>();
|
HashSet<ProgramNode> loadedNodes = new HashSet<ProgramNode>();
|
||||||
ProgramNode nodeToLoad = firstNode;
|
ProgramNode nodeToLoad = robot.currentNode;
|
||||||
while (nodeToLoad != null && !loadedNodes.Contains(nodeToLoad))
|
while (nodeToLoad != null && !loadedNodes.Contains(nodeToLoad))
|
||||||
{
|
{
|
||||||
loadedNodes.Add(nodeToLoad);
|
loadedNodes.Add(nodeToLoad);
|
||||||
@@ -238,12 +294,10 @@ public partial class CodingWindow : PanelContainer
|
|||||||
|
|
||||||
public void OnNodeConnect(StringName from, int fromPort, StringName to, int toPort)
|
public void OnNodeConnect(StringName from, int fromPort, StringName to, int toPort)
|
||||||
{
|
{
|
||||||
GD.Print($"From {fromPort} to {toPort}");
|
|
||||||
if (to == from) return;
|
if (to == from) return;
|
||||||
|
|
||||||
foreach (Dictionary connection in editorWindow.GetConnectionList())
|
foreach (Dictionary connection in editorWindow.GetConnectionList())
|
||||||
{
|
{
|
||||||
if (connection["to_node"].AsStringName() == to && (int)connection["to_port"] == toPort) return;
|
|
||||||
if (connection["from_node"].AsStringName() == from && (int)connection["from_port"] == fromPort) return;
|
if (connection["from_node"].AsStringName() == from && (int)connection["from_port"] == fromPort) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
public partial class StartNodeDisplay : NodeDisplay
|
||||||
|
{
|
||||||
|
protected override ProgramNode CreateProgramNode()
|
||||||
|
{
|
||||||
|
return new StartNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://c7w5380k530wb
|
||||||
@@ -81,7 +81,7 @@ public class Pathfinding
|
|||||||
|
|
||||||
if (!aStar.ArePointsConnected(fromId, toId))
|
if (!aStar.ArePointsConnected(fromId, toId))
|
||||||
{
|
{
|
||||||
aStar.ConnectPoints(fromId, toId);
|
aStar.ConnectPoints(fromId, toId, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true
|
|||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="RuinAdventurer"
|
config/name="RuinAdventurer"
|
||||||
run/main_scene="uid://dlommaelbbw2b"
|
run/main_scene="res://Scenes/MainMenu.tscn"
|
||||||
config/features=PackedStringArray("4.6", "C#", "Forward Plus")
|
config/features=PackedStringArray("4.6", "C#", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user