From 79e88dc82124b8f7064874160b5cf06a23183e2d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 16:21:12 -0500 Subject: [PATCH] tests: fix resume mock session registration and RDRAM sizing 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. --- src/netplay.rs | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/netplay.rs b/src/netplay.rs index f80dbcc..6d27a08 100644 --- a/src/netplay.rs +++ b/src/netplay.rs @@ -1219,13 +1219,24 @@ mod tests { .build(); let reliable_channel = socket.take_channel(1).unwrap(); - let session = ggrs::SessionBuilder::::new() - .with_num_players(1) - .unwrap() - .add_player(ggrs::PlayerType::Local, player_number) - .unwrap() - .start_p2p_session(TestSocket) + let mut builder = ggrs::SessionBuilder::::new() + .with_num_players(player_number + 1) .unwrap(); + // GGRS requires every handle to be registered: the local player at + // `player_number`, Remote placeholders (a dummy nil PeerId — the + // socket never sends to it) for the rest. + let dummy_peer: matchbox_socket::PeerId = + serde_json::from_str("\"00000000-0000-0000-0000-000000000000\"") + .expect("nil PeerId parses"); + for handle in 0..=player_number { + let player_type = if handle == player_number { + ggrs::PlayerType::Local + } else { + ggrs::PlayerType::Remote(dummy_peer) + }; + builder = builder.add_player(player_type, handle).unwrap(); + } + let session = builder.start_p2p_session(TestSocket).unwrap(); Netplay { disconnected: false, @@ -1301,8 +1312,11 @@ mod tests { // Peer loads the embedded savestate into a fresh device (no disk), // exactly like resume_session_peer: load_from_memory -> - // load_savestate_from_data, then issue #5's frame reset. + // load_savestate_from_data, then issue #5's frame reset. The RDRAM + // backing store is pre-sized like a real emulated device, matching + // the saved session's RDRAM. let mut peer_device = crate::device::Device::new(false); + peer_device.rdram.mem.resize(0x800, 0); peer_device.netplay = Some(mock_netplay(1)); apply_resume_state(&mut peer_device, &peer_save).expect("peer applies the state"); @@ -1363,7 +1377,10 @@ mod tests { // Fresh device stands in for the host's just-launched session; the // savestate was captured from a different Device instance above. + // RDRAM is pre-sized like a real emulated device so the saved + // session's RDRAM can be restored. let mut host_session = Device::new(false); + host_session.rdram.mem.resize(0x800, 0); host_session.ui.game_hash = "DEADBEEF-C01DF00D".to_string(); host_session.netplay = Some(mock_netplay(0)); host_session.netplay.as_mut().unwrap().state_path = Some(path.clone());