mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
4ffa1543cc
Casual/ranked queues need servers allocated per match and shut down afterwards, so cost is incurred only while a match runs - while the existing Docker and CI gates keep passing unchanged. Measured against the repo's own cosmicclash-server image rather than estimated: the runtime image is ~148 MB of content, and boot to the server_started line is ~870 ms on the container's own clock. That was taken under x86_64 emulation on an arm64 host, so it is a pessimistic bound and is recorded as one - it needs re-measuring on native Linux before it sets any timeout. Two findings that would each break a naive implementation, both hit while taking that measurement: - Godot's stdout is block-buffered off a TTY. A detached container logs nothing at all - server_started does not appear even after 35s - so an orchestrator readiness probe that greps the log hangs forever. Probe the UDP socket or flush explicitly. - --port defaults to 7777 and the Dockerfile hardcodes EXPOSE 7777/udp, so several matches cannot share a host without a port range or an address per match. Being UDP, L7 ingress routing does not apply. Also records the honest tension in 'only pay during a match': a server must listen before players connect, and image pull plus scheduling can dwarf 870 ms, so the recommendation is match-level scale-to-zero over a small warm node pool rather than node-level scale-to-zero. The rule for keeping verify-phase6 and verify-enet-integration green: every allocation feature is opt-in via a ServerConfig flag defaulting to current behaviour, with a second Compose file rather than mutating compose.phase6-smoke.yml.
94 lines
4.7 KiB
Markdown
94 lines
4.7 KiB
Markdown
# Multiplayer — next work
|
||
|
||
Short, current checklist for online multiplayer. Historical design decisions,
|
||
implementation evidence, and completed work stay in
|
||
[`multiplayer-todo.md`](multiplayer-todo.md).
|
||
|
||
## Release blockers
|
||
|
||
- [ ] **Phase 4 playtest:** a human playtest at roughly 100 ms RTT. Confirm
|
||
that ship and ball interaction feel local and contact corrections feel like
|
||
bumps rather than glitches.
|
||
- [ ] **Phase 5 session:** complete a real 3v3 match with a mid-match
|
||
disconnect and late joiner.
|
||
- [ ] **Phase 6 external check:** run the exported Docker server and clients
|
||
from separate machines over the internet, then play a full match. Keep this
|
||
controlled-only until Steam identity is complete.
|
||
|
||
## Phase 7 — Steam, identity, discovery
|
||
|
||
- [ ] Obtain the pinned GodotSteam client/server builds and Steamworks SDK
|
||
access described in [`STEAM.md`](STEAM.md).
|
||
- [ ] Run `make verify-steam-templates` with the custom executables and fix
|
||
any custom-template failures.
|
||
- [ ] Validate a two-account Steam SDR host/join using the existing explicit
|
||
`NetworkManager` Steam transport. ENet direct-IP must keep passing its smoke
|
||
test.
|
||
- [ ] Build the Steam server browser: internet, LAN, favourites, and history.
|
||
- [ ] Add Steam auth tickets, verified Steam identity in the roster, and a
|
||
persistent ban list. This fixes the slot-reclaim security issue below.
|
||
|
||
## Phase 8 — casual and ranked matchmaking (1.0 launch blocker)
|
||
|
||
Design and reasoning: [`docs/MATCHMAKING.md`](docs/MATCHMAKING.md). This is a
|
||
different server model from the community-server one that exists today —
|
||
players queue, a matchmaker groups them, and a server is allocated per match.
|
||
Phase 7's Steam auth tickets are a hard prerequisite: a rating attached to a
|
||
spoofable identity is worse than no rating.
|
||
|
||
- [ ] Decide the rating algorithm (Glicko-2 recommended over Elo for a small
|
||
launch population) and how a team result distributes across individuals.
|
||
- [ ] Choose the backend language and hosting, and cost out allocated servers
|
||
per match at expected population.
|
||
- [ ] Stand up the backend: Steam auth ticket validation via the Steamworks
|
||
Web API, queue, rating store, server allocator.
|
||
- [ ] Add an assigned-roster server mode so only matched SteamIDs may claim a
|
||
slot, replacing the first-come model.
|
||
- [ ] Add server-authoritative match result reporting to the backend over a
|
||
channel a client cannot forge.
|
||
- [ ] Client queue UI: playlist select, estimated wait, accept/decline,
|
||
connect-on-assignment, post-match rating delta.
|
||
- [ ] Casual and ranked playlist rulesets (backfill, bots, abandon penalties,
|
||
arena restriction — see the comparison table in the design doc).
|
||
|
||
Server orchestration (same phase — the servers must autoscale and bill only
|
||
for the duration of a match):
|
||
|
||
- [ ] Choose the orchestrator (Agones on Kubernetes is the recommended
|
||
default; it models allocation, readiness and per-match lifetime natively).
|
||
- [ ] Fix readiness detection. Godot's stdout is block-buffered off a TTY, so
|
||
`server_started` never appears in `docker logs` for a detached container —
|
||
a log-grep readiness probe hangs forever. Probe the UDP socket, or flush.
|
||
- [ ] Support more than one match per host: a per-container port from a range,
|
||
or one address per match. `--port` defaults to 7777 and the Dockerfile
|
||
hardcodes `EXPOSE 7777/udp`.
|
||
- [ ] Add a no-show timeout so an allocated server that never fills abandons
|
||
and exits instead of idling at cost.
|
||
- [ ] Re-measure boot-to-listening on native x86_64 Linux. The repo's current
|
||
figure is ~870 ms, measured under emulation on arm64 — a pessimistic bound.
|
||
- [ ] Re-measure the SERVER.md sizing estimate (6–10 processes/core,
|
||
150–250 MB RSS) under real concurrency before it sizes a bill.
|
||
- [ ] Keep `make verify-phase6` and `make verify-enet-integration` green:
|
||
every allocation feature is opt-in via a `ServerConfig` flag defaulting to
|
||
today's behaviour, with a second Compose file for the allocated path rather
|
||
than mutating `compose.phase6-smoke.yml`.
|
||
|
||
## Known issues to resolve before public hosting
|
||
|
||
- [ ] Slot reclaim is currently keyed by display name, so someone can take a
|
||
disconnected player's reserved slot. Do not expose public servers before
|
||
verified Steam identity lands.
|
||
- [ ] Investigate occasional input loss during a long server stall; the
|
||
existing sequence resync recovers it, but transport delivery is variable.
|
||
- [ ] Fix the remaining `_broadcast_snapshot` packet-send stderr race.
|
||
|
||
## Decide after the latency playtest
|
||
|
||
- [ ] Decide whether client-only, contact-cohort shadow physics is worthwhile
|
||
for the remaining prediction weakness.
|
||
|
||
## Explicitly deferred
|
||
|
||
120 Hz simulation, latency-gap measurement, audio hooks, and split-screen are
|
||
not part of the current multiplayer release path.
|