SignalBus API
The main SignalBus class provides the core functionality for signal management and communication.
Static Methods
get_singleton() -> SignalBus*
Returns the global SignalBus singleton instance.
var bus = SignalBus.get_singleton()Returns: SignalBus singleton instance or null if not initialized
Signal Operations
emit(signal_name: String, args: Array) -> void
Emits a signal on the default channel with the given arguments.
Parameters:
signal_name(String): Name of the signal to emitargs(Array): Array of arguments to pass to subscribers
bus.emit("player_died", [])
bus.emit("item_collected", ["sword", 100])
bus.emit("level_completed", ["level_1", 1500])emit_on_channel(channel: String, signal_name: String, args: Array) -> void
Emits a signal on a specific channel.
Parameters:
channel(String): Channel name to emit onsignal_name(String): Name of the signal to emitargs(Array): Array of arguments to pass to subscribers
bus.emit_on_channel("ui", "show_notification", ["Level Up!"])
bus.emit_on_channel("audio", "play_sound", ["level_up"])
bus.emit_on_channel("gameplay", "enemy_spawned", ["goblin", Vector2(100, 50)])Subscription Management
subscribe(signal_name: String, callable: Callable) -> int
Subscribes to a signal on the default channel.
Parameters:
signal_name(String): Name of the signal to subscribe tocallable(Callable): Function to call when signal is emitted
Returns: Subscription ID (int) for unsubscribing, or -1 on error
var sub_id = bus.subscribe("player_died", _on_player_died)
var sub_id2 = bus.subscribe("item_collected", _on_item_collected)
func _on_player_died():
print("Player died!")
func _on_item_collected(item_type, value):
print("Collected item: %s, value: %d" % [item_type, value])subscribe_on_channel(channel: String, signal_name: String, callable: Callable) -> int
Subscribes to a signal on a specific channel.
Parameters:
channel(String): Channel name to subscribe onsignal_name(String): Name of the signal to subscribe tocallable(Callable): Function to call when signal is emitted
Returns: Subscription ID (int) for unsubscribing, or -1 on error
var sub_id = bus.subscribe_on_channel("ui", "button_clicked", _on_ui_button)
var sub_id2 = bus.subscribe_on_channel("audio", "sound_played", _on_audio_sound)
func _on_ui_button(button_id):
print("UI button clicked: %d" % button_id)
func _on_audio_sound(sound_name):
play_sound(sound_name)unsubscribe(subscription_id: int) -> bool
Removes a specific subscription by ID.
Parameters:
subscription_id(int): ID returned bysubscribe()orsubscribe_on_channel()
Returns: true if subscription was found and removed, false otherwise
var sub_id = bus.subscribe("test_signal", _on_test)
# Later...
var success = bus.unsubscribe(sub_id)
if success:
print("Successfully unsubscribed")unsubscribe_all(subscriber: Object) -> void
Removes all subscriptions for a specific object.
Parameters:
subscriber(Object): Object whose subscriptions should be removed
func _exit_tree():
bus.unsubscribe_all(self) # Remove all subscriptions from this nodeInstance Signals
get_instance_signal(object: Object, base_signal: String) -> String
Generates a unique signal name for an object instance.
Parameters:
object(Object): Object instance to generate signal forbase_signal(String): Base signal name
Returns: Unique signal name (String) in format "base_signal_instanceId"
var unique_signal = bus.get_instance_signal(enemy, "on_damage")
# Returns something like "on_damage_123456"subscribe_instance(object: Object, base_signal: String, callable: Callable) -> int
Subscribes to an instance-specific signal.
Parameters:
object(Object): Object instance to subscribe forbase_signal(String): Base signal namecallable(Callable): Function to call when signal is emitted
Returns: Subscription ID (int) for unsubscribing, or -1 on error
# Each enemy subscribes to its own damage signal
bus.subscribe_instance(enemy1, "on_damage", _on_enemy1_damage)
bus.subscribe_instance(enemy2, "on_damage", _on_enemy2_damage)emit_instance(object: Object, base_signal: String, args: Array) -> void
Emits a signal to a specific object instance.
Parameters:
object(Object): Object instance to emit signal forbase_signal(String): Base signal nameargs(Array): Array of arguments to pass to subscribers
# Deal damage to specific enemy
bus.emit_instance(target_enemy, "on_damage", [25])Signal Filtering
subscribe_filtered(signal_name: String, filter: Callable, callable: Callable) -> int
Subscribes to a signal with a filter condition.
Parameters:
signal_name(String): Name of the signal to subscribe tofilter(Callable): Function that returnstrueif signal should be processedcallable(Callable): Function to call when signal passes filter
Returns: Subscription ID (int) for unsubscribing, or -1 on error
# Only receive valuable items (value > 50)
var sub_id = bus.subscribe_filtered(
"item_collected",
func(item_type, value): return value > 50,
_on_valuable_item
)
func _on_valuable_item(item_type, value):
print("Valuable item collected: %s, value: %d" % [item_type, value])subscribe_filtered_on_channel(channel: String, signal_name: String, filter: Callable, callable: Callable) -> int
Subscribes to a filtered signal on a specific channel.
Parameters:
channel(String): Channel name to subscribe onsignal_name(String): Name of the signal to subscribe tofilter(Callable): Function that returnstrueif signal should be processedcallable(Callable): Function to call when signal passes filter
Returns: Subscription ID (int) for unsubscribing, or -1 on error
# Only receive boss damage events
var sub_id = bus.subscribe_filtered_on_channel(
"gameplay",
"enemy_damaged",
func(enemy_type, damage): return enemy_type == "boss",
_on_boss_damaged
)Async Operations
subscribe_async(signal_name: String, callback: Callable) -> int
Subscribes to an async signal.
Parameters:
signal_name(String): Name of the async signal to subscribe tocallback(Callable): Function to execute in background thread
Returns: Subscription ID (int) for unsubscribing, or -1 on error
var sub_id = bus.subscribe_async("save_game", func(data):
# This runs in background thread
save_to_file(data)
)subscribe_async_with_callbacks(signal_name: String, callback: Callable, on_complete: Callable, on_error: Callable) -> int
Subscribes to an async signal with completion and error callbacks.
Parameters:
signal_name(String): Name of the async signal to subscribe tocallback(Callable): Function to execute in background threadon_complete(Callable): Function to call on main thread when callback completeson_error(Callable): Function to call on main thread when callback fails
Returns: Subscription ID (int) for unsubscribing, or -1 on error
var sub_id = bus.subscribe_async_with_callbacks(
"load_level",
func(level_name): # Background
return load_level_data(level_name)
,
func(level_data): # Main thread on success
current_level = level_data
show_level_loaded()
,
func(error): # Main thread on error
show_error("Failed to load level: " + error)
)emit_async(signal_name: String, args: Array) -> Array
Emits an async signal.
Parameters:
signal_name(String): Name of the async signal to emitargs(Array): Array of arguments to pass to subscribers
Returns: Array of task IDs (Array) for the created async tasks
var task_ids = bus.emit_async("save_game", [game_data])
print("Created %d async tasks" % task_ids.size())unsubscribe_async(subscription_id: int) -> bool
Removes an async subscription.
Parameters:
subscription_id(int): ID returned by async subscription methods
Returns: true if subscription was found and removed, false otherwise
var sub_id = bus.subscribe_async("save_game", save_callback)
var success = bus.unsubscribe_async(sub_id)process_async_tasks() -> void
Processes completed async tasks. Must be called regularly from main thread.
func _process(_delta):
bus.process_async_tasks() # Handle completed async tasksget_active_async_task_count() -> int
Returns the number of currently active async tasks.
Returns: Number of active tasks (int)
var active_count = bus.get_active_async_task_count()
print("Active tasks: %d" % active_count)wait_all_async_tasks() -> void
Waits for all async tasks to complete. Blocks until all tasks are done.
func _exit_tree():
bus.wait_all_async_tasks() # Wait for saves to completecancel_async_task(task_id: int) -> bool
Cancels an async task.
Parameters:
task_id(int): ID of the task to cancel
Returns: true if task was cancelled, false otherwise
var task_ids = bus.emit_async("heavy_operation", [data])
for task_id in task_ids:
if bus.cancel_async_task(task_id):
print("Cancelled task: %d" % task_id)Debug and Monitoring
set_debug_enabled(enabled: bool) -> void
Enables or disables debug logging.
Parameters:
enabled(bool):trueto enable debug mode,falseto disable
if OS.is_debug_build():
bus.set_debug_enabled(true)get_signal_list() -> Array[Dictionary]
Returns information about all registered signals.
Returns: Array of dictionaries with signal information:
name(String): Signal namechannel(String): Channel namesubscriber_count(int): Number of subscribers
var signals = bus.get_signal_list()
for signal_info in signals:
print("Signal: %s, Channel: %s, Subscribers: %d" % [
signal_info.name, signal_info.channel, signal_info.subscriber_count
])get_channel_list() -> PackedStringArray
Returns a list of all active channels.
Returns: Array of channel names (PackedStringArray)
var channels = bus.get_channel_list()
print("Active channels: ", channels)get_subscriber_count(signal_name: String) -> int
Returns the total number of subscribers for a signal across all channels.
Parameters:
signal_name(String): Name of the signal to count subscribers for
Returns: Number of subscribers (int)
var count = bus.get_subscriber_count("player_died")
print("Subscribers: %d" % count)get_subscriber_count_on_channel(channel: String, signal_name: String) -> int
Returns the number of subscribers for a signal on a specific channel.
Parameters:
channel(String): Channel name to checksignal_name(String): Signal name to count subscribers for
Returns: Number of subscribers (int)
var count = bus.get_subscriber_count_on_channel("ui", "button_clicked")
print("UI button subscribers: %d" % count)get_total_signals_emitted() -> int
Returns the total number of signals emitted since startup.
Returns: Total signal count (int)
var total = bus.get_total_signals_emitted()
print("Total signals emitted: %d" % total)Signal Bridging
bridge_signal(node: Node, signal_name: String) -> int64_t
Bridges a node signal to the default channel.
Parameters:
node(Node): Node object to bridge fromsignal_name(String): Signal name to bridge
Returns: Bridge ID (int64_t) for managing the bridge, or -1 on error
var bridge_id = bus.bridge_signal($Button, "pressed")
var timer_bridge = bus.bridge_signal($GameTimer, "timeout")bridge_signal_to_channel(node: Node, signal_name: String, channel: String) -> int64_t
Bridges a node signal to a specific channel.
Parameters:
node(Node): Node object to bridge fromsignal_name(String): Signal name to bridgechannel(String): Target channel name
Returns: Bridge ID (int64_t) for managing the bridge, or -1 on error
var bridge_id = bus.bridge_signal_to_channel($SettingsButton, "pressed", "ui")
var enemy_bridge = bus.bridge_signal_to_channel($Enemy, "died", "gameplay")relay_node_signal(node: Node, node_signal: String, bus_signal: String) -> int64_t
Relays a node signal with a different bus signal name.
Parameters:
node(Node): Node object to relay fromnode_signal(String): Node signal namebus_signal(String): Bus signal name to emit
Returns: Bridge ID (int64_t) for managing the bridge, or -1 on error
var bridge_id = bus.relay_node_signal($StartButton, "pressed", "menu_action")
var health_bridge = bus.relay_node_signal($Player, "health_changed", "player_health_update")relay_node_signal_to_channel(node: Node, node_signal: String, bus_signal: String, channel: String) -> int64_t
Relays a node signal to a specific channel with a different bus signal name.
Parameters:
node(Node): Node object to relay fromnode_signal(String): Node signal namebus_signal(String): Bus signal name to emitchannel(String): Target channel name
Returns: Bridge ID (int64_t) for managing the bridge, or -1 on error
var bridge_id = bus.relay_node_signal_to_channel(
$QuitButton,
"pressed",
"quit_requested",
"ui"
)unbridge_signal(bridge_id: int64_t) -> bool
Removes a signal bridge.
Parameters:
bridge_id(int64_t): Bridge ID returned by bridge methods
Returns: true if bridge was found and removed, false otherwise
var bridge_id = bus.bridge_signal($Button, "pressed")
# Later...
var success = bus.unbridge_signal(bridge_id)
if success:
print("Bridge removed successfully")cleanup_invalid_bridges() -> int32_t
Cleans up invalid bridges (nodes that have been freed).
Returns: Number of bridges cleaned up (int32_t)
var cleaned = bus.cleanup_invalid_bridges()
print("Cleaned up ", cleaned, " invalid bridges")Channel Management
clear_channel(channel: String) -> void
Removes all subscriptions from a specific channel.
Parameters:
channel(String): Channel name to clear
bus.clear_channel("ui") # Remove all UI channel subscriptionsclear_all() -> void
Removes all subscriptions from all channels.
bus.clear_all() # Remove all subscriptions everywhereError Handling
Most methods return error codes or boolean values to indicate success/failure:
- Subscription methods: Return
-1on error, positive ID on success - Unsubscribe methods: Return
trueon success,falseon failure - Debug mode: Check
bus.set_debug_enabled(true)for detailed error logging
Thread Safety
- All synchronous methods must be called from the main thread
- Async callbacks execute in background threads
- Completion/error callbacks execute on main thread
- Never access scene tree in async callbacks