Skip to content

Player ​

On-foot movement and state sync of players, player streaming, the life cycle (spawn, death, respawn), and the server's commands to a player: teleport, appearance, animations, styles, camera, physics and HUD values.

Player model ​

The keys bitmask ​

Frame.keys (u16) has bit i set while the key of action i is pressed. The bit order is part of the protocol.

BitAction
0forward
1backward
2left
3right
4sprint
5jump
6sneak / walk
7fire
8aim

Bits 9..15 are unused; the server keeps only bits 0..8 (player:keys()).

  • Held keys (movement, sprint, walk, aim) are sampled as their state at the moment the frame is sent, so a release goes out at once.
  • Momentary keys (jump, fire) are latched between sends and cleared on send, so a tap between two frames is not lost.
  • The aim bit is set while the sender actually aims, not only while it holds the aim key: the game enters aiming by itself when the player fires without the aim key, and receivers raise the weapon and play the shot by this bit. In a vehicle the aim bit means a passenger leaning out for a drive-by, and cam is the direction of that aim; receivers hold the drive-by pose by these two fields.
  • Crouch is not a key: it is the ducked pose of the frame. Crouching in the game is a toggle, so replaying the key would lose its parity. The sender reports its pose; the receiver brings the copy to that pose through the game's own crouch and stand-up transitions.

Player streaming ​

