RivalityFX Docsrivalityfx.com ↗

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

EventPayloadWhen
engine:playerJoinedsrcThe player's engine session begins — the engine creates its Player on first contact (the first engine:lobbyOpen). Fires once per session.
engine:playerLeftsrcThe session ends (disconnect). Fired while the player is still resolvableEngine.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) → lobbymatch | 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).

EventPayloadWhen
engine:presenceChangedsrc, stateThe 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:

EventPayloadWhen
engine:playerEnteredLobbysrcThe player is now in the lobby hub (on connect, or returning from a match/spectate). Idempotent: fires only on a real change.
engine:playerLeftLobbysrcThe 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:presenceChanged and filter on state. A specific event is added only where a named consumer needs it.

Ordering

On connect: engine:playerJoinedengine: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