From ioquake3 wiki
At its basic level, a server message consists of the ID of the last client command that it received along with a list of server operations. There are several different types of server operations. To identify which type of operation it is, each operation in the list starts with an 8-bit identifier code. The last operation in the list is identified with a special EOF code.
Structures
top-level format
nop
| 8 bits | 0x01 nop indicator
|
gamestate
| 8 bits | 0x02 gamestate indicator
|
| 32 bits | server's last command ID
|
| (<configstring> | <baseline>)*
|
| 8 bits | 0x08 EOF indicator
|
| 32 bits | client ID
|
| 32 bits | randomly generated checksum seed value
|
configstring
| 8 bits | 0x03 configstring indicator
|
| 16 bits | config ID
|
| string | config value
|
baseline
| 8 bits | 0x04 baseline indicator
|
| <entity>
|
server-command
| 8 bits | 0x05 server-command indicator
|
| 32 bits | command ID
|
| string | command value
|
download
| 8 bits | 0x06 download indicator
|
| 16 bits | block number
|
| if {block number} == 0x0000: // first block
|
| 32 bits | file size
|
| if {file size} == 0xFFFFFFFF: // error indicator
|
|
|
| else
|
| 16 bits | block size
|
| data | data stream, {block size} bytes long
|
|
|
| else
|
| 16 bits | block size
|
| data | data stream, {block size} bytes long
|
|
snapshot
| 8 bits | 0x07 snapshot indicator
|
| 32 bits | server time
|
| 8 bits | last frame num
|
| 8 bits | snapshot flag bits
|
| 8 bits | area mask size
|
| data | area mask, {area mask size} bytes long
|
| <player-state>
|
| <entity>*
|
| 10 bits | 0x3FF end of entities indicator
|
entity
| 10 bits | entity ID
|
| 1 bit | removed-entity indicator
|
| if removed-entity != 0x1:
|
| 1 bit | changed-entity indicator
|
| if changed-entity == 0x1:
|
| 8 bits | max changed field index
|
| loop {max changed field index} times:
|
| 1 bit | changed-field indicator
|
| if changed-field == 0x1:
|
| 1 bit | is-not-zero indicator
|
| if is-not-zero == 0x1:
|
|
|
| else:
|
|
|
|
|
|
|
int-value
| N bits | value, where N depends on field index
|
float-value
| 1 bit | full-float indicator
|
| if full-float == 0x1:
|
| 32 bits | value, as C float
|
|
| else:
|
| 13 bits | value, as unsigned int; subtract (1<<12) to return signed int
|
|
If a field has floating point values, but its current value is a small integer (< ±4096) without a fractional part, then it is transmitted as a 13-bit unsigned integer instead of transmitting it as a full 32-bit float. To convert a small signed integer that is between -4096 and 4095 to a 13-bit unsigned integer, we simply add 4096 (1<<12) to the number before we send it and then subtract 4096 after it's received.
player-state
| 8 bits | max changed field index
|
| loop {max changed field index} times:
|
| 1 bit | changed-field indicator
|
| if changed-field == 0x1:
|
|
|
|
| 1 bit | changed-state indicator
|
| if changed-state == 0x1:
|
|
|
values
| 1 bit | changed-values indicator
|
| if changed-values == 0x1:
|
| 16 bits | changed value bitmask
|
| loop for each bit set in {changed value bitmask}:
|
|
|
|
See also