docs(multiplayer): split spec into MULTIPLAYER_SPEC.md, trim task doc to outstanding work

multiplayer-next.md was a 1662-line mix of standing architecture spec
and task-completion tracking, most of which was dense per-task DONE
evidence for finished Phases 0-6. Split it:

- MULTIPLAYER_SPEC.md (new): the locked architecture decisions, wire
  format, server-side input handling, prediction/reconciliation,
  latency/frame-rate budget, and match lifecycle state machine -
  standing design reference, not task-tracked.
- multiplayer-next.md (trimmed 1662 -> ~370 lines): only outstanding
  work remains - §0 status, §7 Phase 7/8 task tables condensed to
  "what's left" per task, §8-11 reference material (refactoring notes,
  gotchas, testing, flagged items). Phases 0-6 collapsed to a pointer
  at git history instead of ~500 lines of DONE evidence.

Also:
- Repointed every `multiplayer-next.md §N` code comment (N 1-6) across
  Game/scripts, Game/tools and Game/tests to MULTIPLAYER_SPEC.md, since
  those sections moved. Task-number references (`task N.N`, §7-11)
  correctly still point at multiplayer-next.md.
- Updated CLAUDE.md's doc index and docs/TECH_STACK.md's spec-section
  citations to match.
- TODO.md: added a "what's left to actually finish multiplayer
  (human-actionable)" checklist pulled from multiplayer-next.md §0 and
  docs/MATCHMAKING.md - things that need a person (hardware, a design
  decision, a Steam App ID, hands on a controller), not more agent code.
This commit is contained in:
Josh Creek
2026-09-04 22:43:13 +01:00
parent de263f30e8
commit b43ad207c1
21 changed files with 848 additions and 1543 deletions
+11 -11
View File
@@ -56,7 +56,7 @@ snapshot/restore API. That fact is why the multiplayer architecture is
server-authoritative with client-side prediction of only the local ship,
rather than rollback/resimulation netcode — rollback would require
deterministic replay, which no physics engine choice here provides
(`multiplayer-next.md` §1, decision 1).
(`MULTIPLAYER_SPEC.md` §1, decision 1).
## Multiplayer transport: Godot's built-in `MultiplayerAPI` over ENet
@@ -71,7 +71,7 @@ Design choices layered on top of the built-in peer, and why:
- **`ENetMultiplayerPeer.server_relay` is forced to `false`.** It defaults
to `true`, which lets any client `rpc()` any other client *through the
server* — incompatible with a server-authoritative model. Called out in
`multiplayer-next.md` §2.1 as "the single highest-value one-line security
`MULTIPLAYER_SPEC.md` §2.1 as "the single highest-value one-line security
change in the document."
- **Manual multiplayer polling**, not Godot's automatic idle-frame poll.
`NetworkManager` calls `set_multiplayer_poll_enabled(false)` because the
@@ -84,7 +84,7 @@ Design choices layered on top of the built-in peer, and why:
- **A custom binary wire format** (`net_codec.gd`) rather than raw RPC
argument marshalling, for compact, quantised input/snapshot packets sent
at high frequency — no stated alternative was considered in the docs, but
the packet-size/channel-intent design in `multiplayer-next.md` §2 is
the packet-size/channel-intent design in `MULTIPLAYER_SPEC.md` §2 is
extensive and deliberate.
## Optional multiplayer transport: Steam (GodotSteam)
@@ -96,14 +96,14 @@ Relay), from a custom GodotSteam-patched Godot build (not stock Godot —
use ENet only, and a build without the `steam` feature is fully functional
without it.
**Why it's optional and why raw ENet remains primary:** `multiplayer-next.md`
states plainly that "Docker/VPS is the primary v1 deployment path. Raw ENet
self-hosting needs port forwarding, and SDR is Phase 7 — so [the ENet
phases] ship something that works on LAN or a VPS and nowhere else." Steam/SDR
is being added later specifically to remove the port-forwarding requirement
and to supply verified player identity — direct-IP ENet's slot-reclaim logic
is keyed by display name today, which is insecure against a public server
(see `multiplayer-next.md`).
**Why it's optional and why raw ENet remains primary:** per
`multiplayer-next.md`, Docker/VPS is the primary v1 deployment path, and raw
ENet self-hosting needs port forwarding while SDR is Phase 7 — so the ENet
phases ship something that works on LAN or a VPS today, and nowhere else
yet. Steam/SDR is being added later specifically to remove the
port-forwarding requirement and to supply verified player identity —
direct-IP ENet's slot-reclaim logic is keyed by display name today, which is
insecure against a public server (`multiplayer-next.md` §0, known defect C).
## Dedicated server hosting: Docker (primary) or native systemd