mock_netplay built a one-player session for a local handle of 1,
which the vendored ggrs fork rejects; register every handle (the
local player at player_number, dummy Remote PeerIds elsewhere).
The resume tests loaded saved states into fresh Device::new(false)
instances whose RDRAM backing store is empty, tripping
copy_from_slice in apply_savestate; pre-size the RDRAM like a real
emulated device, matching the saved session's RDRAM.
wait_for_ready_all counted acks by removing them from the by-name
messages map, which collapses every ack that arrives in the same
channel poll into one entry: with 3+ players the host could
undercount and time out a session whose peers all synced. Count the
matching messages of each decoded batch instead (process_reliable_messages
now returns the batch it decoded).
Add message-name constants and reliable-channel helpers for netplay
session state transfer:
- Message-name constants: netplay_state, netplay_state_ready,
resync_state, resync_ready
- Chunked message codec (encode_message_chunks / decode_message /
decode_packets) reusing the existing 16 KiB reliable-channel
transport; send_message/process_reliable_messages refactored onto it
- send_netplay_state / receive_netplay_state for full session state
- send_ready / wait_for_ready ack helpers (10s timeout, same pattern
as receive_message); receive_message extracted to wait_for_message
with preserve of input_delay/disconnect side effects
- Large payloads (>1MB) accumulate into incoming_message until a full
postcard message parses
- Unit tests: 5MB payload round-trip through the chunked codec, ack
send/receive within timeout, missing ack times out with the standard
panic pattern
Closes#1
Add host-side netplay session save:
- storage::paths.netplay_state_file_path next to other state files
- savestates::create_savestate_in_memory + SavestateData::save_to_memory
(in-memory capture, same zip layout as on-disk savestates)
- netplay::save_netplay_session(device, path): postcard-encodes
{state, frame, input_delay, rom_hash, players}, zstd-compresses and
writes atomically (tmp + rename); onscreen 'Session saved — safe to quit'
- only the host (player_number 0) may save; others get an onscreen notice
- configurable hotkey (emulation.netplay_save_key, default F7), edge
triggered in ui::input::get and consumed per-frame in check_callback
- unit tests: encode/decode round-trip + file metadata verification
After a netplay savestate load, the GGRS session's internal frame counter
must be reset to match the savestate's frame, or desync detection fires
immediately on resume.
Changes:
- Patch vendored ggrs 0.13.0 to expose set_current_frame(frame) on
P2PSession and SyncTestSession, with internal SyncLayer and InputQueue
reset methods to clear stale saved states, checksum history, and input
queues
- Add [patch.crates-io] ggrs = { path = 'vendor/ggrs' } in Cargo.toml
- Add netplay::reset_frame(session, frame) wrapper function
- Record current GGRS frame in Savestate.netplay_frame during
create_savestate when in netplay context
- Call reset_frame after load_savestate in netplay context
- Add tests: advance 120 frames, reset to 60, verify current_frame()==60
and clean resume with matching inputs; reset to 0; idempotent reset
Closes#5
* update netplay
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more
* more