Server events
Stability: Beta. Newly introduced; consumable now, but the shape (src-only
payloads, event names) may still change.
These are events the engine emits on the server event bus (TriggerEvent), so
any resource on the server can listen with AddEventHandler — they cross the
resource boundary, so a chat, stats, or announce resource can react without the
engine knowing it exists.
They are distinct from:
- Client events — server → client (what a player's screen does).
- Lobby contract — client → server (how a player joins/leaves).
- Hooks — per-mode descriptor callbacks (scene-scoped).
All payloads are src-only (the player's server id). Resolve whatever you need
yourself (GetPlayerName(src), your own per-src store). Richer context — where a
player moved — is available via engine:presenceChanged.
Player session lifecycle
| Event | Payload | When |
|---|---|---|
engine:playerJoined | src | The player's engine session begins — the engine creates its Player on first contact (the first engine:lobbyOpen). Fires once per session. |
engine:playerLeft | src | The session ends (disconnect). Fired while the player is still resolvable — Engine.playerOf(src) still returns the Player in your handler, your last chance to read final state. |
engine:playerLeft is the engine-level counterpart to FiveM's core playerDropped;
prefer it when you want the engine's own session boundary (e.g. to flush per-player
stats keyed by src).
Presence lifecycle
A player's presence is their macro location, an FSM: nil (just connected, not
yet placed) → lobby → match | spectating and back. Every transition routes
through one chokepoint (Player:setPresence), so a single event covers them all.
Note there is no room (or arena) presence: a player waiting in an arena
stays lobby (in the hub world, bucket 0) — the arena is a lobby activity
(status), not a location. They only leave lobby when the match launches
(match) or they start watching (spectating).
| Event | Payload | When |
|---|---|---|
engine:presenceChanged | src, state | The player moved to state ('lobby' / 'match' / 'spectating'). The generic primitive — filter state for the transition you care about. |
Lobby enter/leave (convenience)
The lobby hub publishes two specific events on top of presenceChanged, so a
companion resource doesn't have to filter:
| Event | Payload | When |
|---|---|---|
engine:playerEnteredLobby | src | The player is now in the lobby hub (on connect, or returning from a match/spectate). Idempotent: fires only on a real change. |
engine:playerLeftLobby | src | The player left the lobby hub (a match launched, or they started spectating, or they disconnected from the lobby). |
These are the only specific presence events today. Match and spectate equivalents are intentionally not emitted — listen to
engine:presenceChangedand filter onstate. A specific event is added only where a named consumer needs it.
Ordering
On connect:
engine:playerJoined → engine:presenceChanged('lobby') → engine:playerEnteredLobby.
On disconnect:
engine:playerLeftLobby (if they were in the lobby) → engine:playerLeft. A
mid-match disconnect tears the scene down without a presence transition, so it
does not fire a spurious playerEnteredLobby.
Example — a lobby join/leave announcer
-- a companion resource, server side
AddEventHandler('engine:playerEnteredLobby', function(src)
print(('%s entered the lobby'):format(GetPlayerName(src)))
end)
AddEventHandler('engine:playerLeftLobby', function(src)
print(('%s left the lobby'):format(GetPlayerName(src)))
end)See also
- Client events — the server → client output contract.
- Lobby contract — the client → server join/leave events.
- Hooks — per-mode descriptor callbacks.