Some checks failed
Rust / build-linux (linux-x86_64, X64, ubuntu-24.04, x86_64-unknown-linux-gnu) (pull_request) Failing after 5s
Rust / build-android (29.0.14206865, ubuntu-24.04, 33) (pull_request) Failing after 2s
Rust-lint / lint-linux (pull_request) Failing after 2s
Rust / build-linux (linux-aarch64, ARM64, ubuntu-24.04-arm, aarch64-unknown-linux-gnu) (pull_request) Has been cancelled
Rust / build-windows (windows-aarch64, woa64, windows-11-arm, aarch64-pc-windows-msvc) (pull_request) Has been cancelled
Rust / build-windows (windows-x86_64, win64, windows-2025, x86_64-pc-windows-msvc) (pull_request) Has been cancelled
Rust / build-macos (macos-aarch64, ARM64, aarch64-apple-darwin) (pull_request) Has been cancelled
Rust / Collect release artifacts (pull_request) Has been cancelled
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
73 lines
2.2 KiB
Rust
73 lines
2.2 KiB
Rust
mod stubs;
|
|
mod stubs_enum;
|
|
|
|
use ggrs::{GgrsError, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket};
|
|
use serial_test::serial;
|
|
use stubs_enum::{EnumInput, GameStubEnum, StubEnumConfig};
|
|
|
|
#[test]
|
|
#[serial]
|
|
fn test_advance_frame_p2p_sessions_enum() -> Result<(), GgrsError> {
|
|
let addr1 = stubs_enum::localhost(7860);
|
|
let addr2 = stubs_enum::localhost(7861);
|
|
|
|
let socket1 = UdpNonBlockingSocket::bind_to_port(7860).unwrap();
|
|
let mut sess1 = SessionBuilder::<StubEnumConfig>::new()
|
|
.add_player(PlayerType::Local, 0)?
|
|
.add_player(PlayerType::Remote(addr2), 1)?
|
|
.start_p2p_session(socket1)?;
|
|
|
|
let socket2 = UdpNonBlockingSocket::bind_to_port(7861).unwrap();
|
|
let mut sess2 = SessionBuilder::<StubEnumConfig>::new()
|
|
.add_player(PlayerType::Remote(addr1), 0)?
|
|
.add_player(PlayerType::Local, 1)?
|
|
.start_p2p_session(socket2)?;
|
|
|
|
assert!(sess1.current_state() == SessionState::Synchronizing);
|
|
assert!(sess2.current_state() == SessionState::Synchronizing);
|
|
|
|
stubs::sync_p2p_sessions(&mut sess1, &mut sess2);
|
|
|
|
assert!(sess1.current_state() == SessionState::Running);
|
|
assert!(sess2.current_state() == SessionState::Running);
|
|
|
|
let mut stub1 = GameStubEnum::new();
|
|
let mut stub2 = GameStubEnum::new();
|
|
let reps = 10;
|
|
for i in 0..reps {
|
|
sess1.poll_remote_clients();
|
|
sess2.poll_remote_clients();
|
|
|
|
sess1
|
|
.add_local_input(
|
|
0,
|
|
if i % 2 == 0 {
|
|
EnumInput::Val1
|
|
} else {
|
|
EnumInput::Val2
|
|
},
|
|
)
|
|
.unwrap();
|
|
let requests1 = sess1.advance_frame().unwrap();
|
|
stub1.handle_requests(requests1);
|
|
sess2
|
|
.add_local_input(
|
|
1,
|
|
if i % 3 == 0 {
|
|
EnumInput::Val1
|
|
} else {
|
|
EnumInput::Val2
|
|
},
|
|
)
|
|
.unwrap();
|
|
let requests2 = sess2.advance_frame().unwrap();
|
|
stub2.handle_requests(requests2);
|
|
|
|
// gamestate evolves
|
|
assert_eq!(stub1.gs.frame, i + 1);
|
|
assert_eq!(stub2.gs.frame, i + 1);
|
|
}
|
|
|
|
Ok(())
|
|
}
|