A player is shown to another player only when both are in the same world scope (virtual_world + interior, as for pickups and vehicles) and within distance. The scope itself is not on the wire. The server is the authority: it keeps a per-recipient set of shown players; the client only creates and removes the copy of a player. Decision: ADR 0035.

  • Distance is measured from the recipient's stream center (its body, or its camera while the camera is not its own, see SetCamera) to the server's position of the player: shown within 420 m, hidden 40 m beyond that. This covers the longest hitscan ray (400 m): a shot does not go to a player the shooter is not shown to. A weapon range set by the gamemode extends the show distance to the ray of that range (range × 3) + 20 m.
  • A seated player is shown exactly when its vehicle is shown (VehicleSync, 200 m; the recipient's own vehicle is always shown), not by its own distance. Shots from a vehicle do not reach past the vehicle's radius. Showing and hiding a vehicle that has other players inside, together with those players, is one transition: the players first, then the vehicle and its seats. A hide stops the relays at once, and its packets go out together once the queue has room; a show that lacks room waits as a whole and goes after the hides not yet sent.
  • A spectate target (SetCamera mode = 2) is shown at any distance.
  • A label or a blip attached to a player is shown only while the player is shown.
  • The resource events player_stream_in(player, for_player) and player_stream_out(player, for_player) fire on every change of the set, scope changes included: they report the server's decision, not the creation of a copy on the client. A disconnect does not fire them (player_disconnect does).
  • Packets about a subject go only to recipients it is shown to: RemotePlayerSync, RemoteWeaponShot, RemoteProjectileCreate, RemoteSatchelDetonate, PlayerWasted, PlayerSpawned. RemoteStealthKill also goes to both participants; PlayerSkills and the animation packets also go to the subject itself. PlayerLeave goes to everyone; ChatMessage goes to everyone or to the recipients the gamemode picked (send_chat), regardless of streaming.
  • Show (on entering range, or a scope change of either side) is a snapshot on the reliable event lane: PlayerSkills, PlayerNametag, and the current ApplyAnimation with elapsed_ms, if one is playing. The client creates the copy on the next RemotePlayerSync; a dead subject appears as a corpse.
  • Hide is PlayerStreamOut. Death and respawn of the subject while it is hidden do not go to the recipient: a new show always builds the copy anew from a living frame.
  • Show and hide are droppable events: when the queue is full, the streaming reconcile (every 1 s) repeats them. Relays about the subject stop at once, whatever the queue. A show counts only once its whole snapshot is queued, and waits for a hide not yet sent: on the lane a hide always precedes the next show.
  • A seated player is always in its vehicle's scope. A change of virtual_world or interior (TeleportPlayer to another area) first frees the seat: VehicleOccupancy exit precedes TeleportPlayer in the player's stream, and the client leaves the vehicle instantly on an area change. The vehicle stays in its scope. A server-side seating into a vehicle of another scope is refused.

Packets ​

PlayerSync (0x03) ​

Client → Server, unreliable. The owner's movement, input and observed state. The payload after seq is the Frame, a fixed 102-byte structure; RemotePlayerSync carries the same Frame layout. Inside the Frame, the input is keys plus the ducked pose. The name of a player is never in a frame: it rides PlayerNametag.

The owner sends a frame at once when any of these change, and otherwise as a heartbeat every 100 ms; changes are sampled about every 16 ms:

  • keys or ducked;
  • move_state, so that tiring from sprint to run while the sprint key stays held goes out at once;
  • on_ground, because a step off a low ledge with unchanged input can start and end between heartbeats;
  • hp or armor, so damage reaches the others within a frame;
  • weapon, state, clip or total, so clip use and the start and end of a reload are timely;
  • special_action, jet_thrust or jet_stop (the jetpack controls are not in keys).
[u8  packet_id = 0x03]
[u64 session_token]     // the token from ServerHello; a mismatch drops the packet
[u32 seq]               // monotonic per connection; stale and out-of-order frames are dropped
[f32 x]                 // ─┐ Frame (102 bytes): world position
[f32 y]
[f32 z]
[f32 yaw]               // body heading, degrees
[u16 keys]              // the keys bitmask, see "The keys bitmask"
[u8  ducked]            // 1 crouched (a pose, not a key)
[f32 cam_x]             // aim direction, unit world vector
[f32 cam_y]
[f32 cam_z]
[f32 vel_x]             // body velocity, world units per physics step (50 steps per second)
[f32 vel_y]
[f32 vel_z]
[f32 shift_x]           // animation-driven displacement in the body's frame: x strafe
[f32 shift_y]           //                                                     y forward
[u8  move_state]        // actual speed band: 0 unset, 1 still, 4 walk, 5 jog, 6 run, 7 sprint
[u8  on_ground]         // 1 standing on ground, 0 in the air (jump, step off, fall)
[f32 hp]                // the owner's health as its game shows it
[f32 armor]             // the owner's armor as its game shows it
[u8  alive]             // 1 alive, 0 dead
[u16 death_epoch]       // life generation within the connection; the relay carries the server's
[u8  weapon]            // held weapon type (0 = unarmed)
[u8  state]             // weapon state: 0 ready, 1 firing, 2 reloading, 3 out of ammo, 4 melee hit landing
[u16 clip]              // rounds in the clip
[u16 total]             // total rounds of the held weapon
[f32 cam_yaw]           // the sender's camera orientation for movement controls, radians
[u16 weapon_rev]        // last applied inventory revision
[u8  parachute_stage]   // 0 none, 1 skydive, 2 open, 3 canopy
[u8  paused]            // 1 while the sender's game menu is open
[u8  on_fire]           // 1 while the sender's body burns
[u8  special_action]    // 0 none, 1 jetpack, 2 hands up, 3 phone, 4..7 dance styles 1..4, 8 carry
[u16 special_rev]       // last taken SetSpecialAction revision
[i8  jet_thrust]        // ─┐ jetpack controls after the sender's input step, 0 without a jetpack:
[u8  jet_stop]          //  │ thrust -1 down / 0 / 1 up, stop,
[f32 jet_strafe]        //  │ strafe -3..3,
[f32 jet_angle]         // ─┘ thrust angle, radians
[u16 aim_target]        // player id under the sender's aim, 0xFFFF none (Client → Server only)
[u16 physics_rev]       // last applied SetVelocity / SetGravity revision (Client → Server only)
[u16 vital_rev]         // revision of the last health / armor command taken (Client → Server only)
[u32 damage_seq]        // seq of the last DamageReport sent (Client → Server only)

Total: 115 bytes (1 + 8 token + 4 seq + Frame 102). The sender is identified by its address and session_token; there is no player id in the packet.

Example: player_sync.bin.

Admission ​

  • PlayerSync is dropped until the player has been granted its connect spawn (SpawnPlayer).
  • The server applies and relays a frame only if seq is newer than the last accepted one from this connection (serial number arithmetic on the wrapping u32). A duplicate or overtaken frame is dropped whole, so it cannot roll back paused, the position or the life state.
  • A non-finite float fails decoding (strict decoding).
  • A frame is dropped if its position is outside the world (|x|, |y| ≤ 6000, z in -200..=4000), parachute_stage > 3, special_action > 8 or jet_thrust outside -1..=1.
  • The server takes the position and the pose (heading, move_state, crouch) only from the frame of a living player (alive both on the server and in the frame). A living player's position is held to what the body could have covered since the previous frame (the movement check, see physics_rev below).
  • While the player has world bounds (SetWorldBounds), an on-foot position beyond an edge counts as on the edge, without velocity outward through that edge and without shift, before the movement check and every other reader. A seated player's frame is not touched: the vehicle is held by its driver's bounds (VehicleFrame). A teleport or new bounds that leave the body outside start the movement check from the edge.
  • While the player is frozen, SetFrozen rules apply.

Fields ​

The owner fills every field from its own game. The relay column is what RemotePlayerSync carries.

FieldRelay value
x, y, zThe owner's, after world bounds, freeze and the movement check. While the server holds the player dead: the server's last position of the player.
yaw, ducked, move_state, on_ground, shift, cam_yaw, parachute_stage, weapon_rev, special_revThe owner's.
keysThe owner's; 0 while paused or frozen; the fire bit is cleared for a weapon that uses ammo when the server's inventory has none.
camNormalized by the server.
velThe owner's, capped to a length of 5 units per step (250 m/s).
hp, armorThe server's ledger, not the owner's values.
alive, death_epochThe server's life state and generation.
weapon, clip, totalFrom the server's inventory: the frame's weapon if it is in the inventory (or 0), otherwise the last confirmed one; clip and total from the inventory.
stateThe owner's; a value above 4 becomes 0.
paused, on_fire, special_actionThe server's value.
jet_*With the jetpack: the owner's, jet_strafe clamped to ±3 and jet_angle to ±1.5; otherwise 0.
aim_targetAlways 0xFFFF.
physics_rev, vital_rev, damage_seqAlways 0.

Position, velocity and on_ground. A receiver writes vel into the copy once per new packet and lets the game's physics move it. The position error is corrected gradually on top of the physics, not overwritten; a large 3D error teleports the copy. Height depends on on_ground: with on_ground = 1 the receiver corrects only x and y and leaves z to the game (jumps and gravity play natively; a near-zero vel.z on the ground would suppress the start of a fall); with on_ground = 0 it applies the full x, y, z, so a fall or a step off a ledge that started on the sender carries its real vertical speed instead of waiting for the copy's own gravity.

keys and move_state. A receiver replays keys on the copy to animate actions (jump, fire, aim, weapon pose). move_state is the sender's actual speed band, including fatigue (sprint drops to run while the sprint key is held): the receiver gates the copy's sprint by move_state, not by the sprint key, and the copy does not tire on its own.

shift. Carried but not applied by receivers. The strafe component x cannot be derived from keys while armed; on foot without a weapon x is about 0 and y is the forward motion.

cam and cam_yaw. cam is the sender's aim direction; the copy aims along it. cam_yaw is the orientation of the sender's camera that the game's on-foot movement is relative to (movement direction = stick angle − camera orientation). A receiver moves the copy relative to the sender's cam_yaw, not its own camera; otherwise the copy would walk sideways.

hp and armor. The owner reports the health and armor its game shows; damage to the owner is applied by the owner's game. The server clamps them to 0..=200, lowers its own ledger by them (Health accounting and death) and relays its ledger. A receiver shows these values on the copy every tick, and damage the receiver's own game deals to the copy is undone: a copy takes no local damage. The server never relays a lethal hp while it holds the player alive (a death commits through DeathReport or the server's ledger); otherwise a frame with alive = 1, hp <= 0 could overtake the commit and the copy would collapse without its death.

vital_rev and damage_seq. The owner captures them together with hp and armor: vital_rev is the revision of the last health / armor command it took (applied, or dropped because the player was dead), damage_seq is the seq of the last DamageReport it sent. With them the server takes the frame in the client's order (see Health accounting and death). The relay carries 0.

alive and death_epoch. These are the life state, not the death and respawn edges: the edges ride the reliable events DeathReport, PlayerWasted and PlayerSpawned (ADR 0017). alive serves late joiners and recovery (a new receiver learns that a player is already dead and shows it as a static corpse) and tells receivers to stop replaying the copy's input. A fresh death is played by PlayerWasted, a new copy is built by PlayerSpawned. death_epoch is the life generation within the connection, incremented on respawn and independent of player_token; it serves correlation, not ordering. The owner can report its own death but cannot revive itself: the server stamps its own alive and death_epoch into the relay, and revival is server-gated through RespawnPlayer (ADR 0045). Reordering is closed by seq.

weapon, state, clip, total. The owner reports the held weapon, its state and its ammo. A receiver equips the copy with that weapon when the type changes and mirrors state, clip and total every tick, so the copy reloads in step with the real player. These fields carry only the look of the weapon and its ammo: bullets and damage ride WeaponShot.

weapon_rev. The server keeps the player's weapon inventory and a revision incremented on every weapon change it makes (ADR 0024). The client echoes the revision of the last weapon command it applied successfully, in reliable lane order; the value only grows, and a failed apply does not advance it. The server reconciles its inventory with the frame's observation only when the echo equals its current revision: the armed weapon only within the inventory, ammo only downward. A frame that overtook an in-flight change is ignored, so a frame cannot lower the inventory early, and a client cannot grant itself weapons or ammo through a frame. Receivers do not use it.

Ammo of continuous weapons. The flamethrower, the spray can and the fire extinguisher with fire held spend at least 10 rounds per second of holding from the server's inventory, whatever the frame shows.

parachute_stage. The sender's parachute stage, owned by the sender (latest wins, tolerant of loss). The server relays it without interpretation. A receiver plays the same stage animations and the canopy on the copy; the pose variant (bank, steer, brake) follows the replayed keys, and the descent rides the normal velocity sync (on_ground = 0, vel.z). A receiver treats a value above 3 as 0. The death or removal of the copy ends the stage.

paused. 1 while the sender's game menu is open. The sender's world keeps running under the menu, so the motion in the frame is real while the input is neutral (keys = 0). The server keeps the last accepted value as the player's pause state (player:is_paused(), event player_pause(player, paused) on change) and relays it. A change is accepted at most once per second. A paused frame has its keys zeroed before every consumer (fire, animations, relay); an accepted transition into pause releases the keys at once. A receiver shows an AFK mark above the name tag. The vehicle of a paused driver is driven by its syncer (VehicleSyncer).

on_fire. 1 while the sender's body burns, whatever lit it (SetOnFire, a molotov, a flamethrower, touching a burning body). The server keeps it (player:is_on_fire()) and relays its own value. It is accepted only from a living body: a frame of a dead player or from the respawn window counts as 0 at once, and a respawn grant clears it. A change between 0 and 1 counts at most once per second; faster changes keep the previous value. PlayerSpawned clears the receiver's copy of the previous life until the next RemotePlayerSync. A receiver keeps the copy burning exactly while the bit is set: the fire has no author and does not spread, does not burn out early, and goes out at 0. Only the victim counts fire damage (the copy takes none). A false bit sets fire, without an author, to those right next to the copy: environmental damage, as touching a burning body in the game.

special_action, special_rev, jet_*. The special action is owned by the server and set by the gamemode (SetSpecialAction):

ValueAction
0none
1jetpack
2hands up (stands still)
3phone (walks with a phone at the ear)
4..7dance styles 1..4 (dances in place; direction keys play moves, and copies play them from the frame's keys)
8carry (walks as if carrying a load, no sprint or jump: the owner's client keeps both out of the game and out of keys)

The frame carries what the sender's body shows and the echo of the revision of the last SetSpecialAction taken (applied or refused: a dead or seated player does not take an action). The owner can only end an action (its game ended it: the jetpack dropped with the enter key, entering a vehicle): the server clears it on a frame of a living player with special_action = 0 and the current echo. A frame that overtook a SetSpecialAction, or a frame claiming an action, changes nothing. A receiver keeps the copy in the same action while the relay carries it and the copy is alive and on foot; it flies the jetpack by the jet_* fields and the frame's heading, not by its own input. PlayerSpawned clears the copy of the previous life until the next RemotePlayerSync.

aim_target. The sender's claim of the player under its aim. The server accepts it only if the target is alive, shown to the sender and no farther than 10 m + the target's speed × 0.5 s from the sender's camera ray, and the sender is alive, not paused and not frozen; otherwise there is no target and the frame still stands. The server remembers the target with its token. player:target() reads it, and on reading the target (same token, alive, shown) and the sender (alive, not paused, not frozen) are checked again. The relay carries 0xFFFF.

physics_rev. The revision of the last SetVelocity / SetGravity the client applied (or dropped by its own rules), in reliable lane order. The relay carries 0.

  • The server accepts an echo only if it is newer than the previous one and not newer than the last revision sent, and then takes, in order, what the commands up to it change: the throw allowance and the gravity of the movement check, and RemotePlayerSync.gravity.
  • A throw was applied at some moment between its sending and an upper bound: the echo, or without one, the ClientAck of its event + 1 s (the client's apply window; the ack only bounds delivery from above). A throw sets the body's velocity rather than adding to it, and the client applies throws in order, so each throw ends the earlier ones at its own upper bound.
  • Beyond the normal movement limits, a frame is allowed the distance the body could have covered since the previous frame moving, at each moment, no faster than the fastest throw possible at that moment. A throw's window runs from its sending to its upper bound + 4 s (a body in the air barely slows); the horizontal and vertical excess combine as the legs of a right triangle. A frame with the echo may therefore show the path of lost frames.
  • Unused allowance carries over to the next frame, at most 0.25 s at the current speed (frames arrive unevenly); after a frame with the echo, the path of an earlier, faster throw does not accumulate.
  • Each throw grants at most its speed × 4 s in total; up to 8 throws are tracked at once, a newer one evicting the earliest.
  • A command counts as applied without an echo 2 s after its ClientAck or 15 s after sending (the stall limit of the reliable lane): its gravity takes effect, a throw grants its speed.
  • Throws not echoed by a teleport, a respawn or entering a vehicle are discarded.
  • At most 32 commands may await their echo; beyond that the gamemode's call is refused with "queue full".
  • Gravity below the game's own does not change the allowed rise speed and lengthens the allowed time in the air to 4 s / (g / 0.008); at g <= 0 hovering is unlimited and the rise is held to 12.5 m/s.

Server reads and events ​

  • From the frame of a living player the server keeps the velocity (player:velocity(), m/s, at most 250 long), ducked, on_ground, the camera direction (player:camera_front(), normalized; a zero direction is not taken) and keys (bits 0..8 only, player:keys()).
  • Freezing and death release the keys and the aim target on the server: the release event fires once, with the next frame or server pass. Unfreezing restores nothing until a fresh frame.
  • player_key_change(player, key, pressed) fires for every changed key; the next change of the same key counts after 50 ms. A held-back change arrives with the next frame, so a release is never lost and a one-frame press arrives later as a press and a release.
  • player_weapon_reload(player, weapon) fires at the start of a reload (state = 2) of a non-melee weapon the player holds by the inventory, with ammo, in a frame of the current life and the current weapon_rev, while the player is in control (not paused, not frozen), at most once per 250 ms.
  • player_state_change(player, state, previous) and player_interior_change(player, interior, previous) are computed by the server from its own state at most 20 times per second; a change and its reversal within one pass produce no event.

RemotePlayerSync (0x04) ​

Server → Client, unreliable. The server relays a player's frame to the players it is shown to (Player streaming), adding the server-owned appearance and styles.

[u8  packet_id = 0x04]
[u32 player_id]
[u32 player_token]     // the sender's generation: guards against a reused player_id
[u32 seq]              // relayed from PlayerSync; the receiver drops stale and out-of-order frames
[f32 x]                // ─┐ Frame (102 bytes), with the relay values of PlayerSync
[f32 y]
[f32 z]
[f32 yaw]
[u16 keys]
[u8  ducked]
[f32 cam_x]
[f32 cam_y]
[f32 cam_z]
[f32 vel_x]
[f32 vel_y]
[f32 vel_z]
[f32 shift_x]
[f32 shift_y]
[u8  move_state]
[u8  on_ground]
[f32 hp]               // the server's ledger
[f32 armor]            // the server's ledger
[u8  alive]            // the server's life state
[u16 death_epoch]      // the server's life generation
[u8  weapon]           // from the server's inventory
[u8  state]
[u16 clip]             // from the server's inventory
[u16 total]            // from the server's inventory
[f32 cam_yaw]
[u16 weapon_rev]       // not used by receivers
[u8  parachute_stage]
[u8  paused]           // the server's value
[u8  on_fire]          // the server's value
[u8  special_action]   // the server's value
[u16 special_rev]      // not used by receivers
[i8  jet_thrust]       // ─┐ 0 without a jetpack
[u8  jet_stop]         //  │
[f32 jet_strafe]       //  │
[f32 jet_angle]        // ─┘
[u16 aim_target]       // always 0xFFFF
[u16 physics_rev]      // always 0
[u16 vital_rev]        // always 0
[u32 damage_seq]       // always 0 ─┘
[u32 skin]             // the player's model id, set by the server
[u16 variant]          // appearance variation, see SetSkin
[u8  walk_style]       // walking style, see SetWalkingStyle (0 = default)
[u8  fight_style]      // fighting style, see SetFightingStyle
[u8  headless]         // 1 head hidden, see SetHeadless
[u32 damage_group]     // the sender's damage group
[u32 relation_rev]     // revision of the relation
[u8  teammate]         // 1: the sender is a teammate of THIS recipient
[f32 gravity]          // the sender's body gravity, see SetGravity

Total: 137 bytes (1 + 4 + 4 + 4 + 102 + 4 + 2 + 1 + 1 + 1 + 4 + 5 + 4). The server adds the authoritative player_id, the generation player_token, the relayed seq, skin, variant and the stored walk_style, fight_style, headless, damage_group with the relation (Damage groups and relations) and gravity, so copies and late joiners converge on these without a broadcast. There is no name in the frame: it rides the PlayerNametag of the show and of every rename. A gravity outside |g| <= 0.1 or non-finite fails decoding. The receiver is generation-aware (see Sequence and generation). For what a receiver does with each Frame field, see PlayerSync.

Example: remote_player_sync.bin.

PlayerStreamOut (0x45) ​

Server → Client, reliable event lane. The player is no longer shown to the recipient (Player streaming); its session goes on.

[u8  packet_id = 0x45]
[u32 player_id]
[u32 player_token]     // the subject's generation
[u32 event_id]         // position in the per-recipient reliable stream
[u32 last_seq]         // seq of the subject's last RemotePlayerSync sent to the recipient (0: none)
[u32 last_shot_order]  // order of the subject's last accepted shot or ray before the hide (0: none); the next show carries only greater ones

Total: 21 bytes. The recipient removes the copy and the subject's state as on PlayerLeave, but without a tombstone:

  • A RemotePlayerSync of the same generation with seq <= last_seq (signed comparison, survives wrap) is a late frame and is dropped; a newer one means a show and creates the copy anew. A frame of an older generation is dropped.
  • PlayerStreamOut is ignored if a newer generation of id has already been accepted.
  • If a frame of the same generation newer than last_seq has already been accepted (frames of the next show overtook the hide on the reliable lane), the generation stays live, but the copy is rebuilt from a living frame: death and respawn during the hide have not reached the recipient.
  • In both cases the hide at once discards everything pending for the subject (death pose, animations, projectiles, stealth kill); the snapshot of the next show follows it on the lane.
  • Shots and volleys are not on the lane, so their boundary is last_shot_order: stored ones with order up to it are discarded and the order mark is raised to it (a late shot of the previous show is dropped); newer ones belong to the next show and stay. A shot of the previous show that overtook the hide itself is applied before it, on the copy of the same show: the new copy is built only when the hide is processed. Its damage is bounded by the window and the geometry of DamageReport.

Example: player_stream_out.bin.

RespawnRequest (0x0C) ​

Client → Server, unreliable. A dead player asks to be respawned. It sends it on a timer, repeating while dead. This is only a request: the server decides eligibility and timing by its policy (see RespawnPlayer); the client does not revive until RespawnPlayer arrives.

[u8  packet_id = 0x0C]
[u64 session_token]       // the sender's token; a mismatch drops the packet

Total: 9 bytes. The server identifies the player by address and session_token. A request from a living player, from a player that has not completed its connect spawn, or before the server's minimum time dead has passed is ignored. The request is idempotent: repeats before the grant are safe.

Example: respawn_request.bin.

RespawnPlayer (0x0D) ​

Server → Client, unreliable. A respawn grant with the spawn point, sent to one player when it passes the respawn policy (eligibility and timing are server configuration), as the answer to its RespawnRequest. On receipt the client revives its player at the point and sends alive = 1 again, but the server owns the life state: it stamps alive and death_epoch into the relay, and the new generation commits with the grant and the client's first confirming alive = 1 frame. A client cannot fake a respawn through PlayerSync; a death stays reported by the victim.

[u8  packet_id = 0x0D]
[f32 spawn_x]             // spawn position
[f32 spawn_y]
[f32 spawn_z]
[f32 heading]             // facing, radians
[i32 area]                // interior of the point, 0..=255 (0 = outside)

Total: 21 bytes. The client drops the packet if a number is non-finite or area is outside 0..=255. The spawn point comes from the server's spawn policy (ADR 0012); it is the same point the connect SpawnPlayer uses unless the gamemode overrides it. RespawnPlayer goes only to the respawning player. The other clients rebuild its copy from PlayerSpawned, which the server broadcasts on the same grant, not from this packet or the Frame. The client sets area, waits for the point's collision and map to load and places its player the same way as on TeleportPlayer. On the grant the server moves the player's interior scope to the point's area and reconciles streaming; the virtual world stays.

Example: respawn_player.bin.

PlayerSkills (0x10) ​

Server → Client, reliable event lane. A full snapshot of a player's 11 weapon skills.

[u8  packet_id = 0x10]
[u32 id]               // subject player_id
[u32 player_token]     // subject generation (guards against a reused id, as in RemotePlayerSync)
[u32 event_id]         // position in the per-recipient reliable stream
[u16 skills[11]]       // weapon skill values, 0..1000

Total: 35 bytes. Weapon skills are server-authoritative: the client applies the values and never raises a skill itself. The skill of a weapon picks its tier (poor, standard, pro) in the game. Slots:

SlotWeapon types
022 pistol
123 silenced pistol
224 desert eagle
325 shotgun
426 sawn-off shotgun
527 combat shotgun
628 micro SMG, 32 Tec-9
729 SMG
830 AK-47
931 M4
1033 country rifle, 34 sniper rifle

Skills are slow server state and are not in the Frame. Recipients are the subject and the players it is shown to; a show of the subject carries its snapshot (Player streaming).

Example: player_skills.bin.

SetWanted (0x11) ​

Server → Client, reliable event lane.

[u8  packet_id = 0x11]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  level]            // wanted level 0..6

Total: 6 bytes. The server owns the player's wanted level and sends it only to that player: it is the recipient's own state, not a look of its copy, so there is no subject id or token. The server validates 0..6 before sending. The client applies level and re-asserts it on its player every frame, so the game's own writes do not move it; the game's own wanted-level triggers are disabled on the client, so the game never sets the level itself.

Example: set_wanted.bin.

TeleportPlayer (0x15) ​

Server → Client, reliable event lane. Teleports the recipient's own player; there is no subject id or token.

[u8  packet_id = 0x15]
[u32 event_id]         // position in the per-recipient reliable stream
[f32 x][f32 y][f32 z]  // world landing point
[f32 heading]          // heading, degrees
[i32 area]             // the game's area code (interior) of the destination, 0..=255
[u8  ground]           // 1: the client ignores z and puts the player on the ground under x, y once its collision loads

Total: 26 bytes.

  • The client drops the packet if a position or heading value is non-finite, area is outside 0..=255 (the server refuses such a teleport too) or ground is neither 0 nor 1.
  • The client teleports its player, sets the area and waits for the destination's map and collision to load. Latest wins: a new teleport overrides one not yet applied.
  • With ground, the server treats z as a guess until a client frame arrives within 25 m horizontally of the point with on_ground = 1: the client sets the landing height. The server waits for the landing 30 s from the packet's ClientAck, the client 25 s from receiving it. Until the ground is found the client holds the player in the air above the point and its frames carry on_ground = 0; if it finds none it uses z from the packet.
  • For the server, area is the destination interior: a teleport also moves the player's interior scope to area and reconciles streaming (pickups, vehicles and players of the old scope go away, those of the new one arrive; a seated player changing interior is first taken out of the vehicle, see Player streaming). On the wire this shows only as the normal streaming changes and, on a scope change, ScopeChanged.

Example: teleport_player.bin.

SetSkin (0x20) ​

Server → Client, reliable event lane. Sets the model and appearance of the recipient's own player; there is no subject id or token.

[u8  packet_id = 0x20]
[u32 event_id]         // position in the per-recipient reliable stream
[u32 model]            // player model id, from the server's catalog of allowed skins
[u16 variant]          // appearance variation, >= 1

Total: 11 bytes.

  • The server validates model against its catalog of allowed skins (regular characters and special story characters share one numeric pool) and requires variant >= 1; variant has no per-model range and is opaque. The client checks model against the same catalog before applying it.
  • The same model and variant give the same look on every client. A variant of 0 would let each client pick its own random variation, so it is never sent.
  • Model 0 is the default player character with its default clothes; the client ignores variant for it (its look comes from the clothing system, which is not synced).
  • The other players see the new look through RemotePlayerSync (skin, variant).

Example: set_skin.bin.

SetMoney (0x28) ​

Server → Client, reliable event lane. The recipient's own money; sent only to that player, there is no subject id or token.

[u8  packet_id = 0x28]
[u32 event_id]         // position in the per-recipient reliable stream
[i32 amount]           // absolute balance, -999_999_999..=999_999_999

Total: 9 bytes. The range is a sanity bound of the protocol, not a limit of the game. The client sets its player's balance to amount and re-asserts it every frame, so the game's own money changes (taxi fares, money pickups, death, arrest, hospital) do not move it; the HUD counter rolls to the new value. Other clients never see a player's money.

The server stores the balance: it survives death and respawn; a new connection starts at 0, and a disconnect resets it. There is no baseline at connect: a fresh connection shows 0 until the first SetMoney, which carries only changes made while the player is connected. The gamemode sets the balance absolutely (range-checked) or relatively (the result clamped to the range).

Example: set_money.bin.

DeathReport (0x1B) ​

Client → Server, on the client's reliable event lane (the same stream as ClientChat and ClientCommand). The victim reports its own death and its death pose (ADR 0017).

[u8  packet_id = 0x1B]
[u64 token]            // session_token
[u32 event_id]         // position in the sender's reliable stream
[u8  weapon]           // means of death, 0..=54
[u16 anim_group]       // animation group of the death animation
[u16 anim]             // animation id of the death animation

Total: 18 bytes. The dying client reports the death the game picked for its player. The server commits the death into its life state (only for a spawned living player, once per life) and sends PlayerWasted to the players it is shown to. A death the server has already committed from its ledger is not committed again by the report. This is the death edge; the life state (alive) stays in the Frame.

The pose must be one the game produces: weapon 0..=54, and either group 0 with anim 15..20, 22..27, 36, 39, 140 or 191, groups 33..43 with anim 219..221, or group 87 with anim 352. The server replaces any other pose with the default (0, 0, 15), and so does a receiver of PlayerWasted.

Example: death_report.bin.

PlayerWasted (0x1C) ​

Server → Client, reliable event lane. Broadcast of a death and its pose (ADR 0017).

[u8  packet_id = 0x1C]
[u32 id]               // subject player id
[u32 player_token]     // subject generation (a reused id does not apply to another player)
[u32 event_id]         // position in the per-recipient reliable stream
[u8  weapon]           // means of death
[u16 anim_group]       // death animation group
[u16 anim]             // death animation id

Total: 18 bytes. The server builds it from an accepted DeathReport or from a death it committed itself (Health accounting and death). A receiver plays this death with this pose on the subject's copy; this is the edge of a fresh death. It is not sent to the victim, which played its death locally.

Example: player_wasted.bin.

PlayerSpawned (0x1D) ​

Server → Client, reliable event lane. Broadcast of a respawn (ADR 0017).

[u8  packet_id = 0x1D]
[u32 id]               // subject player id
[u32 player_token]     // subject generation
[u32 event_id]         // position in the per-recipient reliable stream
[f32 spawn[3]]         // spawn position
[f32 heading]          // heading, radians
[u32 sync_seq]         // the subject's last accepted PlayerSync seq at the grant

Total: 33 bytes. A non-finite position or heading fails decoding. A receiver rebuilds the subject's copy at spawn / heading. The server sends it to the players the subject is shown to, once per accepted respawn grant (the same point as in RespawnPlayer); a repeated RespawnRequest in the respawn window does not duplicate it, the reliable lane retransmits it until acked. The respawning player itself gets RespawnPlayer.

sync_seq is the barrier of the previous life: the receiver raises the generation's seq mark to it (if the generation's first frame has not arrived yet, the mark waits for it), so a late RemotePlayerSync of the previous life overtaken by this event is dropped.

Example: player_spawned.bin.

RequestSpawn (0x29) ​

Client → Server, unreliable. A connected player that has not spawned asks for its connect spawn (ADR 0022). It sends it on a timer, repeating until SpawnPlayer arrives, as with RespawnRequest. The client's retry makes spawn delivery reliable without the reliable lane, whose receive state resets on reconnect.

[u8  packet_id = 0x29]
[u64 session_token]       // the sender's token; a mismatch drops the packet

Total: 9 bytes. The server identifies the player by address and session_token. The connect spawn is gated by the gamemode (ADR 0023):

  • The server answers with SpawnPlayer only while the connect spawn is not yet confirmed (alive, spawn pending, not respawning) and the gamemode has set the spawn info with spawn_player.
  • Until the gamemode spawns the player, the request grants nothing, but its session_token is validated and keeps the player alive on the server, so the repeating request also serves as a keepalive while the player picks a skin or logs in.
  • After the gamemode sets the spawn info, a repeat before confirmation grants again idempotently (covering a lost SpawnPlayer).
  • After the first living PlayerSync, and during death and respawn, the request is dropped: it is not a second spawn path (death and respawn use RespawnRequest / RespawnPlayer).
  • The grant marks the player spawned; from then on PlayerSync is accepted.

Example: request_spawn.bin.

SpawnPlayer (0x2A) ​

Server → Client, unreliable. The connect spawn grant: the answer to RequestSpawn, carrying the spawn info the gamemode set with spawn_player (ADR 0023). The client creates or teleports its player here and applies the appearance.

[u8  packet_id = 0x2A]
[f32 spawn_x]             // spawn position
[f32 spawn_y]
[f32 spawn_z]
[f32 heading]             // facing, radians
[i32 area]                // interior of the point, 0..=255 (0 = outside)
[u32 skin]                // the player's model id, set by the server
[u16 variant]             // appearance variation, see SetSkin

Total: 27 bytes. The client drops the packet if a position or heading value is non-finite or area is outside 0..=255, and places its player as on RespawnPlayer. On the grant the server moves the player's interior scope to the point's area and reconciles streaming. The gamemode sets the point and skin / variant in spawn_player (usually the point from the spawn policy, ADR 0012). The gamemode API takes the heading of a spawn point in degrees; SpawnPlayer, RespawnPlayer and PlayerSpawned carry it in radians. The packet goes only to the spawning player; the other clients create its copy from the normal RemotePlayerSync after its first PlayerSync.

Example: spawn_player.bin.

ApplyAnimation (0x2B) ​

Server → Client, reliable event lane. Plays a named animation on a player. It goes to the subject and to every player it is shown to: a recipient with id equal to its own applies it to its own player, the others to the subject's copy. The gamemode triggers it (apply_animation); there is no Client → Server packet.

[u8  packet_id = 0x2B]
[u32 id]               // subject player id
[u32 player_token]     // subject generation (a reused id does not apply to another player)
[u32 event_id]         // position in the per-recipient reliable stream
[u8  lib[32]]          // animation library name, NUL-padded ASCII (≤ 31 chars, case-insensitive on the client)
[u8  name[32]]         // animation name, NUL-padded ASCII (≤ 31 chars)
[f32 delta]            // blend-in rate (4.1 is the usual value); finite, > 0 (checked by the server)
[u8  flags]            // bit0 loop, bit1 lock_x, bit2 lock_y, bit3 freeze, bit4 dont_interrupt, bit5 retain_state
[u32 time]             // ms; 0 = to the end (or endless with loop); ≤ 600000 (checked by the server)
[f32 speed]            // playback rate (1 = the authored pace); finite, 0..=10, otherwise dropped
[u32 elapsed_ms]       // 0 = fresh apply; > 0 = replay on show: the time already played

Total: 94 bytes. A non-finite delta fails decoding.

  • Authority. The server owns the trigger; the client only applies. The server checks only the form (it has no catalog of animations); a client silently ignores an unknown lib / name. The server API refuses apply and clear for a player that has not spawned (PlayerNotSpawned) or is dead (PlayerNotAlive).
  • Stored state. The server keeps the current animation per player (start time, speed, parameters). A show of the subject (Player streaming) carries a replay stamped with elapsed_ms, and the receiver advances the animation to the equivalent progress.
  • Flags. dont_interrupt: the client does not cancel the animation on movement and the game does not interrupt it; the subject's pending reactions to game events are cleared on apply. retain_state (crouch only): if the subject was crouched at apply, it crouches again when the animation ends (copies follow through the owner's ducked). freeze ignores time entirely: the frozen pose holds until an explicit clear or death, the stored state does not expire and is replayed on show indefinitely.
  • What ends the stored state: ClearAnimations, death (the death animation replaces it on every client), disconnect, the server's mirror of the movement cancel (by the subject's Frame.keys, for an interruptable non-freeze animation), and the expiry of a timed non-freeze animation: with time > 0 and no freeze the animation ends on clients at start
    • time, so after that moment the server neither reads, rewinds nor replays it. A non-loop non-freeze animation with time = 0 ends at its authored length, which the server does not know; it converges through the movement mirror or an explicit clear. The state does not survive a respawn.
  • Client behavior.
    • A non-freeze replay with elapsed_ms >= time (for time > 0) is dropped (it expired between the server building the replay and its delivery).
    • An animation whose data is not loaded yet waits in a per-player slot (latest wins, about 5 s to load).
    • An animation for a known player whose copy does not exist yet waits in the slot until the copy appears.
    • Movement cancels an interruptable non-freeze animation on every client the same way: on the subject's own client by its live input, on copies by the replayed frame keys. freeze and dont_interrupt hold until ClearAnimations.

Example: apply_animation.bin.

ClearAnimations (0x2C) ​

Server → Client, reliable event lane. Stops a player's named animation; addressed like ApplyAnimation (the subject and the players it is shown to). The client stops only the named animation, not other actions of the player; a clear without a playing animation does nothing. It also cancels an animation still waiting in the slot.

[u8  packet_id = 0x2C]
[u32 id]               // subject player id
[u32 player_token]     // subject generation
[u32 event_id]         // position in the per-recipient reliable stream

Total: 13 bytes.

Example: clear_animations.bin.

SetWalkingStyle (0x2D) ​

Server → Client, reliable event lane. The walking style of the recipient's own player; there is no subject id or token. The client sets its player's walk, run and sprint animations to style while the player has full control (unlike ApplyAnimation, which takes control away). style 0 returns to the default walk.

[u8  packet_id = 0x2D]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  style]            // walking style id (0 = default)

