Plan: refine networking — hybrid per-snake TLV selection, PART framing details, apples only in first part, and 1200-byte safety budget
- Clarify TLV selection between 2-bit and RLE per snake - Define PART inner_type for STATE_FULL/STATE_DELTA and merging by update_id - Apples included only in the first part (full and delta) - Recommend ~1200-byte post-compression budget (<=1280 hard cap)
This commit is contained in:
@@ -62,7 +62,7 @@
|
||||
## Networking & Protocol
|
||||
Constraints and goals:
|
||||
- Use datagrams (unreliable, unordered). Include a packet sequence number for late-packet discard with wraparound handling.
|
||||
- Keep payloads <=1280 bytes to avoid fragmentation; if larger, partition logically.
|
||||
- Keep payloads <=1280 bytes to avoid fragmentation; prefer a safety budget of ~1200 bytes post-compression when partitioning.
|
||||
- Support up to 32 concurrent players; names limited to 16 bytes UTF-8.
|
||||
|
||||
Header (all packets):
|
||||
@@ -107,22 +107,25 @@ State updates (server -> client):
|
||||
- Chunked variants (T=0x10, 0x11): used only when a single snake must be split.
|
||||
- Prefix V with `start_index` (u16, first direction offset from head) and `dirs_in_chunk` (u16); then the encoding for that range (2-bit or RLE respectively).
|
||||
- Client buffers chunks by `(update_id, snake_id)` and assembles when the full [0..len-2] range is present; then applies.
|
||||
- Selection: server chooses per snake whichever TLV (2-bit or RLE) yields fewer bytes.
|
||||
|
||||
Compression:
|
||||
- Primary: domain-specific packing (bits + RLE for segments and apples).
|
||||
- Optional global DEFLATE mode (server-configured): when enabled, server may set flags.compressed=1 and apply DEFLATE to payloads; this mode is negotiated in join_ack and is not changed on the fly (server restart required; clients must reconnect).
|
||||
- Client decompresses if set; otherwise reads packed structs directly.
|
||||
|
||||
Packet partitioning (if >1280 bytes after compression):
|
||||
Packet partitioning (if >~1200–1280 bytes after compression):
|
||||
- Apply to state_full (join and periodic recovery) and large state_delta updates.
|
||||
- Goal: avoid IP fragmentation. Ensure each compressed datagram payload is <1280 bytes.
|
||||
- Goal: avoid IP fragmentation. Ensure each compressed datagram payload is <1280 bytes (use ~1200 target for headroom).
|
||||
- Strategy (whole-snake first):
|
||||
- Sort snakes by estimated compressed size (head + body TLV) descending.
|
||||
- Greedily pack one or more complete snakes per packet while keeping the compressed payload <1280 bytes.
|
||||
- If a snake does not fit with others, send it alone if it fits <1280 bytes.
|
||||
- If a single snake still exceeds 1280 bytes by itself, split that snake into multiple similar-sized chunks using the chunked TLV types.
|
||||
- Framing:
|
||||
- Each part carries `update_id` (u16), `part_index` (u8), `parts_total` (u8), and a sequence of per-snake TLVs (body_2bit/body_rle) and/or chunk TLVs (body_2bit_chunk/body_rle_chunk).
|
||||
- Each PART carries `update_id` (u16), `part_index` (u8), `parts_total` (u8), and `inner_type` (u8: STATE_FULL or STATE_DELTA) followed by the chunk payload.
|
||||
- For STATE_FULL: the chunk payload is `snakes_count + [per-snake records] + apples`. Include apples only in the first part; clients merge across parts using `update_id`.
|
||||
- For STATE_DELTA: the chunk payload is a subset of per-snake changes; include `apples_added/removed` only in the first part; clients merge across parts using `update_id`.
|
||||
- Clients apply complete per-snake TLVs immediately. Chunk TLVs are buffered and assembled by `(update_id, snake_id)` using `start_index` and `dirs_in_chunk` before applying.
|
||||
|
||||
Sequence wrap & ordering:
|
||||
|
||||
Reference in New Issue
Block a user