From a518e46b0fb5e2a6fa9d419231b509e892331c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Thu, 11 Apr 2024 14:56:33 +0000 Subject: [PATCH] add a method to make group instances unique, making them independent (#143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #97 when copying group nodes across decks (including in and out of groups), they become unique and completely independent copies of the original. this is done recursively, so in the case of copying: - group X - contained in Deck A - has another group Z into Deck B, group X will become group Y, group Z will become group W. there is a rare bug that will sometimes cause the deck to save with no groups at all, which i haven't been able to hunt down and don't know how to replicate at the moment. Reviewed-on: https://codeberg.org/StreamGraph/StreamGraph/pulls/143 Co-authored-by: Lera ElvoƩ Co-committed-by: Lera ElvoƩ --- classes/deck/deck.gd | 36 ++++++++++++++++-- classes/deck/deck_holder.gd | 38 ++++++++++++++++--- classes/deck/nodes/general/print.gd | 1 + classes/deck/nodes/group/group_node.gd | 6 +++ .../deck_renderer_graph_edit.gd | 10 +++++ project.godot | 5 +++ 6 files changed, 87 insertions(+), 9 deletions(-) diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index cfac86e..d6fd777 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -25,7 +25,7 @@ var id: String = "" ## If this is a group, this is the local ID of this instance of the group. var instance_id: String = "" ## The parent deck of this deck, if this is a group. -#var _belonging_to: Deck # for groups +var _belonging_to: String = "" # for groups ## The ID of this group's input node. Used only if [member is_group] is [code]true[/code]. var group_input_node: String ## The ID of this group's input node. Used only if [member is_group] is [code]true[/code]. @@ -264,7 +264,7 @@ func group_nodes(nodes_to_group: Array) -> Deck: return x._id ) - var group := DeckHolder.add_empty_group() + var group := DeckHolder.add_empty_group(id) var midpoint := Vector2() @@ -436,8 +436,11 @@ func paste_nodes_from_dict(nodes_to_paste: Dictionary, position: Vector2 = Vecto nodes_to_paste.nodes[node_id].incoming_connections = incoming_connections_res var node := DeckNode.from_dict(nodes_to_paste.nodes[node_id]) + var group_needs_unique := false if node.node_type == "group_node": - var group := DeckHolder.make_new_group_instance(node.group_id) + var group := DeckHolder.make_new_group_instance(node.group_id, id) + var old_group := DeckHolder.get_group_instance(node.group_id, node.group_instance_id) + group_needs_unique = old_group._belonging_to != id node.group_instance_id = group.instance_id group.get_node(group.group_input_node).group_node = node group.get_node(group.group_output_node).group_node = node @@ -445,6 +448,8 @@ func paste_nodes_from_dict(nodes_to_paste: Dictionary, position: Vector2 = Vecto node.output_node = group.get_node(group.group_output_node) node.init_io() add_node_inst(node, ids_map[node_id]) + if group_needs_unique: + node.make_unique() func paste_nodes_from_json(json: String, position: Vector2 = Vector2()) -> void: @@ -478,6 +483,29 @@ func get_referenced_groups() -> Array[String]: return res +func get_referenced_group_instances() -> Array[Dictionary]: + var res: Array[Dictionary] = [] + for node_id: String in nodes: + var node := get_node(node_id) + if node.node_type != "group_node": + continue + res.append({ + "group_id": node.group_id, + "instance_id": node.group_instance_id, + "parent_id": node._belonging_to.id, + "group_node": node_id, + }) + res.append_array(DeckHolder.get_group_instance(node.group_id, node.group_instance_id).get_referenced_group_instances()) + return res + + +func _to_string() -> String: + if not is_group: + return "DeckNode:%s" % id + else: + return "DeckNode:%s::%s" % [id, instance_id] + + ## Returns a [Dictionary] representation of this deck. func to_dict(with_meta: bool = true, group_ids: Array = []) -> Dictionary: var inner := { @@ -536,7 +564,7 @@ static func from_dict(data: Dictionary, path: String = "") -> Deck: var group_id: String = node.group_id var group_instance_id: String = node.group_instance_id var group_data: Dictionary = groups_data[group_id] - var group := DeckHolder.add_group_from_dict(group_data, group_id, group_instance_id) + var group := DeckHolder.add_group_from_dict(group_data, group_id, group_instance_id, deck.id) group.get_node(group.group_input_node).group_node = node group.get_node(group.group_output_node).group_node = node node.init_io() diff --git a/classes/deck/deck_holder.gd b/classes/deck/deck_holder.gd index c5c23c9..eb4f2e9 100644 --- a/classes/deck/deck_holder.gd +++ b/classes/deck/deck_holder.gd @@ -49,10 +49,11 @@ static func open_deck_from_dict(data: Dictionary, path := "") -> Deck: return deck -static func add_group_from_dict(data: Dictionary, deck_id: String, instance_id: String) -> Deck: +static func add_group_from_dict(data: Dictionary, deck_id: String, instance_id: String, parent: String = "") -> Deck: var group := Deck.from_dict(data) group.instance_id = instance_id group.is_group = true + group._belonging_to = parent group.group_input_node = data.deck.group_input_node group.group_output_node = data.deck.group_output_node var instances: Dictionary = decks.get(deck_id, {}) @@ -64,20 +65,47 @@ static func add_group_from_dict(data: Dictionary, deck_id: String, instance_id: group.connect_rpc_signals() signals.deck_added.emit(deck_id) groups_emitted.append(deck_id) - + #print(decks) return group -static func make_new_group_instance(group_id: String) -> Deck: +static func make_new_group_instance(group_id: String, parent: String = "") -> Deck: var group := get_deck(group_id) var data := group.to_dict() - return add_group_from_dict(data, group_id, UUID.v4()) + return add_group_from_dict(data, group_id, UUID.v4(), parent) -static func add_empty_group() -> Deck: +static func make_group_instance_unique(group_id: String, instance_id: String, parent_deck_id: String, group_node_id: String) -> Deck: + if not decks.has(group_id): + return null + var group_node := get_deck(parent_deck_id).get_node(group_node_id) + var inst := get_group_instance(group_id, instance_id) + + var new_id := UUID.v4() + var new_inst_id := UUID.v4() + inst.id = new_id + group_node.group_id = new_id + group_node.group_instance_id = new_inst_id + var data := inst.to_dict() + #data.instance_id = new_inst_id + (decks[group_id] as Dictionary).erase(instance_id) + var new_instance := add_group_from_dict(data, new_id, new_inst_id, parent_deck_id) + + group_node.init_io() + + #TODO: some weird close bug + var instances := inst.get_referenced_group_instances() + for instance: Dictionary in instances: + make_group_instance_unique(instance.group_id, instance.instance_id, instance.parent_id, instance.group_node) + + return new_instance + + +static func add_empty_group(parent: String = "") -> Deck: var group := Deck.new() group.is_group = true group.id = UUID.v4() + group._belonging_to = parent group.instance_id = UUID.v4() decks[group.id] = {group.instance_id: group} connect_group_signals(group) diff --git a/classes/deck/nodes/general/print.gd b/classes/deck/nodes/general/print.gd index 7ad57e0..7ca7b7a 100644 --- a/classes/deck/nodes/general/print.gd +++ b/classes/deck/nodes/general/print.gd @@ -24,6 +24,7 @@ func _init() -> void: func _receive(to_input_port: int, data: Variant) -> void: + print(_belonging_to.get_reference_count()) var data_to_print := "" if to_input_port == 1: data = await resolve_input_port_value_async(0) diff --git a/classes/deck/nodes/group/group_node.gd b/classes/deck/nodes/group/group_node.gd index 38ceab6..facf26c 100644 --- a/classes/deck/nodes/group/group_node.gd +++ b/classes/deck/nodes/group/group_node.gd @@ -48,6 +48,10 @@ func init_io() -> void: setup_connections() +func make_unique() -> Deck: + return DeckHolder.make_group_instance_unique(group_id, group_instance_id, _belonging_to.id, _id) + + func setup_connections() -> void: input_node.ports_updated.connect(recalculate_ports) output_node.ports_updated.connect(recalculate_ports) @@ -74,6 +78,8 @@ func recalculate_ports() -> void: func _receive(to_input_port: int, data: Variant): + var i = DeckHolder.get_group_instance(group_id, group_instance_id).get_node(input_node_id) + #i.send(get_input_ports()[to_input_port].index_of_type, data) input_node.send(get_input_ports()[to_input_port].index_of_type, data) diff --git a/graph_node_renderer/deck_renderer_graph_edit.gd b/graph_node_renderer/deck_renderer_graph_edit.gd index 39ab6c3..b67e769 100644 --- a/graph_node_renderer/deck_renderer_graph_edit.gd +++ b/graph_node_renderer/deck_renderer_graph_edit.gd @@ -219,6 +219,16 @@ func _gui_input(event: InputEvent) -> void: deck.group_nodes(nodes) refresh_connections() get_viewport().set_input_as_handled() + + if event.is_action_pressed("debug_make_unique") and get_selected_nodes().size() == 1: + var node: DeckNode = get_selected_nodes().map( + func(x: DeckNodeRendererGraphNode): + return x.node + )[0] + if node.node_type != "group_node": + return + + node.make_unique() if event.is_action_pressed("rename_node") and get_selected_nodes().size() == 1: var node: DeckNodeRendererGraphNode = get_selected_nodes()[0] diff --git a/project.godot b/project.godot index d81b0bf..c72947f 100644 --- a/project.godot +++ b/project.godot @@ -45,6 +45,11 @@ toggle_bottom_dock={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":78,"key_label":0,"unicode":110,"echo":false,"script":null) ] } +debug_make_unique={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194335,"key_label":0,"unicode":0,"echo":false,"script":null) +] +} [rendering]