From 39a18a4087113218e39cd3e0930ce118f92960f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sat, 10 Jun 2023 20:13:16 +0300 Subject: [PATCH 01/17] types, ports, nodes, decks, test renderer --- classes/UUID.gd | 88 +++++++++++++++++++++++++++++ classes/deck/deck.gd | 57 +++++++++++++++++++ classes/deck/deck_node.gd | 41 ++++++++++++++ classes/deck/nodes/button.gd | 11 ++++ classes/deck/nodes/print.gd | 18 ++++++ classes/deck/port.gd | 11 ++++ classes/types/deck_type.gd | 106 +++++++++++++++++++++++++++++++++++ port_drawer.gd | 53 ++++++++++++++++++ port_drawer.tscn | 16 ++++++ project.godot | 2 + test.gd | 32 +++++++++++ test.tscn | 46 +++++++++++++++ test_node_renderer.gd | 38 +++++++++++++ test_node_renderer.tscn | 39 +++++++++++++ 14 files changed, 558 insertions(+) create mode 100644 classes/UUID.gd create mode 100644 classes/deck/deck.gd create mode 100644 classes/deck/deck_node.gd create mode 100644 classes/deck/nodes/button.gd create mode 100644 classes/deck/nodes/print.gd create mode 100644 classes/deck/port.gd create mode 100644 classes/types/deck_type.gd create mode 100644 port_drawer.gd create mode 100644 port_drawer.tscn create mode 100644 test.gd create mode 100644 test.tscn create mode 100644 test_node_renderer.gd create mode 100644 test_node_renderer.tscn diff --git a/classes/UUID.gd b/classes/UUID.gd new file mode 100644 index 0000000..c03281a --- /dev/null +++ b/classes/UUID.gd @@ -0,0 +1,88 @@ +# MIT License +# +# Copyright (c) 2023 Xavier Sellier +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Note: The code might not be as pretty it could be, since it's written +# in a way that maximizes performance. Methods are inlined and loops are avoided. +class_name UUID +const BYTE_MASK: int = 0b11111111 + + +static func uuidbin() -> Array: + randomize() + # 16 random bytes with the bytes on index 6 and 8 modified + return [ + randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK, + randi() & BYTE_MASK, randi() & BYTE_MASK, ((randi() & BYTE_MASK) & 0x0f) | 0x40, randi() & BYTE_MASK, + ((randi() & BYTE_MASK) & 0x3f) | 0x80, randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK, + randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK, randi() & BYTE_MASK, + ] + +static func uuidbinrng(rng: RandomNumberGenerator) -> Array: + rng.randomize() + return [ + rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, + rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, ((rng.randi() & BYTE_MASK) & 0x0f) | 0x40, rng.randi() & BYTE_MASK, + ((rng.randi() & BYTE_MASK) & 0x3f) | 0x80, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, + rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, rng.randi() & BYTE_MASK, + ] + +static func v4() -> String: + # 16 random bytes with the bytes on index 6 and 8 modified + var b = uuidbin() + + return '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % [ + # low + b[0], b[1], b[2], b[3], + + # mid + b[4], b[5], + + # hi + b[6], b[7], + + # clock + b[8], b[9], + + # clock + b[10], b[11], b[12], b[13], b[14], b[15] + ] + +static func v4_rng(rng: RandomNumberGenerator) -> String: + # 16 random bytes with the bytes on index 6 and 8 modified + var b = uuidbinrng(rng) + + return '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % [ + # low + b[0], b[1], b[2], b[3], + + # mid + b[4], b[5], + + # hi + b[6], b[7], + + # clock + b[8], b[9], + + # clock + b[10], b[11], b[12], b[13], b[14], b[15] + ] diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd new file mode 100644 index 0000000..f32ef42 --- /dev/null +++ b/classes/deck/deck.gd @@ -0,0 +1,57 @@ +class_name Deck + +var nodes: Dictionary + +enum Types{ + ERROR = -1, + BOOL, + NUMERIC, + STRING, + ARRAY, + DICTIONARY, +} + + +static var type_assoc: Dictionary = { + Types.ERROR: DeckType.DeckTypeError, + Types.BOOL: DeckType.DeckTypeBool, + Types.NUMERIC: DeckType.DeckTypeNumeric, + Types.STRING: DeckType.DeckTypeString, + Types.ARRAY: DeckType.DeckTypeArray, + Types.DICTIONARY: DeckType.DeckTypeDictionary, +} + + + +func add_node(node: GDScript, meta: Dictionary = {}) -> DeckNode: + # TODO: accept instances of DeckNode instead of instancing here? + var uuid := UUID.v4() + var node_inst: DeckNode = node.new() as DeckNode + nodes[uuid] = node_inst + node_inst._belonging_to = self + node_inst._id = uuid + + if !meta.is_empty(): + for k in meta: + node_inst.set_meta(k, meta[k]) + + return node_inst + + +func get_node(uuid: String) -> DeckNode: + return nodes.get(uuid) + + +func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> bool: + # first, check that we can do the type conversion. + var type_a: Types = from_node.input_ports[from_port].type + var type_b: Types = to_node.output_ports[to_port].type + var err: DeckType = (type_assoc[type_b] as GDScript).from(type_assoc[type_a]) + if err is DeckType.DeckTypeError: + print(err.error_message) + return false + + # TODO: prevent duplicate connections + + from_node.add_outgoing_connection(from_port, to_node._id, to_port) + return true diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd new file mode 100644 index 0000000..62f0ab6 --- /dev/null +++ b/classes/deck/deck_node.gd @@ -0,0 +1,41 @@ +class_name DeckNode + +var name: String +var input_ports: Array[Port] +var output_ports: Array[Port] +var outgoing_connections: Dictionary + +var _belonging_to: Deck +var _id: String + + +func add_input_port(type: Deck.Types, label: String, descriptor: String = "") -> void: + var port := Port.new(type, label, descriptor) + input_ports.append(port) + + +func add_output_port(type: Deck.Types, label: String, descriptor: String = "") -> void: + var port := Port.new(type, label, descriptor) + output_ports.append(port) + + +func send(from_port: int, data: DeckType, extra_data: Array = []) -> void: + if !(outgoing_connections.get(from_port)): + return + + for connection in outgoing_connections[from_port]: + connection = connection as Dictionary + # key is node uuid + # value is input port on destination node + for node in connection: + _belonging_to.get_node(node)._receive(connection[node], data, extra_data) + + +func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: + pass + + +func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> void: + var port_connections: Array = outgoing_connections.get(from_port, []) + port_connections.append({to_node: to_port}) + outgoing_connections[from_port] = port_connections diff --git a/classes/deck/nodes/button.gd b/classes/deck/nodes/button.gd new file mode 100644 index 0000000..8b6bd03 --- /dev/null +++ b/classes/deck/nodes/button.gd @@ -0,0 +1,11 @@ +extends DeckNode + + +func _init() -> void: + add_output_port( + Deck.Types.STRING, + "Press me", + "button" + ) + + name = "Button" diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd new file mode 100644 index 0000000..eaf3aae --- /dev/null +++ b/classes/deck/nodes/print.gd @@ -0,0 +1,18 @@ +extends DeckNode + + +func _init() -> void: + add_input_port( + Deck.Types.STRING, + "Input", + "field" + ) + + name = "Print" + + +func _receive(_to_port: int, data: DeckType, extra_data: Array = []) -> void: + # we only have one port, so we can skip checking which port we received on + var data_to_print = data.get_value() + print(data_to_print) + print("extra data: ", extra_data) diff --git a/classes/deck/port.gd b/classes/deck/port.gd new file mode 100644 index 0000000..258ae10 --- /dev/null +++ b/classes/deck/port.gd @@ -0,0 +1,11 @@ +class_name Port + +var type: Deck.Types +var label: String +var descriptor: String + + +func _init(p_type: Deck.Types, p_label: String, p_descriptor: String = "") -> void: + type = p_type + label = p_label + descriptor = p_descriptor diff --git a/classes/types/deck_type.gd b/classes/types/deck_type.gd new file mode 100644 index 0000000..da7e437 --- /dev/null +++ b/classes/types/deck_type.gd @@ -0,0 +1,106 @@ +class_name DeckType + +var _value: Variant +var _success: bool = true + + +func is_valid() -> bool: + return _success + + +func get_value() -> Variant: + return _value + + +static func from(other: DeckType): + return null + + +class DeckTypeError extends DeckType: + var error_message: String + + + func _init(p_error_message: String = ""): + _value = self + _success = false + + error_message = p_error_message + + + static func from(other: DeckType) -> DeckTypeError: + return DeckTypeError.new() + + +class DeckTypeNumeric extends DeckType: + static func from(other: DeckType): + if other is DeckTypeNumeric: + return other + + if other is DeckTypeString: + if (other.get_value() as String).is_valid_float(): + var value: float = float(other.get_value() as String) + var inst := DeckTypeNumeric.new() + inst._value = value + return inst + else: + var err: DeckTypeError = DeckTypeError.from(other) + err.error_message = "Conversion from String to Numeric failed, check the number" + return err + + if other is DeckTypeBool: + var inst := DeckTypeNumeric.new() + inst._value = float(other.get_value() as bool) + return inst + + var err: DeckTypeError = DeckTypeError.from(other) + err.error_message = "Conversion to Numeric is only possible from String or Bool." + return err + + +class DeckTypeString extends DeckType: + static func from(other: DeckType): + if other is DeckTypeString: + return other + + var inst := DeckTypeString.new() + inst._value = var_to_str(other.get_value()) + + +class DeckTypeBool extends DeckType: + static func from(other: DeckType): + if other is DeckTypeBool: + return other + + if other is DeckTypeNumeric: + var inst := DeckTypeBool.new() + inst._value = bool(other.get_value()) + return inst + + if other is DeckTypeDictionary or other is DeckTypeArray: + var inst := DeckTypeBool.new() + inst._value = !other.get_value().is_empty() + return inst + + +class DeckTypeArray extends DeckType: + static func from(other: DeckType): + if other is DeckTypeString: + var inst := DeckTypeArray.new() + inst._value = str_to_var(other.get_value()) + return inst + + var err: DeckTypeError = DeckTypeError.from(other) + err.error_message = "conversions to Array is only possible from String" + return err + + +class DeckTypeDictionary extends DeckType: + static func from(other: DeckType): + if other is DeckTypeString: + var inst := DeckTypeDictionary.new() + inst._value = str_to_var(other.get_value()) + return inst + + var err: DeckTypeError = DeckTypeError.from(other) + err.error_message = "conversions to Dictionary is only possible from String" + return err diff --git a/port_drawer.gd b/port_drawer.gd new file mode 100644 index 0000000..7e07c20 --- /dev/null +++ b/port_drawer.gd @@ -0,0 +1,53 @@ +extends HBoxContainer + +@onready var left_slot: ColorRect = $LeftSlot +@onready var right_slot: ColorRect = $RightSlot + +var text: String + +signal button_pressed + + +func set_input_enabled(enabled: bool) -> void: + left_slot.visible = enabled + + +func set_output_enabled(enabled: bool) -> void: + right_slot.visible = enabled + + +func add_label(text: String) -> void: + var l := Label.new() + add_child(l) + l.text = text + move_child(l, 1) + l.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + +func add_field() -> void: + var le := LineEdit.new() + add_child(le) + move_child(le, 1) + le.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + le.text_changed.connect( + func(new_text: String): + text = new_text + ) + + +func get_text() -> String: + return text + + +func add_button(text: String) -> void: + var b := Button.new() + b.text = text + add_child(b) + move_child(b, 1) + b.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + b.pressed.connect( + func(): + button_pressed.emit() + ) diff --git a/port_drawer.tscn b/port_drawer.tscn new file mode 100644 index 0000000..a7bb465 --- /dev/null +++ b/port_drawer.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=2 format=3 uid="uid://ddqtmahfxel26"] + +[ext_resource type="Script" path="res://port_drawer.gd" id="1_wot5w"] + +[node name="PortDrawer" type="HBoxContainer"] +script = ExtResource("1_wot5w") + +[node name="LeftSlot" type="ColorRect" parent="."] +visible = false +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 + +[node name="RightSlot" type="ColorRect" parent="."] +visible = false +custom_minimum_size = Vector2(12, 12) +layout_mode = 2 diff --git a/project.godot b/project.godot index 34c5313..064e347 100644 --- a/project.godot +++ b/project.godot @@ -11,5 +11,7 @@ config_version=5 [application] config/name="Re-DotDeck" +config/tags=PackedStringArray("dot_deck") +run/main_scene="res://test.tscn" config/features=PackedStringArray("4.1", "Forward Plus") config/icon="res://icon.svg" diff --git a/test.gd b/test.gd new file mode 100644 index 0000000..e67e833 --- /dev/null +++ b/test.gd @@ -0,0 +1,32 @@ +extends Control + +var node_renderer_scene := preload("res://test_node_renderer.tscn") +@onready var nodes_container: HBoxContainer = $NodesContainer + +@onready var add_button_button: Button = $AddButtonButton +@onready var add_print_button: Button = $AddPrintButton +@onready var connect_them_button: Button = $ConnectThemButton + +var deck: Deck = Deck.new() +var button_node = preload("res://classes/deck/nodes/button.gd") +var print_node = preload("res://classes/deck/nodes/print.gd") + + +func _ready() -> void: + add_button_button.pressed.connect( + func(): + var node := deck.add_node(button_node) + var node_renderer = node_renderer_scene.instantiate() + node_renderer.node = node + nodes_container.add_child(node_renderer) + add_button_button.disabled = true + ) + + add_print_button.pressed.connect( + func(): + var node := deck.add_node(print_node) + var node_renderer = node_renderer_scene.instantiate() + node_renderer.node = node + nodes_container.add_child(node_renderer) + add_print_button.disabled = true + ) diff --git a/test.tscn b/test.tscn new file mode 100644 index 0000000..769c9dc --- /dev/null +++ b/test.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=2 format=3 uid="uid://bhpd6rfiuimw5"] + +[ext_resource type="Script" path="res://test.gd" id="1_in4g7"] + +[node name="Test" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_in4g7") + +[node name="AddButtonButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 26.0 +offset_top = 576.0 +offset_right = 119.0 +offset_bottom = 607.0 +text = "Add Button" + +[node name="AddPrintButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 152.0 +offset_top = 576.0 +offset_right = 248.0 +offset_bottom = 607.0 +text = "Add Print" + +[node name="ConnectThemButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 283.0 +offset_top = 576.0 +offset_right = 379.0 +offset_bottom = 607.0 +text = "Connect them" + +[node name="NodesContainer" type="HBoxContainer" parent="."] +layout_mode = 1 +anchors_preset = -1 +anchor_right = 0.999646 +anchor_bottom = 0.245654 +offset_right = 0.40799 +offset_bottom = -0.184006 +theme_override_constants/separation = 20 +metadata/_edit_use_anchors_ = true diff --git a/test_node_renderer.gd b/test_node_renderer.gd new file mode 100644 index 0000000..33ca14d --- /dev/null +++ b/test_node_renderer.gd @@ -0,0 +1,38 @@ +extends PanelContainer + +@onready var name_label: Label = %NameLabel +@onready var elements_container: VBoxContainer = %ElementsContainer + +var node: DeckNode +const PortDrawer := preload("res://port_drawer.gd") +var port_drawer_scene := preload("res://port_drawer.tscn") + +# THIS IS SUPER JANK AND A HACK FOR DEMONSTRATION PURPOSES +# PLEASE DO NOT ACTUALLY DO ANYTHING THIS CLASS DOES +# IN THE REAL PROJECT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +func _ready() -> void: + name_label.text = node.name + for input_port in node.input_ports: + var port_drawer: PortDrawer = port_drawer_scene.instantiate() + elements_container.add_child(port_drawer) + port_drawer.set_input_enabled(true) + match input_port.descriptor: + "field": + port_drawer.add_field() +# "button": +# port_drawer.add_button(input_port.label) + _: + port_drawer.add_label(input_port.label) + + for i in node.output_ports.size(): + if elements_container.get_child_count() - 1 < i: + var pd: PortDrawer = port_drawer_scene.instantiate() + elements_container.add_child(pd) + var port_drawer: PortDrawer = elements_container.get_child(i) + port_drawer.set_output_enabled(true) + var output_port := node.output_ports[i] + if output_port.descriptor == "button": + port_drawer.add_button(output_port.label) + + diff --git a/test_node_renderer.tscn b/test_node_renderer.tscn new file mode 100644 index 0000000..d50f9da --- /dev/null +++ b/test_node_renderer.tscn @@ -0,0 +1,39 @@ +[gd_scene load_steps=2 format=3 uid="uid://ch8s1d7vobhi4"] + +[ext_resource type="Script" path="res://test_node_renderer.gd" id="1_85wy1"] + +[node name="TestNodeRenderer" type="PanelContainer"] +custom_minimum_size = Vector2(300, 0) +anchors_preset = -1 +anchor_right = 0.26 +anchor_bottom = 0.34 +offset_right = 0.47998 +offset_bottom = -0.320007 +script = ExtResource("1_85wy1") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="HSeparator" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="ColorRect" type="ColorRect" parent="VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(4, 0) +layout_mode = 2 +color = Color(1, 1, 0.34902, 1) + +[node name="NameLabel" type="Label" parent="VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Name" + +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"] +layout_mode = 2 + +[node name="ElementsContainer" type="VBoxContainer" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 From 6b43e807d6b41ba903a1ae6e37b41fde0b95303d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sat, 10 Jun 2023 21:23:57 +0300 Subject: [PATCH 02/17] receive callbacks --- classes/deck/nodes/print.gd | 17 +++++++++++++---- classes/deck/port.gd | 8 +++++++- classes/types/deck_type.gd | 24 ++++++++++++++++++++++++ port_drawer.gd | 3 ++- test_node_renderer.gd | 24 ++++++++++++++++++------ 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index eaf3aae..208b4a0 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -4,15 +4,24 @@ extends DeckNode func _init() -> void: add_input_port( Deck.Types.STRING, - "Input", + "Text to print", "field" ) + add_input_port( + Deck.Types.BOOL, + "Trigger", + "button" + ) + name = "Print" -func _receive(_to_port: int, data: DeckType, extra_data: Array = []) -> void: - # we only have one port, so we can skip checking which port we received on - var data_to_print = data.get_value() +func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: + if to_port != 1: + return + +# var data_to_print = data.get_value() + var data_to_print = input_ports[0].value_callback.call() print(data_to_print) print("extra data: ", extra_data) diff --git a/classes/deck/port.gd b/classes/deck/port.gd index 258ae10..055cf04 100644 --- a/classes/deck/port.gd +++ b/classes/deck/port.gd @@ -3,9 +3,15 @@ class_name Port var type: Deck.Types var label: String var descriptor: String +var value_callback: Callable -func _init(p_type: Deck.Types, p_label: String, p_descriptor: String = "") -> void: +func _init( + p_type: Deck.Types, + p_label: String, + p_descriptor: String = "", + p_value_callback: Callable = Callable()) -> void: type = p_type label = p_label descriptor = p_descriptor + value_callback = p_value_callback diff --git a/classes/types/deck_type.gd b/classes/types/deck_type.gd index da7e437..040e138 100644 --- a/classes/types/deck_type.gd +++ b/classes/types/deck_type.gd @@ -12,6 +12,10 @@ func get_value() -> Variant: return _value +func set_value(new_value: Variant) -> void: + _value = new_value + + static func from(other: DeckType): return null @@ -32,6 +36,10 @@ class DeckTypeError extends DeckType: class DeckTypeNumeric extends DeckType: + func _init(value: float = 0.0) -> void: + _value = value + + static func from(other: DeckType): if other is DeckTypeNumeric: return other @@ -58,6 +66,10 @@ class DeckTypeNumeric extends DeckType: class DeckTypeString extends DeckType: + func _init(value: String = "") -> void: + _value = value + + static func from(other: DeckType): if other is DeckTypeString: return other @@ -67,6 +79,10 @@ class DeckTypeString extends DeckType: class DeckTypeBool extends DeckType: + func _init(value: bool = false) -> void: + _value = value + + static func from(other: DeckType): if other is DeckTypeBool: return other @@ -83,6 +99,10 @@ class DeckTypeBool extends DeckType: class DeckTypeArray extends DeckType: + func _init(value: Array = []) -> void: + _value = value + + static func from(other: DeckType): if other is DeckTypeString: var inst := DeckTypeArray.new() @@ -95,6 +115,10 @@ class DeckTypeArray extends DeckType: class DeckTypeDictionary extends DeckType: + func _init(value: Dictionary = {}) -> void: + _value = value + + static func from(other: DeckType): if other is DeckTypeString: var inst := DeckTypeDictionary.new() diff --git a/port_drawer.gd b/port_drawer.gd index 7e07c20..7c500d3 100644 --- a/port_drawer.gd +++ b/port_drawer.gd @@ -24,11 +24,12 @@ func add_label(text: String) -> void: l.size_flags_horizontal = Control.SIZE_EXPAND_FILL -func add_field() -> void: +func add_field(placeholder: String = "") -> void: var le := LineEdit.new() add_child(le) move_child(le, 1) le.size_flags_horizontal = Control.SIZE_EXPAND_FILL + le.placeholder_text = placeholder le.text_changed.connect( func(new_text: String): diff --git a/test_node_renderer.gd b/test_node_renderer.gd index 33ca14d..55ad263 100644 --- a/test_node_renderer.gd +++ b/test_node_renderer.gd @@ -13,15 +13,20 @@ var port_drawer_scene := preload("res://port_drawer.tscn") func _ready() -> void: name_label.text = node.name - for input_port in node.input_ports: + for i in node.input_ports.size(): + var input_port := node.input_ports[i] var port_drawer: PortDrawer = port_drawer_scene.instantiate() elements_container.add_child(port_drawer) port_drawer.set_input_enabled(true) match input_port.descriptor: "field": - port_drawer.add_field() -# "button": -# port_drawer.add_button(input_port.label) + port_drawer.add_field(input_port.label) + input_port.value_callback = port_drawer.get_text + "button": + port_drawer.add_button(input_port.label) + port_drawer.button_pressed.connect(func(): + node._receive(i, DeckType.DeckTypeString.new("memes")) + ) _: port_drawer.add_label(input_port.label) @@ -32,7 +37,14 @@ func _ready() -> void: var port_drawer: PortDrawer = elements_container.get_child(i) port_drawer.set_output_enabled(true) var output_port := node.output_ports[i] - if output_port.descriptor == "button": - port_drawer.add_button(output_port.label) + match output_port.descriptor: + "field": + port_drawer.add_field(output_port.label) + output_port.value_callback = port_drawer.get_text + "button": + port_drawer.add_button(output_port.label) + _: + port_drawer.add_label(output_port.label) + From badd1e2450b52dda49e9004a3bf1d30c0f6c132c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sun, 11 Jun 2023 18:39:11 +0300 Subject: [PATCH 03/17] fix connections --- classes/deck/deck.gd | 7 +++---- classes/deck/deck_node.gd | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index f32ef42..b2bd3f9 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -22,7 +22,6 @@ static var type_assoc: Dictionary = { } - func add_node(node: GDScript, meta: Dictionary = {}) -> DeckNode: # TODO: accept instances of DeckNode instead of instancing here? var uuid := UUID.v4() @@ -44,9 +43,9 @@ func get_node(uuid: String) -> DeckNode: func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> bool: # first, check that we can do the type conversion. - var type_a: Types = from_node.input_ports[from_port].type - var type_b: Types = to_node.output_ports[to_port].type - var err: DeckType = (type_assoc[type_b] as GDScript).from(type_assoc[type_a]) + var type_a: Types = from_node.output_ports[from_port].type + var type_b: Types = to_node.input_ports[to_port].type + var err: DeckType = (type_assoc[type_b]).from(type_assoc[type_a].new()) if err is DeckType.DeckTypeError: print(err.error_message) return false diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 62f0ab6..73b97bf 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -20,7 +20,7 @@ func add_output_port(type: Deck.Types, label: String, descriptor: String = "") - func send(from_port: int, data: DeckType, extra_data: Array = []) -> void: - if !(outgoing_connections.get(from_port)): + if outgoing_connections.get(from_port) == null: return for connection in outgoing_connections[from_port]: From 2c4a937a76d986112cbffedeb092573a2a25f8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sun, 11 Jun 2023 18:39:26 +0300 Subject: [PATCH 04/17] test connections --- classes/deck/nodes/print.gd | 4 ++-- test.gd | 10 ++++++++++ test_node_renderer.gd | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index 208b4a0..3ae7733 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -21,7 +21,7 @@ func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: if to_port != 1: return -# var data_to_print = data.get_value() - var data_to_print = input_ports[0].value_callback.call() + var data_to_print = data.get_value() +# var data_to_print = input_ports[0].value_callback.call() print(data_to_print) print("extra data: ", extra_data) diff --git a/test.gd b/test.gd index e67e833..6d89590 100644 --- a/test.gd +++ b/test.gd @@ -13,6 +13,8 @@ var print_node = preload("res://classes/deck/nodes/print.gd") func _ready() -> void: + var a = [1, 2, 3] + var b = [2, 1, 3] add_button_button.pressed.connect( func(): var node := deck.add_node(button_node) @@ -30,3 +32,11 @@ func _ready() -> void: nodes_container.add_child(node_renderer) add_print_button.disabled = true ) + + connect_them_button.pressed.connect( + func(): + var node_a: DeckNode = nodes_container.get_child(0).node + var node_b: DeckNode = nodes_container.get_child(1).node + + deck.connect_nodes(node_a, node_b, 0, 1) + ) diff --git a/test_node_renderer.gd b/test_node_renderer.gd index 55ad263..f8938e3 100644 --- a/test_node_renderer.gd +++ b/test_node_renderer.gd @@ -43,6 +43,9 @@ func _ready() -> void: output_port.value_callback = port_drawer.get_text "button": port_drawer.add_button(output_port.label) + port_drawer.button_pressed.connect(func(): + node.send(i, DeckType.DeckTypeBool.new(true)) + ) _: port_drawer.add_label(output_port.label) From c2b04e816b9f53fc6d251d44b3657fb48b9018ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sun, 11 Jun 2023 19:26:12 +0300 Subject: [PATCH 05/17] remove connection method in deck node, disconnect nodes method in deck --- classes/deck/deck.gd | 5 +++++ classes/deck/deck_node.gd | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index b2bd3f9..09887f8 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -54,3 +54,8 @@ func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_po from_node.add_outgoing_connection(from_port, to_node._id, to_port) return true + + +func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> void: + var hash = {to_node._id: to_port}.hash() + from_node.remove_outgoing_connection(from_port, hash) diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 73b97bf..108d210 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -39,3 +39,20 @@ func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> v var port_connections: Array = outgoing_connections.get(from_port, []) port_connections.append({to_node: to_port}) outgoing_connections[from_port] = port_connections + + +func remove_outgoing_connection(from_port: int, connection_hash: int) -> void: + var port_connections: Array = (outgoing_connections.get(from_port, []) as Array).duplicate(true) + if port_connections.is_empty(): + return + + var to_remove: int = -1 + for i in port_connections.size(): + if port_connections[i].hash() == connection_hash: + to_remove = i + + if to_remove == -1: + return + + port_connections.remove_at(to_remove) + outgoing_connections[from_port] = port_connections From 0a309cf530696a5eb1aba169324047cb451fb107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sun, 11 Jun 2023 19:26:21 +0300 Subject: [PATCH 06/17] test disconnections --- test.gd | 11 +++++++++-- test.tscn | 8 ++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/test.gd b/test.gd index 6d89590..fbe3c1c 100644 --- a/test.gd +++ b/test.gd @@ -6,6 +6,7 @@ var node_renderer_scene := preload("res://test_node_renderer.tscn") @onready var add_button_button: Button = $AddButtonButton @onready var add_print_button: Button = $AddPrintButton @onready var connect_them_button: Button = $ConnectThemButton +@onready var disconnect_them_button: Button = $DisconnectThemButton var deck: Deck = Deck.new() var button_node = preload("res://classes/deck/nodes/button.gd") @@ -13,8 +14,6 @@ var print_node = preload("res://classes/deck/nodes/print.gd") func _ready() -> void: - var a = [1, 2, 3] - var b = [2, 1, 3] add_button_button.pressed.connect( func(): var node := deck.add_node(button_node) @@ -40,3 +39,11 @@ func _ready() -> void: deck.connect_nodes(node_a, node_b, 0, 1) ) + + disconnect_them_button.pressed.connect( + func(): + var node_a: DeckNode = nodes_container.get_child(0).node + var node_b: DeckNode = nodes_container.get_child(1).node + + deck.disconnect_nodes(node_a, node_b, 0, 1) + ) diff --git a/test.tscn b/test.tscn index 769c9dc..c849215 100644 --- a/test.tscn +++ b/test.tscn @@ -35,6 +35,14 @@ offset_right = 379.0 offset_bottom = 607.0 text = "Connect them" +[node name="DisconnectThemButton" type="Button" parent="."] +layout_mode = 0 +offset_left = 421.0 +offset_top = 576.0 +offset_right = 538.0 +offset_bottom = 607.0 +text = "Disconnect them" + [node name="NodesContainer" type="HBoxContainer" parent="."] layout_mode = 1 anchors_preset = -1 From f0f3b2e685aae41887fc5f103949bd061c02edf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Mon, 12 Jun 2023 18:32:16 +0300 Subject: [PATCH 07/17] unify ports into one container array --- classes/deck/deck_node.gd | 91 +++++++++++++++++++++++++++++++++++-- classes/deck/nodes/print.gd | 6 +++ classes/deck/port.gd | 16 ++++++- 3 files changed, 107 insertions(+), 6 deletions(-) diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 108d210..63b4525 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -5,18 +5,39 @@ var input_ports: Array[Port] var output_ports: Array[Port] var outgoing_connections: Dictionary +var ports: Array[Port] + var _belonging_to: Deck var _id: String +enum PortType{ + INPUT, ## Input port type (slot on the left). + OUTPUT, ## Output port type (slot on the right). + VIRTUAL, ## Virtual port type (no slot on left [i]or[/i] right). +} + func add_input_port(type: Deck.Types, label: String, descriptor: String = "") -> void: - var port := Port.new(type, label, descriptor) - input_ports.append(port) + var port := Port.new(type, label, ports.size(), PortType.INPUT, get_input_ports().size(), descriptor) + ports.append(port) func add_output_port(type: Deck.Types, label: String, descriptor: String = "") -> void: - var port := Port.new(type, label, descriptor) - output_ports.append(port) + var port := Port.new(type, label, ports.size(), PortType.OUTPUT, get_output_ports().size(), descriptor) + ports.append(port) + + +func add_virtual_port(type: Deck.Types, label: String, descriptor: String = "") -> void: + var port := Port.new(type, label, ports.size(), PortType.VIRTUAL, get_virtual_ports().size(), descriptor) + ports.append(port) + + +func send_from_output_port(output_port: int, data: DeckType, extra_data: Array = []) -> void: + var global_port := get_global_port_idx_from_output(output_port) + if global_port == -1: + return + + send(global_port, data, extra_data) func send(from_port: int, data: DeckType, extra_data: Array = []) -> void: @@ -35,6 +56,14 @@ func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: pass +func add_outgoing_connection_to_port(output_port: int, to_node: String, to_input_port: int) -> void: + add_outgoing_connection( + get_global_port_idx_from_output(output_port), + to_node, + get_node(to_node).get_global_port_idx_from_input(to_input_port) + ) + + func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> void: var port_connections: Array = outgoing_connections.get(from_port, []) port_connections.append({to_node: to_port}) @@ -56,3 +85,57 @@ func remove_outgoing_connection(from_port: int, connection_hash: int) -> void: port_connections.remove_at(to_remove) outgoing_connections[from_port] = port_connections + + +func remove_outgoing_connection_from_port(output_port: int, connection_hash: int) -> void: + remove_outgoing_connection(get_global_port_idx_from_output(output_port), connection_hash) + + +func get_input_ports() -> Array[Port]: + return ports.filter( + func(port: Port) -> bool: + return port.port_type == PortType.INPUT + ) + + +func get_output_ports() -> Array[Port]: + return ports.filter( + func(port: Port) -> bool: + return port.port_type == PortType.OUTPUT + ) + + +func get_virtual_ports() -> Array[Port]: + return ports.filter( + func(port: Port) -> bool: + return port.port_type == PortType.VIRTUAL + ) + + +func get_global_port_idx_from_input(idx: int) -> int: + if get_input_ports().size() > idx: + return get_input_ports()[idx].index + else: + return -1 + + +func get_global_port_idx_from_output(idx: int) -> int: + if get_output_ports().size() > idx: + return get_output_ports()[idx].index + else: + return -1 + + +func get_global_port_idx_from_virtual(idx: int) -> int: + if get_virtual_ports().size() > idx: + return get_virtual_ports()[idx].index + else: + return -1 + + +func get_all_ports() -> Array[Port]: + return ports + + +func get_node(uuid: String) -> DeckNode: + return _belonging_to.get_node(uuid) diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index 3ae7733..9bd45d5 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -14,6 +14,12 @@ func _init() -> void: "button" ) + add_output_port( + Deck.Types.BOOL, + "On Trigger", + "label" + ) + name = "Print" diff --git a/classes/deck/port.gd b/classes/deck/port.gd index 055cf04..6ec1db3 100644 --- a/classes/deck/port.gd +++ b/classes/deck/port.gd @@ -5,13 +5,25 @@ var label: String var descriptor: String var value_callback: Callable +var port_type: DeckNode.PortType +var index_of_type: int +var index: int + func _init( p_type: Deck.Types, p_label: String, + p_index: int, + p_port_type: DeckNode.PortType, + p_index_of_type: int, p_descriptor: String = "", - p_value_callback: Callable = Callable()) -> void: +# p_value_callback: Callable = Callable(), + ) -> void: type = p_type label = p_label descriptor = p_descriptor - value_callback = p_value_callback +# value_callback = p_value_callback + + port_type = p_port_type + index_of_type = p_index_of_type + index = p_index From 318efb9c347a5b80758cfcccdb1a87e9617a3502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Mon, 12 Jun 2023 18:32:36 +0300 Subject: [PATCH 08/17] graphedit renderer beginnings --- .../deck_node_renderer_graph_node.gd | 40 +++++++++++++++++++ .../deck_node_renderer_graph_node.tscn | 9 +++++ .../deck_renderer_graph_edit.gd | 32 +++++++++++++++ .../deck_renderer_graph_edit.tscn | 12 ++++++ project.godot | 2 +- 5 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 graph_node_renderer/deck_node_renderer_graph_node.gd create mode 100644 graph_node_renderer/deck_node_renderer_graph_node.tscn create mode 100644 graph_node_renderer/deck_renderer_graph_edit.gd create mode 100644 graph_node_renderer/deck_renderer_graph_edit.tscn diff --git a/graph_node_renderer/deck_node_renderer_graph_node.gd b/graph_node_renderer/deck_node_renderer_graph_node.gd new file mode 100644 index 0000000..9a553c3 --- /dev/null +++ b/graph_node_renderer/deck_node_renderer_graph_node.gd @@ -0,0 +1,40 @@ +extends GraphNode +class_name DeckNodeRendererGraphNode + +var node: DeckNode + + +func _ready() -> void: + title = node.name + + for port in node.get_all_ports(): + var descriptor_split := port.descriptor.split(":") + match descriptor_split[0]: + "button": + var button := Button.new() + add_child(button) + button.text = port.label + if port.port_type == DeckNode.PortType.OUTPUT: + button.pressed.connect( + func(): + node.send(port.index, DeckType.DeckTypeString.new("Button Pressed")) + ) + "field": + var line_edit := LineEdit.new() + add_child(line_edit) + line_edit.placeholder_text = port.label + port.value_callback = line_edit.get_text + _: + var label := Label.new() + add_child(label) + label.text = port.label + + set_slot( + port.index, + port.port_type == DeckNode.PortType.INPUT, + 0, + Color.WHITE, + port.port_type == DeckNode.PortType.OUTPUT, + 0, + Color.WHITE, + ) diff --git a/graph_node_renderer/deck_node_renderer_graph_node.tscn b/graph_node_renderer/deck_node_renderer_graph_node.tscn new file mode 100644 index 0000000..d716bd1 --- /dev/null +++ b/graph_node_renderer/deck_node_renderer_graph_node.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://vjpj2074hiex"] + +[ext_resource type="Script" path="res://graph_node_renderer/deck_node_renderer_graph_node.gd" id="1_pos0w"] + +[node name="DeckNodeRendererGraphNode" type="GraphNode"] +offset_right = 280.0 +offset_bottom = 217.0 +title = "Deck Node" +script = ExtResource("1_pos0w") diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd new file mode 100644 index 0000000..929be2b --- /dev/null +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -0,0 +1,32 @@ +extends GraphEdit + +const NODE_SCENE := preload("res://graph_node_renderer/deck_node_renderer_graph_node.tscn") + +var deck: Deck = Deck.new() +var button_node = preload("res://classes/deck/nodes/button.gd") +var print_node = preload("res://classes/deck/nodes/print.gd") + + +func _ready() -> void: + var add_button := Button.new() + add_button.text = "Button" + var add_print := Button.new() + add_print.text = "Print" + get_zoom_hbox().add_child(add_button) + get_zoom_hbox().add_child(add_print) + + add_button.pressed.connect( + func(): + var node := deck.add_node(button_node) + var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() + node_renderer.node = node + add_child(node_renderer) + ) + + add_print.pressed.connect( + func(): + var node := deck.add_node(print_node) + var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() + node_renderer.node = node + add_child(node_renderer) + ) diff --git a/graph_node_renderer/deck_renderer_graph_edit.tscn b/graph_node_renderer/deck_renderer_graph_edit.tscn new file mode 100644 index 0000000..7f6f336 --- /dev/null +++ b/graph_node_renderer/deck_renderer_graph_edit.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=2 format=3 uid="uid://b18qpb48df14l"] + +[ext_resource type="Script" path="res://graph_node_renderer/deck_renderer_graph_edit.gd" id="1_pojfs"] + +[node name="DeckRendererGraphEdit" type="GraphEdit"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +right_disconnects = true +script = ExtResource("1_pojfs") diff --git a/project.godot b/project.godot index 064e347..80a16fb 100644 --- a/project.godot +++ b/project.godot @@ -12,6 +12,6 @@ config_version=5 config/name="Re-DotDeck" config/tags=PackedStringArray("dot_deck") -run/main_scene="res://test.tscn" +run/main_scene="res://graph_node_renderer/deck_renderer_graph_edit.tscn" config/features=PackedStringArray("4.1", "Forward Plus") config/icon="res://icon.svg" From a5acd3a1c36c249e89e8291a68b723635483a8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Mon, 12 Jun 2023 18:59:30 +0300 Subject: [PATCH 09/17] fix connections but 2 --- classes/deck/deck.gd | 4 ++-- classes/deck/nodes/button.gd | 2 +- classes/deck/nodes/print.gd | 3 ++- .../deck_node_renderer_graph_node.gd | 7 ++++++- graph_node_renderer/deck_renderer_graph_edit.gd | 13 +++++++++++++ project.godot | 1 + 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index 09887f8..c466be3 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -43,8 +43,8 @@ func get_node(uuid: String) -> DeckNode: func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> bool: # first, check that we can do the type conversion. - var type_a: Types = from_node.output_ports[from_port].type - var type_b: Types = to_node.input_ports[to_port].type + var type_a: Types = from_node.ports[from_port].type + var type_b: Types = to_node.ports[to_port].type var err: DeckType = (type_assoc[type_b]).from(type_assoc[type_a].new()) if err is DeckType.DeckTypeError: print(err.error_message) diff --git a/classes/deck/nodes/button.gd b/classes/deck/nodes/button.gd index 8b6bd03..f983540 100644 --- a/classes/deck/nodes/button.gd +++ b/classes/deck/nodes/button.gd @@ -3,7 +3,7 @@ extends DeckNode func _init() -> void: add_output_port( - Deck.Types.STRING, + Deck.Types.BOOL, "Press me", "button" ) diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index 9bd45d5..e042156 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -27,7 +27,8 @@ func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: if to_port != 1: return - var data_to_print = data.get_value() + var data_to_print = ports[0].value_callback.call() if ports[0].value_callback.call() != "" else data.get_value() # var data_to_print = input_ports[0].value_callback.call() print(data_to_print) print("extra data: ", extra_data) + send(2, DeckType.DeckTypeBool.new(true)) diff --git a/graph_node_renderer/deck_node_renderer_graph_node.gd b/graph_node_renderer/deck_node_renderer_graph_node.gd index 9a553c3..4854c7d 100644 --- a/graph_node_renderer/deck_node_renderer_graph_node.gd +++ b/graph_node_renderer/deck_node_renderer_graph_node.gd @@ -17,7 +17,12 @@ func _ready() -> void: if port.port_type == DeckNode.PortType.OUTPUT: button.pressed.connect( func(): - node.send(port.index, DeckType.DeckTypeString.new("Button Pressed")) + node.send(port.index, DeckType.DeckTypeBool.new(true)) + ) + elif port.port_type == DeckNode.PortType.INPUT: + button.pressed.connect( + func(): + node._receive(port.index, DeckType.DeckTypeBool.new(true)) ) "field": var line_edit := LineEdit.new() diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index 929be2b..473cb18 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -30,3 +30,16 @@ func _ready() -> void: node_renderer.node = node add_child(node_renderer) ) + + connection_request.connect(attempt_connection) + + +func attempt_connection(from_node_name: StringName, from_port: int, to_node_name: StringName, to_port: int) -> void: + var from_node: DeckNode = get_node(NodePath(from_node_name)).node + var to_node: DeckNode = get_node(NodePath(to_node_name)).node + + var from_output := from_node.get_global_port_idx_from_output(from_port) + var to_input := to_node.get_global_port_idx_from_input(to_port) + + if deck.connect_nodes(from_node, to_node, from_output, to_input): + connect_node(from_node_name, from_port, to_node_name, to_port) diff --git a/project.godot b/project.godot index 80a16fb..a0a95f3 100644 --- a/project.godot +++ b/project.godot @@ -14,4 +14,5 @@ config/name="Re-DotDeck" config/tags=PackedStringArray("dot_deck") run/main_scene="res://graph_node_renderer/deck_renderer_graph_edit.tscn" config/features=PackedStringArray("4.1", "Forward Plus") +run/low_processor_mode=true config/icon="res://icon.svg" From 83d5fae1bdce8c41fed8f0bf1949bc197566c953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Tue, 13 Jun 2023 16:06:17 +0300 Subject: [PATCH 10/17] test disconnections but 2 --- graph_node_renderer/deck_renderer_graph_edit.gd | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index 473cb18..aeff7e6 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -32,6 +32,7 @@ func _ready() -> void: ) connection_request.connect(attempt_connection) + disconnection_request.connect(attempt_disconnect) func attempt_connection(from_node_name: StringName, from_port: int, to_node_name: StringName, to_port: int) -> void: @@ -43,3 +44,15 @@ func attempt_connection(from_node_name: StringName, from_port: int, to_node_name if deck.connect_nodes(from_node, to_node, from_output, to_input): connect_node(from_node_name, from_port, to_node_name, to_port) + + +func attempt_disconnect(from_node_name: StringName, from_port: int, to_node_name: StringName, to_port: int) -> void: + var from_node: DeckNode = get_node(NodePath(from_node_name)).node + var to_node: DeckNode = get_node(NodePath(to_node_name)).node + + var from_output := from_node.get_global_port_idx_from_output(from_port) + var to_input := to_node.get_global_port_idx_from_input(to_port) + + deck.disconnect_nodes(from_node, to_node, from_output, to_input) + + disconnect_node(from_node_name, from_port, to_node_name, to_port) From 46169147a446562f52450ea76945c31424c4ac7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Tue, 13 Jun 2023 18:23:10 +0300 Subject: [PATCH 11/17] add call time resolution of port values --- classes/deck/deck.gd | 2 + classes/deck/deck_node.gd | 23 +++++++- classes/deck/nodes/get_deck_var.gd | 16 ++++++ classes/deck/nodes/print.gd | 9 +++- classes/deck/nodes/set_deck_var.gd | 52 +++++++++++++++++++ .../deck_renderer_graph_edit.gd | 25 ++++++++- 6 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 classes/deck/nodes/get_deck_var.gd create mode 100644 classes/deck/nodes/set_deck_var.gd diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index c466be3..2f16d2e 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -21,6 +21,8 @@ static var type_assoc: Dictionary = { Types.DICTIONARY: DeckType.DeckTypeDictionary, } +var variable_stack: Dictionary = {} + func add_node(node: GDScript, meta: Dictionary = {}) -> DeckNode: # TODO: accept instances of DeckNode instead of instancing here? diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 63b4525..4d410a3 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -4,6 +4,7 @@ var name: String var input_ports: Array[Port] var output_ports: Array[Port] var outgoing_connections: Dictionary +var incoming_connections: Dictionary var ports: Array[Port] @@ -49,7 +50,7 @@ func send(from_port: int, data: DeckType, extra_data: Array = []) -> void: # key is node uuid # value is input port on destination node for node in connection: - _belonging_to.get_node(node)._receive(connection[node], data, extra_data) + get_node(node)._receive(connection[node], data, extra_data) func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: @@ -68,6 +69,26 @@ func add_outgoing_connection(from_port: int, to_node: String, to_port: int) -> v var port_connections: Array = outgoing_connections.get(from_port, []) port_connections.append({to_node: to_port}) outgoing_connections[from_port] = port_connections + get_node(to_node).add_incoming_connection(to_port, _id, from_port) + + +func add_incoming_connection(to_port: int, from_node: String, from_port: int) -> void: + var connection := {from_node: from_port} + incoming_connections[to_port] = connection + + +func request_value(on_port: int) -> Variant: + if !incoming_connections.has(on_port): + return null + + var connection: Dictionary = incoming_connections[on_port] + var node := get_node(connection.keys()[0]) + return node._value_request(connection.values()[0]) + + +# override this +func _value_request(from_port: int) -> Variant: + return null func remove_outgoing_connection(from_port: int, connection_hash: int) -> void: diff --git a/classes/deck/nodes/get_deck_var.gd b/classes/deck/nodes/get_deck_var.gd new file mode 100644 index 0000000..7e64b0e --- /dev/null +++ b/classes/deck/nodes/get_deck_var.gd @@ -0,0 +1,16 @@ +extends DeckNode + + +func _init() -> void: + add_output_port( + Deck.Types.STRING, + "Variable", + "field" + ) + + name = "Get Deck Var" + + +func _value_request(from_port: int) -> Variant: + var key = ports[0].value_callback.call() + return _belonging_to.variable_stack[key] diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index e042156..23955ab 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -27,7 +27,14 @@ func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: if to_port != 1: return - var data_to_print = ports[0].value_callback.call() if ports[0].value_callback.call() != "" else data.get_value() + var data_to_print + if request_value(0) != null: + data_to_print = request_value(0) + elif ports[0].value_callback.call() != "": + data_to_print = ports[0].value_callback.call() + else: + data_to_print = data.get_value() + # var data_to_print = input_ports[0].value_callback.call() print(data_to_print) print("extra data: ", extra_data) diff --git a/classes/deck/nodes/set_deck_var.gd b/classes/deck/nodes/set_deck_var.gd new file mode 100644 index 0000000..ac25dfe --- /dev/null +++ b/classes/deck/nodes/set_deck_var.gd @@ -0,0 +1,52 @@ +extends DeckNode + + +func _init() -> void: + add_input_port( + Deck.Types.STRING, + "Variable Name", + "field" + ) + + add_input_port( + Deck.Types.STRING, + "Value", + "field" + ) + + add_input_port( + Deck.Types.BOOL, + "Set", + "button" + ) + + add_output_port( + Deck.Types.STRING, + "Value", + "label" + ) + + name = "Set Deck Var" + + +func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: + if to_port != 2: + return + + var var_name: String = get_value_for_port(0, data) + # String for now, until i figure out an Any type + var var_value: String = get_value_for_port(1, data) + + _belonging_to.variable_stack[var_name] = var_value + + send(3, DeckType.DeckTypeString.new(var_value)) + +# this can probably go into DeckNode with a different name that makes it clear +# that it prioritizes call-time resolution +func get_value_for_port(port: int, data: DeckType) -> Variant: + if request_value(port) != null: + return request_value(port) + elif ports[port].value_callback.call() != "": + return ports[port].value_callback.call() + else: + return data.get_value() diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index aeff7e6..d52900c 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -5,15 +5,22 @@ const NODE_SCENE := preload("res://graph_node_renderer/deck_node_renderer_graph_ var deck: Deck = Deck.new() var button_node = preload("res://classes/deck/nodes/button.gd") var print_node = preload("res://classes/deck/nodes/print.gd") - +var get_var_node = preload("res://classes/deck/nodes/get_deck_var.gd") +var set_var_node = preload("res://classes/deck/nodes/set_deck_var.gd") func _ready() -> void: var add_button := Button.new() add_button.text = "Button" var add_print := Button.new() add_print.text = "Print" + var get_var := Button.new() + get_var.text = "Get Var" + var set_var := Button.new() + set_var.text = "Set Var" get_zoom_hbox().add_child(add_button) get_zoom_hbox().add_child(add_print) + get_zoom_hbox().add_child(get_var) + get_zoom_hbox().add_child(set_var) add_button.pressed.connect( func(): @@ -31,6 +38,22 @@ func _ready() -> void: add_child(node_renderer) ) + get_var.pressed.connect( + func(): + var node := deck.add_node(get_var_node) + var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() + node_renderer.node = node + add_child(node_renderer) + ) + + set_var.pressed.connect( + func(): + var node := deck.add_node(set_var_node) + var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() + node_renderer.node = node + add_child(node_renderer) + ) + connection_request.connect(attempt_connection) disconnection_request.connect(attempt_disconnect) From 074edb1e1f4c225dcb866d672f0526facf337e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sat, 24 Jun 2023 06:39:50 +0300 Subject: [PATCH 12/17] serialize to json/dictionary, instance by type --- classes/deck/deck.gd | 28 +++++++++++++++ classes/deck/deck_node.gd | 19 ++++++++++ classes/deck/node_db.gd | 27 ++++++++++++++ classes/deck/nodes/button.gd | 2 ++ classes/deck/nodes/get_deck_var.gd | 2 ++ classes/deck/nodes/no_type.gd | 1 + classes/deck/nodes/print.gd | 2 ++ classes/deck/nodes/set_deck_var.gd | 2 ++ .../deck_node_renderer_graph_node.gd | 4 +++ .../deck_node_renderer_graph_node.tscn | 2 ++ .../deck_renderer_graph_edit.gd | 35 ++++++++++++++----- .../deck_renderer_graph_edit.tscn | 2 ++ project.godot | 4 +++ 13 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 classes/deck/node_db.gd create mode 100644 classes/deck/nodes/no_type.gd diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index 2f16d2e..b18df9d 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -39,6 +39,19 @@ func add_node(node: GDScript, meta: Dictionary = {}) -> DeckNode: return node_inst +func add_node_inst(node: DeckNode) -> DeckNode: + var uuid := UUID.v4() + nodes[uuid] = node + node._belonging_to = self + node._id = uuid + +# if !meta.is_empty(): +# for k in meta: +# node.set_meta(k, meta[k]) + + return node + + func get_node(uuid: String) -> DeckNode: return nodes.get(uuid) @@ -61,3 +74,18 @@ func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_po func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> void: var hash = {to_node._id: to_port}.hash() from_node.remove_outgoing_connection(from_port, hash) + + +func to_json(with_meta: bool = true) -> String: + var inner := {"nodes": {}} + + for id in nodes.keys(): + inner["nodes"][id] = nodes[id].to_dict(with_meta) + + var d := {"deck": inner} + + if with_meta: + d["meta"] = {} + for meta in get_meta_list(): + d["meta"][meta] = get_meta(meta) + return JSON.stringify(d, "\t", false) diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 4d410a3..79bf106 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -10,6 +10,9 @@ var ports: Array[Port] var _belonging_to: Deck var _id: String +var node_type: String + +var props_to_serialize: Array[StringName] enum PortType{ INPUT, ## Input port type (slot on the left). @@ -160,3 +163,19 @@ func get_all_ports() -> Array[Port]: func get_node(uuid: String) -> DeckNode: return _belonging_to.get_node(uuid) + + +func to_dict(with_meta: bool = true) -> Dictionary: + var d := { + "_id": _id, + "name": name, + "outgoing_connections": outgoing_connections, + "incoming_connections": incoming_connections, + "props": props_to_serialize, + "node_type": node_type, + } + if with_meta: + d["meta"] = {} + for meta in get_meta_list(): + d["meta"][meta] = get_meta(meta) + return d diff --git a/classes/deck/node_db.gd b/classes/deck/node_db.gd new file mode 100644 index 0000000..294824e --- /dev/null +++ b/classes/deck/node_db.gd @@ -0,0 +1,27 @@ +extends Node + +const BASE_NODE_PATH := "res://classes/deck/nodes/" +var nodes: Dictionary = {} + + +func _init() -> void: + var dir := DirAccess.open(BASE_NODE_PATH) + dir.list_dir_begin() + var current_file := dir.get_next() + while current_file != "": + print(current_file) + if current_file.ends_with(".gd"): + var f := FileAccess.open(BASE_NODE_PATH.path_join(current_file), FileAccess.READ) + var line := f.get_line() + if !line.begins_with("###type="): + current_file = dir.get_next() + continue + nodes[line.trim_prefix("###type=")] = BASE_NODE_PATH.path_join(current_file) + current_file = dir.get_next() + + +func instance_node(type: String) -> DeckNode: + if !nodes.has(type): + return null + + return load(nodes[type]).new() diff --git a/classes/deck/nodes/button.gd b/classes/deck/nodes/button.gd index f983540..2c0da4b 100644 --- a/classes/deck/nodes/button.gd +++ b/classes/deck/nodes/button.gd @@ -1,3 +1,4 @@ +###type=button extends DeckNode @@ -9,3 +10,4 @@ func _init() -> void: ) name = "Button" + node_type = name.to_snake_case() diff --git a/classes/deck/nodes/get_deck_var.gd b/classes/deck/nodes/get_deck_var.gd index 7e64b0e..9de6736 100644 --- a/classes/deck/nodes/get_deck_var.gd +++ b/classes/deck/nodes/get_deck_var.gd @@ -1,3 +1,4 @@ +###type=get_deck_var extends DeckNode @@ -9,6 +10,7 @@ func _init() -> void: ) name = "Get Deck Var" + node_type = name.to_snake_case() func _value_request(from_port: int) -> Variant: diff --git a/classes/deck/nodes/no_type.gd b/classes/deck/nodes/no_type.gd new file mode 100644 index 0000000..61510e1 --- /dev/null +++ b/classes/deck/nodes/no_type.gd @@ -0,0 +1 @@ +extends Node diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index 23955ab..a6cf3e9 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -1,3 +1,4 @@ +###type=print extends DeckNode @@ -21,6 +22,7 @@ func _init() -> void: ) name = "Print" + node_type = name.to_snake_case() func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: diff --git a/classes/deck/nodes/set_deck_var.gd b/classes/deck/nodes/set_deck_var.gd index ac25dfe..b8cc44f 100644 --- a/classes/deck/nodes/set_deck_var.gd +++ b/classes/deck/nodes/set_deck_var.gd @@ -1,3 +1,4 @@ +###type=set_deck_var extends DeckNode @@ -27,6 +28,7 @@ func _init() -> void: ) name = "Set Deck Var" + node_type = name.to_snake_case() func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: diff --git a/graph_node_renderer/deck_node_renderer_graph_node.gd b/graph_node_renderer/deck_node_renderer_graph_node.gd index 4854c7d..7c8ab1e 100644 --- a/graph_node_renderer/deck_node_renderer_graph_node.gd +++ b/graph_node_renderer/deck_node_renderer_graph_node.gd @@ -43,3 +43,7 @@ func _ready() -> void: 0, Color.WHITE, ) + + +func _on_position_offset_changed() -> void: + node.set_meta("position_offset", position_offset) diff --git a/graph_node_renderer/deck_node_renderer_graph_node.tscn b/graph_node_renderer/deck_node_renderer_graph_node.tscn index d716bd1..2d66ba3 100644 --- a/graph_node_renderer/deck_node_renderer_graph_node.tscn +++ b/graph_node_renderer/deck_node_renderer_graph_node.tscn @@ -7,3 +7,5 @@ offset_right = 280.0 offset_bottom = 217.0 title = "Deck Node" script = ExtResource("1_pos0w") + +[connection signal="position_offset_changed" from="." to="." method="_on_position_offset_changed"] diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index d52900c..d4900bb 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -3,10 +3,10 @@ extends GraphEdit const NODE_SCENE := preload("res://graph_node_renderer/deck_node_renderer_graph_node.tscn") var deck: Deck = Deck.new() -var button_node = preload("res://classes/deck/nodes/button.gd") -var print_node = preload("res://classes/deck/nodes/print.gd") -var get_var_node = preload("res://classes/deck/nodes/get_deck_var.gd") -var set_var_node = preload("res://classes/deck/nodes/set_deck_var.gd") +#var button_node = preload("res://classes/deck/nodes/button.gd") +#var print_node = preload("res://classes/deck/nodes/print.gd") +#var get_var_node = preload("res://classes/deck/nodes/get_deck_var.gd") +#var set_var_node = preload("res://classes/deck/nodes/set_deck_var.gd") func _ready() -> void: var add_button := Button.new() @@ -22,9 +22,21 @@ func _ready() -> void: get_zoom_hbox().add_child(get_var) get_zoom_hbox().add_child(set_var) + var save_btn := Button.new() + save_btn.text = "Save" + get_zoom_hbox().add_child(save_btn) + + save_btn.pressed.connect( + func(): + var t = deck.to_json() + var f := FileAccess.open("user://save_test.json", FileAccess.WRITE) + f.store_string(t) + ) + add_button.pressed.connect( func(): - var node := deck.add_node(button_node) + var node := NodeDB.instance_node("button") + deck.add_node_inst(node) var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() node_renderer.node = node add_child(node_renderer) @@ -32,7 +44,8 @@ func _ready() -> void: add_print.pressed.connect( func(): - var node := deck.add_node(print_node) + var node := NodeDB.instance_node("print") + deck.add_node_inst(node) var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() node_renderer.node = node add_child(node_renderer) @@ -40,7 +53,8 @@ func _ready() -> void: get_var.pressed.connect( func(): - var node := deck.add_node(get_var_node) + var node := NodeDB.instance_node("get_deck_var") + deck.add_node_inst(node) var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() node_renderer.node = node add_child(node_renderer) @@ -48,7 +62,8 @@ func _ready() -> void: set_var.pressed.connect( func(): - var node := deck.add_node(set_var_node) + var node := NodeDB.instance_node("set_deck_varbutton") + deck.add_node_inst(node) var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() node_renderer.node = node add_child(node_renderer) @@ -79,3 +94,7 @@ func attempt_disconnect(from_node_name: StringName, from_port: int, to_node_name deck.disconnect_nodes(from_node, to_node, from_output, to_input) disconnect_node(from_node_name, from_port, to_node_name, to_port) + + +func _on_scroll_offset_changed(offset: Vector2) -> void: + deck.set_meta("offset", offset) diff --git a/graph_node_renderer/deck_renderer_graph_edit.tscn b/graph_node_renderer/deck_renderer_graph_edit.tscn index 7f6f336..a7720e3 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.tscn +++ b/graph_node_renderer/deck_renderer_graph_edit.tscn @@ -10,3 +10,5 @@ grow_horizontal = 2 grow_vertical = 2 right_disconnects = true script = ExtResource("1_pojfs") + +[connection signal="scroll_offset_changed" from="." to="." method="_on_scroll_offset_changed"] diff --git a/project.godot b/project.godot index a0a95f3..844c23c 100644 --- a/project.godot +++ b/project.godot @@ -16,3 +16,7 @@ run/main_scene="res://graph_node_renderer/deck_renderer_graph_edit.tscn" config/features=PackedStringArray("4.1", "Forward Plus") run/low_processor_mode=true config/icon="res://icon.svg" + +[autoload] + +NodeDB="*res://classes/deck/node_db.gd" From f9069db8be33efea110665d20ce13a3a0783d8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Fri, 21 Jul 2023 08:30:12 +0300 Subject: [PATCH 13/17] new way to instance nodes --- classes/deck/deck_node.gd | 3 ++ classes/deck/node_db.gd | 34 +++++++++++++++---- classes/deck/nodes/button.gd | 8 ++--- classes/deck/nodes/get_deck_var.gd | 8 ++--- classes/deck/nodes/no_type.gd | 1 - classes/deck/nodes/print.gd | 8 ++--- classes/deck/nodes/set_deck_var.gd | 8 ++--- .../deck_renderer_graph_edit.gd | 2 +- 8 files changed, 47 insertions(+), 25 deletions(-) delete mode 100644 classes/deck/nodes/no_type.gd diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 79bf106..4f3e4e5 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -12,6 +12,9 @@ var _belonging_to: Deck var _id: String var node_type: String +var description: String +var aliases: Array[String] + var props_to_serialize: Array[StringName] enum PortType{ diff --git a/classes/deck/node_db.gd b/classes/deck/node_db.gd index 294824e..2758602 100644 --- a/classes/deck/node_db.gd +++ b/classes/deck/node_db.gd @@ -1,6 +1,8 @@ extends Node const BASE_NODE_PATH := "res://classes/deck/nodes/" + +# Dictionary[node_type, NodeDescriptor] var nodes: Dictionary = {} @@ -11,12 +13,11 @@ func _init() -> void: while current_file != "": print(current_file) if current_file.ends_with(".gd"): - var f := FileAccess.open(BASE_NODE_PATH.path_join(current_file), FileAccess.READ) - var line := f.get_line() - if !line.begins_with("###type="): - current_file = dir.get_next() - continue - nodes[line.trim_prefix("###type=")] = BASE_NODE_PATH.path_join(current_file) +# var f := FileAccess.open(BASE_NODE_PATH.path_join(current_file), FileAccess.READ) + var script_path := BASE_NODE_PATH.path_join(current_file) + var node: DeckNode = load(script_path).new() as DeckNode + var descriptor := NodeDescriptor.new(script_path, node.name, node.description, node.aliases) + nodes[node.node_type] = descriptor current_file = dir.get_next() @@ -24,4 +25,23 @@ func instance_node(type: String) -> DeckNode: if !nodes.has(type): return null - return load(nodes[type]).new() + return load(nodes[type]["script_path"]).new() + + +class NodeDescriptor: + var name: String + var description: String + var aliases: String + + var script_path: String + + + func _init(p_script_path: String, p_name: String, p_description: String, p_aliases: Array[String]) -> void: + script_path = p_script_path + + name = p_name + description = p_description + aliases = p_aliases.reduce( + func(accum, el) -> void: + accum += el + , "") diff --git a/classes/deck/nodes/button.gd b/classes/deck/nodes/button.gd index 2c0da4b..3bb3b15 100644 --- a/classes/deck/nodes/button.gd +++ b/classes/deck/nodes/button.gd @@ -1,13 +1,13 @@ -###type=button extends DeckNode func _init() -> void: + name = "Button" + node_type = "button" + description = "a button" + add_output_port( Deck.Types.BOOL, "Press me", "button" ) - - name = "Button" - node_type = name.to_snake_case() diff --git a/classes/deck/nodes/get_deck_var.gd b/classes/deck/nodes/get_deck_var.gd index 9de6736..b37a4ab 100644 --- a/classes/deck/nodes/get_deck_var.gd +++ b/classes/deck/nodes/get_deck_var.gd @@ -1,17 +1,17 @@ -###type=get_deck_var extends DeckNode func _init() -> void: + name = "Get Deck Var" + node_type = name.to_snake_case() + description = "retrieve a deck variable" + add_output_port( Deck.Types.STRING, "Variable", "field" ) - name = "Get Deck Var" - node_type = name.to_snake_case() - func _value_request(from_port: int) -> Variant: var key = ports[0].value_callback.call() diff --git a/classes/deck/nodes/no_type.gd b/classes/deck/nodes/no_type.gd deleted file mode 100644 index 61510e1..0000000 --- a/classes/deck/nodes/no_type.gd +++ /dev/null @@ -1 +0,0 @@ -extends Node diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index a6cf3e9..327217d 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -1,8 +1,11 @@ -###type=print extends DeckNode func _init() -> void: + name = "Print" + node_type = name.to_snake_case() + description = "print a value" + add_input_port( Deck.Types.STRING, "Text to print", @@ -21,9 +24,6 @@ func _init() -> void: "label" ) - name = "Print" - node_type = name.to_snake_case() - func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: if to_port != 1: diff --git a/classes/deck/nodes/set_deck_var.gd b/classes/deck/nodes/set_deck_var.gd index b8cc44f..400aabd 100644 --- a/classes/deck/nodes/set_deck_var.gd +++ b/classes/deck/nodes/set_deck_var.gd @@ -1,8 +1,11 @@ -###type=set_deck_var extends DeckNode func _init() -> void: + name = "Set Deck Var" + node_type = name.to_snake_case() + description = "set deck variable" + add_input_port( Deck.Types.STRING, "Variable Name", @@ -27,9 +30,6 @@ func _init() -> void: "label" ) - name = "Set Deck Var" - node_type = name.to_snake_case() - func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: if to_port != 2: diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index d4900bb..a83fcdb 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -62,7 +62,7 @@ func _ready() -> void: set_var.pressed.connect( func(): - var node := NodeDB.instance_node("set_deck_varbutton") + var node := NodeDB.instance_node("set_deck_var") deck.add_node_inst(node) var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() node_renderer.node = node From 97aa95bf6ba6049f39422279bef2062f88198600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Fri, 21 Jul 2023 09:39:38 +0300 Subject: [PATCH 14/17] cache node index and load it --- classes/deck/node_db.gd | 71 +++++++++++++++++++++++++++++++++++++---- project.godot | 2 ++ 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/classes/deck/node_db.gd b/classes/deck/node_db.gd index 2758602..21b820e 100644 --- a/classes/deck/node_db.gd +++ b/classes/deck/node_db.gd @@ -1,25 +1,34 @@ extends Node const BASE_NODE_PATH := "res://classes/deck/nodes/" +const NODE_INDEX_CACHE_PATH := "user://nodes_index.json" # Dictionary[node_type, NodeDescriptor] var nodes: Dictionary = {} func _init() -> void: + if load_node_index(): + return + var dir := DirAccess.open(BASE_NODE_PATH) dir.list_dir_begin() var current_file := dir.get_next() while current_file != "": print(current_file) if current_file.ends_with(".gd"): -# var f := FileAccess.open(BASE_NODE_PATH.path_join(current_file), FileAccess.READ) var script_path := BASE_NODE_PATH.path_join(current_file) var node: DeckNode = load(script_path).new() as DeckNode - var descriptor := NodeDescriptor.new(script_path, node.name, node.description, node.aliases) + var aliases: String = node.aliases.reduce( + func(accum, el) -> void: + accum += el + , "") + var descriptor := NodeDescriptor.new(script_path, node.name, node.description, aliases) nodes[node.node_type] = descriptor current_file = dir.get_next() + save_node_index() + func instance_node(type: String) -> DeckNode: if !nodes.has(type): @@ -28,6 +37,37 @@ func instance_node(type: String) -> DeckNode: return load(nodes[type]["script_path"]).new() +func save_node_index() -> void: + var d := {} + for node_type in nodes: + var nd: NodeDescriptor = nodes[node_type] as NodeDescriptor + d[node_type] = nd.to_dictionary() + + var json := JSON.stringify(d, "\t") + var f := FileAccess.open(NODE_INDEX_CACHE_PATH, FileAccess.WRITE) + f.store_string(json) + + +func load_node_index() -> bool: + var f := FileAccess.open(NODE_INDEX_CACHE_PATH, FileAccess.READ) + if f == null: + print("node index file does not exist") + return false + + var data: Dictionary = JSON.parse_string(f.get_as_text()) as Dictionary + if data.is_empty(): + print("node index file exists, but is empty") + return false + + for node_type in data: + var nd_dict: Dictionary = data[node_type] + var nd := NodeDescriptor.from_dictionary(nd_dict) + nodes[node_type] = nd + + print("node index file exists, loaded") + return true + + class NodeDescriptor: var name: String var description: String @@ -36,12 +76,29 @@ class NodeDescriptor: var script_path: String - func _init(p_script_path: String, p_name: String, p_description: String, p_aliases: Array[String]) -> void: + func _init(p_script_path: String, p_name: String, p_description: String, p_aliases: String) -> void: script_path = p_script_path name = p_name description = p_description - aliases = p_aliases.reduce( - func(accum, el) -> void: - accum += el - , "") + aliases = p_aliases + + + func to_dictionary() -> Dictionary: + var d := { + "name": name, + "description": description, + "aliases": aliases, + "script_path": script_path + } + return d + + + static func from_dictionary(data: Dictionary) -> NodeDescriptor: + var nd := NodeDescriptor.new( + data.get("script_path", ""), + data.get("name", ""), + data.get("description", ""), + data.get("aliases", "")) + + return nd diff --git a/project.godot b/project.godot index 844c23c..be8e78f 100644 --- a/project.godot +++ b/project.godot @@ -13,6 +13,8 @@ config_version=5 config/name="Re-DotDeck" config/tags=PackedStringArray("dot_deck") run/main_scene="res://graph_node_renderer/deck_renderer_graph_edit.tscn" +config/use_custom_user_dir=true +config/custom_user_dir_name="dotdeck" config/features=PackedStringArray("4.1", "Forward Plus") run/low_processor_mode=true config/icon="res://icon.svg" From 3c5dfdd6fdcb34c11f1ffcb5f0c33abb55133ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Fri, 21 Jul 2023 11:10:24 +0300 Subject: [PATCH 15/17] loading decks --- classes/deck/deck.gd | 53 +++++++++++++++--- classes/deck/deck_node.gd | 6 ++- classes/deck/nodes/print.gd | 6 +++ .../deck_renderer_graph_edit.gd | 30 +++++++++++ test.gd | 49 ----------------- test.tscn | 54 ------------------- 6 files changed, 88 insertions(+), 110 deletions(-) delete mode 100644 test.gd delete mode 100644 test.tscn diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index b18df9d..88d1f03 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -39,11 +39,17 @@ func add_node(node: GDScript, meta: Dictionary = {}) -> DeckNode: return node_inst -func add_node_inst(node: DeckNode) -> DeckNode: - var uuid := UUID.v4() - nodes[uuid] = node - node._belonging_to = self - node._id = uuid +func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool = true) -> DeckNode: + if assign_to_self: + node._belonging_to = self + + if assign_id == "": + var uuid := UUID.v4() + nodes[uuid] = node + node._id = uuid + else: + nodes[assign_id] = node + # if !meta.is_empty(): # for k in meta: @@ -77,7 +83,7 @@ func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to func to_json(with_meta: bool = true) -> String: - var inner := {"nodes": {}} + var inner := {"nodes": {}, "variable_stack": variable_stack} for id in nodes.keys(): inner["nodes"][id] = nodes[id].to_dict(with_meta) @@ -89,3 +95,38 @@ func to_json(with_meta: bool = true) -> String: for meta in get_meta_list(): d["meta"][meta] = get_meta(meta) return JSON.stringify(d, "\t", false) + + +static func from_json(json: String) -> Deck: + var data: Dictionary = JSON.parse_string(json) as Dictionary + var deck := Deck.new() + + deck.variable_stack = data.deck.variable_stack + + for key in data.meta: + deck.set_meta(key, data.meta[key]) + + var nodes_data: Dictionary = data.deck.nodes as Dictionary + + for node_id in nodes_data: + var node := deck.add_node_inst(NodeDB.instance_node(nodes_data[node_id].node_type), node_id, false) + node._id = node_id + node.name = nodes_data[node_id].name + node._belonging_to = deck +# node.outgoing_connections = nodes_data[node_id].outgoing_connections +# node.incoming_connections = nodes_data[node_id].incoming_connections + for connection_id in nodes_data[node_id].outgoing_connections: + var connection_data = nodes_data[node_id].outgoing_connections[connection_id] + node.outgoing_connections[int(connection_id)] = connection_data + + for connection_id in nodes_data[node_id].incoming_connections: + var connection_data = nodes_data[node_id].incoming_connections[connection_id] + node.incoming_connections[int(connection_id)] = connection_data + + for key in nodes_data[node_id].meta: + node.set_meta(key, nodes_data[node_id].meta[key]) + + for prop in nodes_data[node_id].props: + node.set(prop, nodes_data[node_id].props[prop]) + + return deck diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 4f3e4e5..a40af53 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -174,9 +174,13 @@ func to_dict(with_meta: bool = true) -> Dictionary: "name": name, "outgoing_connections": outgoing_connections, "incoming_connections": incoming_connections, - "props": props_to_serialize, + "props": {}, "node_type": node_type, } + + for prop in props_to_serialize: + d.props[prop] = get(prop) + if with_meta: d["meta"] = {} for meta in get_meta_list(): diff --git a/classes/deck/nodes/print.gd b/classes/deck/nodes/print.gd index 327217d..0296121 100644 --- a/classes/deck/nodes/print.gd +++ b/classes/deck/nodes/print.gd @@ -1,11 +1,15 @@ extends DeckNode +var times_activated := 0 + func _init() -> void: name = "Print" node_type = name.to_snake_case() description = "print a value" + props_to_serialize = [&"times_activated"] + add_input_port( Deck.Types.STRING, "Text to print", @@ -37,6 +41,8 @@ func _receive(to_port: int, data: DeckType, extra_data: Array = []) -> void: else: data_to_print = data.get_value() + times_activated += 1 + # var data_to_print = input_ports[0].value_callback.call() print(data_to_print) print("extra data: ", extra_data) diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index a83fcdb..dfadf4c 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -25,6 +25,9 @@ func _ready() -> void: var save_btn := Button.new() save_btn.text = "Save" get_zoom_hbox().add_child(save_btn) + var load_btn := Button.new() + load_btn.text = "Load" + get_zoom_hbox().add_child(load_btn) save_btn.pressed.connect( func(): @@ -33,6 +36,23 @@ func _ready() -> void: f.store_string(t) ) + load_btn.pressed.connect( + func(): + var f := FileAccess.open("user://save_test.json", FileAccess.READ) + for i in get_children(): + i.queue_free() + + deck = Deck.from_json(f.get_as_text()) + scroll_offset = str_to_vector2(deck.get_meta("offset", "")) + + for node_id in deck.nodes: + var node_renderer: DeckNodeRendererGraphNode = NODE_SCENE.instantiate() + node_renderer.node = deck.nodes[node_id] + add_child(node_renderer) + node_renderer.position_offset = str_to_vector2(deck.nodes[node_id].get_meta("position_offset", "")) + ) + + add_button.pressed.connect( func(): var node := NodeDB.instance_node("button") @@ -98,3 +118,13 @@ func attempt_disconnect(from_node_name: StringName, from_port: int, to_node_name func _on_scroll_offset_changed(offset: Vector2) -> void: deck.set_meta("offset", offset) + + +func str_to_vector2(s: String) -> Vector2: + if s.is_empty(): + return Vector2() + + var san := s.trim_prefix("(").trim_suffix(")").split(",") + var x := float(san[0]) + var y := float(san[1]) + return Vector2(x, y) diff --git a/test.gd b/test.gd deleted file mode 100644 index fbe3c1c..0000000 --- a/test.gd +++ /dev/null @@ -1,49 +0,0 @@ -extends Control - -var node_renderer_scene := preload("res://test_node_renderer.tscn") -@onready var nodes_container: HBoxContainer = $NodesContainer - -@onready var add_button_button: Button = $AddButtonButton -@onready var add_print_button: Button = $AddPrintButton -@onready var connect_them_button: Button = $ConnectThemButton -@onready var disconnect_them_button: Button = $DisconnectThemButton - -var deck: Deck = Deck.new() -var button_node = preload("res://classes/deck/nodes/button.gd") -var print_node = preload("res://classes/deck/nodes/print.gd") - - -func _ready() -> void: - add_button_button.pressed.connect( - func(): - var node := deck.add_node(button_node) - var node_renderer = node_renderer_scene.instantiate() - node_renderer.node = node - nodes_container.add_child(node_renderer) - add_button_button.disabled = true - ) - - add_print_button.pressed.connect( - func(): - var node := deck.add_node(print_node) - var node_renderer = node_renderer_scene.instantiate() - node_renderer.node = node - nodes_container.add_child(node_renderer) - add_print_button.disabled = true - ) - - connect_them_button.pressed.connect( - func(): - var node_a: DeckNode = nodes_container.get_child(0).node - var node_b: DeckNode = nodes_container.get_child(1).node - - deck.connect_nodes(node_a, node_b, 0, 1) - ) - - disconnect_them_button.pressed.connect( - func(): - var node_a: DeckNode = nodes_container.get_child(0).node - var node_b: DeckNode = nodes_container.get_child(1).node - - deck.disconnect_nodes(node_a, node_b, 0, 1) - ) diff --git a/test.tscn b/test.tscn deleted file mode 100644 index c849215..0000000 --- a/test.tscn +++ /dev/null @@ -1,54 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://bhpd6rfiuimw5"] - -[ext_resource type="Script" path="res://test.gd" id="1_in4g7"] - -[node name="Test" type="Control"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -script = ExtResource("1_in4g7") - -[node name="AddButtonButton" type="Button" parent="."] -layout_mode = 0 -offset_left = 26.0 -offset_top = 576.0 -offset_right = 119.0 -offset_bottom = 607.0 -text = "Add Button" - -[node name="AddPrintButton" type="Button" parent="."] -layout_mode = 0 -offset_left = 152.0 -offset_top = 576.0 -offset_right = 248.0 -offset_bottom = 607.0 -text = "Add Print" - -[node name="ConnectThemButton" type="Button" parent="."] -layout_mode = 0 -offset_left = 283.0 -offset_top = 576.0 -offset_right = 379.0 -offset_bottom = 607.0 -text = "Connect them" - -[node name="DisconnectThemButton" type="Button" parent="."] -layout_mode = 0 -offset_left = 421.0 -offset_top = 576.0 -offset_right = 538.0 -offset_bottom = 607.0 -text = "Disconnect them" - -[node name="NodesContainer" type="HBoxContainer" parent="."] -layout_mode = 1 -anchors_preset = -1 -anchor_right = 0.999646 -anchor_bottom = 0.245654 -offset_right = 0.40799 -offset_bottom = -0.184006 -theme_override_constants/separation = 20 -metadata/_edit_use_anchors_ = true From 2f92233ca0994bf5ea8902759d42c3ddc1a2f4c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Fri, 21 Jul 2023 11:26:43 +0300 Subject: [PATCH 16/17] saving and loading port values --- classes/deck/deck.gd | 4 ++++ classes/deck/deck_node.gd | 6 ++++++ classes/deck/port.gd | 6 ++++++ graph_node_renderer/deck_node_renderer_graph_node.gd | 3 +++ 4 files changed, 19 insertions(+) diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index 88d1f03..153a67c 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -123,6 +123,10 @@ static func from_json(json: String) -> Deck: var connection_data = nodes_data[node_id].incoming_connections[connection_id] node.incoming_connections[int(connection_id)] = connection_data + for i in nodes_data[node_id].port_values.size(): + var port_value = nodes_data[node_id].port_values[i] + node.ports[i].value = port_value + for key in nodes_data[node_id].meta: node.set_meta(key, nodes_data[node_id].meta[key]) diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index a40af53..3597f7b 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -176,11 +176,17 @@ func to_dict(with_meta: bool = true) -> Dictionary: "incoming_connections": incoming_connections, "props": {}, "node_type": node_type, + "port_values": [] } for prop in props_to_serialize: d.props[prop] = get(prop) + ports.map( + func(port: Port) -> void: + d.port_values.append(port.value) + ) + if with_meta: d["meta"] = {} for meta in get_meta_list(): diff --git a/classes/deck/port.gd b/classes/deck/port.gd index 6ec1db3..61d47d5 100644 --- a/classes/deck/port.gd +++ b/classes/deck/port.gd @@ -9,6 +9,8 @@ var port_type: DeckNode.PortType var index_of_type: int var index: int +var value: Variant: set = set_value + func _init( p_type: Deck.Types, @@ -27,3 +29,7 @@ func _init( port_type = p_port_type index_of_type = p_index_of_type index = p_index + + +func set_value(v: Variant) -> void: + value = v diff --git a/graph_node_renderer/deck_node_renderer_graph_node.gd b/graph_node_renderer/deck_node_renderer_graph_node.gd index 7c8ab1e..ec37e2f 100644 --- a/graph_node_renderer/deck_node_renderer_graph_node.gd +++ b/graph_node_renderer/deck_node_renderer_graph_node.gd @@ -27,8 +27,11 @@ func _ready() -> void: "field": var line_edit := LineEdit.new() add_child(line_edit) + if port.value: + line_edit.text = str(port.value) line_edit.placeholder_text = port.label port.value_callback = line_edit.get_text + line_edit.text_changed.connect(port.set_value) _: var label := Label.new() add_child(label) From 4ed9b37b0fef2e97e346a8ad23caa9eec3f14644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Fri, 21 Jul 2023 12:12:20 +0300 Subject: [PATCH 17/17] properly disconnect nodes, removing incoming connections on target node --- classes/deck/deck.gd | 16 +++++++++++++ classes/deck/deck_node.gd | 8 +++++++ .../deck_renderer_graph_edit.gd | 24 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index 153a67c..0da3237 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -79,7 +79,19 @@ func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_po func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_port: int, to_port: int) -> void: var hash = {to_node._id: to_port}.hash() +# prints({to_node._id: to_port}, "-", {to_node._id: to_port}.hash()) +# prints(from_node.outgoing_connections[0][0], "-", from_node.outgoing_connections[0][0].hash()) +# +# var a = {to_node._id: to_port} +# var b = from_node.outgoing_connections[0][0] +# +# print(typeof(a.values()[0])) +# print(typeof(b.values()[0])) +# +# prints(a, b) + from_node.remove_outgoing_connection(from_port, hash) + to_node.remove_incoming_connection(to_port) func to_json(with_meta: bool = true) -> String: @@ -117,10 +129,14 @@ static func from_json(json: String) -> Deck: # node.incoming_connections = nodes_data[node_id].incoming_connections for connection_id in nodes_data[node_id].outgoing_connections: var connection_data = nodes_data[node_id].outgoing_connections[connection_id] + for connection in connection_data: + connection[connection.keys()[0]] = int(connection.values()[0]) node.outgoing_connections[int(connection_id)] = connection_data for connection_id in nodes_data[node_id].incoming_connections: var connection_data = nodes_data[node_id].incoming_connections[connection_id] + for connection in connection_data: + connection_data[connection] = int(connection_data[connection]) node.incoming_connections[int(connection_id)] = connection_data for i in nodes_data[node_id].port_values.size(): diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd index 3597f7b..d63ef30 100644 --- a/classes/deck/deck_node.gd +++ b/classes/deck/deck_node.gd @@ -102,18 +102,26 @@ func remove_outgoing_connection(from_port: int, connection_hash: int) -> void: if port_connections.is_empty(): return + var incoming_connection := {} + var to_remove: int = -1 for i in port_connections.size(): if port_connections[i].hash() == connection_hash: + to_remove = i if to_remove == -1: + print('nothing to remove') return port_connections.remove_at(to_remove) outgoing_connections[from_port] = port_connections +func remove_incoming_connection(to_port: int) -> void: + incoming_connections.erase(to_port) + + func remove_outgoing_connection_from_port(output_port: int, connection_hash: int) -> void: remove_outgoing_connection(get_global_port_idx_from_output(output_port), connection_hash) diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index dfadf4c..25d12be 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -50,6 +50,30 @@ func _ready() -> void: node_renderer.node = deck.nodes[node_id] add_child(node_renderer) node_renderer.position_offset = str_to_vector2(deck.nodes[node_id].get_meta("position_offset", "")) + + for node_id in deck.nodes: + var node: DeckNode = deck.nodes[node_id] + var from_node_name = get_children().filter( + func(c: DeckNodeRendererGraphNode): + return c.node._id == node_id + )[0].name +# "outgoing_connections": { +# "0": [ +# { +# "c8cc7dce-2a86-461c-a24f-0a4dbd06f379": 1 +# } +# ] +# }, + for from_port in node.outgoing_connections: + for connection in node.outgoing_connections[from_port]: + var to_node_id = connection.keys()[0] + var to_node_port = connection.values()[0] + var to_node_name = get_children().filter( + func(c: DeckNodeRendererGraphNode): + return c.node._id == to_node_id + )[0].name + prints(from_node_name, to_node_name) + connect_node(from_node_name, from_port, to_node_name, to_node_port) )