Skip to content

R-Type network protocol

This document specifies the protocol spoken between the R-Type server and its clients, built on the Aegis2D net module. It describes every byte on the wire, so that a new client or server can be written from it alone.

Status

Draft of protocol version 1. Sections are added as the protocol is implemented; the ones not written yet are listed at the end of this page.

1. Conventions

1.1 Requirements language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals.

1.2 Terminology

Term Meaning
Server The authoritative process: it runs the simulation and decides everything.
Client A player's process: it sends inputs and displays what the server sends.
Peer The other end of a communication, client or server.
Session A player's stay on the server, from login to disconnection, identified by a session token.
Datagram One UDP payload, header included.
Packet The content of a datagram: the header followed by the payload of its type.

1.3 Transport

The server listens on one TCP port and one UDP port, both configurable.

  • TCP carries the session. A client opens a TCP connection to log in and receives a session token. The connection stays open for the whole session, and its closure ends the session. TCP MUST NOT carry gameplay data.
  • TCP messages are framed. TCP delivers a byte stream, so each message travels behind its length: a u16 (section 1.4) giving the number of bytes that follow, then those bytes. A message MUST NOT exceed 4096 bytes, prefix excluded; a receiver MUST close the connection when a prefix announces more, before reading further. The string "hi" as a message is sent as 02 00 68 69.
  • UDP carries the game. Every in-game message travels in UDP datagrams, in both directions. Each datagram MUST start with the packet header (section 2).
  • Datagram size. A datagram, header included, MUST NOT exceed 1200 bytes, so that IP never fragments it. A receiver MUST drop larger datagrams.

1.4 Encoding

  • Multi-byte numbers are little-endian: the least significant byte comes first.
  • Fields follow each other in the order given, with no padding or alignment.
  • The types below are the only ones used:
Type Size (bytes) Encoding
u8, u16, u32, u64 1, 2, 4, 8 Unsigned integer, little-endian
i8, i16, i32, i64 1, 2, 4, 8 Signed integer, two's complement, little-endian
f32 4 IEEE 754 binary32, its bits sent as a u32
f64 8 IEEE 754 binary64, its bits sent as a u64
bool 1 0 for false, 1 for true; any other value makes the packet invalid
string 2 + n Length n as a u16, then n bytes of UTF-8, without terminator

For example, the u32 value 0x11223344 is sent as the bytes 44 33 22 11, and the string "hi" as 02 00 68 69.

Packed payloads. The Snapshot payload (4.3) is packed bit by bit instead (net::BitWriter): bit n of the payload is bit n % 8 (from the least significant) of byte n / 8, and each field is written from its least significant bit. Its types:

Type Size (bits) Encoding
bN N Unsigned integer of N bits
sN N Signed integer of N bits, two's complement
bit 1 1 for true
varint 8 to 40 An unsigned integer of up to 32 bits in groups of 7 bits, the lowest first, each followed by a bit set when another group follows. A value has a single encoding: a last group of 0 (other than the lone group of the value 0), a sixth group or a value above 32 bits makes the packet invalid

The last byte is completed with 0 bits; any other padding makes the packet invalid.

1.5 Validation

Every byte received is untrusted. A receiver MUST check that a field fits in the bytes remaining before reading it, and MUST drop a packet that ends before its last field or that contains an invalid value. A dropped packet MUST NOT change any state. Every check, the size limits and what is logged are gathered in section 6.

The Aegis2D implementation is net::BinaryWriter and net::BinaryReader (aegis2d/net/binary.hpp): every read is bounds-checked, and the first failure rejects the rest of the packet. TCP framing is net::TcpConnection (aegis2d/net/tcp_connection.hpp).

Sections

Section Content Status
1 Conventions, transport and encoding (this page) Written
2 UDP packet header Written
3 Session: TCP login and session token, binding the UDP endpoint Written
4 Gameplay messages: inputs, snapshots, events Written
5 Reliability: acknowledgements, resending events, heartbeat and timeouts Written
6 Malformed and unknown packets: size limits, rejection rules, logging Written