diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd
index 963b9ba..af3a043 100644
--- a/classes/deck/deck.gd
+++ b/classes/deck/deck.gd
@@ -114,24 +114,42 @@ func get_node(uuid: String) -> DeckNode:
return nodes.get(uuid)
-## Attempt to connect two nodes. Returns [code]true[/code] if the connection succeeded.
-func connect_nodes(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> bool:
+## Returns [code]true[/code] if the connection between two nodes is legal.
+func is_valid_connection(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> bool:
+ # do not connect to self
+ if from_node_id == to_node_id:
+ return false
+
var from_node := get_node(from_node_id)
var to_node := get_node(to_node_id)
- # check that we can do the type conversion
- var type_a: DeckType.Types = from_node.get_output_ports()[from_output_port].type
- var type_b: DeckType.Types = to_node.get_input_ports()[to_input_port].type
- if !DeckType.can_convert(type_a, type_b):
- DeckHolder.logger.log_deck(
- "Can not convert from %s to %s." % [DeckType.type_str(type_a), DeckType.type_str(type_b)],
- Logger.LogType.ERROR
- )
+
+ var usage_from: Port.UsageType = from_node.get_output_ports()[from_output_port].usage_type
+ var usage_to: Port.UsageType = to_node.get_input_ports()[to_input_port].usage_type
+ # incompatible usages
+ if (usage_from != Port.UsageType.BOTH) && (usage_to != Port.UsageType.BOTH):
+ if usage_from != usage_to:
+ return false
+
+ var type_from: DeckType.Types = from_node.get_output_ports()[from_output_port].type
+ var type_to: DeckType.Types = to_node.get_input_ports()[to_input_port].type
+ # incompatible types
+ if !DeckType.can_convert(type_from, type_to):
return false
-
- # refuse duplicate connections
+
+ # duplicate connection
if from_node.has_outgoing_connection_exact(from_output_port, to_node_id, to_input_port):
- print("no duplicates")
return false
+
+ return true
+
+
+## Attempt to connect two nodes. Returns [code]true[/code] if the connection succeeded.
+func connect_nodes(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int) -> bool:
+ if !is_valid_connection(from_node_id, to_node_id, from_output_port, to_input_port):
+ return false
+
+ var from_node := get_node(from_node_id)
+ var to_node := get_node(to_node_id)
if to_node.has_incoming_connection(to_input_port):
var connection: Dictionary = to_node.incoming_connections[to_input_port]
@@ -139,7 +157,6 @@ func connect_nodes(from_node_id: String, to_node_id: String, from_output_port: i
var node_out_port: int = connection.values()[0]
disconnect_nodes(node_id, to_node_id, node_out_port, to_input_port)
-
if is_group && emit_group_signals:
nodes_connected_in_group.emit(from_node_id, to_node_id, from_output_port, to_input_port, self)
diff --git a/classes/deck/deck_node.gd b/classes/deck/deck_node.gd
index 459b12a..0036733 100644
--- a/classes/deck/deck_node.gd
+++ b/classes/deck/deck_node.gd
@@ -74,23 +74,40 @@ signal renamed(new_name: String)
## Add an input port to this node. Usually only used at initialization.
-func add_input_port(type: DeckType.Types, label: String, descriptor: String = "") -> void:
- add_port(type, label, PortType.INPUT, get_input_ports().size(), descriptor)
+func add_input_port(
+ type: DeckType.Types,
+ label: String,
+ descriptor: String = "",
+ usage: Port.UsageType = Port.UsageType.BOTH) -> void:
+ add_port(type, label, PortType.INPUT, get_input_ports().size(), descriptor, usage)
## Add an output port to this node. Usually only used at initialization.
-func add_output_port(type: DeckType.Types, label: String, descriptor: String = "") -> void:
- add_port(type, label, PortType.OUTPUT, get_output_ports().size(), descriptor)
+func add_output_port(
+ type: DeckType.Types,
+ label: String,
+ descriptor: String = "",
+ usage: Port.UsageType = Port.UsageType.BOTH) -> void:
+ add_port(type, label, PortType.OUTPUT, get_output_ports().size(), descriptor, usage)
## Add a virtual port to this node. Usually only used at initialization.
-func add_virtual_port(type: DeckType.Types, label: String, descriptor: String = "") -> void:
- add_port(type, label, PortType.VIRTUAL, get_virtual_ports().size(), descriptor)
+func add_virtual_port(
+ type: DeckType.Types,
+ label: String,
+ descriptor: String = "",
+ usage: Port.UsageType = Port.UsageType.BOTH) -> void:
+ add_port(type, label, PortType.VIRTUAL, get_virtual_ports().size(), descriptor, usage)
## Add a port to this node. Usually only used at initialization.
-func add_port(type: DeckType.Types, label: String, port_type: PortType, index_of_type: int, descriptor: String = "") -> void:
- var port := Port.new(type, label, ports.size(), port_type, index_of_type, descriptor)
+func add_port(type: DeckType.Types,
+ label: String,
+ port_type: PortType,
+ index_of_type: int,
+ descriptor: String = "",
+ usage: Port.UsageType = Port.UsageType.BOTH) -> void:
+ var port := Port.new(type, label, ports.size(), port_type, index_of_type, descriptor, usage)
ports.append(port)
port_added.emit(ports.size() - 1)
port.value_updated.connect(
diff --git a/classes/deck/nodes/general/is_equal.gd b/classes/deck/nodes/general/is_equal.gd
index d1169fd..674eb40 100644
--- a/classes/deck/nodes/general/is_equal.gd
+++ b/classes/deck/nodes/general/is_equal.gd
@@ -32,3 +32,14 @@ func _value_request(on_port: int) -> Variant:
var b = await resolve_input_port_value_async(1)
return a == b
+
+
+func _receive(on_port: int, data: Variant, extra_data: Array = []) -> void:
+ if on_port == 0:
+ var b = await resolve_input_port_value_async(1)
+ if data == b:
+ send(0, true)
+ else:
+ var b = await resolve_input_port_value_async(0)
+ if data == b:
+ send(0, true)
diff --git a/classes/deck/nodes/test/test_connection_types.gd b/classes/deck/nodes/test/test_connection_types.gd
new file mode 100644
index 0000000..1f075b8
--- /dev/null
+++ b/classes/deck/nodes/test/test_connection_types.gd
@@ -0,0 +1,33 @@
+# (c) 2023-present Eroax
+# (c) 2023-present Yagich
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+extends DeckNode
+
+
+func _init() -> void:
+ name = "Test Usage"
+ node_type = name.to_snake_case()
+
+ add_input_port(
+ DeckType.Types.ANY, "Both", "", Port.UsageType.BOTH
+ )
+
+ add_input_port(
+ DeckType.Types.ANY, "Trigger", "", Port.UsageType.TRIGGER
+ )
+
+ add_input_port(
+ DeckType.Types.ANY, "Value", "", Port.UsageType.VALUE_REQUEST
+ )
+
+ add_output_port(
+ DeckType.Types.ANY, "Both", "", Port.UsageType.BOTH
+ )
+
+ add_output_port(
+ DeckType.Types.ANY, "Trigger", "", Port.UsageType.TRIGGER
+ )
+
+ add_output_port(
+ DeckType.Types.ANY, "Value", "", Port.UsageType.VALUE_REQUEST
+ )
diff --git a/classes/deck/nodes/twitch/twitch_chat_received.gd b/classes/deck/nodes/twitch/twitch_chat_received.gd
index cc38e6b..1a693ac 100644
--- a/classes/deck/nodes/twitch/twitch_chat_received.gd
+++ b/classes/deck/nodes/twitch/twitch_chat_received.gd
@@ -14,10 +14,10 @@ func _init():
node_type = "twitch_chat_received"
description = "Receives Twitch chat events from a Twitch connection."
- add_output_port(DeckType.Types.STRING, "Username")
- add_output_port(DeckType.Types.STRING, "Message")
- add_output_port(DeckType.Types.STRING, "Channel")
- add_output_port(DeckType.Types.DICTIONARY, "Tags")
+ add_output_port(DeckType.Types.STRING, "Username", "", Port.UsageType.TRIGGER)
+ add_output_port(DeckType.Types.STRING, "Message", "", Port.UsageType.TRIGGER)
+ add_output_port(DeckType.Types.STRING, "Channel", "", Port.UsageType.TRIGGER)
+ add_output_port(DeckType.Types.DICTIONARY, "Tags", "", Port.UsageType.TRIGGER)
add_output_port(
DeckType.Types.BOOL,
@@ -37,7 +37,10 @@ func _event_received(event_name : StringName, event_data : Dictionary = {}):
message = event_data.message
channel = event_data.channel
tags = event_data
-
+ send(0, username)
+ send(1, message)
+ send(2, channel)
+ send(3, tags)
send(4, true)
diff --git a/classes/deck/port.gd b/classes/deck/port.gd
index 110fcbc..3b4ea53 100644
--- a/classes/deck/port.gd
+++ b/classes/deck/port.gd
@@ -7,6 +7,12 @@ class_name Port
## Ports are used for connections between [DeckNode]s and can contain data that is passed between
## them on a node.
+enum UsageType {
+ TRIGGER, ## Port can send or receive events, not request values.
+ VALUE_REQUEST, ## Port can request values and respond to value requests, not send or receive events.
+ BOTH, ## Port can send or receive events [b]and[/b] request and respond to value requests.
+}
+
## The type index of this port.
var type: DeckType.Types
## The label of this port. Used by the renderer to display. How it's displayed depends on the renderer
@@ -22,6 +28,8 @@ var value_callback: Callable
## The type of this port (input, output or virtual)
var port_type: DeckNode.PortType
+## The usage type of this port (see [enum UsageType]).
+var usage_type: UsageType
## The local index of this port.
var index_of_type: int
## The global index of this port.
@@ -41,6 +49,7 @@ func _init(
p_index_of_type: int,
p_descriptor: String = "",
# p_value_callback: Callable = Callable(),
+ p_usage_type: UsageType = UsageType.BOTH,
) -> void:
type = p_type
label = p_label
@@ -50,6 +59,7 @@ func _init(
port_type = p_port_type
index_of_type = p_index_of_type
index = p_index
+ usage_type = p_usage_type
func set_value(v: Variant) -> void:
diff --git a/graph_node_renderer/deck_node_renderer_graph_node.gd b/graph_node_renderer/deck_node_renderer_graph_node.gd
index 377c594..d5131f6 100644
--- a/graph_node_renderer/deck_node_renderer_graph_node.gd
+++ b/graph_node_renderer/deck_node_renderer_graph_node.gd
@@ -19,6 +19,11 @@ const TYPE_COLORS := {
DeckType.Types.ANY: Color.WHITE,
}
+const PORT_USAGE_ICONS := {
+ Port.UsageType.TRIGGER: preload("res://graph_node_renderer/textures/port_trigger_12.svg"),
+ Port.UsageType.VALUE_REQUEST: preload("res://graph_node_renderer/textures/port_data_request_12.svg"),
+ Port.UsageType.BOTH: preload("res://graph_node_renderer/textures/port_any_12.svg"),
+}
## Setups up all the properties based off [member node]. Including looping through
## [method DeckNode.get_all_ports()] and setting up all the descriptors.
@@ -204,4 +209,6 @@ func update_port(port: Port) -> void:
port.port_type == DeckNode.PortType.OUTPUT,
port.type,
TYPE_COLORS[port.type],
+ PORT_USAGE_ICONS[port.usage_type],
+ PORT_USAGE_ICONS[port.usage_type],
)
diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd
index c781cc2..02095d3 100644
--- a/graph_node_renderer/deck_renderer_graph_edit.gd
+++ b/graph_node_renderer/deck_renderer_graph_edit.gd
@@ -87,6 +87,13 @@ func attempt_connection(from_node_name: StringName, from_port: int, to_node_name
)
dirty = true
+
+func _is_node_hover_valid(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> bool:
+ var from_node_renderer: DeckNodeRendererGraphNode = get_node(NodePath(from_node))
+ var to_node_renderer: DeckNodeRendererGraphNode = get_node(NodePath(to_node))
+
+ return deck.is_valid_connection(from_node_renderer.node._id, to_node_renderer.node._id, from_port, to_port)
+
## Receives [signal GraphEdit.disconnection_request] and attempts to disconnect the two [DeckNode]s
## involved, utilizes [NodeDB] for accessing them.
func attempt_disconnect(from_node_name: StringName, from_port: int, to_node_name: StringName, to_port: int) -> void:
diff --git a/graph_node_renderer/textures/port_any_12.svg b/graph_node_renderer/textures/port_any_12.svg
new file mode 100644
index 0000000..cce736c
--- /dev/null
+++ b/graph_node_renderer/textures/port_any_12.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/graph_node_renderer/textures/port_any_12.svg.import b/graph_node_renderer/textures/port_any_12.svg.import
new file mode 100644
index 0000000..74bdff6
--- /dev/null
+++ b/graph_node_renderer/textures/port_any_12.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c0qh34njvu4xt"
+path="res://.godot/imported/port_any_12.svg-64aca00b3bf28084e8a38d718780e0ff.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://graph_node_renderer/textures/port_any_12.svg"
+dest_files=["res://.godot/imported/port_any_12.svg-64aca00b3bf28084e8a38d718780e0ff.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/graph_node_renderer/textures/port_data_request_12.svg b/graph_node_renderer/textures/port_data_request_12.svg
new file mode 100644
index 0000000..e73eaab
--- /dev/null
+++ b/graph_node_renderer/textures/port_data_request_12.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/graph_node_renderer/textures/port_data_request_12.svg.import b/graph_node_renderer/textures/port_data_request_12.svg.import
new file mode 100644
index 0000000..ebefa7d
--- /dev/null
+++ b/graph_node_renderer/textures/port_data_request_12.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b5houge8j0lij"
+path="res://.godot/imported/port_data_request_12.svg-da181e9908b91f72dfc70f3dd7196720.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://graph_node_renderer/textures/port_data_request_12.svg"
+dest_files=["res://.godot/imported/port_data_request_12.svg-da181e9908b91f72dfc70f3dd7196720.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/graph_node_renderer/textures/port_trigger_12.svg b/graph_node_renderer/textures/port_trigger_12.svg
new file mode 100644
index 0000000..02cc890
--- /dev/null
+++ b/graph_node_renderer/textures/port_trigger_12.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/graph_node_renderer/textures/port_trigger_12.svg.import b/graph_node_renderer/textures/port_trigger_12.svg.import
new file mode 100644
index 0000000..be616c0
--- /dev/null
+++ b/graph_node_renderer/textures/port_trigger_12.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://tbxgx46ch210"
+path="res://.godot/imported/port_trigger_12.svg-ddfb2ada8bfb56f098470a2797045ba0.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://graph_node_renderer/textures/port_trigger_12.svg"
+dest_files=["res://.godot/imported/port_trigger_12.svg-ddfb2ada8bfb56f098470a2797045ba0.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false