Files
MovementTests/addons/gdUnit4/src/core/GdUnitSignalCollector.gd
Minimata caeae26a09
Some checks failed
Create tag and build when new code gets to main / BumpTag (push) Successful in 22s
Create tag and build when new code gets to main / Test (push) Failing after 2m10s
Create tag and build when new code gets to main / Export (push) Has been skipped
fixed camera and sword animation issue and upgraded to Godot 4.6
2026-01-27 17:47:19 +01:00

130 lines
5.3 KiB
GDScript

# It connects to all signals of given emitter and collects received signals and arguments
# The collected signals are cleand finally when the emitter is freed.
class_name GdUnitSignalCollector
extends RefCounted
const NO_ARG :Variant = GdUnitConstants.NO_ARG
const SIGNAL_BLACK_LIST = []#["tree_exiting", "tree_exited", "child_exiting_tree"]
# {
# emitter<Object> : {
# signal_name<String> : [signal_args<Array>],
# ...
# }
# }
var _collected_signals :Dictionary = {}
func clear() -> void:
for emitter :Object in _collected_signals.keys():
if is_instance_valid(emitter):
unregister_emitter(emitter)
# connect to all possible signals defined by the emitter
# prepares the signal collection to store received signals and arguments
func register_emitter(emitter: Object, force_recreate := false) -> void:
if is_instance_valid(emitter):
# check emitter is already registerd
if _collected_signals.has(emitter):
if not force_recreate:
return
# If the flag recreate is set to true, emitters that are already registered must be deregistered before recreating,
# otherwise signals that have already been collected will be evaluated.
unregister_emitter(emitter)
_collected_signals[emitter] = Dictionary()
# connect to 'tree_exiting' of the emitter to finally release all acquired resources/connections.
if emitter is Node and !(emitter as Node).tree_exiting.is_connected(unregister_emitter):
(emitter as Node).tree_exiting.connect(unregister_emitter.bind(emitter))
# connect to all signals of the emitter we want to collect
for signal_def in emitter.get_signal_list():
var signal_name :String = signal_def["name"]
# set inital collected to empty
if not is_signal_collecting(emitter, signal_name):
_collected_signals[emitter][signal_name] = Array()
if SIGNAL_BLACK_LIST.find(signal_name) != -1:
continue
if !emitter.is_connected(signal_name, _on_signal_emmited):
var err := emitter.connect(signal_name, _on_signal_emmited.bind(emitter, signal_name))
if err != OK:
push_error("Can't connect to signal %s on %s. Error: %s" % [signal_name, emitter, error_string(err)])
# unregister all acquired resources/connections, otherwise it ends up in orphans
# is called when the emitter is removed from the parent
func unregister_emitter(emitter :Object) -> void:
if is_instance_valid(emitter):
for signal_def in emitter.get_signal_list():
var signal_name :String = signal_def["name"]
if emitter.is_connected(signal_name, _on_signal_emmited):
emitter.disconnect(signal_name, _on_signal_emmited.bind(emitter, signal_name))
@warning_ignore("return_value_discarded")
_collected_signals.erase(emitter)
# receives the signal from the emitter with all emitted signal arguments and additional the emitter and signal_name as last two arguements
func _on_signal_emmited(
arg0 :Variant= NO_ARG,
arg1 :Variant= NO_ARG,
arg2 :Variant= NO_ARG,
arg3 :Variant= NO_ARG,
arg4 :Variant= NO_ARG,
arg5 :Variant= NO_ARG,
arg6 :Variant= NO_ARG,
arg7 :Variant= NO_ARG,
arg8 :Variant= NO_ARG,
arg9 :Variant= NO_ARG,
arg10 :Variant= NO_ARG,
arg11 :Variant= NO_ARG) -> void:
var signal_args :Array = GdArrayTools.filter_value([arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11], NO_ARG)
# extract the emitter and signal_name from the last two arguments (see line 61 where is added)
var signal_name :String = signal_args.pop_back()
var emitter :Object = signal_args.pop_back()
#prints("_on_signal_emmited:", emitter, signal_name, signal_args)
if is_signal_collecting(emitter, signal_name):
@warning_ignore("unsafe_cast")
(_collected_signals[emitter][signal_name] as Array).append(signal_args)
func reset_received_signals(emitter: Object, signal_name: String, signal_args: Array) -> void:
#_debug_signal_list("before claer");
if _collected_signals.has(emitter):
var signals_by_emitter :Dictionary = _collected_signals[emitter]
if signals_by_emitter.has(signal_name):
var received_args: Array = _collected_signals[emitter][signal_name]
# We iterate backwarts over to received_args to remove matching args.
# This will avoid array corruption see comment on `erase` otherwise we need a timeconsuming duplicate before
for arg_pos: int in range(received_args.size()-1, -1, -1):
var arg: Variant = received_args[arg_pos]
if GdObjects.equals(arg, signal_args):
received_args.remove_at(arg_pos)
#_debug_signal_list("after claer");
func is_signal_collecting(emitter: Object, signal_name: String) -> bool:
@warning_ignore("unsafe_cast")
return _collected_signals.has(emitter) and (_collected_signals[emitter] as Dictionary).has(signal_name)
func match(emitter: Object, signal_name: String, args: Array) -> bool:
#prints("match", signal_name, _collected_signals[emitter][signal_name]);
if _collected_signals.is_empty() or not _collected_signals.has(emitter):
return false
for received_args :Variant in _collected_signals[emitter][signal_name]:
#prints("testing", signal_name, received_args, "vs", args)
if GdObjects.equals(received_args, args):
return true
return false
func _debug_signal_list(message :String) -> void:
prints("-----", message, "-------")
prints("senders {")
for emitter :Object in _collected_signals:
prints("\t", emitter)
for signal_name :String in _collected_signals[emitter]:
var args :Variant = _collected_signals[emitter][signal_name]
prints("\t\t", signal_name, args)
prints("}")