summaryrefslogtreecommitdiff
path: root/addons/gdUnit4/src/core/GdUnitSignalCollector.gd
diff options
context:
space:
mode:
Diffstat (limited to 'addons/gdUnit4/src/core/GdUnitSignalCollector.gd')
-rw-r--r--addons/gdUnit4/src/core/GdUnitSignalCollector.gd129
1 files changed, 129 insertions, 0 deletions
diff --git a/addons/gdUnit4/src/core/GdUnitSignalCollector.gd b/addons/gdUnit4/src/core/GdUnitSignalCollector.gd
new file mode 100644
index 0000000..0cb6ad7
--- /dev/null
+++ b/addons/gdUnit4/src/core/GdUnitSignalCollector.gd
@@ -0,0 +1,129 @@
+# 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("}")