Total: 6 bytes. Stored state: the server keeps the value per player (it survives respawn; a new connection starts at 0) and stamps it into RemotePlayerSync.walk_style, so copies and late joiners converge without a broadcast. Valid ids: 0, 54..70 (player and weapon gaits) and 118..138 (walking styles, including 127 blind man). The server refuses others, and the client applies the same allowlist: it drops a SetWalkingStyle outside it on decode and skips such a RemotePlayerSync.walk_style on apply. A style whose animations are not loaded is silently ignored.

Example: set_walking_style.bin.

SetFightingStyle (0x56) ​

Server → Client, reliable event lane. The fighting style of the recipient's own player: the combo set of unarmed and brass-knuckle attacks. The same model as SetWalkingStyle: stored state (survives respawn and a skin change; a new connection starts at 15), stamped into RemotePlayerSync.fight_style. A change takes effect from the next combo.

[u8  packet_id = 0x56]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  style]            // fighting style (4..7, 15, 16)

Total: 6 bytes. Valid values: 4 normal, 5 boxing, 6 kung fu, 7 knee-head, 15 grab-kick (default), 16 elbow; 8..14 are the combo sets of melee weapons, not styles. The server refuses others, and the client applies the same allowlist: it drops a SetFightingStyle outside it on decode and skips such a RemotePlayerSync.fight_style on apply.

