Wax

Signals

Run a function when something happens.

A signal is an event you can listen to. You connect a function to it. Each time the event happens, your function runs.

init.lua
game.MapChanged:Connect(function(name)
    ui.Notify("You are now on " .. name, { title = "Map changed" })
end)

When the event happens, the signal fires. game.MapChanged fires when the world changes, and it gives your function the new map's name.

Signals that Wax gives you

SignalFires whenYour function gets
game.MapChangedThe world changes.The new map's name.
ui.OpenedThe menu opens.Nothing.
ui.ClosedThe menu closes.Nothing.
ui.KeyChangedThe menu key changes.The new key.
ui.ThemeChangedThe theme changes.The theme's name.
window.Opened, window.ClosedA window is shown or hidden.Nothing.
window.PageChangedAnother page of a window is chosen.The page's name.
control.ChangedThe user changes a control.The new value.

Controls have a few more. Each one is listed with its control on the Controls page.

Stop listening

Connect gives back a connection. Call Disconnect on it to stop.

init.lua
local connection = ui.Opened:Connect(function()
    print("The menu opened.")
end)

local window = ui.Window({ title = "Signals" })
window:Button("Stop printing", function()
    connection:Disconnect()
    print("Still connected:", connection.Connected)   -- false
end)

When your mod reloads, Wax disconnects everything the mod connected. You only need Disconnect to stop before that.

Only once

Once is like Connect, but your function runs for the next fire only.

init.lua
ui.Opened:Once(function()
    ui.Notify("You opened the menu for the first time since this mod loaded.")
end)

Wait for a signal

Inside a task, Wait pauses until the signal fires. It gives back what the signal sent.

init.lua
task.spawn(function()
    print("Waiting for a map change...")
    local name = game.MapChanged:Wait()
    print("The map is now", name)
end)

Make your own signal

Signal.new makes a signal. Fire fires it. Whatever you pass to Fire reaches every connected function.

init.lua
local scored = Signal.new("scored")

scored:Connect(function(points)
    print("Scored", points)
end)

scored:Once(function()
    print("First score!")
end)

scored:Fire(10)
scored:Fire(5)

The log shows:

First score!
Scored 10
Scored 5

The newest connection runs first. That is why First score! comes before Scored 10.

Use your own signals to keep the parts of a mod apart. One file fires scored. Another file listens and updates the window. Neither has to know how the other works.

The functions

FunctionWhat it does
Signal.new(name)Makes a signal. The name shows up in error messages.
signal:Connect(fn)Runs fn on every fire. Gives back a connection.
signal:Once(fn)Runs fn on the next fire only.
signal:Wait()Pauses the task until the next fire, and gives back what was fired.
signal:Fire(...)Runs every connected function with these values.
signal:FireDirect(...)The same, a little faster. The functions must not wait.
signal:DisconnectAll()Disconnects every function.
connection:Disconnect()Stops one function from being called again.
connection.Connectedfalse once the connection was disconnected.

Good to know

  • A connected function runs as a task, so it may call task.wait. With FireDirect it may not.
  • An error in one function does not stop the others. It goes to the log.

Every function is listed in the signals reference.

On this page