Byte Order and Packing
The match server runs on an x86 machine; some players are on ARM phones. When the server sends the number 7777, every client must read 7777, not 24862. And with 16 kites sent 20 times a second, every byte saved per kite is worth having. This lesson turns a kite's state into exact bytes and back.
The rule
On the wire, big end first — convert every multi-byte number, both ways.
A number longer than one byte can be stored in two orders:
- Big-endian — the most significant byte first. 7777 is
0x1E61, sent as1E 61. This is network byte order, used by the IP, TCP and UDP headers. - Little-endian — the least significant byte first:
61 1E. This is how x86 machines, and in practice ARM ones too, hold numbers in memory. Read61 1Eas big-endian and you get 24862.
So a program converts on the way out and again on the way in. In C, htons and htonl ("host to network, short or long") convert 16-bit and 32-bit values going out, and ntohs and ntohl convert them coming in. On a big-endian machine they do nothing, which is fine: the same code stays correct everywhere. In Python, the struct module packs and converts in one step, and the ! prefix means network order:
import struct
# protocol id "MA", sequence, ack, ack bits: 2 + 2 + 2 + 4 bytes
header = struct.pack("!HHHI", 0x4D41, 1042, 1039, 0b1101)
len(header) # 10
struct.unpack("!HHHI", header) # (19777, 1042, 1039, 13)A single byte needs no conversion; order only matters when a number spans several bytes.
Packing makes each field exactly as big as it needs to be. Here is the 8-byte Manja Arena kite:
| Field | Bytes | Meaning |
|---|---|---|
| kite id | 1 | 0 to 15 |
| x, y | 2 + 2 | position in tenths of a metre |
| heading | 1 | 256 steps per full turn, about 1.4° each |
| tension | 1 | 0 to 255 |
| flags | 1 | bit 0 pulling, bit 1 cut, bit 2 boosting |
Flags are read and written with bit operations: flags & (1 << 2) tests boosting, and flags | (1 << 1) sets cut.
Never copy a C struct straight onto the wire with memcpy. The compiler may insert padding between fields, and the machine's own byte order leaks out. Pack every field explicitly.
The shortcut
To store an angle in one byte: byte = degrees × 256 ÷ 360. To read it back: degrees = byte × 360 ÷ 256.
The state
Kite 5 is at x = 41.0 m and y = 22.5 m, heading 90°, with tension 200, pulling and boosting.
Drills
Answer fast — trust the rule.
Port 7777 is 0x1E61. In what order do its bytes go on the wire?
Which field needs no byte-order conversion?
A kite's heading is 270°. Which byte encodes it, at 256 steps per full turn?
A kite's flags byte is 0b101. Which flags are set?
Why shouldn't the server memcpy its C kite struct straight into a packet?
Remember
- On the wire, big end first — convert every multi-byte number, both ways.
- Angle byte = degrees × 256 ÷ 360; pack every field explicitly.
- Trap: sending raw structs, or forgetting to convert on the way back in.