Example: set_fighting_style.bin.

SetHeadless (0x57) ​

Server → Client, reliable event lane. Hides the head of the recipient's own player. The same model as SetFightingStyle: stored state, stamped into RemotePlayerSync.headless.

[u8  packet_id = 0x57]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  headless]         // 1 head hidden, 0 shown

Total: 6 bytes. It survives a skin change. A new respawn grant clears it: the server sends the owner SetHeadless(0) on the reliable lane (RespawnPlayer itself is unreliable, so the client does not clear the state itself), and receivers reset their copy on PlayerSpawned. A new connection starts at 0. Damage never removes a player's head in the game; only this state hides it.

Example: set_headless.bin.

SetFrozen (0x72) ​

Server → Client, reliable event lane. Takes away or returns control of the recipient's own player. Control is taken while the gamemode froze the player or its camera is not its own (SetCamera); the packet goes when the combined result changes. Stored server state, not sent to observers: a frozen player's frames go without input. Death does not clear it; a new respawn grant does: the server sends the owner SetFrozen(0) on the reliable lane. Set before the first spawn, it holds the player from the spawn. A new connection starts unfrozen.

[u8  packet_id = 0x72]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  frozen]           // 1 control taken, 0 returned

Total: 6 bytes. While the player is frozen, the server:

  • zeroes keys of its PlayerSync before every check and the relay;
  • holds the frame's position within 8 m horizontally and 3 m upward of where it was frozen, teleported or spawned, falling being free (seated: 25 m from the vehicle); beyond that the frame counts as on the boundary with zero velocity, the other fields are accepted;
  • drops its WeaponShot, VehicleShot, ProjectileCreate, SatchelDetonate, StealthKillRequest, refuses its VehicleEnter, ignores VehicleRemoteEnter and VehicleControl; it accepts VehicleExit, and the gamemode may move and seat the player;
  • does not credit it with contact damage in a DamageReport (melee, ramming, rotor): such a report of the victim is refused;
  • does not count it as controlling any vehicle, like a paused driver: its vehicle gets a syncer, it is never a syncer or the pilot of an RC vehicle, and its VehicleFrame, VehicleExplode, VehicleTow, VehicleWinch are dropped;
  • holds the vehicle it drives with a VehicleTransform freeze (except a train) while it drives and is frozen; the gamemode's own vehicle freeze is a separate cause, and neither clears the other.

