Vehicles
Server-owned vehicles: streaming, seats, the driving and syncing of vehicle state, weapons, towing, the helicopter winch, trains, remote-controlled vehicles, destruction and damage, and the gamemode's commands for health, parameters, tuning, handling, transform and colors. The server owns every vehicle's existence and life; the controlling player (the driver, or for a vehicle without a driver its syncer) reports its motion, damage and destruction, and the server checks, stores and relays them.
Packets
VehicleSync (0x36)
[u8 packet_id = 0x36]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u32 vehicle_id] // the server's vehicle id
[u8 active] // 1 = show (all fields apply), 0 = hide (only vehicle_id matters)
[u16 model] // vehicle model, 400..=611 (the server validates it before sending)
[f32 x][f32 y][f32 z] // world spawn position
[f32 heading] // spawn heading, degrees
[u8 color1][u8 color2] // primary / secondary color index, 0..=127
[f32 health] // vehicle health
[u8 flags] // bit0 = wrecked, bit1 = drowned (only with bit0); trains: bit2 = faces along the track
// (clockwise), bit3 = derailed
[u8 epoch] // the vehicle's generation (life)
[VehicleDamageStatus damage] // 18 bytes, see VehicleDamage
[u16 params] // bit0 engine, bit1 lights, bit2 locked, bit3 magnet, bit4 small magnet, bit5..8 as in
// VehicleParams
[u8 doors] // doors open by the last command: bit = bonnet, boot, LF, RF, LR, RR
[u32 relay_seq] // the vehicle's relay serial at the time of the show; 0 on a hide
[u16 health_rev] // revision of the last gamemode health command the show includes
[u16 damage_rev] // the same for the damage command
[u32 tractor_id] // the vehicle towing this one; 0xFFFFFFFF = not hitched
[u32 lifter_id] // the helicopter whose winch carries this one; 0xFFFFFFFF = none
[u16 part] // the moving part at relay_seq, as VehicleState.part; 0 on a hide
[u16 siren_rev] // revision of the last gamemode siren switch, as VehicleParams.siren_rev
[u16 pose_rev] // revision of the last gamemode transform, as VehicleTransform.pose_revTotal: 79 bytes. Authority: the server owns a vehicle's existence, model, spawn position, heading, colors and world scope. The gamemode creates and destroys vehicles (dlmp.create_vehicle / destroy_vehicle); a resource is the cleanup owner of its vehicles, and stopping it removes them. The packet rides the same reliable stream as PickupSync (its own event_id, the shared ClientAck); a hide carries zeroed placeholder fields.
Streaming. As with pickups, the server keeps a per-player streamed set. A vehicle is shown when it comes within 200 m of the player's last known position while both share virtual_world and interior (the scope is not sent on the wire), and hidden when it leaves that distance, the scope changes or it is removed. On connect the client gets the vehicles visible from its spawn point, then deltas every tick. The client mirrors the set: it creates a vehicle on a show and removes it on a hide; a vehicle the local player sits in is removed only after the player has left it. A packet of the wrong length or with NaN/Inf in the position, heading or health is dropped.
Life. A show carries the vehicle's current life: health (the last value accepted from the controlling player, 0 for a wreck), the wrecked flag and epoch. A wreck appears as a burnt-out hulk at once, without fire or an explosion. A show whose epoch differs from the recipient's existing copy is a respawn: the client removes the old vehicle (after the local player has left it) and creates the new one. A respawn (dlmp.respawn_vehicle) sends such a show to everyone the vehicle is streamed to, after a VehicleOccupancy exit for everyone who sat in it. A show also carries the damage: the vehicle appears dented, without parts flying off; a respawn clears the damage.
Revisions. relay_seq is the vehicle's serial (see RemoteVehicleFrame) at which the show was assembled; a respawn does not reset it. The recipient raises the vehicle's mark to it: a RemoteVehicleFrame whose serial is not newer than the show (already cached or delayed in the network) is not applied over the shown state; a frame newer than the show that arrived before it stays. A copy created from a show counts as having taken its health_rev and damage_rev (see VehicleHealth, RemoteVehicleDamage) and its pose_rev (see VehicleTransform); a copy kept across a hide and a show takes the new pose_rev.
Attached state.
tractor_id(seeVehicleTrailer): the recipient hitches the copies as soon as it has both.lifter_id(seeVehicleLift): the recipient hangs the copy on the magnet of the helicopter's copy as soon as it has both and the helicopter has lowered its rope.part(seeVehicleFrame) is the last moving-part position the server accepted; a respawn resets it. The recipient sets it on the copy once per show (later frames move the part) and the part's collision as soon as the copy can take it.paramscarries the recipient's own lock and objective marker (seeVehicleParams).- A show places the vehicle level at
heading; any other rotation (on its roof, on a slope) and the pose of a frozen vehicle come in theVehicleTransformthat follows. - A show of a vehicle with tuning (including a respawn's) is followed by
VehicleTuning, and of one with gamemode handling byVehicleHandling. color1/color2are the colors the gamemode last set (VehicleColors).
Trains. A locomotive model stands for a whole train: 537 is a freight train with three 569 flatcars, 538 a passenger train with three 570 carriages, 449 a tram without carriages; the carriage models (569, 570, 590) are never spawned on their own. The recipient creates the train on the track nearest to x, y, z, the locomotive at the nearest point of that track, without a driver or passengers. A train ignores heading; it faces along the track or against it (flags bit2). A derailed train (bit3) is created on the track and derails at once. The server treats a train as one vehicle: seats, frames, streaming and hiding belong to the locomotive. Seats: 0 is the driver, 1..5 the locomotive's passengers, then 5 passenger seats per carriage in order (537 and 538 have 21 seats, 449 has 6). Each recipient's carriages follow the locomotive on their own.
Example: vehicle_sync.bin.
VehicleEnter (0x37)
[u8 packet_id = 0x37]
[u64 token] // the sender's session token
[u32 event_id] // position in the Client → Server reliable stream (shared with ClientChat, PickupTouch)
[u32 vehicle_id] // the server's vehicle id
[u8 seat] // 0 = driver, 1.. = passenger seatTotal: 18 bytes. A seat request. The server accepts it if all of these hold:
- the vehicle is streamed to the sender and is now in the sender's virtual world and interior (the streamed set may lag behind a scope change);
- the sender is alive, spawned and not frozen (
SetFrozen); - the sender's last position is within 15 m of the vehicle's server position (a train carriage's seat: plus 25 m for every carriage up to and including the seat's);
- the seat exists on the model (the server holds a per-model seat table; the RC models 441, 464, 465, 501, 564 and 594 have no seats and are driven without boarding, see
VehicleRemote) and is free; - the sender does not sit in another vehicle;
- a train is not derailed (the game does not seat anyone in a derailed train;
dlmp.put_player_in_vehicledoes); - the vehicle is not wrecked (see
VehicleExplode) and not locked for the sender. The lock is the sender's own if the gamemode set one (dlmp.set_vehicle_locked_for), otherwise the vehicle's.
The answer is a VehicleOccupancy: enter to everyone the vehicle is streamed to, or deny to the sender only. A request that passes the checks waits for the resource event vehicle_start_enter(vehicle, player, seat, jacked): false from a handler is a deny; otherwise the server checks everything again and seats the player (a seat taken in the meantime, a respawn of the vehicle or jacking switched off is a deny). An accepted entry raises player_enter_vehicle(player, vehicle, seat) for resources.
Jacking. seat = 0 of a vehicle another player drives is a jack request. If jacking is off (dlmp.set_vehicle_jacking(false)) or a check fails, the answer is an immediate deny. Otherwise the answer waits for the resource events vehicle_start_enter (jacked = the driver) and vehicle_jack(vehicle, jacker, victim): false from any handler is a deny; otherwise the previous driver gets VehicleOccupancy jacked, then the sender's enter goes to everyone the vehicle is streamed to. A driver who has changed by then is a deny; a seat that has become free is a plain enter. On a deny of a jack the client seats its player as a passenger at the nearest free door.
Example: vehicle_enter.bin.
VehicleExit (0x38)
[u8 packet_id = 0x38]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 vehicle_id]Total: 17 bytes. The sender left the vehicle or cancelled its entry. It counts only if the sender sits in exactly vehicle_id; otherwise (a duplicate, or the seat was already freed by a death, the server or a refusal) it is a no-op. Freeing the seat sends VehicleOccupancy exit and raises player_exit_vehicle(player, vehicle, seat).
Example: vehicle_exit.bin.
VehicleOccupancy (0x39)
[u8 packet_id = 0x39]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u32 vehicle_id]
[u32 player_id] // whose seat changed
[u32 player_token] // that player's generation (the recipient ignores a different generation of the id)
[u8 seat] // 0 = driver, 1.. = passenger
[u8 kind] // 0 exit, 1 enter, 2 warp, 3 deny, 4 jacked; any other value drops the packetTotal: 19 bytes. Authority: the server.
kind | Meaning |
|---|---|
0 exit | The seat is free: exit, cancelled entry, death, remove_player_from_vehicle. |
1 enter | Entry on the player's request. Recipients play the full entry animation if the remote player is near the vehicle. |
2 warp | Instant seating by the server: dlmp.put_player_in_vehicle, and the snapshot of occupied seats when the vehicle is shown to a new recipient. |
3 deny | Refusal; only to the requester. |
4 jacked | The driver's seat went to a jacker. Recipients do not unseat the driver themselves: the jacker's entry animation (its enter follows) pulls the driver out. If the pull-out has not started within 8 s, the client replaces it with an exit. A driver who was still walking to the door at jacked abandons the entry and does not ask for the seat again. |
A vehicle is always streamed to its occupants, and an occupant is always in the vehicle's world scope (see Player streaming). While a vehicle is hidden from a recipient, its seat changes do not reach that recipient; so on a hide (VehicleSync active = 0) the client forgets every seat in that vehicle, and the next show sends whoever sits in it then. A disconnect frees the seat without a broadcast (PlayerLeave closes it).
Delivery is critical: nothing repeats a seat change or the seat snapshot after a show, so these events are never dropped when the recipient's queue is full; an overflow of the lane disconnects the client (see Disconnect). VehicleDeath, VehicleSyncer, RemoteVehicleDamage, VehicleHealth and VehicleParams are delivered the same way. The show and hide of a vehicle (VehicleSync) are droppable: the streaming reconciliation repeats them. The vehicle's motion travels in VehicleFrame / RemoteVehicleFrame, from the driver or, without a driver, from the syncer (VehicleSyncer).
Example: vehicle_occupancy.bin.
VehicleFrame (0x3A)
[u8 packet_id = 0x3A]
[u64 token] // the sender's session_token
[u32 seq] // the sender's monotonic vehicle frame counter (its own, not shared with PlayerSync)
[u32 vehicle_id]
[VehicleState state] // 156 bytes, belowExample: vehicle_frame.bin.
VehicleState
[f32 pos[3]] // world position
[f32 rot[4]] // rotation, unit quaternion x, y, z, w (axes: x right, y forward, z up)
[f32 move_speed[3]] // velocity, game units per physics step
[f32 turn_speed[3]] // angular velocity, radians per physics step
[f32 raw_steer] // steering input -1..1
[f32 steer] // steering angle of the wheels, radians
[f32 gas] // -1..1, negative = reverse
[f32 brake] // 0..1
[u8 flags] // bit0 handbrake, bit1 horn, bit2 siren, bit3 bicycle hop took off, bit4 water cannon of a
// Firetruck / SWAT sprays, bit5 train derailed, bit6 police Maverick (497) searchlight on
[f32 health] // vehicle health at the sender
[u8 epoch] // the vehicle generation the state belongs to
[u8 doors[6]] // how far each door is open: bonnet, boot, LF, RF, LR, RR; 0 closed ..= 255 open
[f32 lean] // bike rider's lean: -1 forward ..= 1 back; 0 for other vehicles
[f32 lean_angle] // bike's sideways tilt, radians; 0 for other vehicles
[f32 pedal] // bicycle rider's pedalling effort: above 5 sprints, 0 coasts; 0 for other vehicles
[f32 hop] // bicycle bunny hop charge: 0 none ..= 25 full crouch; 0 for other vehicles
[f32 yaw] // helicopter / plane flight controls, -1..1: yaw,
[f32 pitch] // pitch,
[f32 roll] // roll,
[f32 throttle] // throttle; 0 for other vehicles
[f32 rotor] // helicopter rotor / plane propeller speed; 0 for other vehicles
[u16 part] // moving part: Hydra 520 thrust nozzle 0 forward ..= 5000 down; tow truck 525 and tractor 531
// boom 0 raised ..= 20000 lowered; Dumper 406 bed, Packer 443 ramp, Dozer 486 blade,
// Forklift 530 forks, Andromada 592 cargo door 0 at rest ..= 2500; 0 for other vehicles
[u8 gear] // plane landing gear: 0 down ..= 255 up; 0 for other vehicles
[u16 health_rev] // revision of the last gamemode health command the sender's copy took
[f32 turret_yaw] // Rhino / Firetruck / SWAT turret: yaw relative to the vehicle, radians, -π..π (0 forward)
[f32 turret_pitch] // and pitch, radians, |·| ≤ π/2; 0 for other vehicles
[f32 rail] // train on rails: the locomotive's distance along the track, meters from the track start
[f32 rail_speed] // speed along the track, units per physics step, + = distance grows
[u8 track] // track 0..=3; 0 for other vehicles
[f32 rope] // helicopter winch rope, how far it is wound in: 0.01 lowered ..= 0.84 raised; 0 without a winch
[u16 siren_rev] // revision of the last gamemode siren switch the sender's copy took
[f32 nitro] // nitro level: 1 ready, -1..0 burning, 0..1 refilling; 1 without nitro
[u16 hydraulics] // hydraulics: 0 off, 20..=59 on, 60 posed, 500..=504 raised; 0 without hydraulics
[i16 hydraulic_lr] // hydraulics pose axes -128..=128: left-right,
[i16 hydraulic_ud] // front-back; 0 while the pose control is off
[u16 pose_rev] // revision of the last gamemode transform the sender's copy tookTotal: 173 bytes (VehicleState is 156). The vehicle's state from its driver or syncer. Unreliable, like PlayerSync. The driver sends it at a fixed rate (~30 Hz) while it sits at the wheel of a server-owned vehicle. The syncer of a vehicle without a driver sends its frames every ~100 ms while it moves, its health changes or a door moves, for another ~300 ms after that, and right after it is made the syncer.
Acceptance. The server accepts a frame only if all of these hold:
- the sender is the player the server holds in seat 0 of this vehicle or, while seat 0 is empty or its player is paused, the vehicle's syncer; the syncer must be alive;
epochis the vehicle's current one;pose_revequals the current transform revision (VehicleTransform), so a frame sent before a gamemode command does not undo it;seqis newer than the last frame accepted for this vehicle from the same connection.seqis one cyclic u32 counter over all of the sender's vehicles, compared by serial number arithmetic (newer if ahead by less than 2^31). The mark is kept per connection and vehicle and survives a change of controller, so neither a frame of another vehicle nor a delayed frame from an earlier period of control rolls the server state back;- the state is within coarse bounds:
| Field | Bound |
|---|---|
pos | inside the world: |x|, |y| ≤ 6000, z in −200..=4000 |
rot | |norm − 1| ≤ 0.1 |
move_speed | length ≤ 5 units per step |
turn_speed | length ≤ 1 radian per step |
raw_steer, gas | −1.01..=1.01 |
steer | |·| ≤ π/2 |
brake | 0..=1.01 |
health | |·| ≤ 100000 |
lean | −1.01..=1.01 |
lean_angle | |·| ≤ π/2 |
pedal | 0..=100 |
hop | 0..=25 |
yaw, pitch, roll, throttle | |·| ≤ 2 |
rotor | 0..=2 |
turret_yaw | |·| ≤ π + 0.01 |
turret_pitch | |·| ≤ π/2 |
part | ≤ 20000 |
rail | 0..=100000 |
rail_speed | |·| ≤ 4 |
track | ≤ 3 |
rope | 0..=1 |
nitro | |·| ≤ 1.01 |
hydraulics | 0..=60 or 500..=504 |
hydraulic_lr, hydraulic_ud | |·| ≤ 128 |
NaN/Inf in any float fails the decode. The client clamps these fields into their bounds before sending and before applying another client's frame. A rejected frame is dropped silently.
What an accepted frame changes. It updates the vehicle's server position, rotation and velocities, which drive streaming, a show to a new recipient and Lua vehicle:position() / heading() / rotation() / velocity() / turn_velocity(). A frozen vehicle's frame does not change them: the relay carries the frozen position and rotation and zero velocities. A frame only lowers the vehicle's health (vehicle:health()), only while the vehicle is not wrecked, and only if its health_rev equals the server's current revision: a frame sent before a gamemode command does not undo it, and a frame cannot repair the vehicle.
Field rules. The server rewrites fields before the relay:
flagsbits outside the defined ones are cleared. The water cannon bit is cleared on a model without a water cannon (other than Firetruck 407 and SWAT 601); the turret is zeroed on a model without a turret (other than Rhino 432 and those two).partis clamped per model: Hydra ≤ 5000; tow truck and tractor ≤ 20000; Dumper, Packer, Dozer, Forklift and Andromada ≤ 2500; every other model 0. Only a live pilot (seat 0, not paused) moves the part; the boom of the tow truck and the tractor moves for any controlling player (the game also sets it on a hitch without a driver). Otherwise the frame carries the server's part. The server moves the part of Dumper, Packer, Dozer and Andromada toward the pilot's value at no more than 500 per second, and the Forklift's forks at 500 up and 1000 down (the game's rates), with half a second of margin; a part that lags behind catches up with the pilot's value in later frames, the syncer's included. The server keeps the part it relayed, and aVehicleSyncshow carries it.- The searchlight bit is cleared on a model other than 497. Only a live pilot (seat 0, not paused) switches it; a syncer's frame carries the server's value: the last of a paused pilot, off without a pilot.
ropeis 0 on a vehicle without a winch, otherwise clamped to at most 0.84.- On a model that is not a train,
rail,rail_speed,trackand the derailed bit are zeroed. On a train the server takes the speed from the frame while the train is on its rails. The derailed bit derails the train only if the frame is from the driver (not from the syncer of an empty train, and not while the driver is paused), the speed of this or the previous accepted frame is ≥ 0.9 (the game derails only a driven train faster than 1.0 on a curve), and the gamemode has not put the train back on its rails since the last frame without the bit. A frame cannot put a train back on its rails. The relay carries the server's derailed bit.
Siren. Only a live pilot switches the siren bit (bit2), and only on a vehicle that has a siren (VehicleParams bit8); on a vehicle without one the bit is cleared, and a syncer's frame carries the server's value. A gamemode command (dlmp.set_vehicle_siren, set_vehicle_has_siren) raises the siren revision (VehicleParams.siren_rev; a VehicleSync show carries the same). The pilot's bit counts only if the frame's siren_rev equals the current revision, so a frame sent before the command does not undo it, whatever it shows. A pilot switches the siren at most 4 times a second across all its vehicles (2 at once); a switch past that is taken by the next frame once the limit allows. The command is a switch, not a ban: a copy that took it switches the siren on its own afterward; the ban is dlmp.set_vehicle_has_siren(false). The relay carries the server's siren_rev.
Nitro and hydraulics. They belong to a vehicle with that tuning part (VehicleTuning); for any other vehicle the server sets nitro to 1 and zeroes the hydraulics. Only a live pilot (seat 0, not paused) of a vehicle that is not wrecked lights the nitro: a frame that turns to burning (nitro < 0) spends a server charge (VehicleTuning.nitro). Without charges, or earlier than 18 s after the previous charge burnt out (the game lights only a full tank, which refills in 20 s at the fastest), a burning frame is not accepted, and the relay carries the previous level. A charge burns for at most 25 s (the game burns it for 20 s); after that the server counts it as burnt out. When the last charge burns out the server removes the nitro (VehicleTuning without it). Every spent charge and the removal go to everyone the vehicle is streamed to as VehicleTuning, the driver included. Only a live pilot of a vehicle that is not wrecked moves the hydraulics; a syncer's frame carries the server state with zero axes. The relay carries nitro clamped to ±1.
Rate limits. The server accepts from one connection, on average, at most 31 frames a second of a vehicle it drives (as driver or RC driver) and 10.5 a second of a vehicle it syncs, and at most 115 a second for all vehicles together (one driven and eight synced), each with half a second of burst; it drops the rest. The client sends frames of at most eight synced vehicles every 100 ms, however many it syncs, the longest-waiting first.
RemoteVehicleFrame (0x3B)
[u8 packet_id = 0x3B]
[u32 source_id] // the sender: the player in seat 0, or the syncer of a vehicle without a driver
[u32 source_token] // its generation (the recipient ignores a different generation of the id)
[u32 seq] // the vehicle's relay serial: +1 for every frame the server accepts, cyclic
[u32 vehicle_id]
[VehicleState state] // as in VehicleFrame; health, health_rev, siren_rev, nitro, hydraulics and pose_rev are the server's
[u32 relation_rev] // see Damage groups and relations
[u8 teammate]Total: 178 bytes. The relay of an accepted VehicleFrame to everyone the vehicle is streamed to, except the sender. relation_rev / teammate: see Damage groups and relations. seq is not the sender's seq but the vehicle's serial on the server: it grows with every accepted frame, whoever controls the vehicle, so it gives one order across a change of controller (the senders' counters are unrelated). The recipient keeps the last frame per vehicle and drops a frame that is not newer by serial number arithmetic (newer if ahead by less than 2^31); a frame of a different epoch than its copy is not applied. A frame is applied as follows:
- A vehicle driven by this sender's remote player on the recipient: the velocities once per new frame, then the position and rotation converge smoothly to the received ones, and the driver's steering, gas, brake and handbrake drive the vehicle instead of local input. A driver silent for more than ~0.5 s stops driving the vehicle. This covers cars, motorbikes and bicycles (a bike also takes the rider's lean, and the copy's tilt is set to the received one; a bicycle takes the rider's pedalling, sprint and hop: the rider's pose, crouch and jump follow
pedal/hop, the motion follows the frames); quad bikes (with the rider'sleanlike a bike, the tilt built from the steering), boats, helicopters and planes (the pilot's flight controls instead of local input; the copy's rotor / propeller, landing gear and nozzle are set to the received values). The recipient's local keys do not act on this vehicle. - A vehicle without a driver that the recipient does not sync itself: the same velocities and smooth convergence, without driving inputs. A frame older than ~0.5 s is not applied; the vehicle's own physics keeps running between frames.
- Health: a vehicle the recipient does not control (neither drives nor syncs) keeps the
healthof the last frame for as long as needed while it is not wrecked: smoke and fire look the same for everyone, and local hits do not accumulate. - Doors: in both cases the doors converge smoothly to the received open share within the same convergence window.
- Tow truck and tractor boom: both copies (driven or without a driver) set the received position on every new frame; the height of the hook a towed vehicle hangs on depends on it.
- Moving part of Dumper, Packer, Dozer, Forklift and Andromada: likewise on every new frame, together with its collision; between frames the part stands still, and the local part key does not act on the remote driver's vehicle.
- Turret and water cannon: on a vehicle driven by the remote player the turret stands at the received position (the local camera and keys do not turn it), and the water cannon sprays while the frame carries its bit; without a fresh frame from the driver the spray stops and the turret stays.
- Winch rope: both copies set the received length on every new frame, and local keys do not change it; where the load hangs depends on it. Searchlight: the remote pilot's copy switches it by the bit and points it where the pilot's does (a point in front of and below the helicopter by its pose).
- Nitro and hydraulics: the remote driver's copy burns nitro by the received level (it never lights a charge itself); the copy's hydraulics are on, raise and lower by the received state, and the pose follows the received axes.
- Train on rails: the copy takes the track and the speed along it and converges its distance along the track to the received one within the same window (farther than 50 m or on another track, at once); the game builds the carriages' pose from the distance. The copy's speed is held below the derail threshold and the remainder moves the distance: only the controlling player's copy derails. A derailed train converges by position, like a car.
Example: remote_vehicle_frame.bin.
VehicleShot (0x47)
[u8 packet_id = 0x47]
[u64 token] // the sender's session_token
[u32 order] // number of the first ray; the salvo's rays take order..order+count-1 in the counter shared with WeaponShot
[u32 vehicle_id] // the vehicle the sender drives
[u8 count] // rays in the salvo, 1..=2
[f32 rays[2][6]] // start_xyz, end_xyz of each ray; an unused slot is zeros
[u16 props_rev] // as in WeaponShotTotal: 68 bytes. A salvo of the driver's vehicle weapon. Unreliable, like WeaponShot. The sender sends the rays its game computed for one salvo: machine guns send the bullet rays, the Rhino cannon sends the aim ray the shell explodes on. The model defines the weapon:
| Model | Weapon | Rays | Hit weapon id | Game interval |
|---|---|---|---|---|
| Hunter 425 | machine gun | 1 | 38 | 60 ms |
| Sea Sparrow 447 | machine gun | 1 | 31 | 40 ms |
| Rustler 476 | twin machine guns | 2 | 31 | 80 ms |
| Predator 430 | twin machine guns | 2 | 52 | 150 ms |
| Rhino 432 | cannon | 1 | 51 (explosion) | 800 ms |
| RC Baron 464 | machine gun | 1 | 31 | 40 ms |
| RC Tiger 564 | minigun | 1 | 38 | 60 ms |
The server accepts a salvo if all of these hold:
- the sender is the spawned, live driver (seat 0) of this vehicle and the vehicle is not wrecked; for an RC, the player who drives it (
VehicleRemote); for RC Tiger, only while detonation is off; - the model has a weapon and
countequals its ray count; - every ray starts within 25 of the vehicle by its last accepted frame;
- every ray's length is within the weapon's limit: machine guns as a
WeaponShotof their hit weapon at the std skill tier with the gamemode's range; Predator and the cannon 90; orderis greater than the sender's last accepted number;- at least half the model's game interval has passed since the previous salvo.
A refusal is a drop plus a warning. Strict decoding drops count outside 1..=2, NaN/Inf in a used ray and a non-zero unused slot. Machine-gun rays are remembered to correlate a DamageReport with the hit weapon from the table, and count as a shot passing by vehicles (attribution of VehicleExplode); the cannon's ray becomes the cause of the explosion (see DamageReport). An accepted salvo is relayed as RemoteVehicleShot to those the shooter is shown to (see Player streaming).
Example: vehicle_shot.bin.
RemoteVehicleShot (0x48)
[u8 packet_id = 0x48]
[u32 id] // the shooter
[u32 player_token] // its generation
[u32 order] // from VehicleShot
[u32 vehicle_id]
[u8 count]
[f32 rays[2][6]]
[u16 props_rev] // from VehicleShot; for the cannon the server does not check it and the recipient does not read it
[u32 relation_rev] // see Damage groups and relations
[u8 teammate]
[ShotRewind rewind] // 34 bytes, see RemoteWeaponShot; for machine-gun rays; always rewound = 0 for the cannonTotal: 107 bytes. relation_rev / teammate: see Damage groups and relations; rewind: see RemoteWeaponShot. The recipient replays a machine-gun salvo with the weapon properties table of its props_rev, like a RemoteWeaponShot. It applies the salvo only for the shooter's current generation and discards stale ones by order together with RemoteWeaponShot (the counter is shared; an accepted salvo moves the mark to its last ray). A salvo that arrives before the shooter, the vehicle or the shooter's seat is shown waits for them; one older than ~0.5 s is not applied. The recipient checks the salvo against its own copy of the vehicle: a model with a weapon, count equal to its ray count, every ray starting within 40 of the copy, the length within the weapon's limit; otherwise it drops the salvo. If the shooter's remote player drives the recipient's copy of vehicle_id, that copy fires the salvo along the received rays: machine guns as bullets with tracers, muzzle flash and sound, the cannon as a shot and an explosion on the ray. For the time of the salvo's traces the recipient stands by rewind, as with RemoteWeaponShot. The victim's game computes the damage; the hit names the shooter and the ray number (DamageReport).
Example: remote_vehicle_shot.bin.
VehicleTow (0x49)
[u8 packet_id = 0x49]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 trailer_id] // the trailer (or towed vehicle); 0xFFFFFFFF is invalid
[u8 trailer_epoch]
[u32 tractor_id] // the towing vehicle; 0xFFFFFFFF = unhitch
[u8 tractor_epoch] // 0 on unhitchTotal: 23 bytes. Hitching. The game hitches and unhitches on the copy of the controlling player of the tractor (the driver, or without a driver its syncer): a tow truck lowers its boom onto a vehicle, a tractor backs up to a trailer, a hitch that is stretched or turned over breaks. The client sends VehicleTow for each such change once the game has made it on its copy (a change the game refuses sends nothing; a hitch it cannot report it undoes at once). On the other copies the game does not change the hitch; the server holds them. There is no unhitch key.
- Hitch: the server accepts it from a live, spawned player who controls the tractor, if both vehicles of these epochs are intact, streamed to the player and in the player's virtual world and interior; the trailer has no driver, does not hang on anything, the tractor tows nothing, the chain has no loop and at most 4 links; the game hitches the pair itself (tow truck 525: any vehicle except a trailer, a motorbike and a boat; tractor 531: the same and trailer 610; semis 403, 514, 515 and trailers 606, 607: trailers; 552: 611; 485, 583: 606..608); and the server positions are within 25 m. Then the resource event
trailer_attach(trailer, tractor, player):falsefrom a handler refuses; otherwise the server checks again and hitches. - Unhitch: accepted from the player who controls the trailer's current tractor, for the trailer's epoch; raises
trailer_detach(trailer, tractor, player). - Repeating the same hitch or unhitch changes nothing and raises no events. On a refusal, an unknown epoch, or a drop by the vehicle event rate limit (shared with
VehicleEnter, seeVehicleControl) the sender gets aVehicleTrailerwith the server's hitch, and its copy returns to it.
A gamemode hitch (dlmp.attach_trailer) is checked the same way except for the player: the same model pairs (the game holds no other hitch) and the same 25 m.
The controlling player of the tractor drives the hitched trailer: the server makes it the trailer's syncer (VehicleSyncer), and it sends the trailer's frames only while its copy of the trailer hangs on exactly the server's hitch (or on nothing, if there is no hitch). A hitch the game does not make on its copy it unhitches (VehicleTow without a tractor, event trailer_detach). The server unhitches a vehicle itself, without resource events, when a driver gets into it, when the trailer or the tractor is wrecked, and on their respawn and removal. A frozen vehicle (VehicleTransform) is never hitched, as trailer or as tractor.
Example: vehicle_tow.bin.
VehicleTrailer (0x4A)
[u8 packet_id = 0x4A]
[u32 event_id] // position in the Server → Client reliable stream
[u32 trailer_id]
[u32 tractor_id] // 0xFFFFFFFF = hitched to nothing
[u8 place] // 1 = the gamemode hitched it: the trailer is placed at the tractor's hook; only with a tractor_idTotal: 14 bytes. The trailer's current hitch, sent to everyone the trailer is streamed to on every change (critical, like VehicleOccupancy), and to the sole sender of a refused VehicleTow. The recipient brings its copy to it as soon as it has both vehicles and holds it there: a break the game makes on a copy without control of the tractor is not let through, and a removed hitch is restored (at most once per 0.5 s). place = 1 (dlmp.attach_trailer) puts the trailer at the hook with the tractor's heading, and the boom of the tow truck and the tractor at 10000; otherwise the hitch pulls the trailer from where it stands. The copy of the tractor's controlling player always puts the trailer at the hook when it brings it to the hitch: its pose of the trailer is the source of frames, and a pose the game cannot hold on a hitch would break the hitch at once. place without a tractor or place > 1 drops the packet.
Example: vehicle_trailer.bin.
VehicleWinch (0x4F)
[u8 packet_id = 0x4F]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 vehicle_id] // the load; 0xFFFFFFFF is invalid
[u8 vehicle_epoch]
[u32 heli_id] // the helicopter whose magnet picked it up; 0xFFFFFFFF = released
[u8 heli_epoch] // 0 on releaseTotal: 23 bytes. Winch. The gamemode gives a helicopter a winch (dlmp.set_vehicle_winch, a bit in VehicleParams); the rope hangs on every copy. The pilot lowers and raises the rope with the game's keys, the magnet at its end picks up the vehicle it touches, and the pilot releases it with the drop key. Only the copy of the helicopter's controlling player (the pilot, without a pilot its syncer; keys only for the pilot) picks up and releases. The client sends VehicleWinch for each change once the game has made it on its copy (a vehicle that is not the server's, a vehicle with people in it, or something that is not a vehicle it releases at once); on other copies the magnet picks up nothing and local keys do not reach the rope.
- Pick-up: the server accepts it from a live, spawned player who controls the helicopter, if both vehicles of these epochs are intact, streamed to the player and in the player's virtual world and interior; the helicopter has a winch whose magnet takes this model (magnet: cars, monster trucks, motorbikes, Dinghy 473 and Vortex 539, but not the quad bike, bicycles, trailers, trains, other boats or aircraft; small magnet: only RC Tiger 564); nobody sits in the load (in any seat) and nobody drives it remotely; neither the load nor the helicopter is in a hitch; the helicopter carries nothing; the load does not hang on another helicopter; and the server positions are within 30 m. Then the resource event
winch_attach(vehicle, heli, player):falsefrom a handler refuses; otherwise the server checks again and hangs the load. - Release: accepted from the player who controls the load's current helicopter, for the load's epoch; raises
winch_detach(vehicle, heli, player). - Repeating the same changes nothing and raises no events. On a refusal, an unknown epoch, or a drop by the vehicle event rate limit (shared with
VehicleEnter) the sender gets aVehicleLiftwith the server state, and its copy returns to it.
The controlling player of the helicopter drives the load: the server makes it the load's syncer (VehicleSyncer), and it sends the load's frames only while its copy of the load hangs on exactly the server's helicopter (or on nothing). The server releases the load itself, without resource events, when a player gets into it (any seat) or someone takes it remotely, when the load or the helicopter is wrecked, on their respawn and removal, and when the winch is removed or changed. A frozen vehicle (VehicleTransform) is never picked up, as load or as helicopter.
Example: vehicle_winch.bin.
VehicleLift (0x50)
[u8 packet_id = 0x50]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id] // the load
[u32 heli_id] // the helicopter whose winch carries it; 0xFFFFFFFF = noneTotal: 13 bytes. The load's current winch, sent to everyone the vehicle is streamed to on every change (critical, like VehicleOccupancy), and to the sole sender of a refused VehicleWinch. The recipient hangs its copy on the magnet of the helicopter's copy as soon as it has both and the helicopter has lowered its rope, and holds it there: a release the game makes on a copy without control of the helicopter is not let through (the load is hung back at most once per 0.5 s), and the magnet releases anything the server did not hang on the rope.
Example: vehicle_lift.bin.
TrainState (0x4B)
[u8 packet_id = 0x4B]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id] // the locomotive
[u8 flags] // bit0 = faces along the track (clockwise), bit1 = derailed, bit2 = the packet sets the speed
[f32 speed] // speed along the track, units per step, + = distance grows; only with bit2, otherwise 0Total: 14 bytes. A train's direction and derailment; authority: the server. Sent to everyone the train is streamed to (critical, like VehicleOccupancy) on every change: a derailment the controlling player reported (see VehicleFrame), and the gamemode commands dlmp.set_train_direction / set_train_derailed / set_train_speed. The recipient holds its copy at the server's direction and derailment. A reversal turns every carriage around (the carriages keep their places on the track, and the reversed locomotive pushes them); a derailment releases every carriage into physics; a return puts the locomotive, stationary, at the nearest point of its track. The driver's copy keeps its own derailment until it is confirmed and returns to the rails only on the server's return. Every copy of the same generation, including one created later, takes the speed (bit2) once, and the controlling player's frames continue from it; a train without a driver brakes to a stop, as an empty train does in the game. Unknown bits, NaN/Inf, |speed| > 4, and a speed without bit2 drop the packet.
Example: train_state.bin.
VehicleRemote (0x4C)
[u8 packet_id = 0x4C]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id] // the RC the recipient now drives; 0xFFFFFFFF = none any more
[u8 detonation] // 1 = the fire key and an RC Bandit crash blow it up; 0 with 0xFFFFFFFFTotal: 10 bytes. Remote-controlled vehicles. Sent only to the player concerned (the packet names no player), critical. The gamemode gives a player an RC model (dlmp.set_remote_vehicle): the client takes its copy under remote control (the camera and keys drive the RC; the body stands still with neutral input in PlayerSync), and the server makes the player the RC's syncer (see VehicleSyncer; frames as in VehicleFrame). An RC has no driver: to observers it is an ordinary vehicle without a driver. The packet comes again when detonation changes, and with 0xFFFFFFFF when the RC is released: an exit by key (VehicleRemoteExit), the RC farther than dlmp.rc_range() from the body by the RC's frame (150 m by default, at most 180), death, a world scope change, getting into a vehicle, the RC's explosion, respawn or removal, or dlmp.remove_remote_vehicle. The RC's engine is an ordinary parameter (see VehicleParams) that the gamemode switches on: an RC has no seated driver to send VehicleControl. Detonation: see VehicleExplode. A client that has blown up an RC does not take it again until the next VehicleRemote: a detonation under a detonation value the server has already changed is refused, and the packet with the new value returns the RC. detonation above 1, or non-zero with 0xFFFFFFFF, drops the packet.
Example: vehicle_remote.bin.
VehicleRemoteExit (0x4D)
[u8 packet_id = 0x4D]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 vehicle_id] // the RC the sender drivesTotal: 17 bytes. Leaving an RC. The F key while the player drives an RC. The server releases the RC (VehicleRemote with 0xFFFFFFFF) only if the sender drives exactly this RC; the rate limit is shared with VehicleEnter. Resources get player_remote_exit(player, vehicle, "exit") ("range" when the RC is released by distance). Another player's RC or a repeated exit is a no-op with a ServerAck.
Example: vehicle_remote_exit.bin.
VehicleRemoteEnter (0x4E)
[u8 packet_id = 0x4E]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 vehicle_id] // an RC near the senderTotal: 17 bytes. Taking an RC by key. The F key on foot near an RC: nobody boards an RC, so this is how a player takes it again after an exit. The server checks the same as for a gamemode grant (VehicleRemote: alive, on foot, the same world scope, the RC streamed, not wrecked, nobody driving it), plus the RC's lock, that the sender drives no RC (exit first), that the sender is not frozen, and that the RC is within 10 m of the sender's position; the rate limit is shared with VehicleEnter. A request that passes goes to resources as player_remote_enter(player, vehicle): false from a handler refuses; otherwise the server checks again and grants the RC (VehicleRemote). A refusal is only a ServerAck; there is no other answer.
Example: vehicle_remote_enter.bin.
VehicleSyncer (0x3C)
[u8 packet_id = 0x3C]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id]
[u8 active] // 1 = start syncing, 0 = stopTotal: 10 bytes. The syncer of a vehicle without a driver. Sent only to the syncer itself. The server keeps at most one syncer per vehicle without a driver, chosen in this order:
- a hitched vehicle (
VehicleTrailer): the player who controls its tractor (the driver or the tractor's syncer), if the vehicle is streamed to that player; its passengers do not sync it. Likewise a winch load (VehicleLift): the player who controls the helicopter; - a vehicle with a passenger: the first passenger;
- otherwise the previous syncer, while the vehicle is streamed to it and it is closer than 130 m;
- otherwise the nearest spawned player the vehicle is streamed to, within 130 m; if there is none, the vehicle has no syncer.
A vehicle with a driver has no syncer: the driver sends its frames. A driver who is paused (paused in its PlayerSync) or frozen (SetFrozen) does not count: the vehicle gets a syncer by the rules above, and after the pause the driver takes the vehicle over from wherever the syncer brought it. A paused or frozen player is never a syncer. The choice is recomputed on every streaming update (the server's periodic tick and any change of seats). A change of syncer sends active = 0 to the previous one and active = 1 to the new one, and raises the resource event vehicle_syncer(vehicle, syncer, previous) (nil = no syncer / the previous one left), once per vehicle per handled packet or tick: changes within one pass collapse, and a return to the previous syncer is not reported.
Example: vehicle_syncer.bin.
VehicleExplode (0x3D)
[u8 packet_id = 0x3D]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 vehicle_id]
[u8 epoch] // the vehicle generation that blew up
[u8 cause] // 0 exploded, 1 drowned
[u8 has_attacker] // 1 = an attacker follows, 0 = none (the fields are zero)
[u32 attacker_id] // the player the copy holds as the last to damage it
[u32 attacker_token] // its generationTotal: 28 bytes. A vehicle's explosion. The client blows up a server-owned vehicle only on VehicleDeath; until then every copy holds off the explosion and keeps burning. The controlling player (the driver, without a driver the syncer) sends VehicleExplode when its copy should blow up (burning, a crash, a bomb) and repeats it at most once a second until the death is confirmed: an explosion refused at first (an instant one from ramming) is accepted after the burning.
The server accepts the first explosion of the current epoch from a live player who controls the vehicle now, if the server's health of the vehicle allows it: the vehicle has been burning (health below 250) for at least 4 s, or, for a plane or helicopter, it burns and either moved faster than 0.2 per step in its last frame or the explosion has a credited killer (below). A train neither explodes nor drowns: its VehicleExplode is refused. The vehicle then becomes a wreck (health 0); entering it is refused (VehicleOccupancy deny; dlmp.put_player_in_vehicle returns an error); resources get vehicle_death(vehicle, cause, killer) (cause is "explosion" or "water", killer a player or nil). Another player's, a repeated or a stale explosion is dropped silently. The occupants die in their own clients (DeathReport as usual).
RC detonation. An RC explosion from the player who drives it (VehicleRemote) with detonation on is accepted at once, without burning, and credited to that player (killer is the sender; the attacker in the packet does not matter); the RC is released.
The vehicle's killer. The attacker is whoever the game recorded as the last to damage the copy, if that is a player: a shot, an explosion or fire; if it is a vehicle, its driver (an aircraft rocket, ramming). Damage from the world gives no attacker. Ramming alone is never the cause. The server credits the attacker with an explosion (cause = 0) only if it is not the sender itself and the same player of the same generation in the same scope explains the explosion with an accepted action:
| Action | Window before the explosion | Distance from the vehicle |
|---|---|---|
WeaponShot whose ray passed within 8 of the center of the vehicle of this epoch | 20 s | — |
ProjectileCreate 16 (grenade), SatchelDetonate | 20 s | 60 / — |
ProjectileCreate 18 (molotov), flamethrower, a credited explosion of another vehicle, CreateExplosion with this creator | 85 s | 80 |
ProjectileCreate 19 / 20 (rocket) | 85 s | 200 (fired from a vehicle: plus the rocket's flight path, see ProjectileCreate); a rocket 20 at any distance for its target vehicle of this epoch |
The windows with fire cover the fire the cause leaves behind (65 s) and the burning of a vehicle it set alight. A credited killer goes into VehicleDeath and vehicle_death(vehicle, cause, killer). Everyone alive in the vehicle gets that killer for 5 s: a DeathReport in that window raises player_death with this killer and weapon 51, unless another accepted damage or that player's VehicleExit came first (a dead client sends no exit). The vehicle's explosion and fire become the killer's cause for DamageReport 51 / 37. Explosion damage occurs for everyone, the controlling player included, only after the accepted explosion: the copies blow up on VehicleDeath. An uncredited attacker means no killer. The core never respawns a vehicle; that is the gamemode's choice (dlmp.respawn_vehicle). Covered: cars (including the quad bike), motorbikes, boats, helicopters and planes.
Drowning (cause = 1). The controlling player sends it when its copy has sunk so far that the engine dies and the occupants drown, and has stayed so for more than 1.5 s (a short dip is not a death). The server accepts it like an explosion (once per epoch; an unknown cause is dropped): the vehicle becomes a wreck, but its health stays at the last reported value; resources get vehicle_death(vehicle, "water", nil). The server does not unseat the occupants; they get out and drown as usual.
Example: vehicle_explode.bin.
VehicleDeath (0x3E)
[u8 packet_id = 0x3E]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id]
[u8 epoch]
[u8 cause] // as in VehicleExplode
[u8 has_killer] // 1 = a killer follows, 0 = none (the fields are zero)
[u32 killer_id] // the killer the server credited
[u32 killer_token]Total: 20 bytes. An accepted VehicleExplode, sent to everyone the vehicle is streamed to, the sender included. The recipient blows up its copy of this epoch (fire, explosion, death of the occupants) if it is not yet wrecked; a copy of another epoch is left alone. The killer becomes the author of this explosion and fire on the recipient, so their damage arrives in DamageReport with that killer. A drowned vehicle (cause = 1) is left alone: it stays as it is and never explodes for anyone; a show of such a vehicle (VehicleSync bit1) creates it looking intact, not as a silent hulk.
Example: vehicle_death.bin.
VehicleDamage (0x3F)
[u8 packet_id = 0x3F]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 vehicle_id]
[u8 epoch] // the vehicle generation
[VehicleDamageStatus status]
[u16 damage_rev] // revision of the last gamemode damage command the copy tookExample: vehicle_damage.bin.
VehicleDamageStatus
[u32 panels] // 4 bits per panel, nibble i = panel i: 0 LF fender, 1 RF, 2 LR, 3 RR, 4 windscreen,
// 5 front bumper, 6 rear bumper; each 0..3; bits 28..31 are 0
[u8 doors[6]] // bonnet, boot, LF, RF, LR, RR; 0 intact, 2 damaged, 4 missing
[u32 lights] // broken light bits: 2 bits per light, 1 = broken (mask 0x55)
[u8 wheels[4]] // 0 intact, 1 burst, 2 fallen offTotal: 38 bytes (the status is 18). Whether a door is open is not damage: it is the open share in VehicleState, so a door in the status is only 0, 2 or 4 (the server accepts ≤ 4 and clears the open bit 1 in a report).
The vehicle's damage. The controlling player (the driver, without a driver the syncer) sends it when its copy's status changes, at most ~10 times a second (the latest wins). The server accepts a status of the current epoch from a live player who controls the vehicle now, while the vehicle is not wrecked, if the values are in range (seven panels each ≤ 3 with the top nibble clear, doors ≤ 4, wheels ≤ 2) and damage_rev equals the server's current revision; otherwise it drops the report silently. A report only adds damage: the server takes the per-component maximum with the stored status (lights: the union within the mask); only the gamemode and a respawn repair. The stored status (shown to late joiners, cleared by a respawn) goes to the others as RemoteVehicleDamage, only if it changed. Covered: cars (and the quad bike, monster trucks) and motorbikes. A motorbike's status is its wheels only: wheels[0] front and wheels[1] rear (0 intact, 1 burst), the rest zero. Bicycles, boats and aircraft have no status.
RemoteVehicleDamage (0x40)
[u8 packet_id = 0x40]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id]
[u8 epoch]
[VehicleDamageStatus status]
[u16 damage_rev] // revision of the last gamemode damage commandTotal: 30 bytes. An accepted VehicleDamage, sent to everyone the vehicle is streamed to except the sender. A recipient that does not control the vehicle brings its copy of this epoch to the status: parts coming off now fly off, parts lost earlier do not; where the status is less damaged than the copy, the copy is repaired first. A copy the recipient does not control is checked against the last status once a second, so its local damage does not stay. The windscreen (panel 4) is drawn cracked at 1 or 2 and knocked out at 3.
A status the gamemode sets (set_vehicle_damage_status / repair_vehicle) goes to everyone the vehicle is streamed to, including the controlling player, with a new damage_rev (the relay of a report does not change the revision). The controlling player brings its copy to it (with parts flying off) and from then on sends VehicleDamage with that revision; the server drops its report sent before the command.
Example: remote_vehicle_damage.bin.
VehicleHealth (0x41)
[u8 packet_id = 0x41]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id]
[u8 epoch] // the vehicle generation
[f32 health] // 0 ..= 100000; 1000 is full
[u16 health_rev] // the new health command revisionTotal: 16 bytes. The vehicle's health from the gamemode. The server sends it to everyone the vehicle is streamed to, including the controlling player, when the gamemode sets the health (set_vehicle_health, repair_vehicle); never for a wreck. Every recipient sets this health on its copy of this epoch (below 250 the vehicle burns and blows up as usual, at the controlling player). A non-controlling recipient holds it until a frame with a new health arrives. A copy that set this health echoes health_rev in VehicleState from that moment; a frame with an older health revision does not change the health. Revisions are u16: a copy lags behind by fewer than 512 commands (beyond that the reliable lane disconnects it), so an equality check never mistakes an old revision after a wrap. A VehicleSync show after the command carries the new health and revision.
Example: vehicle_health.bin.
VehicleParams (0x42)
[u8 packet_id = 0x42]
[u32 event_id] // position in the Server → Client reliable stream
[u32 vehicle_id]
[u16 params] // bit0 engine, bit1 lights, bit2 locked for the recipient, bit3 magnet, bit4 small magnet
// (the helicopter's winch, at most one of the two), bit5 alarm, bit6 siren, bit7 objective marker
// for the recipient, bit8 has a siren
[u8 doors] // doors open by the last command (bit = bonnet, boot, LF, RF, LR, RR)
[u8 doors_set] // doors this command opened or closed
[u16 siren_rev] // revision of the last gamemode siren switch; the driver's copy echoes it in its framesTotal: 15 bytes. Vehicle parameters; authority: the server. They change by a gamemode command (dlmp.set_vehicle_engine, set_vehicle_lights, set_vehicle_locked, set_vehicle_door, the helicopter winch set_vehicle_winch, set_vehicle_alarm, set_vehicle_siren, set_vehicle_has_siren, set_vehicle_locked_for, set_vehicle_objective) or by a driver's VehicleControl the gamemode lets through. The server sends the packet to everyone the vehicle is streamed to when a parameter changes (a door command always); a parameter of one player goes to that player only. params and doors are the full state, and a VehicleSync show carries the same. The lock (bit2) is the recipient's own if the gamemode set one, otherwise the vehicle's; the objective marker (bit7) is only the recipient's own.
Defaults. Everything is off, the doors are closed, the vehicle is unlocked; a siren exists on models that have one (Firetruck 407, Ambulance 416, Mr Whoopee 423, 427, 433, 490, 523, 528, 596..599, 601; not Rhino 432 and not the Predator boat 430). A siren can be given only to cars, motorbikes, bicycles and Vortex 539; on boats, aircraft, trains, trailers and RCs it is mute. The core never starts an engine on its own. A respawn is a new life with default parameters: the engine, lights, alarm and siren are off, the doors closed, and the lock, the winch and the per-player parameters are removed (a gamemode that needs a permanent lock or winch sets them after dlmp.respawn_vehicle); a given or removed siren (bit8) stays. A player leaving also removes that player's parameters.
The recipient:
- holds its copy's engine equal to
paramsevery frame (the game starts it itself when a driver gets in); without the engine the vehicle does not move, and a sinking vehicle's engine does not start; - sets the lights, the lock and the winch on a change (the lights shine only with the engine running, as the game draws them); a removed or changed winch takes the rope and hook away and releases the load, and the helicopter lowers a new rope on its next step;
- opens or closes the doors in
doors_setonce (on a show, the open ones fromdoors); afterwards a door lives as usual (swings, closes when someone gets in), and its open share travels inVehicleState; - keeps the alarm sounding while bit5 is set (the horn sounds intermittently, the lights flash only with the engine running), and a cleared bit silences it; it is heard on cars and motorbikes;
- sets the siren (bit6) and its presence (bit8) on a change: a vehicle with a given siren switches it on with a short press of the driver's horn and sounds without flashing lights; a vehicle whose siren was removed only sounds its horn;
- sets the objective marker (bit7), an arrow above the vehicle without a radar icon, on a change.
The server does not seat a player in a locked vehicle on a VehicleEnter (VehicleOccupancy deny), and the clients show the attempt to open a locked door; dlmp.put_player_in_vehicle does not check the lock; getting out is always possible.
Example: vehicle_params.bin.
VehicleControl (0x43)
[u8 packet_id = 0x43]
[u64 token]
[u32 event_id] // position in the Client → Server reliable stream
[u32 vehicle_id]
[u8 control] // 0 engine, 1 lights, 2 lock
[u8 value] // 1 on / lock, 0 off / unlockTotal: 19 bytes. The driver's keys. The server accepts only the engine and the lights, from the player in seat 0 of this vehicle who is not frozen, while the vehicle is not wrecked (control = 2 is dropped: only the gamemode locks a vehicle), and raises the resource event vehicle_control(vehicle, player, control, on) (control is "engine" or "lights"). If no handler returns false, the server applies the request as a gamemode command (VehicleParams to everyone); otherwise nothing changes. Everything else is dropped silently. A lock also holds the driver who locked it in, so only the gamemode sets it (dlmp.set_vehicle_locked).
Vehicle event rate limit. VehicleEnter, VehicleExit, VehicleControl, VehicleDamage, VehicleTow, VehicleWinch, VehicleRemoteExit and VehicleRemoteEnter of one connection share one limit: at most 30 at once and 15 a second. An event past it is acknowledged but dropped.
Example: vehicle_control.bin.
VehicleTuning (0x52)
[u8 packet_id = 0x52]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u32 vehicle_id]
[u16 components[17]] // the part of each kind (index = kind, 0..16), 0 = none; part id 1000..=1193
[u8 paintjob] // 0..=7, 0xFF = plain colors
[u8 plate[8]] // A-Z, 0-9, space; all 0 = the game's plate (random on each copy)
[u8 dirt] // 0..=15, 0xFF = not set
[u8 flags] // bit0 taxi light
[u8 nitro] // nitro charges left, 0..=100; 0 without nitroTotal: 55 bytes. Vehicle tuning; authority: the server. The gamemode sets it (dlmp.add_vehicle_component, remove_vehicle_component, set_vehicle_paintjob, set_vehicle_plate, set_vehicle_dirt, set_vehicle_taxi_light, set_vehicle_nitro_charges); the client only applies it. Nitro charges: a part is installed full (1008: 5, 1009: 2, 1010: 10, and full again when installed again), a respawn refills them, removal zeroes them; the pilot's burning spends them (VehicleFrame). The packet is the whole state; the server sends it, critical, to everyone the vehicle is streamed to on a change, and after every VehicleSync show (including a respawn's) of a vehicle with non-empty tuning. A respawn keeps the tuning.
Part kinds, as the game numbers them: 0 hood, 1 vents, 2 spoiler, 3 side skirts, 4 front bull bar, 5 rear bull bar, 6 lamps, 7 roof, 8 nitro, 9 hydraulics, 10 stereo, 11 unused, 12 wheels, 13 exhaust, 14 front bumper, 15 rear bumper, 16 misc. The server refuses a part the model does not take by the game's data (carmods): the model's class is car, monster truck or quad bike; the part is in the model's own list (or is the pair of one); wheels, nitro, hydraulics and stereo fit every such model. A paintjob must be below the model's paintjob count; the taxi light only fits 420 and 438. The client decoder rejects a packet with a part id out of range, a paintjob ≥ 8 (other than 0xFF), a plate character outside the set or a partly set plate, dirt > 15 (other than 0xFF), an unknown flag, or more than 100 charges.
The recipient brings every copy of the vehicle to the packet, including one created later (after streaming or a respawn), and a vehicle without tuning to the empty state: parts missing from the packet are removed (including the hydraulics the game gives lowriders on its own when it creates them). A part is loaded before it is installed; a part that does not fit the model by the client's data or sits in the wrong kind is skipped. The nitro charges are set right after the parts, once per packet: between packets the driver's copy spends them itself, as the game does. The paintjob, plate, dirt and taxi light are set after the parts; a removed plate becomes a new random one. The dirt then changes on each copy with driving, as in the game. Hiding a vehicle forgets its tuning (the next show sends it again).
Example: vehicle_tuning.bin.
VehicleHandling (0x53)
[u8 packet_id = 0x53]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u32 vehicle_id]
[u32 mask] // bit i = property i is set by the gamemode; bits 21..31 are 0
[f32 values[21]] // the value of a set property (HANDLING.CFG units), 0 for one not setTotal: 97 bytes. Vehicle handling; authority: the server. The gamemode sets it (dlmp.set_vehicle_handling); the client only applies it. The packet is the whole state; the server sends it, critical, to everyone the vehicle is streamed to on a change, and after every VehicleSync show (including a respawn's) of a vehicle with at least one property set. A respawn keeps the handling.
| i | Property | Range | i | Property | Range |
|---|---|---|---|---|---|
| 0 | mass, kg | 1..=100000 | 11 | abs | 0 or 1 |
| 1 | turn_mass | 1..=10000000 | 12 | steering_lock, degrees | 0..=360 |
| 2 | drag_coeff | 0..=200 | 13 | suspension_force_level | 0..=100 |
| 3–5 | center_of_mass_x / _y / _z, m | −10..=10 | 14 | suspension_damping | 0..=100 |
| 6 | traction_multiplier | −100..=100 | 15 | suspension_high_speed_damping | 0..=600 |
| 7 | traction_loss | 0..=100 | 16 | collision_damage_multiplier | 0..=10 |
| 8 | traction_bias | 0..=1 | 17 | max_velocity, km/h | 0.1..=1000 |
| 9 | brake_deceleration | 0..=1000 | 18 | engine_acceleration | 0..=1000 |
| 10 | brake_bias | 0..=1 | 19 | engine_inertia | 0.01..=1000 |
| 20 | number_of_gears | 1..=5, integer |
The client decoder rejects a packet with a property bit ≥ 21, a set property's value out of range (or NaN), a fractional ABS or gear count, or a non-zero value of a property that is not set. The drive type, suspension height and model flags are not settable by the gamemode.
The recipient applies the set properties on top of the model's values from HANDLING.CFG to every copy of the vehicle, including one created later (after streaming or a respawn); a vehicle without set properties drives with the model's values. Hiding a vehicle forgets its handling.
Example: vehicle_handling.bin.
VehicleTransform (0x54)
[u8 packet_id = 0x54]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u32 vehicle_id]
[u8 epoch] // the vehicle generation
[u32 relay_seq] // the vehicle's relay serial at the time of the command (see RemoteVehicleFrame)
[u16 pose_rev] // the new transform revision
[u8 flags] // bit0 position, bit1 rotation, bit2 velocity, bit3 angular velocity; bit4 frozen
// (only with bit0 and bit1); bits 5..7 are 0
[f32 pos[3]] // world position
[f32 rot[4]] // unit quaternion x, y, z, w, as VehicleState.rot
[f32 move_speed[3]] // velocity, game units per physics step
[f32 turn_speed[3]] // angular velocity, radians per physics stepTotal: 69 bytes. Position, rotation, velocities and freezing of a vehicle by the gamemode. The controlling player drives the vehicle's position and velocities; a gamemode command (dlmp.set_vehicle_position / set_vehicle_rotation / set_vehicle_velocity / set_vehicle_turn_velocity / set_vehicle_frozen) is the server's, with a revision. The server sends the packet, critical, to everyone the vehicle is streamed to, the controlling player included; fields not set in flags are zero. The fields apply to the copy of this epoch once: a position teleports the vehicle, which stops there (velocities 0); a rotation keeps the velocities. A copy that took the packet echoes pose_rev in VehicleState from that moment; the server drops a frame with an older revision (as with health_rev; the revisions are u16). The recipient raises the vehicle's mark to relay_seq, as with a VehicleSync show: a frame sent before the command is not applied over it; if a frame newer than the command arrived before it, the pose and velocities from the packet are not applied, since that frame already carries them. A copy not yet created takes the packet as soon as it appears.
Freezing (bit4). Every copy holds the vehicle at the received pos / rot with zero velocities every frame and before every physics step: neither the driver nor a push moves it. The server keeps its own pose in the frames of a frozen vehicle (see VehicleFrame). A freezing packet always carries the server's position and rotation; unfreezing is a packet without bit4 and fields. A gamemode position or rotation also moves a frozen vehicle (a packet with bit4); velocities are not set on it. A respawn keeps the freeze; a VehicleSync show of a frozen vehicle (including a respawn's) is followed, critical, by this packet with the current revision, and likewise with the rotation bit when the server's rotation of the vehicle is not level at its heading (a show does not restore velocities). A frozen vehicle is never taken by a hitch (VehicleTow, dlmp.attach_trailer) or a winch (VehicleWinch), including as a tractor or a helicopter.
Server checks. The position is inside the world (as in VehicleFrame), the velocity ≤ 200 m/s, the angular velocity ≤ 25 rad/s (on the wire per step, divided by 50), all finite; the vehicle is not a train and not a wreck. A new position, rotation or freeze first releases the vehicle from any hitch and winch (both ends, VehicleTrailer / VehicleLift); a new position carries the occupants along (their server position is the vehicle's until their next frame), and streaming follows it in the same response. The client decoder rejects an unknown bit, a freeze without position and rotation, NaN/Inf, a set field outside the vehicle frame bounds (position inside the world, |rotation norm − 1| ≤ 0.1, velocity ≤ 5, angular velocity ≤ 1 per step), and a non-zero field that is not set.
Example: vehicle_transform.bin.
VehicleColors (0x55)
[u8 packet_id = 0x55]
[u32 event_id] // position in the per-recipient Server → Client reliable stream
[u32 vehicle_id]
[u8 color1][u8 color2] // primary / secondary color index, 0..=127Total: 11 bytes. Repainting a vehicle by the gamemode. The server sends it to everyone the vehicle is streamed to when the gamemode changes the colors (dlmp.set_vehicle_colors); only for a vehicle that is not wrecked, and not without a change. Every recipient repaints its copy and reapplies the paintjob, if there is one (VehicleTuning). A respawn keeps the colors; a VehicleSync show carries the current ones. The client decoder rejects a color above 127.
Example: vehicle_colors.bin.
