Client events
Stability: Stable.
These are the events the engine sends server → client. The engine's client is mode-agnostic: it just applies whatever the server sends, so your mode never ships client code to make rounds work.
You normally trigger these indirectly — the drivers and
write-exports emit them for you (e.g. spawnAll →
engine:spawn, the driver → engine:live). A custom
tick can also emit them explicitly with
announce:
exports.engine:announce(sceneId, 'engine:live')Events
| Event | Payload | Effect on the client |
|---|---|---|
engine:spawn | { point | area, team, live?, armor, loadout } | (Re)spawn with the armour/loadout — standing on point, or the air drop into area. See the payload table below. |
engine:live | — | The round is live (a flag flip — the player may still be mid-drop; the chute stays until landing). |
engine:roundEnd | result table | Egocentric banner: { won = true } → ROUND WON, { won = false } → ROUND LOST, { draw = true } → DRAW, {} (spectator) → ROUND OVER. |
engine:matchOver | result table | Same shapes: VICTORY / DEFEAT / DRAW / MATCH OVER. |
engine:spectate | targets | Spectate the given teammate server ids (list). Sent to the dead when the mode doesn't respawn them. |
engine:team | team | nil | Update the local team index (nil = not in a match). Re-fires locally as engine:teamChanged — see below. |
engine:left | — | Drop team/spectate/HUD and hand spawn ownership back to the lobby. |
engine:spawn payload
Placement comes from the battleground (battleground SDK), and
so does the entrance. The server sends exactly one of point or area — the
client applies what it is handed and never chooses:
point(the battleground declaresspawnsfor this mode) — a ground spawn: the player starts standing on the point for their seat, facingw. No parachute.area(onlyareas) — the air drop: the player appears high above the team area and parachutes down.
Either way the spawn is vulnerable from frame one (no freeze, no invincibility — on a drop the parachute itself, not invincibility, guarantees a soft landing).
| Field | Type | Notes |
|---|---|---|
point | { x, y, z, w } | The ground spawn for this player's seat (w = heading in degrees). Mutually exclusive with area. |
area | { x, y, z, r, face } | The team's air-drop area (centre + radius r to scatter in; face = heading number or 'center'). |
team | number | The player's team index (1..teamCount). |
live | boolean | true ⇒ the round is already running (a mid-round respawn); absent/false ⇒ still forming (engine:live follows). |
armor | number | Body armour (the mode's symmetric kit). |
loadout | list | { { 'WEAPON_HASH', ammo }, ... }; the first entry is auto-equipped as the primary. |
The spawn model is never in the payload: every combatant keeps the skin they
equipped in the lobby (customization), with a freemode body as the structural
fallback — appearance carries no team identity.
Listening from other client resources
engine:team re-fires locally as engine:teamChanged so other client
resources (e.g. a custom NUI menu) can track whether the player is in a match
without coupling to the engine:
RegisterNetEvent('engine:teamChanged', function(team)
-- team is the index (1..teamCount), or nil when the player returns to the lobby
end)Notes
- These events are an output contract: the engine emits them. To make a player join/leave, use the lobby contract (client → server), not these events.
- The client never auto-respawns on death — respawns are round-driven (the server
decides via
engine:spawn/ the driver).
See also
- Write-exports —
announce,spawnAll,setState. - Lobby contract — the client → server join/leave events.
- Hooks — emitting events from a custom
tick.