Example: set_frozen.bin.

SetCamera (0x73) ​

Server → Client, reliable event lane. What the recipient's own camera shows. Stored server state, not sent to observers. Death keeps it; a new respawn grant clears it: the server sends the owner mode = 0 on the lane. Set before the first spawn, it takes effect from the spawn. A new connection starts with its own camera.

[u8     packet_id = 0x73]
[u32    event_id]         // position in the per-recipient reliable stream
[u8     mode]             // 0 own camera, 1 fixed, 2 spectate, 3 free (map editing session only); others are dropped by the client
[f32;3  pos]              // mode 1: camera position, otherwise zeros
[f32;3  look_at]          // mode 1: look-at point, otherwise zeros
[u32    transition_ms]    // mode 1: transition from the current view, 0 = at once, at most 60000; otherwise 0
[u8     target_present]   // mode 2: 1, otherwise 0
[u32    target_id]
[u32    target_token]     // generation of the target's id
[u32    prev_action]      // mode 2: action_id (ActionDeclare) for the spectator panel, 0 = none
[u32    next_action]      // the same

Total: 51 bytes.

  • While the camera is not its own, the player has no control (SetFrozen), and players, vehicles, pickups, blips and labels are streamed from the camera's position (mode = 2: from the target's position), not from the body. Touching a pickup is still checked against the body.
  • Order on the lane: a foreign camera goes after SetFrozen, the return of the own camera before it.
  • A transition (transition_ms > 0) moves the camera from the current view to pos along the curve (1 - cos(π·t)) / 2; the stream center follows the same curve from the previous center. Server and client clocks are not synchronized: the center's time runs only while the packet is acked and the client sends PlayerSync frames, so the center is approximate and does not affect authority.
  • mode = 2: the target is spawned and in the player's scope. When the target changes scope or leaves, the server sends mode = 0 and fires spectate_lost(player, target) to resources. The target's death and respawn do not end the spectating; while the client has no copy of the target, the view holds still. The panel shows the target's name and the keys the player bound to the two actions (ActionDeclare); pressing them is handled by the gamemode, there are no new Client → Server packets.
  • mode = 3 starts from the current view, with zero position fields; the client flies the camera and reports its position (EditCamera), and the world streams from it. It exists only in a map editing session (EntityEdit); the end of the session returns the own camera, and while the session lasts the gamemode cannot set another camera. The client holds the body in place without falling; freezing applies as usual.
  • The server allows pos and look_at within ±100000 on each axis and no closer than 0.01 to each other. The client drops non-finite coordinates, coordinates beyond these bounds, pos equal to look_at, and a target_id out of range.

