World
Server-owned world state shown to each client: pickups, time of day and weather, garage doors, 3D labels, checkpoints, radar blips, gang zones, colshape outlines, objects and map waypoints. All of it is server-authoritative; the client reports only pickup touches and its map waypoint. "World bounds" on this page means |x|, |y| ≤ 6000 and z from −200 to 4000.
Every Server → Client packet here travels on the reliable event lane: its event_id is the position in the per-recipient stream, acknowledged with the shared ClientAck (0x0E). The per-player primitives (Label3D, Checkpoint, Blip, GangZone, ColshapeShape, ObjectState) share one active contract: active = 1 shows the primitive or replaces its shown state, active = 0 hides it and only the id matters. Scope (virtual world and interior) is never on the wire.
Packets
PickupSync (0x12)
[u8 packet_id = 0x12]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u32 pickup_id] // server pickup id
[u8 active] // 1 = show (all fields), 0 = remove (only pickup_id matters)
[u32 model] // an object model from the server's model table, or one of the 50 weapon models (321..373)
[f32 x][f32 y][f32 z] // world position: |x|, |y| ≤ 4095, z from −200 to 4000
[f32 scale] // uniform scale 0.1..10; 1.0 = the model's own size
[u8 highlight] // 1 = the pickup glows (default), 0 = glow off
[u32 rev] // pose revision, grows with every move; the `rev` an EntityEdit of the pickup carriesTotal: 35 bytes. Server → Client, reliable event lane, in the same stream as ChatMessage (0x08) and the other reliable packets. The server owns the set of pickups (dlmp.create_pickup, load_map) and checks model, position and scale on creation and on every move (Pickup:set_position).
The client drops the whole packet, without an ack, when active or highlight is neither 0 nor 1, or, with active = 1, when the position or the scale is outside the ranges above. It checks model and position once more before placing the pickup; it places pickups at a resolution of 1/8 m, which is why |x| and |y| stop at 4095. A show (active = 1) of a pickup already shown to this client replaces it: the client places it anew at the new position or with the new model. A move is sent as such a show with a new rev to every client the pickup is streamed to, as critical: nothing else would resend it. The correction after a refused edit (EntityEdit) is critical as well.
Streaming. Per player: a pickup is shown while it is within the server's draw distance of the player and in the player's scope (virtual world and interior), and removed when it leaves that distance, turns inactive (waiting for its respawn) or is deleted. A new connection receives the visible pickups again.
Touch and effect. The pickup's type and reward are not on the wire: the client gives every pickup the same behavior, applies no effect itself and only detects touches (PickupTouch). The touch policy (collectible / static) and the respawn are server state. The effect and the decision to consume belong to the gamemode (ADR 0019): it receives pickup_interact, consumes the pickup with collect_pickup and grants the effect with grant packets (GiveWeapon (0x16), GiveHealth (0x17) / GiveArmor (0x18)). The client sees only the pickup disappearing and the grant packet. highlight = 0 turns off the pickup's glow.
Example: pickup_sync.bin.
PickupTouch (0x13)
[u8 packet_id = 0x13]
[u64 token] // the sender's session_token
[u32 event_id] // position in the client's Client → Server reliable stream (shared with ClientChat)
[u32 pickup_id] // server id of the pickup the player touchedTotal: 17 bytes. Client → Server, reliable event lane: the same Go-Back-N stream as ClientChat (0x07), with a shared event_id sequence and ServerAck (0x0F); the lane guarantees delivery. The client tests its local player against the pickups the server showed it and sends the event on the outside → inside transition, then retries at a low rate while the player stays inside the radius and the server has not removed the pickup; it never sends one per frame.
The server does not trust the client's position. It checks the token and the reliable order, that the player is spawned and alive, that the pickup exists and is active, that the player's last PlayerSync position is within the touch radius, and that the pickup is currently streamed to this player: a touch of a pickup never shown to the player, or already removed from their view, is refused even from a delayed packet. Touches are idempotent by pickup_id: a retransmission after the pickup was removed finds nothing and does nothing.
An accepted touch never removes the pickup by itself; the server classifies it and hands the interaction to the gamemode:
- collectible: the gamemode receives
PickupInteracted { player, pickup, behavior: Collectible, model }. It either consumes the pickup (collect_pickup→PickupSync active = 0, plus a respawn if configured) and grants the effect (GiveWeapon/GiveHealth/GiveArmoron the collector's reliable event lane), or declines. Until the pickup is consumed the client keeps re-touching and the interaction fires again. A gamemode can thus refuse a health or armor pickup while the player's last known value is already at its maximum: nothing is consumed or granted, and the pickup is collected after the player takes damage. - static: the server accepts the interaction without removing the pickup, once per entry per player: the per-pickup, per-player latch clears when the player's last known position leaves the radius. The gamemode receives
PickupInteracted { …, behavior: Static, model }.
See ADR 0019.
Example: pickup_touch.bin.
SetTime (0x21)
[u8 packet_id = 0x21]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u8 hours] // time of day, 0..=23
[u8 minutes] // 0..=59Total: 7 bytes. Server → Client, reliable event lane, to one player: the recipient's own time of day, in the same stream as SetWanted (0x11) and SetSkin (0x20). The client stops its clock at this time and holds it there; the value overrides the time from ServerHello (0x02) until the next SetTime or RunClock or the end of the connection. The server does not store the per-player value.
SetTime is also the frozen half of the global clock policy (see RunClock): freezing the global clock sends it to everyone, as critical. Different players can be on different times only while the global clock is frozen (the default); while it runs, the periodic RunClock resync resets every client, so a per-player SetTime lasts at most one resync interval. Both the server and the client decoder reject hours outside 0..=23 and minutes outside 0..=59.
Example: set_time.bin.
SetWeather (0x22)
[u8 packet_id = 0x22]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u8 weather] // weather id, 0..=22Total: 6 bytes. Server → Client, reliable event lane, to one player, alongside SetTime. The client switches to weather at once whenever the target changes and holds it. Both the server and the client decoder reject an id above 22: the client indexes its weather table by it, and 0..=22 is the complete set the game has. The server does not store the per-player value.
Example: set_weather.bin.
RunClock (0x23)
[u8 packet_id = 0x23]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u8 hours] // authoritative time of day, 0..=23 (the phase on establish, the target on resync)
[u8 minutes] // 0..=59
[u32 minute_ms] // real milliseconds per game minute, 10..=3_600_000; 1000 is the game's own rateTotal: 11 bytes. Server → Client, reliable event lane, in the same stream as SetTime / SetWanted. It switches the client to a free-running clock: the client stops holding the time, runs the clock at minute_ms per game minute from hours:minutes and lets the sky change smoothly. The running clock is one global, server-owned policy, sent per recipient. The server keeps the authoritative clock and sends RunClock on connect (when the clock runs), on a change of mode or rate, and as a periodic resync every 45 s.
The client treats the first packet, and any packet with a different minute_ms, as a hard establish: it sets the rate and jumps to the given time. Later packets are a resync: a small drift is corrected by briefly adjusting the clock's rate, a large one (after a pause or a menu) by jumping to the given time.
Lanes: a mode change (run, freeze, the establish on connect) is critical and must arrive; the periodic resync is droppable, since a lost snapshot is fixed by the next. A frozen clock has no resync, which is why the freeze (SetTime) is critical. SetTime returns the clock to frozen at HH:MM. The server validates 0..=23, 0..=59 and minute_ms in 10..=3_600_000; the client decoder does the same.
Real time has no packet of its own: it is RunClock with minute_ms = 60000 (one real minute per game minute), with hours and minutes taken from the server's wall clock at a fixed UTC offset; every resync carries the exact real time.
Example: run_clock.bin.
GarageDoors (0x51)
[u8 packet_id = 0x51]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u64 open] // bit id set = the door of game garage id is open; id 0..=49, bits 50..63 = 0Total: 13 bytes. Server-wide doors of the game's garages; all are closed by default, and the gamemode opens and closes them with dlmp.set_garage_open. Garages have no function on the client: repair, respray, tuning, bombs and vehicle storage do not work, and a door is only physics. The initial mask travels in ServerHello (0x02), where the client sets the doors at once; this packet goes on an actual change, to every connected client, as critical, and the door moves at the game's own speed and with its sound. The client decoder rejects this packet (and ServerHello) with any bit at 50 or above.
Example: garage_doors.bin.
Label3D (0x66)
A 3D text label shown to the recipient. Server → Client, reliable event lane, per player: active = 1 on show and on every change, active = 0 on hide (only label_id matters). The server decides what is shown: the same scope, within draw_distance of the label, and at most the 256 nearest. A label attached to a player is not shown to that player; a label with a single viewer is shown only to that viewer. An attached label is shown only while its entity is streamed to the recipient and is hidden after the entity is: the wire carries only its offset. The server reconciles on every change of a label and once a second; the client itself hides a label farther than draw_distance.
[u8 packet_id = 0x66]
[u32 event_id]
[u32 label_id] // monotonic, never reused (one counter shared with Blip, GangZone and Checkpoint)
[u8 active]
[u32 color] // 0xRRGGBB
[f32 x, y, z] // position; when attached, the offset from the entity
[f32 draw_distance] // (0, 300]
[u8 attach_kind] // 0 none, 1 player, 2 vehicle
[u32 attach_id] // player_id or vehicle_id
[u8 text[256]] // UTF-8, NUL-terminated; `\n` breaks the lineTotal: 291 bytes. The decoder rejects active other than 0 / 1 and, with active = 1, a color, position, distance or attach_kind out of range. A label attached to an entity the client is not shown is not drawn. Deleting the attached entity or the label's viewer deletes the label.
Example: label_3d.bin.
Checkpoint (0x67)
The recipient's checkpoint. Server → Client, reliable event lane, per player, with the same active contract. Shown while the player is in its scope; up to 16 per player.
[u8 packet_id = 0x67]
[u32 event_id]
[u32 checkpoint_id]
[u8 active]
[u8 kind] // 0 normal, 1 race, 2 race_finish, 3 air, 4 air_finish
[f32 x, y, z]
[f32 next_x, y, z] // where it points; equal to the position when there is no next point
[f32 radius] // (0, 100]
[u32 color] // 0xRRGGBBTotal: 43 bytes. The server computes entry and exit from the last accepted PlayerSync position of a living, spawned player; the client reports nothing. A ground checkpoint is a cylinder: radius horizontally and max(radius, 5) up and down; an air checkpoint is a sphere. Death and a change of scope count as an exit. Lua events: checkpoint_enter, checkpoint_leave; deleting a checkpoint and the player leaving raise none. Crossings are limited to 20 at once and 4 per second per connection: past that, the check waits for the next frame or tick.
Example: checkpoint.bin.
Blip (0x68)
A marker on the radar and the map. Server → Client, reliable event lane, per player, with the same active contract. Shown while the player is in the blip's scope (for an attached blip, the entity's scope) and, if the gamemode set a draw_distance, within it (a shown blip is hidden 10 m past it); at most the 100 nearest. A blip attached to a player is not shown to that player and waits until both that player and the recipient have spawned for the first time.
[u8 packet_id = 0x68]
[u32 event_id]
[u32 blip_id]
[u8 active]
[u8 sprite] // icon 1..63, 0 = a dot in `color`; always 0 when attached
[u32 color] // 0xRRGGBB
[f32 x, y, z] // when attached, where the entity was by the server's data
[u8 attach_kind] // 0 none, 1 player, 2 vehicle
[u32 attach_id]
[f32 size] // multiplier of the normal dot or icon size, 0.25..4
[u8 flags] // bit 0: pulses on the pause map; bit 1: short range, on the radar only within its range, on the map alwaysTotal: 37 bytes. The decoder rejects size outside 0.25..4 (or not a number), unknown flags bits and, with active = 1, a nonzero sprite on an attached blip; the radar never pulses. An attached blip follows its entity while the entity is shown to the client. Otherwise it stands at x, y, z, updated at most once a second when the entity has moved more than 5. Coordinates of every primitive are within world bounds: the decoder rejects others, so a blip on a player outside the bounds stays at the last valid position.
Example: blip.bin.
GangZone (0x71)
A colored world rectangle on the radar and the map. Server → Client, reliable event lane, per player, with the same active contract. Shown while the player is in the zone's scope and the zone is visible to them (to everyone or to this player), with no distance limit; at most the 1024 nearest by center. A repeated show with the same zone_id replaces the zone. A later zone_id is drawn over an earlier one.
[u8 packet_id = 0x71]
[u32 event_id]
[u32 zone_id]
[u8 active]
[u8 flashing] // 0 or 1
[u32 color] // 0xRRGGBB
[u8 alpha] // 0..255
[u32 flash_color] // 0xRRGGBB; used while flashing
[f32 min_x, min_y]
[f32 max_x, max_y] // greater than min on both axes
[u32 rev] // zone revision, grows with every change; the `rev` an EntityEdit of the zone carriesTotal: 40 bytes. With active = 1 the decoder rejects a color out of range, a degenerate rectangle and corners outside world bounds. While flashing, the color moves smoothly from color to flash_color and back over 1024 ms with a constant alpha; the client keeps the phase. A new connection receives its zones again; a show or hide set for a player is discarded when the player leaves.
Example: gang_zone.bin.
ColshapeShape (0x95)
The outline of a colshape: only its form; who is inside is known only to the server. Server → Client, reliable event lane, per player, with the same active contract. Shown while the resource shows it to this player (Colshape:show, to nobody by default) and the player is in the colshape's scope; at most the 256 nearest by the form's center. The client draws the outline only during an edit session (EditState).
[u8 packet_id = 0x95]
[u32 event_id]
[u32 colshape_id]
[u8 active]
[u8 form] // 0 sphere, 1 cylinder, 2 box (axis-aligned)
[f32 a_x, a_y, a_z] // sphere: center; cylinder: center of the base; box: min
[f32 b_x, b_y, b_z] // sphere: (radius, 0, 0); cylinder: (radius, height, 0); box: max
[u32 rev] // form revision, grows with every change; the `rev` an EntityEdit of the colshape carriesTotal: 39 bytes. With active = 1 the decoder rejects an unknown form, non-finite values, a radius or height not above 0 or above 12000, nonzero fields the form does not use, a box whose min is not below its max on any axis, and a (for a box, also b) outside world bounds. A new connection receives its outlines again; a show set for a player is discarded when the player leaves.
Example: colshape_shape.bin.
ObjectState (0x8A)
Shows, changes and hides an object. Server → Client, reliable event lane, per player, with the same active contract. An object is shown while the player is in its scope, within its stream distance of the player's stream center, and among the 1000 nearest; a viewer limits it to one player. An attached object is shown together with its parent: the parent is shown to this player (a player is always shown to themselves) and the player is in the parent's scope. A chain counts against the limit as a whole, with its parent objects, or not at all. Shows leave 32 slots of the send queue free; the nearest go first, the rest in following passes. Before a landing, shows also take those slots except one kept for TeleportPlayer (0x15), and go before hides; if there is no room for the floor (up to 31 objects), the teleport is refused and changes nothing. A change of the parent's interior resends the shown object with the new interior.
[u8 packet_id = 0x8A]
[u32 event_id]
[u32 object_id] // monotonic, never reused
[u8 active]
[u16 model] // with active = 1, from the server's model table, at most 19999
[f32 x, y, z] // current pose; the offset from the parent when attached
[f32 rx, ry, rz] // degrees, absolute value up to 3600; relative to the parent when attached
[i32 interior] // 0..255: the interior of the object's scope or of its parent
[u8 attach_kind] // 0 none, 1 player, 2 vehicle, 3 object
[u32 attach_id] // player_id, vehicle_id or object_id; 0 when attach_kind is 0
[u32 move_ms] // time left to the target, 0 = standing; up to 3600000
[f32 to_x, to_y, to_z] // movement target
[f32 to_rx, to_ry, to_rz]
[u32 rev] // object revision; echoed by EntityEdit
[u8 bone] // 0 = the body's root; 1..17 = a body bone of the player (only with attach_kind = 1)
[u8 broken] // 0 intact, 1 broken; never on a boneTotal: 79 bytes. With active = 1 the decoder rejects model, attach_kind, interior and move_ms out of range, non-finite values, a position or target outside world bounds, an offset above 1000 on any axis, movement of an attached object, bone above 17, a nonzero bone not on a player, broken other than 0 / 1, and a broken object on a bone. The client checks the model against its own game build and does not create anything that is not an object model. With bone = 0 the offset is from the body's root. An object's rotation is Rz(rz) Rx(rx) Ry(ry); the world pose of an attached object is the parent's pose multiplied by its own (offset and rotation), and of a parent player only the heading counts.
Bones. bone values:
| bone | body part | bone | body part |
|---|---|---|---|
| 1 | spine | 10 | right foot |
| 2 | head | 11 | right calf |
| 3 | left upper arm | 12 | left calf |
| 4 | right upper arm | 13 | left forearm |
| 5 | left hand | 14 | right forearm |
| 6 | right hand | 15 | left clavicle |
| 7 | left thigh | 16 | right clavicle |
| 8 | right thigh | 17 | neck |
| 9 | left foot |
Offset (meters) and rotation are in the bone's own frame. Every client holds the object on the bone of its own copy of the player, so the object follows animation, death, respawn and skin changes. Only clients know the bone's pose: the server treats the object as standing at the player's root (streaming, detach). An object on a bone carries no other objects, there is no attach_in_place onto a bone, and an object on a bone has no collision.
Breaking. Only the gamemode breaks and restores an object (Object:set_broken), only for a model the game can break (flag b of the server's model table, 299 models), and never on a bone; repeating the current state sends nothing. Shots, explosions and vehicles do not break the client's copies. A shown copy going from broken 0 → 1 breaks in front of everyone, with the game's debris and without its explosion (the gamemode creates a barrel's explosion itself with CreateExplosion (0x5A)); an object shown already broken appears at once without a model or collision; 1 → 0 places the copy again intact, with its whole chain. A broken object stays an object: it moves, carries others and streams like an intact one, but has no collision.
Movement and authority. The server is the authority: copies never move or break by themselves, and the client never reports on an object. Movement is uniform and linear in position and angles; the server computes the end itself (object_move_end), and a repeated show carries the time left. The client runs the movement on its own clock from the packet's arrival and meets the end in the same pose, so there is no packet for the end. A player standing on a moving object is carried by their own client, and their frames carry that position.
Ordering around spawns. The objects nearest the landing point go before TeleportPlayer (0x15) in the same queue. SpawnPlayer (0x2A) and RespawnPlayer (0x0D) travel outside that queue, so the server holds the grant until every object at the spawn point is queued and acknowledged by the client, then sends it on its own. The client places everything it has received before the landing. When the parent goes, the object is deleted with its whole chain; a player's death and respawn and a vehicle's respawn do not detach. A new connection receives its objects again.
Example: object_state.bin.
PlayerWaypoint (0x9D)
The waypoint on the player's map as the client has it now. Client → Server, reliable event lane. The client sends it on every change: a click on the map, removal, removal by the game on arrival, a waypoint set by SetWaypoint.
[u8 packet_id = 0x9D]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u8 active] // 1 = a waypoint at pos, 0 = no waypoint
[f32 x, y] // meters; meaningful with active = 1Total: 22 bytes. Dropped silently (but acknowledged) when the player is not spawned yet, active is neither 0 nor 1, a coordinate is not a number or outside ±3000, or it repeats what the server already holds: a point within 1 m of the held one, or "none" again. An accepted change raises player_waypoint within a per-connection limit of 5 at once and 2 per second; past it, the server still holds the new waypoint, and an event with the latest one fires when the limit allows. Never relayed to anyone.
Example: player_waypoint.bin.
SetWaypoint (0x9E)
A waypoint the gamemode puts on the player's map. Server → Client, reliable event lane, to one player; it replaces the player's waypoint, and active = 0 removes it. The server holds it as the player's waypoint at once without raising player_waypoint; the client's answering PlayerWaypoint is not a change. A PlayerWaypoint the client sent before it set this waypoint may arrive after it: it raises player_waypoint with its own point, and the answer to SetWaypoint raises another one with the new point.
[u8 packet_id = 0x9E]
[u32 event_id]
[u8 active]
[f32 x, y] // meters, ±3000Total: 14 bytes. The client rejects active other than 0 / 1 and a point outside ±3000, and sets the waypoint once the player is spawned. The game does not accept every point; the following PlayerWaypoint reports what was actually set.
Example: set_waypoint.bin.
