2023-06-10 19:13:16 +02:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
2023-06-13 17:23:10 +02:00
|
|
|
var variable_stack: Dictionary = {}
|
2023-11-22 05:26:11 +01:00
|
|
|
var save_path: String = ""
|
2023-06-13 17:23:10 +02:00
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
var is_group: bool = false
|
|
|
|
var groups: Dictionary = {} #Dictionary[String -> Deck.id, Deck]
|
|
|
|
var id: String = ""
|
|
|
|
var _belonging_to: Deck # for groups
|
|
|
|
var group_input_node: String
|
|
|
|
var group_output_node: String
|
|
|
|
var group_node: String
|
2023-06-10 19:13:16 +02:00
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
signal node_added(node: DeckNode)
|
|
|
|
signal node_removed(node: DeckNode)
|
2023-06-10 19:13:16 +02:00
|
|
|
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
func add_node_type(type: String, assign_id: String = "", assign_to_self: bool = true) -> DeckNode:
|
|
|
|
var node_inst: DeckNode = NodeDB.instance_node(type)
|
|
|
|
|
|
|
|
return add_node_inst(node_inst, assign_id, assign_to_self)
|
2023-06-10 19:13:16 +02:00
|
|
|
|
|
|
|
|
2023-07-21 10:10:24 +02:00
|
|
|
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
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
node_added.emit(node)
|
2023-06-24 05:39:50 +02:00
|
|
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
|
2023-06-10 19:13:16 +02:00
|
|
|
func get_node(uuid: String) -> DeckNode:
|
|
|
|
return nodes.get(uuid)
|
|
|
|
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
func connect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port: int, to_input_port: int) -> bool:
|
2023-06-10 19:13:16 +02:00
|
|
|
# first, check that we can do the type conversion.
|
2023-11-22 05:26:11 +01:00
|
|
|
var type_a: Types = from_node.get_output_ports()[from_output_port].type
|
|
|
|
var type_b: Types = to_node.get_input_ports()[to_input_port].type
|
2023-06-11 17:39:11 +02:00
|
|
|
var err: DeckType = (type_assoc[type_b]).from(type_assoc[type_a].new())
|
2023-06-10 19:13:16 +02:00
|
|
|
if err is DeckType.DeckTypeError:
|
|
|
|
print(err.error_message)
|
|
|
|
return false
|
|
|
|
|
|
|
|
# TODO: prevent duplicate connections
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
from_node.add_outgoing_connection(from_output_port, to_node._id, to_input_port)
|
2023-06-10 19:13:16 +02:00
|
|
|
return true
|
2023-06-11 18:26:12 +02:00
|
|
|
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
func disconnect_nodes(from_node: DeckNode, to_node: DeckNode, from_output_port: int, to_input_port: int) -> void:
|
|
|
|
var hash = {to_node._id: to_input_port}.hash()
|
|
|
|
|
|
|
|
from_node.remove_outgoing_connection(from_output_port, hash)
|
|
|
|
to_node.remove_incoming_connection(to_input_port)
|
|
|
|
|
|
|
|
|
|
|
|
func is_empty() -> bool:
|
|
|
|
return nodes.is_empty() && variable_stack.is_empty()
|
|
|
|
|
|
|
|
|
|
|
|
func remove_node(uuid: String) -> void:
|
|
|
|
var node = nodes.get(uuid)
|
|
|
|
nodes.erase(uuid)
|
|
|
|
|
|
|
|
node_removed.emit(node)
|
|
|
|
|
|
|
|
|
|
|
|
func group_nodes(nodes_to_group: Array) -> Deck:
|
|
|
|
if nodes_to_group.is_empty():
|
|
|
|
return null
|
|
|
|
|
|
|
|
var node_ids_to_keep := nodes_to_group.map(
|
|
|
|
func(x: DeckNode):
|
|
|
|
return x._id
|
|
|
|
)
|
|
|
|
|
|
|
|
var group := Deck.new()
|
|
|
|
group.is_group = true
|
|
|
|
group._belonging_to = self
|
|
|
|
var group_id := UUID.v4()
|
|
|
|
group.id = group_id
|
|
|
|
|
|
|
|
var midpoint := Vector2()
|
|
|
|
for node: DeckNode in nodes_to_group:
|
|
|
|
if node.node_type == "group_node": # for recursive grouping
|
|
|
|
var _group_id: String = node.group_id
|
|
|
|
var _group: Deck = groups[_group_id]
|
|
|
|
groups.erase(_group)
|
|
|
|
group.groups[_group_id] = _group
|
|
|
|
_group._belonging_to = group
|
|
|
|
|
|
|
|
for from_port: int in node.outgoing_connections:
|
|
|
|
for connection: Dictionary in node.outgoing_connections[from_port]:
|
|
|
|
if !(connection.keys()[0] in node_ids_to_keep):
|
|
|
|
disconnect_nodes(node, get_node(connection.keys()[0]), from_port, connection.values()[0])
|
|
|
|
|
|
|
|
midpoint += node.position_as_vector2()
|
|
|
|
remove_node(node._id)
|
|
|
|
group.add_node_inst(node, node._id)
|
|
|
|
|
|
|
|
midpoint /= nodes_to_group.size()
|
|
|
|
|
|
|
|
var _group_node := add_node_type("group_node")
|
|
|
|
_group_node.group_id = group_id
|
|
|
|
_group_node.position.x = midpoint.x
|
|
|
|
_group_node.position.y = midpoint.y
|
|
|
|
_group_node.position_updated.emit(_group_node.position)
|
|
|
|
group.group_node = _group_node._id
|
2023-07-21 11:12:20 +02:00
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
var input_node := group.add_node_type("group_input")
|
|
|
|
var output_node := group.add_node_type("group_output")
|
|
|
|
group.group_input_node = input_node._id
|
|
|
|
group.group_output_node = output_node._id
|
2023-06-24 05:39:50 +02:00
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
_group_node.input_node = input_node
|
|
|
|
_group_node.output_node = output_node
|
|
|
|
_group_node.setup_connections()
|
2023-06-24 05:39:50 +02:00
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
groups[group_id] = group
|
2023-06-24 05:39:50 +02:00
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
return group
|
|
|
|
|
|
|
|
|
|
|
|
func get_group(uuid: String) -> Deck:
|
|
|
|
return groups.get(uuid)
|
|
|
|
|
|
|
|
|
|
|
|
func to_dict(with_meta: bool = true) -> Dictionary:
|
|
|
|
var inner := {
|
|
|
|
"nodes": {},
|
|
|
|
"variable_stack": variable_stack,
|
|
|
|
"id": id,
|
|
|
|
"groups": {}
|
|
|
|
}
|
|
|
|
|
|
|
|
for node_id in nodes.keys():
|
|
|
|
inner["nodes"][node_id] = nodes[node_id].to_dict(with_meta)
|
|
|
|
|
|
|
|
for group_id in groups.keys():
|
|
|
|
inner["groups"][group_id] = groups[group_id].to_dict(with_meta)
|
|
|
|
|
|
|
|
if is_group:
|
|
|
|
inner["group_node"] = group_node
|
|
|
|
inner["group_input_node"] = group_input_node
|
|
|
|
inner["group_output_node"] = group_output_node
|
2023-06-24 05:39:50 +02:00
|
|
|
|
|
|
|
var d := {"deck": inner}
|
|
|
|
|
|
|
|
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-11-22 05:26:11 +01:00
|
|
|
return d
|
2023-07-21 10:10:24 +02:00
|
|
|
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
static func from_dict(data: Dictionary, path: String = "") -> Deck:
|
2023-07-21 10:10:24 +02:00
|
|
|
var deck := Deck.new()
|
2023-11-22 05:26:11 +01:00
|
|
|
deck.save_path = path
|
2023-07-21 10:10:24 +02:00
|
|
|
deck.variable_stack = data.deck.variable_stack
|
2023-11-22 05:26:11 +01:00
|
|
|
deck.id = data.deck.id
|
2023-07-21 10:10:24 +02:00
|
|
|
|
|
|
|
for key in data.meta:
|
2023-08-08 08:54:17 +02:00
|
|
|
deck.set_meta(key, str_to_var(data.meta[key]))
|
2023-07-21 10:10:24 +02:00
|
|
|
|
|
|
|
var nodes_data: Dictionary = data.deck.nodes as Dictionary
|
|
|
|
|
|
|
|
for node_id in nodes_data:
|
2023-11-22 05:26:11 +01:00
|
|
|
var node := deck.add_node_type(nodes_data[node_id].node_type, node_id, false)
|
2023-07-21 10:10:24 +02:00
|
|
|
node._id = node_id
|
|
|
|
node.name = nodes_data[node_id].name
|
|
|
|
node._belonging_to = deck
|
2023-11-22 05:26:11 +01:00
|
|
|
node.position = nodes_data[node_id].position
|
|
|
|
|
|
|
|
for prop in nodes_data[node_id].props:
|
|
|
|
node.set(prop, nodes_data[node_id].props[prop])
|
|
|
|
|
|
|
|
node._pre_connection()
|
|
|
|
|
2023-07-21 10:10:24 +02:00
|
|
|
for connection_id in nodes_data[node_id].outgoing_connections:
|
|
|
|
var connection_data = nodes_data[node_id].outgoing_connections[connection_id]
|
2023-07-21 11:12:20 +02:00
|
|
|
for connection in connection_data:
|
|
|
|
connection[connection.keys()[0]] = int(connection.values()[0])
|
2023-07-21 10:10:24 +02:00
|
|
|
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]
|
2023-07-21 11:12:20 +02:00
|
|
|
for connection in connection_data:
|
|
|
|
connection_data[connection] = int(connection_data[connection])
|
2023-07-21 10:10:24 +02:00
|
|
|
node.incoming_connections[int(connection_id)] = connection_data
|
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
for i in node.ports.size():
|
|
|
|
var port_value: Variant
|
|
|
|
if (nodes_data[node_id].port_values as Array).size() <= i:
|
|
|
|
port_value = null
|
|
|
|
else:
|
|
|
|
port_value = (nodes_data[node_id].port_values as Array)[i]
|
2023-07-21 10:26:43 +02:00
|
|
|
node.ports[i].value = port_value
|
|
|
|
|
2023-07-21 10:10:24 +02:00
|
|
|
for key in nodes_data[node_id].meta:
|
2023-08-08 08:54:17 +02:00
|
|
|
node.set_meta(key, str_to_var(nodes_data[node_id].meta[key]))
|
2023-07-21 10:10:24 +02:00
|
|
|
|
2023-11-22 05:26:11 +01:00
|
|
|
node._post_load()
|
|
|
|
|
|
|
|
var groups_data: Dictionary = data.deck.groups as Dictionary
|
|
|
|
|
|
|
|
for group_id: String in groups_data:
|
|
|
|
var group := Deck.from_dict(groups_data[group_id])
|
|
|
|
group._belonging_to = deck
|
|
|
|
group.is_group = true
|
|
|
|
deck.groups[group_id] = group
|
|
|
|
group.group_node = groups_data[group_id]["deck"]["group_node"]
|
|
|
|
group.group_input_node = groups_data[group_id]["deck"]["group_input_node"]
|
|
|
|
group.group_output_node = groups_data[group_id]["deck"]["group_output_node"]
|
|
|
|
deck.get_node(group.group_node).init_io()
|
2023-07-21 10:10:24 +02:00
|
|
|
|
|
|
|
return deck
|