Example: set_camera.bin.

SetOnFire (0x58) ​

Server → Client, reliable event lane. Sets the recipient's own player on fire or puts it out. This is a command, not a state: the client sets its player on fire (without an author, without spreading) or puts the fire out; the fire also goes out by the game's own rules and in water, and its damage is environmental damage without an attacker (DamageReport weapon 37). Whether a player burns is Frame.on_fire.

[u8  packet_id = 0x58]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  on_fire]          // 1 set on fire, 0 put out

Total: 6 bytes. The server sends the command only to a living spawned player, and sets fire only to a player on foot whose new life after a respawn is confirmed; the client does not set fire to a dead or seated player. If a fire command went out in the previous life, a new respawn grant sends SetOnFire(0) after it, so a late or retransmitted command does not light the new life.

Example: set_on_fire.bin.

SetSpecialAction (0x59) ​

Server → Client, reliable event lane. The special action of the recipient's own player. Stored state: the server keeps the action and a revision rev (incremented on every SetSpecialAction); observers see it in the relayed Frame.special_action. The client applies it to its player and echoes rev in Frame.special_rev.

[u8  packet_id = 0x59]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  action]           // 0 none, 1 jetpack, 2 hands up, 3 phone, 4..7 dances 1..4, 8 carry
[u16 rev]              // revision; echoed in Frame.special_rev

