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 map of outgoing connections from this node, in the format[br]
|
|
|
|
## [code]Dictionary[int -> output port, Array[Dictionary[String -> DeckNode#_id, int -> input port]]][/code]
|
2023-06-10 19:13:16 +02:00
|
|
|
var outgoing_connections: Dictionary
|
2023-11-25 11:40:53 +01:00
|
|
|
## A map of incoming connections to this node, in the format[br]
|
|
|
|
## [code]Dictionary[int -> input port, [Dictionary[String -> DeckNode#_id, int -> output port]][/code]
|
2023-06-13 17:23:10 +02:00
|
|
|
var incoming_connections: Dictionary
|
2023-06-10 19:13:16 +02: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]
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## The deck this node belongs to.
|
2023-06-10 19:13:16 +02:00
|
|
|
var _belonging_to: Deck
|
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
|
|
|
## The category of this node. Must be snake_case. This is additional data which
|
|
|
|
## a renderer can optionally show to the user.
|
2023-11-23 07:38:10 +01:00
|
|
|
var category: 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-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)
|
|
|
|
|
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.
|
2023-06-10 19:13:16 +02:00
|
|
|
func add_input_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
2023-11-22 05:26:11 +01:00
|
|
|
add_port(type, label, PortType.INPUT, get_input_ports().size(), descriptor)
|
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.
|
2023-06-10 19:13:16 +02:00
|
|
|
func add_output_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
2023-11-22 05:26:11 +01:00
|
|
|
add_port(type, label, PortType.OUTPUT, get_output_ports().size(), descriptor)
|
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.
|
2023-06-12 17:32:16 +02:00
|
|
|
func add_virtual_port(type: Deck.Types, label: String, descriptor: String = "") -> void:
|
2023-11-22 05:26:11 +01:00
|
|
|
add_port(type, label, PortType.VIRTUAL, get_virtual_ports().size(), descriptor)
|
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.
|
2023-11-22 05:26:11 +01:00
|
|
|
func add_port(type: Deck.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)
|
|
|
|
ports.append(port)
|
|
|
|
port_added.emit(ports.size() - 1)
|
|
|
|
ports_updated.emit()
|
|
|
|
|
2023-06-12 17:32:16 +02:00
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Remove a port from this node.
|
2023-11-22 05:26:11 +01:00
|
|
|
func remove_port(port_idx: int) -> void:
|
|
|
|
outgoing_connections.erase(port_idx)
|
|
|
|
incoming_connections.erase(port_idx)
|
|
|
|
ports.remove_at(port_idx)
|
|
|
|
port_removed.emit(port_idx)
|
2023-06-10 19:13:16 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Send data to all outgoing connections on port [param from_output_port].
|
2023-11-22 05:26:11 +01:00
|
|
|
func send(from_output_port: int, data: DeckType, extra_data: Array = []) -> void:
|
|
|
|
if outgoing_connections.get(from_output_port) == null:
|
2023-06-10 19:13:16 +02:00
|
|
|
return
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
for connection in outgoing_connections[from_output_port]:
|
2023-06-10 19:13:16 +02:00
|
|
|
connection = connection as Dictionary
|
|
|
|
# key is node uuid
|
2023-11-22 05:26:11 +01:00
|
|
|
# value is GLOBAL port on destination node
|
2023-06-10 19:13:16 +02:00
|
|
|
for node in connection:
|
2023-06-13 17:23:10 +02:00
|
|
|
get_node(node)._receive(connection[node], data, extra_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-11-22 05:26:11 +01:00
|
|
|
func _receive(to_input_port: int, data: DeckType, extra_data: Array = []) -> void:
|
2023-06-10 19:13:16 +02:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## @deprecated
|
2023-06-12 17:32:16 +02:00
|
|
|
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)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Add a connection from the output port at [param from_port] to [param to_node]'s input port
|
|
|
|
## at [param to_port].
|
2023-06-10 19:13:16 +02:00
|
|
|
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
|
2023-06-13 17:23:10 +02:00
|
|
|
get_node(to_node).add_incoming_connection(to_port, _id, from_port)
|
2023-11-22 05:26:11 +01:00
|
|
|
outgoing_connection_added.emit(from_port)
|
2023-06-13 17:23:10 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Add an incoming connection from [param from_node]'s output port at [param from_port] to this node's
|
|
|
|
## input port at [param to_port].
|
2023-06-13 17:23:10 +02:00
|
|
|
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
|
2023-11-22 05:26:11 +01:00
|
|
|
incoming_connection_added.emit(to_port)
|
2023-06-13 17:23:10 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Request a value from an incoming connection on this node's input port at [param on_port].
|
|
|
|
## Returns [code]null[/code] if no incoming connection exists on that port.
|
|
|
|
## The connected node may also return [code]null[/code].
|
2023-06-13 17:23:10 +02:00
|
|
|
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])
|
|
|
|
|
|
|
|
|
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-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-11-25 11:40:53 +01:00
|
|
|
## Remove an outgoing connection from this node.
|
|
|
|
## Does [b]not[/b] remove the other node's incoming connection equivalent.
|
2023-06-11 18:26:12 +02:00
|
|
|
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
|
|
|
|
|
2023-07-21 11:12:20 +02:00
|
|
|
var incoming_connection := {}
|
|
|
|
|
2023-06-11 18:26:12 +02:00
|
|
|
var to_remove: int = -1
|
|
|
|
for i in port_connections.size():
|
|
|
|
if port_connections[i].hash() == connection_hash:
|
2023-07-21 11:12:20 +02:00
|
|
|
|
2023-06-11 18:26:12 +02:00
|
|
|
to_remove = i
|
|
|
|
|
|
|
|
if to_remove == -1:
|
2023-07-21 11:12:20 +02:00
|
|
|
print('nothing to remove')
|
2023-06-11 18:26:12 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
port_connections.remove_at(to_remove)
|
|
|
|
outgoing_connections[from_port] = port_connections
|
2023-11-22 05:26:11 +01:00
|
|
|
outgoing_connection_removed.emit(from_port)
|
2023-06-12 17:32:16 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Remove an incoming connection to this node on the input port at [param to_port].
|
|
|
|
## Does [b]not[/b] remove the other node's outgoing connection equivalent.
|
2023-07-21 11:12:20 +02:00
|
|
|
func remove_incoming_connection(to_port: int) -> void:
|
|
|
|
incoming_connections.erase(to_port)
|
2023-11-22 05:26:11 +01:00
|
|
|
incoming_connection_removed.emit(to_port)
|
2023-07-21 11:12:20 +02:00
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## @deprecated
|
2023-06-12 17:32:16 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
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 amount of outgoing connections on output port at [param port].
|
2023-11-22 05:26:11 +01:00
|
|
|
func get_outgoing_connection_count(port: int) -> int:
|
|
|
|
return (outgoing_connections[port] as Array).size()
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## @deprecated
|
2023-11-22 05:26:11 +01:00
|
|
|
func get_outgoing_connection_count_on_output(port: int) -> int:
|
|
|
|
return get_outgoing_connection_count(get_global_port_idx_from_output(port))
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Returns [code]true[/code] if the node has an incoming connection in input port at [param port].
|
2023-11-22 05:26:11 +01:00
|
|
|
func has_incoming_connection(port: int) -> bool:
|
|
|
|
return incoming_connections.has(port)
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## @deprecated
|
2023-11-22 05:26:11 +01:00
|
|
|
func has_incoming_connection_on_input(port: int) -> bool:
|
|
|
|
return has_incoming_connection(get_global_port_idx_from_input(port))
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Virtual function that's called during deserialization before connections are loaded in.
|
2023-11-22 05:26:11 +01:00
|
|
|
func _pre_connection() -> void:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2023-11-25 11:40:53 +01:00
|
|
|
## Virtual function that's called after the node has been deserialized.
|
2023-11-22 05:26:11 +01:00
|
|
|
func _post_load() -> void:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
"outgoing_connections": outgoing_connections,
|
|
|
|
"incoming_connections": incoming_connections,
|
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": [],
|
|
|
|
"position": position,
|
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
|
|
|
|
|
|
|
|
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)
|