Skip to content

Instantly share code, notes, and snippets.

@bitbutter
Created July 8, 2024 08:25

Revisions

  1. bitbutter created this gist Jul 8, 2024.
    72 changes: 72 additions & 0 deletions SignalWaiter.gd
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,72 @@
    class_name SignalWaiter

    signal AllFinished

    # Internal variables
    var _active_nodes = {}
    var _signal_connections = {}
    var _callables = []

    ## External method to add a node, its callable, and the signal to listen for.
    ## node: The node to add.
    ## callable: A Callable to call when running.
    ## signal_name: The signal name to listen for from the node.
    func add_item(node: Node, callable: Callable, signal_name: String):
    _active_nodes[node] = true
    _callables.append(callable)
    _wait_for_signal(node, signal_name)

    ## External method to run all callables and await the AllFinished signal.
    func run():
    for callable in _callables:
    if callable != null:
    callable.call()
    if _all_signals_already_emitted():
    emit_signal("AllFinished")
    else:
    await AllFinished

    ## Internal method to set up signal listening on a node.
    func _wait_for_signal(node: Node, signal_name: String):
    if not node.has_signal(signal_name):
    print("Error: Signal '", signal_name, "' not found in ", node)
    return

    var callback = Callable(self, "_on_node_signal_received").bind(node)
    if not node.is_connected(signal_name,callback):
    var err : Error = node.connect(signal_name, callback)
    assert(err == OK, "problem connecting to "+signal_name+". callback:"+str(callback)+". node: "+node.name+". error: "+error_string(err))
    else:
    assert(false,node.name+" "+signal_name+" already connected to signalwaiter callback! (duplicate cells in array?)")
    _signal_connections[node] = [signal_name, callback]

    ## Internal method called when a signal is received.
    func _on_node_signal_received(node: Node):
    _active_nodes[node] = false
    if _all_signals_already_emitted():
    emit_signal("AllFinished")

    ## Internal method to check if all signals have been emitted.
    func _all_signals_already_emitted():
    for waiting_for_this_node in _active_nodes.values():
    if waiting_for_this_node:
    return false
    return true


    # Example code
    #
    #var signal_waiter := SignalWaiter.new()
    #
    ## the nodes all have a jump method, and emit a FinishedJumping signal
    #for n in nodes:
    #signal_waiter.add_item(n,Callable(n,"jump"),"FinishedJumping")
    #
    ## calls the callable for each item
    #signal_waiter.run()
    #
    ## wait "FinishedExploding" emitted by every node
    #await signal_waiter.AllFinished
    #
    ## do the next thing
    #%Label.show()