Total: 8 bytes. An action above 8 fails decoding.

  • The server sends it only to a living spawned player whose new life is confirmed, and a non-zero action only to a player on foot.
  • An action replaces a playing animation: the server sends ClearAnimations first, having checked in advance that the queue has room for both packets.
  • Death ends the action. If an action went out in the previous life, a new respawn grant sends SetSpecialAction(0) after it.
  • A new connection starts at 0 with rev 0: the client ends any action left over from a previous connection.

Example: set_special_action.bin.

SetVelocity (0x90) ​

Server → Client, reliable event lane. Throws the recipient's own player. A command, not a state: the client writes the velocity into its player once (with z > 0 lifting it off the ground, like a jump), then the game moves the body, and observers see the result in its frames.

[u8  packet_id = 0x90]
[u32 event_id]         // position in the per-recipient reliable stream
[f32 vel_x]            // ─┐ units per step (m/s / 50); |vel| <= 2.0 (100 m/s), finite,
[f32 vel_y]            //  │ otherwise the packet fails decoding
[f32 vel_z]            // ─┘
[u16 life]             // the life generation (the frames' death_epoch) the throw is for
[u16 rev]              // the player's physics revision; the client returns it in Frame.physics_rev

Total: 21 bytes. The server sends it only to a living spawned player on foot whose new life is confirmed. The client drops it if its player is dead or seated; if life differs from its current death_epoch (a retransmission that caught up with a respawn); if a TeleportPlayer was delivered after it while it was not yet applied (the teleport stops the body; the cancel takes effect before the teleport); and if it has not applied it within 1 s of receipt (after that the server may already count it as applied, see physics_rev in PlayerSync). The game limits the rise of a player in the air to 0.25 units per step (12.5 m/s).

