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 #
- Binary protocol and handshake. Negotiate protocol/content/rules hashes, seats, seed, and delay; measure round-trip time before frame zero.
- 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.
- 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.
- Time synchronization. Track local versus remote frame advantage and gently adjust tick pacing. Avoid visible hard skips during active inputs.
- Live desync detection. Exchange periodic checksums for confirmed frames, retain a bounded diagnostic trace, and abort with a useful report on mismatch.
- Connection state. Startup synchronization, timeout warnings, disconnect grace, pause/forfeit policy, and rematch without rebuilding the whole room.
- Replay and spectating. Record the seed, metadata, and confirmed input stream. Spectators consume delayed confirmed inputs and catch up without ever affecting the competitors.
- 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.
- 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
maxRetransmitsreference 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.