Monorepo for Aesthetic.Computer aesthetic.computer
core menu-fighter NETCODE.md
5.6 kB

Rollback and peer-to-peer plan #

What is already proven #

lib/fight/sim.mjs is a 60 Hz integer simulation whose complete state lives in an Int32Array. lib/fight/rollback.mjs can rewind and replay it while checking determinism. lib/fight/session.mjs predicts remote input, stores snapshots, rolls back on a bad prediction, sends redundant recent-input windows, and stalls beyond eight speculative frames. Specs compare both peers against an offline ground-truth simulation under latency, jitter, and packet loss.

That is the hard center of rollback. It is not yet production netcode.

Production gaps, in order #

  1. Binary protocol and handshake. Negotiate protocol/content/rules hashes, seats, seed, and delay; measure round-trip time before frame zero.
  2. Direct transport. Add a WebRTC adapter using an unordered data channel with zero retransmits. Use the existing session server only for room presence and offer/answer/ICE signaling.
  3. NAT and tournament routes. Configure STUN plus authenticated TURN and a neutral tournament route. Report whether a match is direct or relayed, but feed every route through the same packet interface.
  4. Time synchronization. Track local versus remote frame advantage and gently adjust tick pacing. Avoid visible hard skips during active inputs.
  5. Live desync detection. Exchange periodic checksums for confirmed frames, retain a bounded diagnostic trace, and abort with a useful report on mismatch.
  6. Connection state. Startup synchronization, timeout warnings, disconnect grace, pause/forfeit policy, and rematch without rebuilding the whole room.
  7. Replay and spectating. Record the seed, metadata, and confirmed input stream. Spectators consume delayed confirmed inputs and catch up without ever affecting the competitors.
  8. Adversarial testing. Run two processes and two engines, inject reordering, duplication, burst loss, clock drift, suspend/resume, and cross-architecture Mac tests. A one-process fake wire remains the fast unit test.
  9. Neutral verification. Mirror authenticated input envelopes and confirmed checksums to a coordinator that can replay and sign the result without becoming authoritative over moment-to-moment gameplay.

Direct Mac-to-Mac path #

Yes: two Macs can play peer to peer now without a native networking rewrite. Each joins a short-lived room over the reliable AC session connection. The server relays SDP offers, answers, and ICE candidates; actual match inputs then flow directly over RTCDataChannel. If NAT traversal fails, ICE selects TURN.

Recommended channel configuration:

peer.createDataChannel("inputs", {
  ordered: false,
  maxRetransmits: 0,
});

The game already repeats a recent input window in every packet, so late packets and transport retransmission only add head-of-line delay. Signaling and match control remain reliable; per-frame inputs do not.

For a local-only mode, Bonjour can discover another native Mac, but it should still produce the same room/transport interface. Start with room codes because they also work across the internet and in the web build.

Direct P2P is appropriate for low-latency competitive play. Tournament policy may intentionally require a nearby relay to hide player network addresses and create neutral telemetry. That adds a route hop, so relay selection and preflight qualification are part of tournament readiness, not operational afterthoughts.

What to borrow #

  • GGPO is the behavioral reference: save/load callbacks, deterministic frame advancement, prediction bounds, frame delay, sync testing, and frame-advantage time synchronization. Its implementation is C++/Windows-focused; use the design, not the platform layer.
  • GGRS is the clearest modern reference for P2P, SyncTest, checksum exchange, disconnect notification, input delay, spectator catch-up, and smooth wait recommendations. It is Rust and is useful as a protocol/test oracle rather than a required dependency.
  • IKEMEN GO is the relevant open MUGEN-compatible study. Its current engine integrates a GGPO fork with full game-state save/load and replay during resimulation. MUGEN itself is not the reusable open-source example.
  • Matchbox demonstrates a clean WebRTC P2P split across web/wasm and native Rust. It validates the transport architecture even if Menu Fighter stays in JavaScript.
  • WebRTC is the web transport standard; MDN's maxRetransmits reference documents the bounded-retransmission channel option.

GGPO is MIT; GGRS and Matchbox are MIT/Apache-2.0; IKEMEN GO is MIT. Preserve licenses if code is copied. Prefer clean-room implementation from the documented behavior because the existing small session already matches the game's needs.

First acceptance test #

On an Apple Silicon Mac and an Intel Mac (or two Apple Silicon Macs to start):

  • join by code and report direct versus relay;
  • exchange 10,000 deterministic frames across two real processes;
  • finish with matching confirmed-frame checksums and replay hashes;
  • stay responsive under 80 ms RTT, 20 ms jitter, 5% random loss, and a short burst-loss profile;
  • disconnect one peer and produce a bounded, comprehensible outcome;
  • replay the recorded match offline to the same final checksum.