Event
util.event.on
SharedRegisters a handler function for the specified event
Syntax
local status = util.event.on(
name,
exec,
config = nil
)The thread instance is only available inside async handlers.
- When
async = true— handler runs inside a dedicated thread; thread can be accessed viautil.thread.current(). - When
async = false— handler runs inline on the calling thread.
On the server, handlers are local-only unless registered with remote = true.
- Local-only (default) — the handler fires for events emitted on the server itself. An event sent by a client never reaches it.
remote = true— the handler can also be triggered by clients. Inside it, variableclientholds the caller's peer id.- Built-in signals — handlers for signals such as
network:peer:joinare local-only too, unless you setremote = true. - Refer to the Event Cheatsheet for patterns.
Parameters
| Type | Name | Description |
|---|---|---|
string | name | Name of the event to subscribe to |
function | exec | Handler function to invoke when the event fires |
table | config | Configuration table Refer Config section |
Returns
| Type | Name | Description |
|---|---|---|
bool | status | true on successful registration, false otherwise |
Config
| Type | Key | Default | Description |
|---|---|---|---|
bool | async | false | • When true - runs the handler inside a dedicated thread• When false - runs the handler inline on the calling thread |
int | subscription_limit | nil | Maximum number of times this handler will fire before being automatically removed • Must be >= 1 if set• Omit for unlimited invocations |
int | priority | 0 | Determines fire order relative to other handlers on the same event • Higher values fire earlier, similar to a z-index • Handlers with equal priority fire in registration order • May be negative |
bool | remote | false | Server only. Lets clients trigger this handler • When true - events a client emits with remote = true reach this handler, and variable client holds the caller's peer id• When false - only events emitted on the server reach it, a client's events skip it• Has no effect on a client, where handlers always receive events from the server |
Callback: exec
exec(...)| Type | Name | Description |
|---|---|---|
any | ... | Arguments forwarded from the emitting call |
Variable: client
A variable the engine sets while a handler runs, so the handler can tell who triggered the event. It exists only on the server.
core.engine.print("info", client) -- peer id (int) when a client triggered the event, nil otherwise| Value | Meaning |
|---|---|
int | The event was triggered by a client. This is that client's peer id, taken from the connection, so a client cannot fake it. Only handlers registered with remote = true are ever called this way |
nil | The event was emitted locally on the server, or the code is running on a client |
- Per resource —
clientis set in the environment the handler function itself runs in. Other resources, and functions called from another resource, do not see it. Pass the peer id along as an argument if they need it. - Nested events — an event emitted locally from inside a handler sees
client = nil, and the outer handler's value is restored afterwards. - Existing global — a resource's own global named
clientis hidden while a handler runs and restored when it returns. - Async handlers — the value is only available until the handler first yields (for example on
thread:sleeporthread:await). Copy it into a local variable before the first yield.
Examples
util.event.on("on_player_join", function(player)
core.engine.print("info", "Player joined:", player)
end)util.event.on("on_buy_item", function(item)
-- `client` is the real peer id, never trust a peer id sent in the arguments
core.engine.print("info", "Peer", client, "wants to buy:", item)
end, { remote = true })util.event.on("on_round_end", function(winner)
give_rewards(winner) -- only runs when the server emits on_round_end itself
end)util.event.on("on_set_name", function(name)
if client then
name = tostring(name):sub(1, 16) -- called by a client, sanitize the input
end
set_player_name(client or 0, name)
end, { remote = true })util.event.on("on_buy_item", function(item)
local buyer = client -- copy before the first yield
util.thread.current():sleep(1000)
core.engine.print("info", "Peer", buyer, "bought:", item)
end, { async = true, remote = true })util.event.on("on_pickup_collected", function(pickup)
core.engine.print("info", "Collected:", pickup)
end, { subscription_limit = 1 })util.event.on("on_round_start", function()
local thread = util.thread.current()
core.engine.print("info", "Round started, waiting 5 seconds...")
thread:sleep(5000)
core.engine.print("info", "5 seconds elapsed")
end, { async = true })util.event.on("sandbox:draw", function()
core.engine.print("info", "Fires first - highest priority")
end, { priority = 10 })
util.event.on("sandbox:draw", function()
core.engine.print("info", "Fires second - default priority")
end)
util.event.on("sandbox:draw", function()
core.engine.print("info", "Fires last - lowest priority")
end, { priority = -10 })