mirror of
https://codeberg.org/StreamGraph/StreamGraph.git
synced 2024-11-13 19:49:55 +01:00
a518e46b0f
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>
282 lines
9.3 KiB
GDScript
282 lines
9.3 KiB
GDScript
# (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)
|
|
class_name DeckHolder
|
|
## @experimental
|
|
## A static class holding references to all decks opened in the current session.
|
|
|
|
## List of decks opened this session.
|
|
#static var decks: Array[Deck]
|
|
static var decks: Dictionary # Dictionary[String -> id, (Deck|Dictionary[String -> instance_id, Deck])]
|
|
|
|
static var groups_emitted: Array[String]
|
|
|
|
static var logger := Logger.new()
|
|
static var signals := Signals.new()
|
|
|
|
|
|
static func _static_init() -> void:
|
|
signals.deck_added.connect(RPCSignalLayer._on_deck_added)
|
|
signals.deck_closed.connect(RPCSignalLayer._on_deck_closed)
|
|
|
|
|
|
## Returns a new empty deck and assigns a new random ID to it.
|
|
static func add_empty_deck() -> Deck:
|
|
var deck := Deck.new()
|
|
var uuid := UUID.v4()
|
|
decks[uuid] = deck
|
|
deck.id = uuid
|
|
deck.connect_rpc_signals()
|
|
signals.deck_added.emit(uuid)
|
|
return deck
|
|
|
|
|
|
## Opens a deck from the [param path].
|
|
static func open_deck_from_file(path: String) -> Deck:
|
|
var f := FileAccess.open(path, FileAccess.READ)
|
|
if f.get_error() != OK:
|
|
return null
|
|
|
|
var deck := open_deck_from_dict(JSON.parse_string(f.get_as_text()), path)
|
|
return deck
|
|
|
|
|
|
static func open_deck_from_dict(data: Dictionary, path := "") -> Deck:
|
|
var deck := Deck.from_dict(data, path)
|
|
decks[deck.id] = deck
|
|
deck.connect_rpc_signals()
|
|
signals.deck_added.emit(deck.id)
|
|
return 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, {})
|
|
instances[instance_id] = group
|
|
decks[deck_id] = instances
|
|
connect_group_signals(group)
|
|
|
|
if deck_id not in groups_emitted:
|
|
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, parent: String = "") -> Deck:
|
|
var group := get_deck(group_id)
|
|
var data := group.to_dict()
|
|
return add_group_from_dict(data, group_id, UUID.v4(), parent)
|
|
|
|
|
|
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)
|
|
if group.id not in groups_emitted:
|
|
group.connect_rpc_signals()
|
|
signals.deck_added.emit(group.id)
|
|
groups_emitted.append(group.id)
|
|
return group
|
|
|
|
|
|
static func connect_group_signals(group: Deck) -> void:
|
|
group.node_added_to_group.connect(DeckHolder._on_node_added_to_group)
|
|
group.node_removed_from_group.connect(DeckHolder._on_node_removed_from_group)
|
|
group.nodes_connected_in_group.connect(DeckHolder._on_nodes_connected_in_group)
|
|
group.nodes_disconnected_in_group.connect(DeckHolder._on_nodes_disconnected_in_group)
|
|
group.node_port_value_updated.connect(DeckHolder._on_node_port_value_updated)
|
|
group.node_renamed.connect(DeckHolder._on_node_renamed)
|
|
group.node_moved.connect(DeckHolder._on_node_moved)
|
|
|
|
|
|
static func get_deck(id: String) -> Deck:
|
|
if not decks.has(id):
|
|
return null
|
|
|
|
if not decks[id] is Dictionary:
|
|
return decks[id]
|
|
else:
|
|
return (decks[id] as Dictionary).values()[0]
|
|
|
|
|
|
static func get_group_instance(group_id: String, instance_id: String) -> Deck:
|
|
if not decks.has(group_id):
|
|
return null
|
|
|
|
if decks[group_id] is Dictionary:
|
|
return (decks[group_id] as Dictionary).get(instance_id)
|
|
else:
|
|
return null
|
|
|
|
|
|
static func close_group_instance(group_id: String, instance_id: String) -> void:
|
|
# this is kinda dumb, but to close groups that may be dangling
|
|
# when all instances are closed, we have to get that list
|
|
# *before* we close the instance
|
|
var dangling_groups := get_deck(group_id).get_referenced_groups()
|
|
|
|
var group_instances: Dictionary = decks.get(group_id, {}) as Dictionary
|
|
group_instances.erase(instance_id)
|
|
if group_instances.is_empty():
|
|
for group in dangling_groups:
|
|
close_all_group_instances(group)
|
|
signals.deck_closed.emit(group_id)
|
|
groups_emitted.erase(group_id)
|
|
decks.erase(group_id)
|
|
|
|
|
|
static func close_all_group_instances(group_id: String) -> void:
|
|
if decks.get(group_id) is Dictionary:
|
|
decks.erase(group_id)
|
|
|
|
|
|
## Unloads a deck. Returns a list of groups that are closed as a result of
|
|
## closing this deck.
|
|
static func close_deck(deck_id: String) -> Array:
|
|
if decks.get(deck_id) is Deck:
|
|
var deck: Deck = decks[deck_id] as Deck
|
|
var groups := deck.get_referenced_groups()
|
|
for group in groups:
|
|
close_all_group_instances(group)
|
|
signals.deck_closed.emit(deck_id)
|
|
decks.erase(deck_id)
|
|
return groups
|
|
return []
|
|
|
|
|
|
static func send_event(event_name: StringName, event_data: Dictionary = {}) -> void:
|
|
for deck_id: String in decks:
|
|
if decks[deck_id] is Deck:
|
|
(decks[deck_id] as Deck).send_event(event_name, event_data)
|
|
else:
|
|
for deck_instance_id: String in decks[deck_id]:
|
|
(decks[deck_id][deck_instance_id] as Deck).send_event(event_name, event_data)
|
|
|
|
|
|
#region group signal callbacks
|
|
static func _on_node_added_to_group(node: DeckNode, assign_id: String, assign_to_self: bool, deck: Deck) -> void:
|
|
var group_id := deck.id
|
|
for instance_id: String in decks[group_id]:
|
|
if instance_id == deck.instance_id:
|
|
continue
|
|
|
|
var instance: Deck = get_group_instance(group_id, instance_id)
|
|
instance.emit_group_signals = false
|
|
var node_duplicate := DeckNode.from_dict(node.to_dict())
|
|
instance.add_node_inst(node_duplicate, assign_id, assign_to_self)
|
|
instance.emit_group_signals = true
|
|
|
|
|
|
static func _on_node_removed_from_group(node_id: String, remove_connections: bool, deck: Deck) -> void:
|
|
var group_id := deck.id
|
|
for instance_id: String in decks[group_id]:
|
|
if instance_id == deck.instance_id:
|
|
continue
|
|
|
|
var instance: Deck = get_group_instance(group_id, instance_id)
|
|
instance.emit_group_signals = false
|
|
instance.remove_node(node_id, remove_connections)
|
|
instance.emit_group_signals = true
|
|
|
|
|
|
static func _on_nodes_connected_in_group(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int, deck: Deck) -> void:
|
|
var group_id := deck.id
|
|
for instance_id: String in decks[group_id]:
|
|
if instance_id == deck.instance_id:
|
|
continue
|
|
|
|
var instance: Deck = get_group_instance(group_id, instance_id)
|
|
instance.emit_group_signals = false
|
|
instance.connect_nodes(from_node_id, to_node_id, from_output_port, to_input_port)
|
|
instance.emit_group_signals = true
|
|
|
|
|
|
static func _on_nodes_disconnected_in_group(from_node_id: String, to_node_id: String, from_output_port: int, to_input_port: int, deck: Deck) -> void:
|
|
var group_id := deck.id
|
|
for instance_id: String in decks[group_id]:
|
|
if instance_id == deck.instance_id:
|
|
continue
|
|
|
|
var instance: Deck = get_group_instance(group_id, instance_id)
|
|
instance.emit_group_signals = false
|
|
instance.disconnect_nodes(from_node_id, to_node_id, from_output_port, to_input_port)
|
|
instance.emit_group_signals = true
|
|
|
|
|
|
static func _on_node_port_value_updated(node_id: String, port_idx: int, new_value: Variant, deck: Deck) -> void:
|
|
var group_id := deck.id
|
|
for instance_id: String in decks[group_id]:
|
|
if instance_id == deck.instance_id:
|
|
continue
|
|
|
|
var instance: Deck = get_group_instance(group_id, instance_id)
|
|
instance.emit_group_signals = false
|
|
instance.get_node(node_id).get_all_ports()[port_idx].set_value_no_signal(new_value)
|
|
instance.emit_group_signals = true
|
|
|
|
|
|
static func _on_node_renamed(node_id: String, new_name: String, deck: Deck) -> void:
|
|
var group_id := deck.id
|
|
for instance_id: String in decks[group_id]:
|
|
if instance_id == deck.instance_id:
|
|
continue
|
|
|
|
var instance: Deck = get_group_instance(group_id, instance_id)
|
|
instance.emit_group_signals = false
|
|
instance.get_node(node_id).name = new_name
|
|
instance.emit_group_signals = true
|
|
|
|
|
|
static func _on_node_moved(node_id: String, new_position: Dictionary, deck: Deck) -> void:
|
|
var group_id := deck.id
|
|
for instance_id: String in decks[group_id]:
|
|
if instance_id == deck.instance_id:
|
|
continue
|
|
|
|
var instance: Deck = get_group_instance(group_id, instance_id)
|
|
instance.emit_group_signals = false
|
|
instance.get_node(node_id).position = new_position.duplicate()
|
|
instance.emit_group_signals = true
|
|
#endregion
|
|
|
|
|
|
class Signals:
|
|
signal deck_added(deck_id: String)
|
|
signal deck_closed(deck_id: String)
|