Example: set_velocity.bin.

SetGravity (0x91) ​

Server → Client, reliable event lane. The body gravity of the recipient's own player. Stored state, stamped into RemotePlayerSync.gravity: the copy falls with the same gravity on every observer. It applies only to the player's body; vehicles and other physics use the game's gravity. It survives death and respawn; a new connection starts at 0.008 (the game's gravity).

[u8  packet_id = 0x91]
[u32 event_id]         // position in the per-recipient reliable stream
[f32 gravity]          // units per step²; 0.008 = the game's; -0.1..0.1, finite, otherwise the packet fails decoding; < 0 pulls up
[u16 rev]              // physics revision shared with SetVelocity; echoed in Frame.physics_rev

Total: 11 bytes. The client applies it in one queue with SetVelocity, in reliable lane order.

Example: set_gravity.bin.

SetDrunkLevel (0x92) ​

Server → Client, reliable event lane. The drunkenness of the recipient's own player, on the game's scale. Stored state, not sent to observers: only the owner sees the effect. It holds until changed and does not wear off by itself; a new respawn grant sends SetDrunkLevel(0) on the lane if the level is not 0. A new connection starts at 0; the end of a session sobers the client.

[u8  packet_id = 0x92]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  level]            // 0 sober .. 255

Total: 6 bytes.

Example: set_drunk_level.bin.

SetPlayerStats (0x93) ​

Server → Client, reliable event lane. Stamina and lung capacity of the recipient's own player. Stored state that observers do not need: fatigue rides move_state, running out of air is the victim's damage. It survives death and respawn; a new connection starts at 1000 / 1000 without a packet, and a client outside a session keeps 1000.

[u8  packet_id = 0x93]
[u32 event_id]         // position in the per-recipient reliable stream
[u16 stamina]          // 0..1000, otherwise the packet fails decoding
[u16 lung_capacity]    // 0..1000, otherwise the packet fails decoding

Total: 9 bytes.

Example: set_player_stats.bin.

SetWorldBounds (0x94) ​

Server → Client, reliable event lane. A rectangle in which the recipient's own player and the vehicle it drives stay. Stored state: the client returns the body or the vehicle to the edge once per frame and removes velocity outward; the server holds the player's frames (PlayerSync) and its vehicle's VehicleFrame inside it while it drives. It survives death and respawn; a new connection starts with the whole world.

[u8  packet_id = 0x94]
[u32 event_id]         // position in the per-recipient reliable stream
[u8  enabled]          // 1 rectangle, 0 the whole world; > 1 fails decoding
[f32 min_x]            // ─┐ with enabled = 1: finite, |v| <= 6000, min < max;
[f32 min_y]            //  │ with enabled = 0: zeros; otherwise the packet fails decoding
[f32 max_x]            //  │
[f32 max_y]            // ─┘

Total: 22 bytes.

Example: set_world_bounds.bin, set_world_bounds_off.bin.

ScopeChanged (0x5D) ​

Server → Client, reliable event lane, sent as a critical event (never refused for a full queue). The recipient's own virtual_world or interior changed. The server sends it on every scope change of the player: a virtual world change, a teleport into another interior (after TeleportPlayer), and a new respawn grant into another interior; what the previous life left behind stays in the scope where it died. The connect spawn does not send it.

[u8  packet_id = 0x5D]
[u32 event_id]         // position in the per-recipient reliable stream; also the barrier for throws

Total: 5 bytes. The client has one world while world scope exists only on the server, so the client itself removes what it had in the scope it left, in order with the other projectile events:

  • projectiles in flight that have not exploded: all except its own thrown with seen_event ≥ event_id (the server accepts those in the new scope, see ProjectileCreate); its own satchels are among the removed ones, and the server clears its satchel latch;
  • world fire, except burning bodies (a player burning is SetOnFire / Frame.on_fire).

Fire within one scope diverges between clients: each client runs spreading and burning out itself.

Example: scope_changed.bin.

SetAnimationProgress (0x2E) / SetAnimationSpeed (0x2F) ​

Server → Client, reliable event lane. Seeks / changes the rate of the player's current named animation; addressed like ApplyAnimation (the subject and the players it is shown to). The current animation is implicit: the server owns the stored animation state and the server API refuses the call when nothing plays (PlayerNotAnimating), so there is no animation name on the wire.

[u8  packet_id = 0x2E / 0x2F]
[u32 id]               // subject player id
[u32 player_token]     // subject generation
[u32 event_id]         // position in the per-recipient reliable stream
[f32 progress|speed]   // 0x2E: 0..=1, finite; 0x2F: 0..=10, finite (0 = pause); otherwise the packet fails decoding

Total: 17 bytes each.

  • A receiver whose animation data is still loading keeps the value in the slot and applies it when the animation starts.
  • progress seeks the animation to that share of its length, wrapping for a looped one; exactly 1.0 lands just before the end, as in the game.
  • speed sets the playback rate; it also enters the stored state and rides the replay on show. progress is stored only for reading through the server API; the replay does not use it (it uses elapsed_ms).

Example: set_animation_progress.bin, set_animation_speed.bin.

Documentation licensed under CC BY 4.0. DarqlineMP is not affiliated with Rockstar Games or Take-Two Interactive. Grand Theft Auto is a trademark of Take-Two Interactive Software, Inc.