feat(netplay,quality): lobby/matchmaking + delayed spectators + desync/RTT hardening + fuzz expansion + ROM Info browser (v2.2.0 "Capstone")#290
Open
doublegate wants to merge 3 commits into
Conversation
…ndbook (v2.2.0) Frontend — read-only ROM Info browser (v2.2.0 "Capstone"): - New Tools -> ROM Info panel (crates/rustynes-frontend/src/debugger/ rom_info_panel.rs). Surfaces, for the loaded ROM, the two dump-identity CRC32 keys (header-excluded game-DB key + full-file No-Intro key), the SHA-256, the effective per-game DB entry (title/mapper/region/mirroring/ submapper), and the decoded cartridge header read off the running Nes (mapper id, region, PRG-ROM/CHR-ROM sizes). Read-only (&Nes) — never mutates the emulator or DB overlay; the core never consults it. - Wired through the standard 5 points: ToolPanel::RomInfo variant, the show_rom_info flag + rom_info_ui state, open_panel arm, the render call, and the any_nes_tool_open lock-gate predicate (the one non-obvious step — a nes-reading tool panel must be OR'd in). The game_db block now reborrows nes via as_deref_mut() so the new block can as_deref() it. Tools-menu entry reuses MenuAction::OpenPanel; CIRCLE_INFO glyph reused. - netplay_ui: DisconnectReason::PeerTimeout arm + a configurable spectator_delay_frames (default 0) feeding SpectatorConfig.delay_frames. Docs: - docs/netplay-webrtc.md: new §4b (lobby/matchmaking, PeerLink RTT with the "why not Mesen's 150 ms" rationale, DesyncStatus), the delayed-stream spectator buffer in §4, and six new Verified-table rows. - docs/frontend.md: the ROM Info browser + the updated any_nes_tool_open / tool-panel list. - MkDocs handbook: four new pages (expansion-audio, pal-region, crt-composite, creator-tools) cross-linked to the authoritative specs, with mkdocs.yml nav entries (markdownlint v0.39.0 clean). - CHANGELOG [Unreleased]: comprehensive v2.2.0 "Capstone" Added/Changed entries (house style). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- spectator.rs: `MAX_DELAY_FRAMES` doc used a plain code span instead of an intra-doc link to the private `MAX_SPECTATOR_FRAME_LOOKAHEAD` const (the `rustdoc::private_intra_doc_links` warning-as-error gate). - connection.rs: add `synced_peer_liveness_grades_then_times_out` — drives two loopback connections to Synced, silences one, and asserts the other grades Live -> Interrupted -> TimedOut and disconnects with `PeerTimeout` under tight test-scale `with_peer_timeouts` thresholds. rustynes-netplay: 102 passed, 2 ignored; rustdoc -D warnings clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r client The browser signaling client's `handle_signal` match over `SignalMessage` (wasm-only, `wasm_netplay.rs`) became non-exhaustive once the lobby / matchmaking variants landed. Add inbound arms: `Matched` (a QuickMatch reply — record slot + room size like `Joined`, surface the room code), `RoomList` (the lobby directory — record the open-room count pending a browse UI), and group the client->server-only `ListRooms` / `QuickMatch` with the existing `Join` / `PublicAddr` ignore arm. Both wasm clippy gates (wasm-winit + wasm-canvas) are clean again. (rustfmt reflow of rom_info_panel.rs included.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
There was a problem hiding this comment.
Pull request overview
Adds the v2.2.0 “Capstone” netplay lobby/matchmaking + spectator-delay + desync/RTT hardening features, expands fuzz coverage for key untrusted-input boundaries, and introduces a read-only ROM Info tool panel with supporting handbook docs.
Changes:
- Netplay signaling gains lobby browse (
ListRooms/RoomList) and matchmaking (QuickMatch/Matched), plus spectator delayed-stream buffering and a graded/sticky desync status surface. - Fuzz surface expands (3 → 8 targets) and
Movie::deserializeis hardened against OOM/DoS patterns found by fuzzing. - Frontend adds Tools → ROM Info panel and docs/MkDocs navigation is updated with new handbook pages.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| mkdocs.yml | Adds handbook pages to the MkDocs nav. |
| fuzz/README.md | Documents new fuzz targets and LSan note; updates CI-friendly target loop. |
| fuzz/Cargo.toml | Adds fuzz binaries + deps for new targets (PPU/APU/netplay/save-state/movie). |
| fuzz/fuzz_targets/save_state.rs | New fuzz target for .rns parsing/restoring surfaces. |
| fuzz/fuzz_targets/ppu_reg_io.rs | New fuzz target driving PPU CPU-facing register I/O. |
| fuzz/fuzz_targets/apu_reg_io.rs | New fuzz target driving APU register/status I/O. |
| fuzz/fuzz_targets/netplay_message.rs | New fuzz target for UDP + JSON signaling parsers. |
| fuzz/fuzz_targets/movie.rs | New fuzz target for .rnm deserialization/serialization. |
| docs/expansion-audio.md | New curated handbook entry point for expansion-audio subsystem. |
| docs/pal-region.md | New curated handbook entry point for PAL/region behavior. |
| docs/crt-composite.md | New curated handbook entry point for display pipeline/composite/CRT filters. |
| docs/creator-tools.md | New curated handbook entry point for creator/debugging tools. |
| docs/netplay-webrtc.md | Documents spectator delay + lobby/matchmaking + desync/liveness changes. |
| docs/frontend.md | Documents ROM Info panel and tool-panel locking behavior updates. |
| crates/rustynes-netplay/src/signaling.rs | Implements RoomInfo, lobby list/matchmaking messages, bounded room-list parsing, relay support. |
| crates/rustynes-netplay/src/spectator.rs | Adds spectator delay_frames with clamping and reveal-horizon logic + tests. |
| crates/rustynes-netplay/src/diagnostics.rs | Adds DesyncStatus (hysteresis + sticky-confirmed) and related APIs/tests. |
| crates/rustynes-netplay/src/connection.rs | Adds PeerLink liveness grading + PeerTimeout disconnect reason + tests. |
| crates/rustynes-netplay/src/lib.rs | Re-exports new netplay types/constants. |
| crates/rustynes-frontend/src/netplay_ui.rs | Wires spectator delay config; surfaces new disconnect reason string. |
| crates/rustynes-frontend/src/wasm_netplay.rs | Handles Matched / RoomList in browser netplay client. |
| crates/rustynes-frontend/src/ui_shell.rs | Adds Tools menu item for ROM Info panel. |
| crates/rustynes-frontend/src/debugger/mod.rs | Adds ROM Info tool panel plumbing + lock-path inclusion. |
| crates/rustynes-frontend/src/debugger/rom_info_panel.rs | New read-only ROM Info tool panel implementation. |
| crates/rustynes-core/src/movie.rs | Hardens .rnm deserializer (bytes/frame=0 + frame_count OOM cap) + regression test. |
| CHANGELOG.md | Documents netplay lobby/delay/desync/liveness, fuzz expansion, ROM Info, and movie hardening. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+668
to
+675
| // Prefer an existing open room for this exact game with a free slot. | ||
| let target = self | ||
| .open_rooms(rom_hash) | ||
| .into_iter() | ||
| .find(|r| r.is_joinable() && (rom_hash.is_empty() || r.rom_hash == rom_hash)) | ||
| .map(|r| r.code); | ||
|
|
||
| let room_code = target.unwrap_or_else(|| self.next_room_code()); |
Comment on lines
+705
to
712
| // Reject a joiner past the room's player count. Drop a freshly-created | ||
| // but now-unused room so a rejected QuickMatch race leaves no ghost. | ||
| if room.slots.len() >= usize::from(max_players) { | ||
| return vec![ | ||
| Action::Send { | ||
| to: client, | ||
| msg: SignalMessage::Error { | ||
| reason: "room full".to_string(), | ||
| }, | ||
| }, | ||
| Action::Close { who: client }, | ||
| ]; | ||
| if room.slots.is_empty() { | ||
| self.rooms.remove(room_code); | ||
| } | ||
| return Err("room full"); | ||
| } |
Comment on lines
+691
to
+693
| // Any datagram from the peer is proof of life — refresh the liveness | ||
| // clock that drives `PeerLink` / `DisconnectReason::PeerTimeout`. | ||
| self.last_recv = now; |
| (hi, lo) | ||
| } | ||
|
|
||
| /// Human-readable size: bytes for < 1 KiB, else KiB. |
Comment on lines
+22
to
+25
| /// Minimal `PpuBus`: an 8 KiB CHR/pattern-table window backing every PPU-space | ||
| /// read/write. Nametable mirroring uses the trait's default `nametable_address`. | ||
| /// This is exactly the surface `cpu_read_register`/`cpu_write_register` reach | ||
| /// through for PPUDATA ($2007) — no mapper side effects, no A12 notifications. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the v2.2.0 "Capstone" netplay lobby (B5) workstream plus the quality pass, entirely in the netplay signaling / session / transport layers, the frontend, the fuzz harness, and docs. The deterministic core is untouched and the rollback determinism contract is preserved — AccuracyCoin holds 141/141 (100%), and save-state / movie replay stays byte-identical.
B5 — Netplay lobby / matchmaking
signaling.rs): newRoomInfo+ fourSignalMessagevariants —ListRooms/RoomList(browse open rooms) andQuickMatch/Matched(server-side quick-play: join any open room for the ROM or create one). Sharedadd_to_roomprimitive;room-listarray parse bounded atMAX_ROOM_LIST(256).spectator.rs):SpectatorConfig.delay_frames(clamped toMAX_DELAY_FRAMES= 512) — a broadcast / anti-spoiler / jitter-smoothing hold; presentation-only, frames still produced byte-identically & in order. Wired toNetplayUi::spectator_delay_frames.diagnostics.rs): gradedDesyncStatus{InSync/Suspect/Desynced} with a hysteresis threshold (3 consecutive mismatches) + sticky-once-confirmed, so a lone reordered checksum can't flash a false desync.connection.rs): gradedPeerLink{Live/Interrupted/TimedOut} driven bylast_recvagainst 2 s / 5 s thresholds +DisconnectReason::PeerTimeout, builder-configurable. Deliberately far above Mesen's known-too-low ~150 ms (rationale documented onPeerLink— a single lost 1 Hz ping or LTE retransmit spike must not trip it; matches GGPO/Parsec grace windows).Quality pass
fuzz/, 3 → 8):ppu_reg_io,apu_reg_io,netplay_message(untrusted network input — highest value),save_state,movie. All build under nightly cargo-fuzz and run clean for tens of thousands of iterations. Themovietarget found two real OOM DoS paths inMovie::deserialize(untrustedframe_countpre-sizing a multi-GBVec; a zero-widthbytes_per_frameloopingframe_countempty pushes) — both fixed byte-identically for valid input, with a regression test.Verification (all green)
cargo fmt --all --check·cargo clippy --workspace --all-targets -D warnings· frontend feature combos (scripting / hd-pack / retroachievements) · both wasm32 gates (wasm-winit + wasm-canvas) ·RUSTDOCFLAGS=-D warnings cargo doc· markdownlint (pinned v0.39.0).rustynes-netplay102 passed / 2 ignored (incl. new lobby / delay / desync-status / PeerLink tests) ·rustynes-coremovie 44 passed (incl. determinism round-trip + new OOM regression) · 8 fuzz targets build + smoke clean.Notes
docs/STATUS.md/to-dos/ROADMAP.mdreconciliation (the final capstone doc-sync step) and thedeploy/RA auth-proxy work (a concurrent v2.1.10 agent owns it).fd82485; the maintainer runs the release ceremony / rebase. Do not merge.🤖 Generated with Claude Code