From 352da0ef5400bf0f61bfbef2f9cc52d5d8886eb5 Mon Sep 17 00:00:00 2001 From: Vladyslav Doloman Date: Tue, 7 Oct 2025 20:46:16 +0300 Subject: [PATCH] =?UTF-8?q?Plan:=20refine=20networking=20=E2=80=94=20hybri?= =?UTF-8?q?d=20per-snake=20TLV=20selection,=20PART=20framing=20details,=20?= =?UTF-8?q?apples=20only=20in=20first=20part,=20and=201200-byte=20safety?= =?UTF-8?q?=20budget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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) --- PROJECT_PLAN.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md index cb91d69..3bdeb71 100644 --- a/PROJECT_PLAN.md +++ b/PROJECT_PLAN.md @@ -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: