2023-12-15 22:44:25 +01:00
|
|
|
# (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)
|
2024-05-08 09:43:45 +02:00
|
|
|
extends Object
|
2023-06-10 19:13:16 +02:00
|
|
|
class_name DeckNode
|
2023-11-25 11:40:53 +01:00
|
|
|
## A node in a [Deck].
|
|
|
|
##
|
|
|
|
## Nodes are the essential building block of a [Deck] graph. They can have connections between ports
|
|
|
|
## and send data through them.
|
2023-06-10 19:13:16 +02:00
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## The name initially shown to a renderer.
|
2023-06-10 19:13:16 +02:00
|
|
|
var name: String
|
2023-11-22 05:26:11 +01:00
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## A list of [Port]s on this node.
|
2023-06-12 17:32:16 +02:00
|
|
|
var ports: Array[Port]
|
|
|
|
|
2024-02-22 08:23:25 +01:00
|
|
|
var _last_send_id: String
|
|
|
|
|
2024-05-08 09:43:45 +02:00
|
|
|
## The [Deck] this node belongs to.
|
2023-06-10 19:13:16 +02:00
|
|
|
var _belonging_to: Deck
|
2024-05-08 09:43:45 +02:00
|
|
|
|
|
|
|
## The instance ID of the group this node belongs to, if it belongs to a group.
|
|
|
|
#var _belonging_to_instance: String
|
2023-11-25 11:40:53 +01:00
|
|
|
## A unique identifier for this node.
|
2023-06-10 19:13:16 +02:00
|
|
|
var _id: String
|
2023-11-25 11:40:53 +01:00
|
|
|
## The type of this node, used for instantiation.
|
2023-06-24 05:39:50 +02:00
|
|
|
var node_type: String
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## The description of this node, shown to the user by a renderer.
|
2023-07-21 07:30:12 +02:00
|
|
|
var description: String
|
2023-11-25 11:40:53 +01:00
|
|
|
## A list of aliases for this node, used by search.
|
2023-07-21 07:30:12 +02:00
|
|
|
var aliases: Array[String]
|
2023-11-25 11:40:53 +01:00
|
|
|
## Controls whether this node should appear in [SearchProvider].
|
2023-11-23 07:38:10 +01:00
|
|
|
var appears_in_search: bool = true
|
2023-07-21 07:30:12 +02:00
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## A list of additional properties to save when this node is saved.
|
2023-06-24 05:39:50 +02:00
|
|
|
var props_to_serialize: Array[StringName]
|
2023-06-10 19:13:16 +02:00
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## The position of this node relative to the parent graph.
|
|
|
|
## Only used by renderers.
|
2023-11-22 05:26:11 +01:00
|
|
|
var position: Dictionary = {"x": 0.0, "y": 0.0}
|
|
|
|
|
2023-12-15 22:44:25 +01:00
|
|
|
## If [code]true[/code], the user can delete this node by normal means.
|
|
|
|
## The parent [Deck] can still delete the node by other means.
|
|
|
|
var user_can_delete: bool = true
|
|
|
|
|
2023-06-12 17:32:16 +02:00
|
|
|
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).
|
|
|
|
}
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when this node has been moved.
|
2023-11-22 05:26:11 +01:00
|
|
|
signal position_updated(new_position: Dictionary)
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when a port has been added.
|
2023-11-22 05:26:11 +01:00
|
|
|
signal port_added(port: int)
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when a port has been removed.
|
2023-11-22 05:26:11 +01:00
|
|
|
signal port_removed(port: int)
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when a port or multiple ports have been updated (added or removed).
|
2023-11-22 05:26:11 +01:00
|
|
|
signal ports_updated()
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when a connection from this node has been added.
|
2023-11-22 05:26:11 +01:00
|
|
|
signal outgoing_connection_added(from_port: int)
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when a connection from this node has been removed.
|
2023-11-22 05:26:11 +01:00
|
|
|
signal outgoing_connection_removed(from_port: int)
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when a connection to this node has been added.
|
2023-11-22 05:26:11 +01:00
|
|
|
signal incoming_connection_added(from_port: int)
|
2023-11-25 11:40:53 +01:00
|
|
|
## Emitted when a connection to this node has been removed.
|
2023-11-22 05:26:11 +01:00
|
|
|
signal incoming_connection_removed(from_port: int)
|
2024-05-08 09:43:45 +02:00
|
|
|
## Emitted when the node is about to be freed.
|
|
|
|
signal about_to_free()
|
2023-11-22 05:26:11 +01:00
|
|
|
|
2023-12-15 22:44:25 +01:00
|
|
|
signal port_value_updated(port_idx: int, new_value: Variant)
|
|
|
|
|
|
|
|
signal renamed(new_name: String)
|
|
|
|
|
2023-06-10 19:13:16 +02:00
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Add an input port to this node. Usually only used at initialization.
|
2024-02-21 05:08:36 +01:00
|
|
|
func add_input_port(
|
|
|
|
type: DeckType.Types,
|
|
|
|
label: String,
|
|
|
|
descriptor: String = "",
|
2024-03-06 08:50:23 +01:00
|
|
|
usage: Port.UsageType = Port.UsageType.BOTH) -> Port:
|
|
|
|
return add_port(type, label, PortType.INPUT, get_input_ports().size(), descriptor, usage)
|
2023-06-10 19:13:16 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Add an output port to this node. Usually only used at initialization.
|
2024-02-21 05:08:36 +01:00
|
|
|
func add_output_port(
|
|
|
|
type: DeckType.Types,
|
|
|
|
label: String,
|
|
|
|
descriptor: String = "",
|
2024-03-06 08:50:23 +01:00
|
|
|
usage: Port.UsageType = Port.UsageType.BOTH) -> Port:
|
|
|
|
return add_port(type, label, PortType.OUTPUT, get_output_ports().size(), descriptor, usage)
|
2023-06-12 17:32:16 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Add a virtual port to this node. Usually only used at initialization.
|
2024-02-21 05:08:36 +01:00
|
|
|
func add_virtual_port(
|
|
|
|
type: DeckType.Types,
|
|
|
|
label: String,
|
|
|
|
descriptor: String = "",
|
2024-03-06 08:50:23 +01:00
|
|
|
usage: Port.UsageType = Port.UsageType.BOTH) -> Port:
|
|
|
|
return add_port(type, label, PortType.VIRTUAL, get_virtual_ports().size(), descriptor, usage)
|
2023-06-12 17:32:16 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Add a port to this node. Usually only used at initialization.
|
2024-02-21 05:08:36 +01:00
|
|
|
func add_port(type: DeckType.Types,
|
|
|
|
label: String,
|
|
|
|
port_type: PortType,
|
|
|
|
index_of_type: int,
|
|
|
|
descriptor: String = "",
|
2024-03-06 08:50:23 +01:00
|
|
|
usage: Port.UsageType = Port.UsageType.BOTH) -> Port:
|
2024-02-21 05:08:36 +01:00
|
|
|
var port := Port.new(type, label, ports.size(), port_type, index_of_type, descriptor, usage)
|
2024-06-14 15:58:47 +02:00
|
|
|
# WARNING: EXPERIMENTAL
|
|
|
|
port.set_value_no_signal(DeckType.DEFAULT_VALUES[type])
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
ports.append(port)
|
|
|
|
port_added.emit(ports.size() - 1)
|
2023-12-15 22:44:25 +01:00
|
|
|
port.value_updated.connect(
|
|
|
|
func(new_value: Variant) -> void:
|
|
|
|
port_value_updated.emit(port.index, new_value)
|
|
|
|
)
|
2023-11-22 05:26:11 +01:00
|
|
|
ports_updated.emit()
|
2024-03-06 08:50:23 +01:00
|
|
|
return port
|
2023-11-22 05:26:11 +01:00
|
|
|
|
2023-06-12 17:32:16 +02:00
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Send data to all outgoing connections on port [param from_output_port].
|
2024-02-22 08:23:25 +01:00
|
|
|
func send(from_output_port: int, data: Variant, send_id: String = UUID.v4()) -> void:
|
2024-04-17 02:24:55 +02:00
|
|
|
_belonging_to.send(_id, from_output_port, data, send_id)
|
2024-02-22 08:23:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
func handle_receive(to_input_port: int, data: Variant, send_id: String) -> void:
|
|
|
|
if send_id == _last_send_id:
|
|
|
|
return
|
|
|
|
|
|
|
|
_last_send_id = send_id
|
|
|
|
_receive(to_input_port, data)
|
2023-06-10 19:13:16 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Virtual function that's called when this node receives data from another node's [method send] call.
|
2023-12-15 22:44:25 +01:00
|
|
|
@warning_ignore("unused_parameter")
|
2024-02-22 08:23:25 +01:00
|
|
|
func _receive(to_input_port: int, data: Variant) -> void:
|
2023-06-10 19:13:16 +02:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
2024-01-25 08:20:41 +01:00
|
|
|
## Asynchronously request a value from an incoming connection on this node's input port at [param on_port].
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns [code]null[/code] if no incoming connection exists on that port.
|
|
|
|
## The connected node may also return [code]null[/code].
|
2023-12-15 22:44:25 +01:00
|
|
|
func request_value_async(on_port: int) -> Variant:
|
2024-04-17 02:24:55 +02:00
|
|
|
return await _belonging_to.request_value_async(_id, on_port)
|
2023-12-15 22:44:25 +01:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Virtual function that's called when this node has been requested a value from the output port
|
|
|
|
## at [param from_port].
|
2023-12-15 22:44:25 +01:00
|
|
|
@warning_ignore("unused_parameter")
|
2023-06-13 17:23:10 +02:00
|
|
|
func _value_request(from_port: int) -> Variant:
|
|
|
|
return null
|
2023-06-11 18:26:12 +02:00
|
|
|
|
|
|
|
|
2023-12-15 22:44:25 +01:00
|
|
|
func rename(new_name: String) -> void:
|
|
|
|
name = new_name
|
|
|
|
renamed.emit(new_name)
|
|
|
|
|
|
|
|
|
|
|
|
@warning_ignore("unused_parameter")
|
|
|
|
func _event_received(event_name: StringName, event_data: Dictionary = {}) -> void:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns a list of all input ports.
|
2023-06-12 17:32:16 +02:00
|
|
|
func get_input_ports() -> Array[Port]:
|
|
|
|
return ports.filter(
|
|
|
|
func(port: Port) -> bool:
|
|
|
|
return port.port_type == PortType.INPUT
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns a list of all output ports.
|
2023-06-12 17:32:16 +02:00
|
|
|
func get_output_ports() -> Array[Port]:
|
|
|
|
return ports.filter(
|
|
|
|
func(port: Port) -> bool:
|
|
|
|
return port.port_type == PortType.OUTPUT
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns a list of all virtual ports.
|
2023-06-12 17:32:16 +02:00
|
|
|
func get_virtual_ports() -> Array[Port]:
|
|
|
|
return ports.filter(
|
|
|
|
func(port: Port) -> bool:
|
|
|
|
return port.port_type == PortType.VIRTUAL
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns the global port index from the input port index at [param idx].
|
2023-06-12 17:32:16 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns the global port index from the output port index at [param idx].
|
2023-06-12 17:32:16 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns the global port index from the virtual port index at [param idx].
|
2023-06-12 17:32:16 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Get a port's local index from the global port index at [param idx].
|
2023-11-22 05:26:11 +01:00
|
|
|
func get_port_type_idx_from_global(idx: int) -> int:
|
|
|
|
return ports[idx].index_of_type
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns the list of all ports.
|
2023-06-12 17:32:16 +02:00
|
|
|
func get_all_ports() -> Array[Port]:
|
|
|
|
return ports
|
|
|
|
|
|
|
|
|
2024-03-06 08:50:23 +01:00
|
|
|
func press_button(port_idx: int) -> void:
|
|
|
|
var port := ports[port_idx]
|
|
|
|
if port.descriptor.split(":")[0] == "button":
|
|
|
|
port.button_pressed.emit()
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Get a sibling node by its' ID.
|
2023-06-12 17:32:16 +02:00
|
|
|
func get_node(uuid: String) -> DeckNode:
|
|
|
|
return _belonging_to.get_node(uuid)
|
2023-06-24 05:39:50 +02:00
|
|
|
|
|
|
|
|
2024-05-08 09:43:45 +02:00
|
|
|
## Get the deck this node belongs to.
|
|
|
|
#func get_deck() -> Deck:
|
|
|
|
#if not DeckHolder.get_deck(_belonging_to).is_group:
|
|
|
|
#return DeckHolder.get_deck(_belonging_to)
|
|
|
|
#else:
|
|
|
|
#return DeckHolder.get_group_instance(_belonging_to, _belonging_to_instance)
|
|
|
|
|
|
|
|
|
2024-04-17 02:24:55 +02:00
|
|
|
## Virtual function that's called during deserialization before connections are loaded in.[br]
|
|
|
|
func _pre_port_load() -> void:
|
2023-11-22 05:26:11 +01:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Virtual function that's called after the node has been deserialized.
|
2024-05-08 09:43:45 +02:00
|
|
|
@warning_ignore("unused_parameter")
|
2024-04-17 04:06:48 +02:00
|
|
|
func _post_load(connections: Deck.NodeConnections) -> void:
|
2023-11-22 05:26:11 +01:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
2024-05-20 06:32:12 +02:00
|
|
|
## Virtual function that's called by the parent [Deck] after the node has been deserialized, and after
|
|
|
|
## [method _post_load].
|
|
|
|
func _post_deck_load() -> void:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-12-15 22:44:25 +01:00
|
|
|
## A helper function to get a value on an input port. Returns the best match in the following
|
|
|
|
## order of priority:[br]
|
2024-01-25 08:20:41 +01:00
|
|
|
## 1. The direct result of [method request value], called asynchronously. [br]
|
|
|
|
## 2. The result of [method Port.value_callback], if it's not equal to [param empty_value]. [br]
|
|
|
|
## 3. The input [Port] at index [param input_port]'s stored [member Port.value], if it's not equal to [param empty_value]. [br]
|
|
|
|
## 4. [code]null[/code].[br]
|
|
|
|
func resolve_input_port_value_async(input_port: int, empty_value: Variant = null) -> Variant:
|
|
|
|
var request = await request_value_async(input_port)
|
|
|
|
if request != null:
|
|
|
|
return request
|
2024-02-21 07:11:29 +01:00
|
|
|
elif get_input_ports()[input_port].value_callback.get_object() and get_input_ports()[input_port].value_callback.call() != empty_value:
|
2023-12-15 22:44:25 +01:00
|
|
|
return get_input_ports()[input_port].value_callback.call()
|
2024-01-25 08:20:41 +01:00
|
|
|
elif get_input_ports()[input_port].value != empty_value:
|
2023-12-15 22:44:25 +01:00
|
|
|
return get_input_ports()[input_port].value
|
|
|
|
else:
|
|
|
|
return null
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns a [Dictionary] representation of this node.
|
2023-06-24 05:39:50 +02:00
|
|
|
func to_dict(with_meta: bool = true) -> Dictionary:
|
|
|
|
var d := {
|
|
|
|
"_id": _id,
|
|
|
|
"name": name,
|
2024-04-17 02:24:55 +02:00
|
|
|
#"outgoing_connections": outgoing_connections.duplicate(true),
|
|
|
|
#"incoming_connections": incoming_connections.duplicate(true),
|
2023-07-21 10:10:24 +02:00
|
|
|
"props": {},
|
2023-06-24 05:39:50 +02:00
|
|
|
"node_type": node_type,
|
2023-11-22 05:26:11 +01:00
|
|
|
"port_values": [],
|
2023-12-15 22:44:25 +01:00
|
|
|
"position": position.duplicate(),
|
2023-06-24 05:39:50 +02:00
|
|
|
}
|
2023-07-21 10:10:24 +02:00
|
|
|
|
|
|
|
for prop in props_to_serialize:
|
|
|
|
d.props[prop] = get(prop)
|
|
|
|
|
2023-07-21 10:26:43 +02:00
|
|
|
ports.map(
|
|
|
|
func(port: Port) -> void:
|
|
|
|
d.port_values.append(port.value)
|
|
|
|
)
|
|
|
|
|
2023-06-24 05:39:50 +02:00
|
|
|
if with_meta:
|
|
|
|
d["meta"] = {}
|
|
|
|
for meta in get_meta_list():
|
2023-08-08 08:54:17 +02:00
|
|
|
d["meta"][meta] = var_to_str(get_meta(meta))
|
2023-06-24 05:39:50 +02:00
|
|
|
return d
|
2023-11-22 05:26:11 +01:00
|
|
|
|
|
|
|
|
2024-04-17 04:06:48 +02:00
|
|
|
static func from_dict(data: Dictionary, connections: Deck.NodeConnections = null) -> DeckNode:
|
2023-12-15 22:44:25 +01:00
|
|
|
var node := NodeDB.instance_node(data.node_type)
|
|
|
|
#node._id = data._id
|
|
|
|
node.name = data.name
|
|
|
|
node.position = data.position
|
|
|
|
|
|
|
|
for prop in data.props:
|
|
|
|
node.set(prop, data.props[prop])
|
|
|
|
|
2024-04-17 02:24:55 +02:00
|
|
|
node._pre_port_load()
|
|
|
|
|
|
|
|
#for from_port in data.outgoing_connections:
|
|
|
|
#var connection_data: Dictionary = data.outgoing_connections[from_port]
|
|
|
|
#node.outgoing_connections[int(from_port)] = {}
|
|
|
|
#for to_node in connection_data:
|
|
|
|
#var input_ports: Array = connection_data[to_node]
|
|
|
|
#node.outgoing_connections[int(from_port)][to_node] = []
|
|
|
|
#for to_input_port in input_ports:
|
|
|
|
#node.outgoing_connections[int(from_port)][to_node].append(int(to_input_port))
|
|
|
|
#
|
|
|
|
#for to_port in data.incoming_connections:
|
|
|
|
#var connection_data = data.incoming_connections[to_port]
|
|
|
|
#for connection in connection_data:
|
|
|
|
#connection_data[connection] = int(connection_data[connection])
|
|
|
|
#node.incoming_connections[int(to_port)] = connection_data
|
2023-12-15 22:44:25 +01:00
|
|
|
|
|
|
|
for i in node.ports.size():
|
|
|
|
var port_value: Variant
|
|
|
|
if (data.port_values as Array).size() <= i:
|
|
|
|
port_value = null
|
|
|
|
else:
|
|
|
|
port_value = (data.port_values as Array)[i]
|
|
|
|
node.ports[i].value = port_value
|
|
|
|
|
|
|
|
for key in data.meta:
|
|
|
|
node.set_meta(key, str_to_var(data.meta[key]))
|
|
|
|
|
2024-04-17 04:06:48 +02:00
|
|
|
node._post_load(connections)
|
2023-12-15 22:44:25 +01:00
|
|
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns the node's [member position] as a [Vector2].
|
2023-11-22 05:26:11 +01:00
|
|
|
func position_as_vector2() -> Vector2:
|
|
|
|
return Vector2(position.x, position.y)
|
2024-05-08 09:43:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
func _notification(what: int) -> void:
|
|
|
|
if what == NOTIFICATION_PREDELETE:
|
|
|
|
about_to_free.emit()
|