Transport
The transport protocol is a custom UDP-based communication layer designed for real-time multiplayer games like R-Type. It facilitates reliable server-client communication with essential features for game networking.
Core Features:
- Unreliable messaging for time-critical game state updates
- Reliable messaging with acknowledgment system
- Robust client/server connection handling with timeout detection
- Future enhancements planned:
- Congestion control and latency monitoring
- Protection against replay attacks
- Packet encryption and signing
This protocol is internally referred to as WOKE
(World-state Online
Kommunication Engine).
Packets
The protocol transmits data through UDP datagrams, with a maximum packet size of 1472 bytes (including UDP and protocol headers) 1.
The fundamental unit of communication is a command. The protocol bundles these commands into packets. Application code interacts only with commands, while packet handling is managed internally by the protocol.
Connection Management
The protocol operates on a 30Hz fixed-rate loop for optimal real-time performance.
During each cycle:
- Both client and server transmit packets containing pending commands
- If no commands are queued, a
KeepAlive
packet maintains the connection - Reliable commands are retransmitted until acknowledged
- Connections are terminated after 32 packets remain unacknowledged
Acknowledgement System
The protocol implements a robust acknowledgment mechanism using two header fields:
ack
: Indicates the sequence number of the last received packetack_bitfield
: A 32-bit field tracking previously acknowledged packets
This dual-field system ensures reliable delivery even when acknowledgment packets are lost.
Reliable Command Delivery
For reliable commands, the sender tracks the initial sequence number and continues transmission until acknowledgment. This ensures guaranteed delivery of critical game data.
Reliable commands are guaranteed to be delivered once, but there is not guarantee of order preservation. This must be implemeted at the application level if required for some commands (e.g. by embedding a timestamp in the command payload).
Communication automatically terminates if the number of pending reliable commands exceeds 1024.
Sequence Number Implementation
The protocol uses 16-bit unsigned integers for sequence numbers, implementing
proper wraparound handling to maintain continuous operation (if sequence numbers
reach 65535
, the next sequence number will be 0
).
Splitted Commands
If a reliable command is larger than the maximum packet size, it is split into multiple parts sent in separate packets. The receiver reassembles the command based on the split index and count (see the command structure below).
Packet Structure
Header Format
Every packet includes a 12-byte header with the following structure:
struct PacketHeader {
uint8_t protocol_id; // Fixed value 0x57 ('W')
uint8_t packet_type; // Defines packet purpose
uint16_t client_id; // Client identifier
uint16_t sequence; // Packet sequence number
uint16_t ack; // Last acknowledged sequence
uint32_t ack_bitfield; // Acknowledgment history
}
enum PacketType {
ConnectionRequest = 0,
ConnectionClosed = 1,
Commands = 2,
KeepAlive = 3,
}
Connection Packets
- ConnectionRequest: Initial client connection request with optional validation payload
- ConnectionClosed: Immediate connection termination signal
- Commands: Container for multiple game commands
- KeepAlive: Connection maintenance packet
Command Structure:
struct Command {
uint16_t command_type; // 10 bits type + 6 bits flags
uint16_t data_size; // Payload length
uint8_t data[]; // Variable-length payload
}
The command_type
field is at least 16
bits but might contain additional data depending on the command flags.
- The first flag bit indicates whether the command is reliable
- The second flag bit indicates whether the command is a part of a larger splitted command
Note the splitted commands are only supported on reliable commands.
Reliable Commands Type
struct ReliableCommandType {
uint16_t command_type; // 10 bits type + 6 bits flags (0b10)
uint16_t reliable_id; // Unique identifier for reliable command
}
Split Commands Type
struct SplitCommandType {
uint16_t command_type; // 10 bits type + 6 bits flags (0b11)
uint16_t reliable_id; // Unique identifier for reliable command
uint16_t split_id; // Unique identifier for splitted command
uint16_t split_index; // Index of the command part
uint16_t split_count; // Total number of command parts
}
References
Built upon principles from:
Aligns with standard network MTU. Behavior on networks with smaller MTU is undefined.