add a method to make group instances unique, making them independent (#143)

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é <yagich@poto.cafe>
Co-committed-by: Lera Elvoé <yagich@poto.cafe>
This commit is contained in:
Lera Elvoé 2024-04-11 14:56:33 +00:00 committed by yagich
parent 2ac9db8350
commit a518e46b0f
6 changed files with 87 additions and 9 deletions

View file

@ -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()

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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]

View file

@ -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]