From aff3d6058441782472a20f5499aefd76b21d1e3d Mon Sep 17 00:00:00 2001 From: Georg Schuppe Date: Fri, 10 Nov 2023 08:30:50 +0100 Subject: [PATCH 1/8] refactor: rename GGRSError to GgrsError --- examples/ex_game/ex_game_p2p.rs | 4 +-- examples/ex_game/ex_game_spectator.rs | 4 +-- src/error.rs | 31 ++++++--------------- src/lib.rs | 2 +- src/network/protocol.rs | 8 +++--- src/sessions/builder.rs | 40 +++++++++++++-------------- src/sessions/p2p_session.rs | 24 ++++++++-------- src/sessions/p2p_spectator_session.rs | 14 +++++----- src/sessions/sync_test_session.rs | 12 ++++---- src/sync_layer.rs | 6 ++-- tests/test_p2p_session.rs | 16 +++++------ tests/test_p2p_spectator_session.rs | 4 +-- tests/test_synctest_session.rs | 8 +++--- tests/test_synctest_session_enum.rs | 4 +-- 14 files changed, 81 insertions(+), 96 deletions(-) diff --git a/examples/ex_game/ex_game_p2p.rs b/examples/ex_game/ex_game_p2p.rs index bc62765..49fad18 100644 --- a/examples/ex_game/ex_game_p2p.rs +++ b/examples/ex_game/ex_game_p2p.rs @@ -1,7 +1,7 @@ mod ex_game; use ex_game::{GGRSConfig, Game}; -use ggrs::{GGRSError, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket}; +use ggrs::{GgrsError, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket}; use instant::{Duration, Instant}; use macroquad::prelude::*; use std::net::SocketAddr; @@ -112,7 +112,7 @@ async fn main() -> Result<(), Box> { match sess.advance_frame() { Ok(requests) => game.handle_requests(requests), - Err(GGRSError::PredictionThreshold) => { + Err(GgrsError::PredictionThreshold) => { println!("Frame {} skipped", sess.current_frame()) } diff --git a/examples/ex_game/ex_game_spectator.rs b/examples/ex_game/ex_game_spectator.rs index 66df7fc..cdcaebe 100644 --- a/examples/ex_game/ex_game_spectator.rs +++ b/examples/ex_game/ex_game_spectator.rs @@ -1,7 +1,7 @@ mod ex_game; use ex_game::{GGRSConfig, Game}; -use ggrs::{GGRSError, GGRSEvent, SessionBuilder, SessionState, UdpNonBlockingSocket}; +use ggrs::{GgrsError, GGRSEvent, SessionBuilder, SessionState, UdpNonBlockingSocket}; use instant::{Duration, Instant}; use macroquad::prelude::*; use std::net::SocketAddr; @@ -79,7 +79,7 @@ async fn main() -> Result<(), Box> { if sess.current_state() == SessionState::Running { match sess.advance_frame() { Ok(requests) => game.handle_requests(requests), - Err(GGRSError::PredictionThreshold) => { + Err(GgrsError::PredictionThreshold) => { println!( "Frame {} skipped: Waiting for input from host.", game.current_frame() diff --git a/src/error.rs b/src/error.rs index 1693baf..f5b18d5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -8,7 +8,7 @@ use crate::Frame; /// /// [`Result<(),GGRSError>`]: std::result::Result #[derive(Debug, Clone, PartialEq, Hash)] -pub enum GGRSError { +pub enum GgrsError { /// When the prediction threshold has been reached, we cannot accept more inputs from the local player. PredictionThreshold, /// You made an invalid request, usually by using wrong parameters for function calls. @@ -27,56 +27,41 @@ pub enum GGRSError { NotSynchronized, /// The spectator got so far behind the host that catching up is impossible. SpectatorTooFarBehind, - /// Deprecated, will be removed in next major release - SocketCreationFailed, - /// Deprecated, will be removed in next major release - PlayerDisconnected, - /// Deprecated, will be removed in next major release - DecodingError, } -impl Display for GGRSError { +impl Display for GgrsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - GGRSError::PredictionThreshold => { + GgrsError::PredictionThreshold => { write!( f, "Prediction threshold is reached, cannot proceed without catching up." ) } - GGRSError::InvalidRequest { info } => { + GgrsError::InvalidRequest { info } => { write!(f, "Invalid Request: {}", info) } - GGRSError::NotSynchronized => { + GgrsError::NotSynchronized => { write!( f, "The session is not yet synchronized with all remote sessions." ) } - GGRSError::MismatchedChecksum { frame } => { + GgrsError::MismatchedChecksum { frame } => { write!( f, "Detected checksum mismatch during rollback on frame {}.", frame ) } - GGRSError::SpectatorTooFarBehind => { + GgrsError::SpectatorTooFarBehind => { write!( f, "The spectator got so far behind the host that catching up is impossible." ) } - GGRSError::SocketCreationFailed => { - write!(f, "Deprecated, will be removed in next major release.") - } - GGRSError::PlayerDisconnected => { - write!(f, "Deprecated, will be removed in next major release.") - } - GGRSError::DecodingError => { - write!(f, "Deprecated, will be removed in next major release.") - } } } } -impl Error for GGRSError {} +impl Error for GgrsError {} diff --git a/src/lib.rs b/src/lib.rs index 5c7a86e..981384d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ //#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] use std::{fmt::Debug, hash::Hash}; -pub use error::GGRSError; +pub use error::GgrsError; pub use network::messages::Message; pub use network::network_stats::NetworkStats; pub use network::udp_socket::UdpNonBlockingSocket; diff --git a/src/network/protocol.rs b/src/network/protocol.rs index 1c21759..32a816a 100644 --- a/src/network/protocol.rs +++ b/src/network/protocol.rs @@ -6,7 +6,7 @@ use crate::network::messages::{ }; use crate::time_sync::TimeSync; use crate::{ - Config, DesyncDetection, Frame, GGRSError, NonBlockingSocket, PlayerHandle, NULL_FRAME, + Config, DesyncDetection, Frame, GgrsError, NonBlockingSocket, PlayerHandle, NULL_FRAME, }; use instant::{Duration, Instant}; @@ -280,15 +280,15 @@ impl UdpProtocol { self.local_frame_advantage = remote_frame - local_frame; } - pub(crate) fn network_stats(&self) -> Result { + pub(crate) fn network_stats(&self) -> Result { if self.state != ProtocolState::Synchronizing && self.state != ProtocolState::Running { - return Err(GGRSError::NotSynchronized); + return Err(GgrsError::NotSynchronized); } let now = millis_since_epoch(); let seconds = (now - self.stats_start_time) / 1000; if seconds == 0 { - return Err(GGRSError::NotSynchronized); + return Err(GgrsError::NotSynchronized); } let total_bytes_sent = self.bytes_sent + (self.packets_sent * UDP_HEADER_SIZE); diff --git a/src/sessions/builder.rs b/src/sessions/builder.rs index bdacb9e..1f0b6d2 100644 --- a/src/sessions/builder.rs +++ b/src/sessions/builder.rs @@ -4,7 +4,7 @@ use instant::Duration; use crate::{ network::protocol::UdpProtocol, sessions::p2p_session::PlayerRegistry, Config, DesyncDetection, - GGRSError, NonBlockingSocket, P2PSession, PlayerHandle, PlayerType, SpectatorSession, + GgrsError, NonBlockingSocket, P2PSession, PlayerHandle, PlayerType, SpectatorSession, SyncTestSession, }; @@ -91,10 +91,10 @@ impl SessionBuilder { mut self, player_type: PlayerType, player_handle: PlayerHandle, - ) -> Result { + ) -> Result { // check if the player handle is already in use if self.player_reg.handles.contains_key(&player_handle) { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Player handle already in use.".to_owned(), }); } @@ -103,21 +103,21 @@ impl SessionBuilder { PlayerType::Local => { self.local_players += 1; if player_handle >= self.num_players { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "The player handle you provided is invalid. For a local player, the handle should be between 0 and num_players".to_owned(), }); } } PlayerType::Remote(_) => { if player_handle >= self.num_players { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "The player handle you provided is invalid. For a remote player, the handle should be between 0 and num_players".to_owned(), }); } } PlayerType::Spectator(_) => { if player_handle < self.num_players { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "The player handle you provided is invalid. For a spectator, the handle should be num_players or higher".to_owned(), }); } @@ -133,9 +133,9 @@ impl SessionBuilder { /// - Returns [`InvalidRequest`] if the prediction window is 0. /// /// [`InvalidRequest`]: GGRSError::InvalidRequest - pub fn with_max_prediction_window(mut self, window: usize) -> Result { + pub fn with_max_prediction_window(mut self, window: usize) -> Result { if window == 0 { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Currently, only prediction windows above 0 are supported".to_owned(), }); } @@ -188,9 +188,9 @@ impl SessionBuilder { /// - Returns [`InvalidRequest`] if the fps is 0 /// /// [`InvalidRequest`]: GGRSError::InvalidRequest - pub fn with_fps(mut self, fps: usize) -> Result { + pub fn with_fps(mut self, fps: usize) -> Result { if fps == 0 { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "FPS should be higher than 0.".to_owned(), }); } @@ -207,15 +207,15 @@ impl SessionBuilder { /// Sets the maximum frames behind. If the spectator is more than this amount of frames behind the received inputs, /// it will catch up with `catchup_speed` amount of frames per step. /// - pub fn with_max_frames_behind(mut self, max_frames_behind: usize) -> Result { + pub fn with_max_frames_behind(mut self, max_frames_behind: usize) -> Result { if max_frames_behind < 1 { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Max frames behind cannot be smaller than 1.".to_owned(), }); } if max_frames_behind >= SPECTATOR_BUFFER_SIZE { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Max frames behind cannot be larger or equal than the Spectator buffer size (60)" .to_owned(), }); @@ -226,15 +226,15 @@ impl SessionBuilder { /// Sets the catchup speed. Per default, this is set to 1, so the spectator never catches up. /// If you want the spectator to catch up to the host if `max_frames_behind` is surpassed, set this to a value higher than 1. - pub fn with_catchup_speed(mut self, catchup_speed: usize) -> Result { + pub fn with_catchup_speed(mut self, catchup_speed: usize) -> Result { if catchup_speed < 1 { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Catchup speed cannot be smaller than 1.".to_owned(), }); } if catchup_speed >= self.max_frames_behind { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Catchup speed cannot be larger or equal than the allowed maximum frames behind host" .to_owned(), }); @@ -251,11 +251,11 @@ impl SessionBuilder { pub fn start_p2p_session( mut self, socket: impl NonBlockingSocket + 'static, - ) -> Result, GGRSError> { + ) -> Result, GgrsError> { // check if all players are added for player_handle in 0..self.num_players { if !self.player_reg.handles.contains_key(&player_handle) { - return Err(GGRSError::InvalidRequest{ + return Err(GgrsError::InvalidRequest{ info: "Not enough players have been added. Keep registering players up to the defined player number.".to_owned(), }); } @@ -340,9 +340,9 @@ impl SessionBuilder { /// Due to the decentralized nature of saving and loading gamestates, checksum comparisons can only be made if `check_distance` is 2 or higher. /// This is a great way to test if your system runs deterministically. /// After creating the session, add a local player, set input delay for them and then start the session. - pub fn start_synctest_session(self) -> Result, GGRSError> { + pub fn start_synctest_session(self) -> Result, GgrsError> { if self.check_dist >= self.max_prediction { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Check distance too big.".to_owned(), }); } diff --git a/src/sessions/p2p_session.rs b/src/sessions/p2p_session.rs index e64f244..432b14d 100644 --- a/src/sessions/p2p_session.rs +++ b/src/sessions/p2p_session.rs @@ -1,4 +1,4 @@ -use crate::error::GGRSError; +use crate::error::GgrsError; use crate::frame_info::PlayerInput; use crate::network::messages::ConnectionStatus; use crate::network::network_stats::NetworkStats; @@ -225,14 +225,14 @@ impl P2PSession { &mut self, player_handle: PlayerHandle, input: T::Input, - ) -> Result<(), GGRSError> { + ) -> Result<(), GgrsError> { // make sure the input is for a registered local player if !self .player_reg .local_player_handles() .contains(&player_handle) { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "The player handle you provided is not referring to a local player." .to_owned(), }); @@ -253,13 +253,13 @@ impl P2PSession { /// [`Vec`]: GGRSRequest /// [`InvalidRequest`]: GGRSError::InvalidRequest /// [`NotSynchronized`]: GGRSError::NotSynchronized - pub fn advance_frame(&mut self) -> Result>, GGRSError> { + pub fn advance_frame(&mut self) -> Result>, GgrsError> { // receive info from remote players, trigger events and send messages self.poll_remote_clients(); // session is not running and synchronized if self.state != SessionState::Running { - return Err(GGRSError::NotSynchronized); + return Err(GgrsError::NotSynchronized); } // This list of requests will be returned to the user @@ -341,7 +341,7 @@ impl P2PSession { self.local_connect_status[handle].last_frame = actual_frame; } None => { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Missing local input while calling advance_frame().".to_owned(), }); } @@ -430,13 +430,13 @@ impl P2PSession { /// - Returns [`InvalidRequest`] if you try to disconnect a local player or the provided handle is invalid. /// /// [`InvalidRequest`]: GGRSError::InvalidRequest - pub fn disconnect_player(&mut self, player_handle: PlayerHandle) -> Result<(), GGRSError> { + pub fn disconnect_player(&mut self, player_handle: PlayerHandle) -> Result<(), GgrsError> { match self.player_reg.handles.get(&player_handle) { // the local player cannot be disconnected - None => Err(GGRSError::InvalidRequest { + None => Err(GgrsError::InvalidRequest { info: "Invalid Player Handle.".to_owned(), }), - Some(PlayerType::Local) => Err(GGRSError::InvalidRequest { + Some(PlayerType::Local) => Err(GgrsError::InvalidRequest { info: "Local Player cannot be disconnected.".to_owned(), }), // a remote player can only be disconnected if not already disconnected, since there is some additional logic attached @@ -446,7 +446,7 @@ impl P2PSession { self.disconnect_player_at_frame(player_handle, last_frame); return Ok(()); } - Err(GGRSError::InvalidRequest { + Err(GgrsError::InvalidRequest { info: "Player already disconnected.".to_owned(), }) } @@ -465,7 +465,7 @@ impl P2PSession { /// /// [`InvalidRequest`]: GGRSError::InvalidRequest /// [`NotSynchronized`]: GGRSError::NotSynchronized - pub fn network_stats(&self, player_handle: PlayerHandle) -> Result { + pub fn network_stats(&self, player_handle: PlayerHandle) -> Result { match self.player_reg.handles.get(&player_handle) { Some(PlayerType::Remote(addr)) => self .player_reg @@ -479,7 +479,7 @@ impl P2PSession { .get(addr) .expect("Endpoint should exist for any registered player") .network_stats(), - _ => Err(GGRSError::InvalidRequest { + _ => Err(GgrsError::InvalidRequest { info: "Given player handle not referring to a remote player or spectator" .to_owned(), }), diff --git a/src/sessions/p2p_spectator_session.rs b/src/sessions/p2p_spectator_session.rs index 7400cce..54dee95 100644 --- a/src/sessions/p2p_spectator_session.rs +++ b/src/sessions/p2p_spectator_session.rs @@ -7,7 +7,7 @@ use crate::{ protocol::{Event, UdpProtocol}, }, sessions::builder::MAX_EVENT_QUEUE_SIZE, - Config, Frame, GGRSError, GGRSEvent, GGRSRequest, InputStatus, NetworkStats, NonBlockingSocket, + Config, Frame, GgrsError, GGRSEvent, GGRSRequest, InputStatus, NetworkStats, NonBlockingSocket, SessionState, NULL_FRAME, }; @@ -88,7 +88,7 @@ impl SpectatorSession { /// - Returns [`NotSynchronized`] if the session is not connected to other clients yet. /// /// [`NotSynchronized`]: GGRSError::NotSynchronized - pub fn network_stats(&self) -> Result { + pub fn network_stats(&self) -> Result { self.host.network_stats() } @@ -106,12 +106,12 @@ impl SpectatorSession { /// /// [`Vec`]: GGRSRequest /// [`NotSynchronized`]: GGRSError::NotSynchronized - pub fn advance_frame(&mut self) -> Result>, GGRSError> { + pub fn advance_frame(&mut self) -> Result>, GgrsError> { // receive info from host, trigger events and send messages self.poll_remote_clients(); if self.state != SessionState::Running { - return Err(GGRSError::NotSynchronized); + return Err(GgrsError::NotSynchronized); } let mut requests = Vec::new(); @@ -173,17 +173,17 @@ impl SpectatorSession { fn inputs_at_frame( &self, frame_to_grab: Frame, - ) -> Result, GGRSError> { + ) -> Result, GgrsError> { let player_inputs = &self.inputs[frame_to_grab as usize % SPECTATOR_BUFFER_SIZE]; // We haven't received the input from the host yet. Wait. if player_inputs[0].frame < frame_to_grab { - return Err(GGRSError::PredictionThreshold); + return Err(GgrsError::PredictionThreshold); } // The host is more than [`SPECTATOR_BUFFER_SIZE`] frames ahead of the spectator. The input we need is gone forever. if player_inputs[0].frame > frame_to_grab { - return Err(GGRSError::SpectatorTooFarBehind); + return Err(GgrsError::SpectatorTooFarBehind); } Ok(player_inputs diff --git a/src/sessions/sync_test_session.rs b/src/sessions/sync_test_session.rs index ba4ecbe..0526b7d 100644 --- a/src/sessions/sync_test_session.rs +++ b/src/sessions/sync_test_session.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::error::GGRSError; +use crate::error::GgrsError; use crate::frame_info::PlayerInput; use crate::network::messages::ConnectionStatus; use crate::sync_layer::SyncLayer; @@ -62,9 +62,9 @@ impl SyncTestSession { &mut self, player_handle: PlayerHandle, input: T::Input, - ) -> Result<(), GGRSError> { + ) -> Result<(), GgrsError> { if player_handle >= self.num_players { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "The player handle you provided is not valid.".to_owned(), }); } @@ -82,7 +82,7 @@ impl SyncTestSession { /// /// [`Vec`]: GGRSRequest /// [`MismatchedChecksum`]: GGRSError::MismatchedChecksum - pub fn advance_frame(&mut self) -> Result>, GGRSError> { + pub fn advance_frame(&mut self) -> Result>, GgrsError> { let mut requests = Vec::new(); // if we advanced far enough into the game do comparisons and rollbacks @@ -91,7 +91,7 @@ impl SyncTestSession { for i in 0..=self.check_distance as i32 { let frame_to_check = self.sync_layer.current_frame() - i; if !self.checksums_consistent(frame_to_check) { - return Err(GGRSError::MismatchedChecksum { + return Err(GgrsError::MismatchedChecksum { frame: frame_to_check, }); } @@ -104,7 +104,7 @@ impl SyncTestSession { // we require inputs for all players if self.num_players != self.local_inputs.len() { - return Err(GGRSError::InvalidRequest { + return Err(GgrsError::InvalidRequest { info: "Missing local input while calling advance_frame().".to_owned(), }); } diff --git a/src/sync_layer.rs b/src/sync_layer.rs index f1714df..2341b40 100644 --- a/src/sync_layer.rs +++ b/src/sync_layer.rs @@ -2,7 +2,7 @@ use bytemuck::Zeroable; use parking_lot::Mutex; use std::sync::Arc; -use crate::error::GGRSError; +use crate::error::GgrsError; use crate::frame_info::{GameState, PlayerInput}; use crate::input_queue::InputQueue; use crate::network::messages::ConnectionStatus; @@ -170,12 +170,12 @@ impl SyncLayer { &mut self, player_handle: PlayerHandle, input: PlayerInput, - ) -> Result { + ) -> Result { let frames_ahead = self.current_frame - self.last_confirmed_frame; if self.current_frame >= self.max_prediction as i32 && frames_ahead >= self.max_prediction as i32 { - return Err(GGRSError::PredictionThreshold); + return Err(GgrsError::PredictionThreshold); } // The input provided should match the current frame, we account for input delay later diff --git a/tests/test_p2p_session.rs b/tests/test_p2p_session.rs index ebdec3e..1a1e860 100644 --- a/tests/test_p2p_session.rs +++ b/tests/test_p2p_session.rs @@ -1,7 +1,7 @@ mod stubs; use ggrs::{ - DesyncDetection, GGRSError, GGRSEvent, PlayerType, SessionBuilder, SessionState, + DesyncDetection, GgrsError, GGRSEvent, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket, }; use serial_test::serial; @@ -10,7 +10,7 @@ use stubs::{StubConfig, StubInput}; #[test] #[serial] -fn test_add_more_players() -> Result<(), GGRSError> { +fn test_add_more_players() -> Result<(), GgrsError> { let socket = UdpNonBlockingSocket::bind_to_port(7777).unwrap(); let remote_addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); let remote_addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8081); @@ -30,7 +30,7 @@ fn test_add_more_players() -> Result<(), GGRSError> { #[test] #[serial] -fn test_start_session() -> Result<(), GGRSError> { +fn test_start_session() -> Result<(), GgrsError> { let socket = UdpNonBlockingSocket::bind_to_port(7777).unwrap(); let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); let spec_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8090); @@ -45,7 +45,7 @@ fn test_start_session() -> Result<(), GGRSError> { #[test] #[serial] -fn test_disconnect_player() -> Result<(), GGRSError> { +fn test_disconnect_player() -> Result<(), GgrsError> { let socket = UdpNonBlockingSocket::bind_to_port(7777).unwrap(); let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080); let spec_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8090); @@ -67,7 +67,7 @@ fn test_disconnect_player() -> Result<(), GGRSError> { #[test] #[serial] -fn test_synchronize_p2p_sessions() -> Result<(), GGRSError> { +fn test_synchronize_p2p_sessions() -> Result<(), GgrsError> { let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777); let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8888); @@ -99,7 +99,7 @@ fn test_synchronize_p2p_sessions() -> Result<(), GGRSError> { #[test] #[serial] -fn test_advance_frame_p2p_sessions() -> Result<(), GGRSError> { +fn test_advance_frame_p2p_sessions() -> Result<(), GgrsError> { let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777); let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8888); @@ -150,7 +150,7 @@ fn test_advance_frame_p2p_sessions() -> Result<(), GGRSError> { #[test] #[serial] -fn test_desyncs_detected() -> Result<(), GGRSError> { +fn test_desyncs_detected() -> Result<(), GgrsError> { let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777); let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8888); let desync_mode = DesyncDetection::On { interval: 100 }; @@ -264,7 +264,7 @@ fn test_desyncs_detected() -> Result<(), GGRSError> { #[test] #[serial] -fn test_desyncs_and_input_delay_no_panic() -> Result<(), GGRSError> { +fn test_desyncs_and_input_delay_no_panic() -> Result<(), GgrsError> { let addr1 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777); let addr2 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8888); let desync_mode = DesyncDetection::On { interval: 100 }; diff --git a/tests/test_p2p_spectator_session.rs b/tests/test_p2p_spectator_session.rs index 537e2af..2539a77 100644 --- a/tests/test_p2p_spectator_session.rs +++ b/tests/test_p2p_spectator_session.rs @@ -1,6 +1,6 @@ mod stubs; -use ggrs::{GGRSError, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket}; +use ggrs::{GgrsError, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket}; use serial_test::serial; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use stubs::StubConfig; @@ -16,7 +16,7 @@ fn test_start_session() { #[test] #[serial] -fn test_synchronize_with_host() -> Result<(), GGRSError> { +fn test_synchronize_with_host() -> Result<(), GgrsError> { let host_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777); let spec_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8888); diff --git a/tests/test_synctest_session.rs b/tests/test_synctest_session.rs index a973b8c..9ede3a4 100644 --- a/tests/test_synctest_session.rs +++ b/tests/test_synctest_session.rs @@ -1,7 +1,7 @@ mod stubs; mod stubs_enum; -use ggrs::{GGRSError, GGRSRequest, SessionBuilder}; +use ggrs::{GgrsError, GGRSRequest, SessionBuilder}; use stubs::{StubConfig, StubInput}; #[test] @@ -12,7 +12,7 @@ fn test_create_session() { } #[test] -fn test_advance_frame_no_rollbacks() -> Result<(), GGRSError> { +fn test_advance_frame_no_rollbacks() -> Result<(), GgrsError> { let check_distance = 0; let mut stub = stubs::GameStub::new(); let mut sess = SessionBuilder::new() @@ -32,7 +32,7 @@ fn test_advance_frame_no_rollbacks() -> Result<(), GGRSError> { } #[test] -fn test_advance_frame_with_rollbacks() -> Result<(), GGRSError> { +fn test_advance_frame_with_rollbacks() -> Result<(), GgrsError> { let check_distance = 2; let mut stub = stubs::GameStub::new(); let mut sess = SessionBuilder::new() @@ -65,7 +65,7 @@ fn test_advance_frame_with_rollbacks() -> Result<(), GGRSError> { } #[test] -fn test_advance_frames_with_delayed_input() -> Result<(), GGRSError> { +fn test_advance_frames_with_delayed_input() -> Result<(), GgrsError> { let check_distance = 7; let mut stub = stubs::GameStub::new(); let mut sess = SessionBuilder::new() diff --git a/tests/test_synctest_session_enum.rs b/tests/test_synctest_session_enum.rs index f704e08..8ba2145 100644 --- a/tests/test_synctest_session_enum.rs +++ b/tests/test_synctest_session_enum.rs @@ -1,9 +1,9 @@ mod stubs_enum; -use ggrs::{GGRSError, SessionBuilder}; +use ggrs::{GgrsError, SessionBuilder}; #[test] -fn test_enum_advance_frames_with_delayed_input() -> Result<(), GGRSError> { +fn test_enum_advance_frames_with_delayed_input() -> Result<(), GgrsError> { let check_distance = 7; let mut stub = stubs_enum::GameStubEnum::new(); let mut sess = SessionBuilder::new() From c14d640cfe3e4a83a6cef16c9f8e6e250fe46a62 Mon Sep 17 00:00:00 2001 From: Georg Schuppe Date: Fri, 10 Nov 2023 08:35:11 +0100 Subject: [PATCH 2/8] refactor: rename GGRSEvent to GgrsEvent --- examples/ex_game/ex_game_spectator.rs | 4 ++-- src/lib.rs | 2 +- src/sessions/p2p_session.rs | 20 ++++++++++---------- src/sessions/p2p_spectator_session.rs | 16 ++++++++-------- tests/test_p2p_session.rs | 10 +++++----- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/ex_game/ex_game_spectator.rs b/examples/ex_game/ex_game_spectator.rs index cdcaebe..157db6f 100644 --- a/examples/ex_game/ex_game_spectator.rs +++ b/examples/ex_game/ex_game_spectator.rs @@ -1,7 +1,7 @@ mod ex_game; use ex_game::{GGRSConfig, Game}; -use ggrs::{GgrsError, GGRSEvent, SessionBuilder, SessionState, UdpNonBlockingSocket}; +use ggrs::{GgrsError, GgrsEvent, SessionBuilder, SessionState, UdpNonBlockingSocket}; use instant::{Duration, Instant}; use macroquad::prelude::*; use std::net::SocketAddr; @@ -59,7 +59,7 @@ async fn main() -> Result<(), Box> { // handle GGRS events for event in sess.events() { println!("Event: {:?}", event); - if let GGRSEvent::Disconnected { .. } = event { + if let GgrsEvent::Disconnected { .. } = event { println!("Disconnected from host."); return Ok(()); } diff --git a/src/lib.rs b/src/lib.rs index 981384d..c9a02c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,7 +113,7 @@ pub enum InputStatus { /// Notifications that you can receive from the session. Handling them is up to the user. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum GGRSEvent +pub enum GgrsEvent where T: Config, { diff --git a/src/sessions/p2p_session.rs b/src/sessions/p2p_session.rs index 432b14d..2a3e7e1 100644 --- a/src/sessions/p2p_session.rs +++ b/src/sessions/p2p_session.rs @@ -6,7 +6,7 @@ use crate::network::protocol::{UdpProtocol, MAX_CHECKSUM_HISTORY_SIZE}; use crate::sync_layer::SyncLayer; use crate::DesyncDetection; use crate::{ - network::protocol::Event, Config, Frame, GGRSEvent, GGRSRequest, NonBlockingSocket, + network::protocol::Event, Config, Frame, GgrsEvent, GGRSRequest, NonBlockingSocket, PlayerHandle, PlayerType, SessionState, NULL_FRAME, }; @@ -147,7 +147,7 @@ where frames_ahead: i32, /// Contains all events to be forwarded to the user. - event_queue: VecDeque>, + event_queue: VecDeque>, /// Contains all local inputs not yet sent into the system. This should have inputs for every local player before calling advance_frame local_inputs: HashMap>, @@ -516,7 +516,7 @@ impl P2PSession { } /// Returns all events that happened since last queried for events. If the number of stored events exceeds `MAX_EVENT_QUEUE_SIZE`, the oldest events will be discarded. - pub fn events(&mut self) -> Drain> { + pub fn events(&mut self) -> Drain> { self.event_queue.drain(..) } @@ -769,7 +769,7 @@ impl P2PSession { && self.frames_ahead >= MIN_RECOMMENDATION as i32 { self.next_recommended_sleep = self.sync_layer.current_frame() + RECOMMENDATION_INTERVAL; - self.event_queue.push_back(GGRSEvent::WaitRecommendation { + self.event_queue.push_back(GgrsEvent::WaitRecommendation { skip_frames: self .frames_ahead .try_into() @@ -815,11 +815,11 @@ impl P2PSession { // forward to user Event::Synchronizing { total, count } => { self.event_queue - .push_back(GGRSEvent::Synchronizing { addr, total, count }); + .push_back(GgrsEvent::Synchronizing { addr, total, count }); } // forward to user Event::NetworkInterrupted { disconnect_timeout } => { - self.event_queue.push_back(GGRSEvent::NetworkInterrupted { + self.event_queue.push_back(GgrsEvent::NetworkInterrupted { addr, disconnect_timeout, }); @@ -827,12 +827,12 @@ impl P2PSession { // forward to user Event::NetworkResumed => { self.event_queue - .push_back(GGRSEvent::NetworkResumed { addr }); + .push_back(GgrsEvent::NetworkResumed { addr }); } // check if all remotes are synced, then forward to user Event::Synchronized => { self.check_initial_sync(); - self.event_queue.push_back(GGRSEvent::Synchronized { addr }); + self.event_queue.push_back(GgrsEvent::Synchronized { addr }); } // disconnect the player, then forward to user Event::Disconnected => { @@ -846,7 +846,7 @@ impl P2PSession { self.disconnect_player_at_frame(handle, last_frame); } - self.event_queue.push_back(GGRSEvent::Disconnected { addr }); + self.event_queue.push_back(GgrsEvent::Disconnected { addr }); } // add the input and all associated information Event::Input { input, player } => { @@ -888,7 +888,7 @@ impl P2PSession { self.local_checksum_history.get(&remote_frame) { if local_checksum != remote_checksum { - self.event_queue.push_back(GGRSEvent::DesyncDetected { + self.event_queue.push_back(GgrsEvent::DesyncDetected { frame: remote_frame, local_checksum, remote_checksum, diff --git a/src/sessions/p2p_spectator_session.rs b/src/sessions/p2p_spectator_session.rs index 54dee95..f36da6d 100644 --- a/src/sessions/p2p_spectator_session.rs +++ b/src/sessions/p2p_spectator_session.rs @@ -7,7 +7,7 @@ use crate::{ protocol::{Event, UdpProtocol}, }, sessions::builder::MAX_EVENT_QUEUE_SIZE, - Config, Frame, GgrsError, GGRSEvent, GGRSRequest, InputStatus, NetworkStats, NonBlockingSocket, + Config, Frame, GgrsError, GgrsEvent, GGRSRequest, InputStatus, NetworkStats, NonBlockingSocket, SessionState, NULL_FRAME, }; @@ -29,7 +29,7 @@ where host_connect_status: Vec, socket: Box>, host: UdpProtocol, - event_queue: VecDeque>, + event_queue: VecDeque>, current_frame: Frame, last_recv_frame: Frame, max_frames_behind: usize, @@ -93,7 +93,7 @@ impl SpectatorSession { } /// Returns all events that happened since last queried for events. If the number of stored events exceeds `MAX_EVENT_QUEUE_SIZE`, the oldest events will be discarded. - pub fn events(&mut self) -> Drain> { + pub fn events(&mut self) -> Drain> { self.event_queue.drain(..) } @@ -206,11 +206,11 @@ impl SpectatorSession { // forward to user Event::Synchronizing { total, count } => { self.event_queue - .push_back(GGRSEvent::Synchronizing { addr, total, count }); + .push_back(GgrsEvent::Synchronizing { addr, total, count }); } // forward to user Event::NetworkInterrupted { disconnect_timeout } => { - self.event_queue.push_back(GGRSEvent::NetworkInterrupted { + self.event_queue.push_back(GgrsEvent::NetworkInterrupted { addr, disconnect_timeout, }); @@ -218,16 +218,16 @@ impl SpectatorSession { // forward to user Event::NetworkResumed => { self.event_queue - .push_back(GGRSEvent::NetworkResumed { addr }); + .push_back(GgrsEvent::NetworkResumed { addr }); } // synced with the host, then forward to user Event::Synchronized => { self.state = SessionState::Running; - self.event_queue.push_back(GGRSEvent::Synchronized { addr }); + self.event_queue.push_back(GgrsEvent::Synchronized { addr }); } // disconnect the player, then forward to user Event::Disconnected => { - self.event_queue.push_back(GGRSEvent::Disconnected { addr }); + self.event_queue.push_back(GgrsEvent::Disconnected { addr }); } // add the input and all associated information Event::Input { input, player } => { diff --git a/tests/test_p2p_session.rs b/tests/test_p2p_session.rs index 1a1e860..caf3738 100644 --- a/tests/test_p2p_session.rs +++ b/tests/test_p2p_session.rs @@ -1,7 +1,7 @@ mod stubs; use ggrs::{ - DesyncDetection, GgrsError, GGRSEvent, PlayerType, SessionBuilder, SessionState, + DesyncDetection, GgrsError, GgrsEvent, PlayerType, SessionBuilder, SessionState, UdpNonBlockingSocket, }; use serial_test::serial; @@ -178,7 +178,7 @@ fn test_desyncs_detected() -> Result<(), GgrsError> { // drain events assert!(sess1.events().chain(sess2.events()).all(|e| match e { - GGRSEvent::Synchronizing { .. } | GGRSEvent::Synchronized { .. } => true, + GgrsEvent::Synchronizing { .. } | GgrsEvent::Synchronized { .. } => true, _ => false, })); @@ -229,7 +229,7 @@ fn test_desyncs_detected() -> Result<(), GgrsError> { assert_eq!(sess1_events.len(), 1); assert_eq!(sess2_events.len(), 1); - let GGRSEvent::DesyncDetected { + let GgrsEvent::DesyncDetected { frame: desync_frame1, local_checksum: desync_local_checksum1, remote_checksum: desync_remote_checksum1, @@ -242,7 +242,7 @@ fn test_desyncs_detected() -> Result<(), GgrsError> { assert_eq!(desync_addr1, addr2); assert_ne!(desync_local_checksum1, desync_remote_checksum1); - let GGRSEvent::DesyncDetected { + let GgrsEvent::DesyncDetected { frame: desync_frame2, local_checksum: desync_local_checksum2, remote_checksum: desync_remote_checksum2, @@ -294,7 +294,7 @@ fn test_desyncs_and_input_delay_no_panic() -> Result<(), GgrsError> { // drain events assert!(sess1.events().chain(sess2.events()).all(|e| match e { - GGRSEvent::Synchronizing { .. } | GGRSEvent::Synchronized { .. } => true, + GgrsEvent::Synchronizing { .. } | GgrsEvent::Synchronized { .. } => true, _ => false, })); From 186edb45a3c3eb5dfe45bc4da66bc5d3321b2413 Mon Sep 17 00:00:00 2001 From: Georg Schuppe Date: Fri, 10 Nov 2023 08:35:52 +0100 Subject: [PATCH 3/8] refactor: rename GGRSRequest to GgrsRequest --- examples/ex_game/ex_game.rs | 10 +++++----- src/lib.rs | 2 +- src/sessions/p2p_session.rs | 12 ++++++------ src/sessions/p2p_spectator_session.rs | 6 +++--- src/sessions/sync_test_session.rs | 10 +++++----- src/sync_layer.rs | 10 +++++----- tests/stubs.rs | 18 +++++++++--------- tests/stubs_enum.rs | 10 +++++----- tests/test_synctest_session.rs | 18 +++++++++--------- 9 files changed, 48 insertions(+), 48 deletions(-) diff --git a/examples/ex_game/ex_game.rs b/examples/ex_game/ex_game.rs index 5297131..bc5a9e8 100644 --- a/examples/ex_game/ex_game.rs +++ b/examples/ex_game/ex_game.rs @@ -1,7 +1,7 @@ use std::net::SocketAddr; use bytemuck::{Pod, Zeroable}; -use ggrs::{Config, Frame, GGRSRequest, GameStateCell, InputStatus, PlayerHandle, NULL_FRAME}; +use ggrs::{Config, Frame, GgrsRequest, GameStateCell, InputStatus, PlayerHandle, NULL_FRAME}; use macroquad::prelude::*; use serde::{Deserialize, Serialize}; @@ -73,12 +73,12 @@ impl Game { } // for each request, call the appropriate function - pub fn handle_requests(&mut self, requests: Vec>) { + pub fn handle_requests(&mut self, requests: Vec>) { for request in requests { match request { - GGRSRequest::LoadGameState { cell, .. } => self.load_game_state(cell), - GGRSRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), - GGRSRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), + GgrsRequest::LoadGameState { cell, .. } => self.load_game_state(cell), + GgrsRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), + GgrsRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), } } } diff --git a/src/lib.rs b/src/lib.rs index c9a02c3..65f76c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,7 +167,7 @@ where } /// Requests that you can receive from the session. Handling them is mandatory. -pub enum GGRSRequest +pub enum GgrsRequest where T: Config, { diff --git a/src/sessions/p2p_session.rs b/src/sessions/p2p_session.rs index 2a3e7e1..7ea5c97 100644 --- a/src/sessions/p2p_session.rs +++ b/src/sessions/p2p_session.rs @@ -6,7 +6,7 @@ use crate::network::protocol::{UdpProtocol, MAX_CHECKSUM_HISTORY_SIZE}; use crate::sync_layer::SyncLayer; use crate::DesyncDetection; use crate::{ - network::protocol::Event, Config, Frame, GgrsEvent, GGRSRequest, NonBlockingSocket, + network::protocol::Event, Config, Frame, GgrsEvent, GgrsRequest, NonBlockingSocket, PlayerHandle, PlayerType, SessionState, NULL_FRAME, }; @@ -253,7 +253,7 @@ impl P2PSession { /// [`Vec`]: GGRSRequest /// [`InvalidRequest`]: GGRSError::InvalidRequest /// [`NotSynchronized`]: GGRSError::NotSynchronized - pub fn advance_frame(&mut self) -> Result>, GgrsError> { + pub fn advance_frame(&mut self) -> Result>, GgrsError> { // receive info from remote players, trigger events and send messages self.poll_remote_clients(); @@ -368,7 +368,7 @@ impl P2PSession { .synchronized_inputs(&self.local_connect_status); // advance the frame count self.sync_layer.advance_frame(); - requests.push(GGRSRequest::AdvanceFrame { inputs }); + requests.push(GgrsRequest::AdvanceFrame { inputs }); Ok(requests) } @@ -625,7 +625,7 @@ impl P2PSession { &mut self, first_incorrect: Frame, min_confirmed: Frame, - requests: &mut Vec>, + requests: &mut Vec>, ) { let current_frame = self.sync_layer.current_frame(); // determine the frame to load @@ -669,7 +669,7 @@ impl P2PSession { // advance the frame self.sync_layer.advance_frame(); - requests.push(GGRSRequest::AdvanceFrame { inputs }); + requests.push(GgrsRequest::AdvanceFrame { inputs }); } // after all this, we should have arrived at the same frame where we started assert_eq!(self.sync_layer.current_frame(), current_frame); @@ -782,7 +782,7 @@ impl P2PSession { &mut self, last_saved: Frame, confirmed_frame: Frame, - requests: &mut Vec>, + requests: &mut Vec>, ) { // in sparse saving mode, we need to make sure not to lose the last saved frame if self.sync_layer.current_frame() - last_saved >= self.max_prediction as i32 { diff --git a/src/sessions/p2p_spectator_session.rs b/src/sessions/p2p_spectator_session.rs index f36da6d..1c0f00c 100644 --- a/src/sessions/p2p_spectator_session.rs +++ b/src/sessions/p2p_spectator_session.rs @@ -7,7 +7,7 @@ use crate::{ protocol::{Event, UdpProtocol}, }, sessions::builder::MAX_EVENT_QUEUE_SIZE, - Config, Frame, GgrsError, GgrsEvent, GGRSRequest, InputStatus, NetworkStats, NonBlockingSocket, + Config, Frame, GgrsError, GgrsEvent, GgrsRequest, InputStatus, NetworkStats, NonBlockingSocket, SessionState, NULL_FRAME, }; @@ -106,7 +106,7 @@ impl SpectatorSession { /// /// [`Vec`]: GGRSRequest /// [`NotSynchronized`]: GGRSError::NotSynchronized - pub fn advance_frame(&mut self) -> Result>, GgrsError> { + pub fn advance_frame(&mut self) -> Result>, GgrsError> { // receive info from host, trigger events and send messages self.poll_remote_clients(); @@ -127,7 +127,7 @@ impl SpectatorSession { let frame_to_grab = self.current_frame + 1; let synced_inputs = self.inputs_at_frame(frame_to_grab)?; - requests.push(GGRSRequest::AdvanceFrame { + requests.push(GgrsRequest::AdvanceFrame { inputs: synced_inputs, }); diff --git a/src/sessions/sync_test_session.rs b/src/sessions/sync_test_session.rs index 0526b7d..02d0f34 100644 --- a/src/sessions/sync_test_session.rs +++ b/src/sessions/sync_test_session.rs @@ -4,7 +4,7 @@ use crate::error::GgrsError; use crate::frame_info::PlayerInput; use crate::network::messages::ConnectionStatus; use crate::sync_layer::SyncLayer; -use crate::{Config, Frame, GGRSRequest, PlayerHandle}; +use crate::{Config, Frame, GgrsRequest, PlayerHandle}; /// During a [`SyncTestSession`], GGRS will simulate a rollback every frame and resimulate the last n states, where n is the given check distance. /// The resimulated checksums will be compared with the original checksums and report if there was a mismatch. @@ -82,7 +82,7 @@ impl SyncTestSession { /// /// [`Vec`]: GGRSRequest /// [`MismatchedChecksum`]: GGRSError::MismatchedChecksum - pub fn advance_frame(&mut self) -> Result>, GgrsError> { + pub fn advance_frame(&mut self) -> Result>, GgrsError> { let mut requests = Vec::new(); // if we advanced far enough into the game do comparisons and rollbacks @@ -128,7 +128,7 @@ impl SyncTestSession { .synchronized_inputs(&self.dummy_connect_status); // advance the frame - requests.push(GGRSRequest::AdvanceFrame { inputs }); + requests.push(GgrsRequest::AdvanceFrame { inputs }); self.sync_layer.advance_frame(); // since this is a sync test, we "cheat" by setting the last confirmed state to the (current state - check_distance), so the sync layer won't complain about missing @@ -180,7 +180,7 @@ impl SyncTestSession { } } - fn adjust_gamestate(&mut self, frame_to: Frame, requests: &mut Vec>) { + fn adjust_gamestate(&mut self, frame_to: Frame, requests: &mut Vec>) { let start_frame = self.sync_layer.current_frame(); let count = start_frame - frame_to; @@ -202,7 +202,7 @@ impl SyncTestSession { // then advance self.sync_layer.advance_frame(); - requests.push(GGRSRequest::AdvanceFrame { inputs }); + requests.push(GgrsRequest::AdvanceFrame { inputs }); } assert_eq!(self.sync_layer.current_frame(), start_frame); } diff --git a/src/sync_layer.rs b/src/sync_layer.rs index 2341b40..3e1582e 100644 --- a/src/sync_layer.rs +++ b/src/sync_layer.rs @@ -6,7 +6,7 @@ use crate::error::GgrsError; use crate::frame_info::{GameState, PlayerInput}; use crate::input_queue::InputQueue; use crate::network::messages::ConnectionStatus; -use crate::{Config, Frame, GGRSRequest, InputStatus, PlayerHandle, NULL_FRAME}; +use crate::{Config, Frame, GgrsRequest, InputStatus, PlayerHandle, NULL_FRAME}; /// An [`Arc`] that you can [`save()`]/[`load()`] a `T` to/from. These will be handed to the user as part of a [`GGRSRequest`]. /// @@ -125,10 +125,10 @@ impl SyncLayer { self.current_frame += 1; } - pub(crate) fn save_current_state(&mut self) -> GGRSRequest { + pub(crate) fn save_current_state(&mut self) -> GgrsRequest { self.last_saved_frame = self.current_frame; let cell = self.saved_states.get_cell(self.current_frame); - GGRSRequest::SaveGameState { + GgrsRequest::SaveGameState { cell, frame: self.current_frame, } @@ -146,7 +146,7 @@ impl SyncLayer { } /// Loads the gamestate indicated by `frame_to_load`. - pub(crate) fn load_frame(&mut self, frame_to_load: Frame) -> GGRSRequest { + pub(crate) fn load_frame(&mut self, frame_to_load: Frame) -> GgrsRequest { // The state should not be the current state or the state should not be in the future or too far away in the past assert!( frame_to_load != NULL_FRAME @@ -158,7 +158,7 @@ impl SyncLayer { assert_eq!(cell.0.lock().frame, frame_to_load); self.current_frame = frame_to_load; - GGRSRequest::LoadGameState { + GgrsRequest::LoadGameState { cell, frame: frame_to_load, } diff --git a/tests/stubs.rs b/tests/stubs.rs index 1eeb117..2b43c50 100644 --- a/tests/stubs.rs +++ b/tests/stubs.rs @@ -3,7 +3,7 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::net::SocketAddr; -use ggrs::{Config, Frame, GGRSRequest, GameStateCell, InputStatus}; +use ggrs::{Config, Frame, GgrsRequest, GameStateCell, InputStatus}; fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); @@ -39,12 +39,12 @@ impl GameStub { } #[allow(dead_code)] - pub fn handle_requests(&mut self, requests: Vec>) { + pub fn handle_requests(&mut self, requests: Vec>) { for request in requests { match request { - GGRSRequest::LoadGameState { cell, .. } => self.load_game_state(cell), - GGRSRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), - GGRSRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), + GgrsRequest::LoadGameState { cell, .. } => self.load_game_state(cell), + GgrsRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), + GgrsRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), } } } @@ -79,12 +79,12 @@ impl RandomChecksumGameStub { } #[allow(dead_code)] - pub fn handle_requests(&mut self, requests: Vec>) { + pub fn handle_requests(&mut self, requests: Vec>) { for request in requests { match request { - GGRSRequest::LoadGameState { cell, .. } => self.load_game_state(cell), - GGRSRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), - GGRSRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), + GgrsRequest::LoadGameState { cell, .. } => self.load_game_state(cell), + GgrsRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), + GgrsRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), } } } diff --git a/tests/stubs_enum.rs b/tests/stubs_enum.rs index 3aa59f1..1fda4f8 100644 --- a/tests/stubs_enum.rs +++ b/tests/stubs_enum.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::net::SocketAddr; -use ggrs::{Config, Frame, GGRSRequest, GameStateCell, InputStatus}; +use ggrs::{Config, Frame, GgrsRequest, GameStateCell, InputStatus}; fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); @@ -45,12 +45,12 @@ impl GameStubEnum { } #[allow(dead_code)] - pub fn handle_requests(&mut self, requests: Vec>) { + pub fn handle_requests(&mut self, requests: Vec>) { for request in requests { match request { - GGRSRequest::LoadGameState { cell, .. } => self.load_game_state(cell), - GGRSRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), - GGRSRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), + GgrsRequest::LoadGameState { cell, .. } => self.load_game_state(cell), + GgrsRequest::SaveGameState { cell, frame } => self.save_game_state(cell, frame), + GgrsRequest::AdvanceFrame { inputs } => self.advance_frame(inputs), } } } diff --git a/tests/test_synctest_session.rs b/tests/test_synctest_session.rs index 9ede3a4..6280242 100644 --- a/tests/test_synctest_session.rs +++ b/tests/test_synctest_session.rs @@ -1,7 +1,7 @@ mod stubs; mod stubs_enum; -use ggrs::{GgrsError, GGRSRequest, SessionBuilder}; +use ggrs::{GgrsError, GgrsRequest, SessionBuilder}; use stubs::{StubConfig, StubInput}; #[test] @@ -45,16 +45,16 @@ fn test_advance_frame_with_rollbacks() -> Result<(), GgrsError> { let requests = sess.advance_frame()?; if i <= check_distance { assert_eq!(requests.len(), 2); // save, advance - assert!(matches!(requests[0], GGRSRequest::SaveGameState { .. })); - assert!(matches!(requests[1], GGRSRequest::AdvanceFrame { .. })); + assert!(matches!(requests[0], GgrsRequest::SaveGameState { .. })); + assert!(matches!(requests[1], GgrsRequest::AdvanceFrame { .. })); } else { assert_eq!(requests.len(), 6); // load, advance, save, advance, save, advance - assert!(matches!(requests[0], GGRSRequest::LoadGameState { .. })); // rollback - assert!(matches!(requests[1], GGRSRequest::AdvanceFrame { .. })); // rollback - assert!(matches!(requests[2], GGRSRequest::SaveGameState { .. })); // rollback - assert!(matches!(requests[3], GGRSRequest::AdvanceFrame { .. })); // rollback - assert!(matches!(requests[4], GGRSRequest::SaveGameState { .. })); - assert!(matches!(requests[5], GGRSRequest::AdvanceFrame { .. })); + assert!(matches!(requests[0], GgrsRequest::LoadGameState { .. })); // rollback + assert!(matches!(requests[1], GgrsRequest::AdvanceFrame { .. })); // rollback + assert!(matches!(requests[2], GgrsRequest::SaveGameState { .. })); // rollback + assert!(matches!(requests[3], GgrsRequest::AdvanceFrame { .. })); // rollback + assert!(matches!(requests[4], GgrsRequest::SaveGameState { .. })); + assert!(matches!(requests[5], GgrsRequest::AdvanceFrame { .. })); } stub.handle_requests(requests); From 2378425b9ba45874127ea0111a843267312f7329 Mon Sep 17 00:00:00 2001 From: Georg Schuppe Date: Fri, 10 Nov 2023 08:37:48 +0100 Subject: [PATCH 4/8] doc: changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index efd442b..79012e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ In this document, all remarkable changes are listed. Not mentioned are smaller c ## Unreleased +- Rename types with GGRS prefix to match rust naming conventions +- Removed deprecated `GgrsError` variants - `GameStateCell` now implements debug. - fixed a bug where checksums of unconfirmed frames were compared during desync detection. - You can now trigger a desync manually in the example game by pressing SPACE. From 63e047d312992b598ee5e0b5b24b834af0c98ad8 Mon Sep 17 00:00:00 2001 From: Georg Schuppe Date: Fri, 10 Nov 2023 08:42:42 +0100 Subject: [PATCH 5/8] chore: cargo fmt --- examples/ex_game/ex_game.rs | 2 +- tests/stubs.rs | 2 +- tests/stubs_enum.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/ex_game/ex_game.rs b/examples/ex_game/ex_game.rs index bc5a9e8..d1ab074 100644 --- a/examples/ex_game/ex_game.rs +++ b/examples/ex_game/ex_game.rs @@ -1,7 +1,7 @@ use std::net::SocketAddr; use bytemuck::{Pod, Zeroable}; -use ggrs::{Config, Frame, GgrsRequest, GameStateCell, InputStatus, PlayerHandle, NULL_FRAME}; +use ggrs::{Config, Frame, GameStateCell, GgrsRequest, InputStatus, PlayerHandle, NULL_FRAME}; use macroquad::prelude::*; use serde::{Deserialize, Serialize}; diff --git a/tests/stubs.rs b/tests/stubs.rs index 2b43c50..e184309 100644 --- a/tests/stubs.rs +++ b/tests/stubs.rs @@ -3,7 +3,7 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::net::SocketAddr; -use ggrs::{Config, Frame, GgrsRequest, GameStateCell, InputStatus}; +use ggrs::{Config, Frame, GameStateCell, GgrsRequest, InputStatus}; fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); diff --git a/tests/stubs_enum.rs b/tests/stubs_enum.rs index 1fda4f8..a9c28d5 100644 --- a/tests/stubs_enum.rs +++ b/tests/stubs_enum.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::net::SocketAddr; -use ggrs::{Config, Frame, GgrsRequest, GameStateCell, InputStatus}; +use ggrs::{Config, Frame, GameStateCell, GgrsRequest, InputStatus}; fn calculate_hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); From 1265cbc6a198319ceaaf3f415a854a894cf0a2b8 Mon Sep 17 00:00:00 2001 From: Georg Schuppe Date: Fri, 10 Nov 2023 09:04:15 +0100 Subject: [PATCH 6/8] doc: update GgrsEvent, GgrsRequest and GgrsError names in docstrings --- CHANGELOG.md | 8 ++++---- examples/ex_game/ex_game.rs | 2 +- src/error.rs | 4 ++-- src/lib.rs | 2 +- src/sessions/builder.rs | 8 ++++---- src/sessions/p2p_session.rs | 18 +++++++++--------- src/sessions/p2p_spectator_session.rs | 8 ++++---- src/sessions/sync_test_session.rs | 8 ++++---- src/sync_layer.rs | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79012e0..de1be76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,7 +94,7 @@ In this document, all remarkable changes are listed. Not mentioned are smaller c ## 0.4.2 -- users are now allowed to save `None` buffers for a `GGRSRequest::SaveRequest`. This allows users to keep their own state history and load/save more efficiently +- users are now allowed to save `None` buffers for a `GgrsRequest::SaveRequest`. This allows users to keep their own state history and load/save more efficiently - added `num_players()`, `input_size()` getters to all sessions ## 0.4.1 @@ -117,8 +117,8 @@ In this document, all remarkable changes are listed. Not mentioned are smaller c ## 0.3.0 -- `GGRSError::InvalidRequest` now has an added `info` field to explain the problem in more detail -- removed unused `GGRSError::GeneralFailure` +- `GgrsError::InvalidRequest` now has an added `info` field to explain the problem in more detail +- removed unused `GgrsError::GeneralFailure` - removed multiple methods in `SyncTestSession`, as they didn't fulfill any meaningful purpose - removed unused sequence number from message header, fixing related issues - fixed an issue where out-of-order packets would cause a crash @@ -152,4 +152,4 @@ In this document, all remarkable changes are listed. Not mentioned are smaller c ## 0.2.0 -- Reworked API: Instead of the user passing a GGRSInterface trait object, GGRS now returns a list of GGRSRequests for the user to fulfill +- Reworked API: Instead of the user passing a GGRSInterface trait object, GGRS now returns a list of GgrsRequests for the user to fulfill diff --git a/examples/ex_game/ex_game.rs b/examples/ex_game/ex_game.rs index d1ab074..fb2c733 100644 --- a/examples/ex_game/ex_game.rs +++ b/examples/ex_game/ex_game.rs @@ -51,7 +51,7 @@ fn fletcher16(data: &[u8]) -> u16 { (sum2 << 8) | sum1 } -// BoxGame will handle rendering, gamestate, inputs and GGRSRequests +// BoxGame will handle rendering, gamestate, inputs and GgrsRequests pub struct Game { num_players: usize, game_state: State, diff --git a/src/error.rs b/src/error.rs index f5b18d5..0ad9881 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,9 +4,9 @@ use std::fmt::Display; use crate::Frame; -/// This enum contains all error messages this library can return. Most API functions will generally return a [`Result<(),GGRSError>`]. +/// This enum contains all error messages this library can return. Most API functions will generally return a [`Result<(),GgrsError>`]. /// -/// [`Result<(),GGRSError>`]: std::result::Result +/// [`Result<(),GgrsError>`]: std::result::Result #[derive(Debug, Clone, PartialEq, Hash)] pub enum GgrsError { /// When the prediction threshold has been reached, we cannot accept more inputs from the local player. diff --git a/src/lib.rs b/src/lib.rs index 65f76c7..a83be8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,7 +143,7 @@ where /// The client will be disconnected in this amount of ms. disconnect_timeout: u128, }, - /// Sent only after a [`GGRSEvent::NetworkInterrupted`] event, if communication with that player has resumed. + /// Sent only after a [`GgrsEvent::NetworkInterrupted`] event, if communication with that player has resumed. NetworkResumed { /// The address of the endpoint. addr: T::Address, diff --git a/src/sessions/builder.rs b/src/sessions/builder.rs index 1f0b6d2..a3b5622 100644 --- a/src/sessions/builder.rs +++ b/src/sessions/builder.rs @@ -85,7 +85,7 @@ impl SessionBuilder { /// - Returns [`InvalidRequest`] if a player with that handle has been added before /// - Returns [`InvalidRequest`] if the handle is invalid for the given [`PlayerType`] /// - /// [`InvalidRequest`]: GGRSError::InvalidRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest /// [`num_players`]: Self#structfield.num_players pub fn add_player( mut self, @@ -132,7 +132,7 @@ impl SessionBuilder { /// # Errors /// - Returns [`InvalidRequest`] if the prediction window is 0. /// - /// [`InvalidRequest`]: GGRSError::InvalidRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest pub fn with_max_prediction_window(mut self, window: usize) -> Result { if window == 0 { return Err(GgrsError::InvalidRequest { @@ -187,7 +187,7 @@ impl SessionBuilder { /// # Errors /// - Returns [`InvalidRequest`] if the fps is 0 /// - /// [`InvalidRequest`]: GGRSError::InvalidRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest pub fn with_fps(mut self, fps: usize) -> Result { if fps == 0 { return Err(GgrsError::InvalidRequest { @@ -247,7 +247,7 @@ impl SessionBuilder { /// # Errors /// - Returns [`InvalidRequest`] if insufficient players have been registered. /// - /// [`InvalidRequest`]: GGRSError::InvalidRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest pub fn start_p2p_session( mut self, socket: impl NonBlockingSocket + 'static, diff --git a/src/sessions/p2p_session.rs b/src/sessions/p2p_session.rs index 7ea5c97..2be138d 100644 --- a/src/sessions/p2p_session.rs +++ b/src/sessions/p2p_session.rs @@ -141,7 +141,7 @@ where /// notes which inputs have already been sent to the spectators next_spectator_frame: Frame, - /// The soonest frame on which the session can send a [`GGRSEvent::WaitRecommendation`] again. + /// The soonest frame on which the session can send a [`GgrsEvent::WaitRecommendation`] again. next_recommended_sleep: Frame, /// How many frames we estimate we are ahead of every remote client frames_ahead: i32, @@ -220,7 +220,7 @@ impl P2PSession { /// - Returns [`InvalidRequest`] when the given handle does not refer to a local player. /// /// [`advance_frame()`]: Self#method.advance_frame - /// [`InvalidRequest`]: GGRSError::InvalidRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest pub fn add_local_input( &mut self, player_handle: PlayerHandle, @@ -243,16 +243,16 @@ impl P2PSession { } /// You should call this to notify GGRS that you are ready to advance your gamestate by a single frame. - /// Returns an order-sensitive [`Vec`]. You should fulfill all requests in the exact order they are provided. + /// Returns an order-sensitive [`Vec`]. You should fulfill all requests in the exact order they are provided. /// Failure to do so will cause panics later. /// /// # Errors /// - Returns [`InvalidRequest`] if the provided player handle refers to a remote player. /// - Returns [`NotSynchronized`] if the session is not yet ready to accept input. In this case, you either need to start the session or wait for synchronization between clients. /// - /// [`Vec`]: GGRSRequest - /// [`InvalidRequest`]: GGRSError::InvalidRequest - /// [`NotSynchronized`]: GGRSError::NotSynchronized + /// [`Vec`]: GgrsRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest + /// [`NotSynchronized`]: GgrsError::NotSynchronized pub fn advance_frame(&mut self) -> Result>, GgrsError> { // receive info from remote players, trigger events and send messages self.poll_remote_clients(); @@ -429,7 +429,7 @@ impl P2PSession { /// # Errors /// - Returns [`InvalidRequest`] if you try to disconnect a local player or the provided handle is invalid. /// - /// [`InvalidRequest`]: GGRSError::InvalidRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest pub fn disconnect_player(&mut self, player_handle: PlayerHandle) -> Result<(), GgrsError> { match self.player_reg.handles.get(&player_handle) { // the local player cannot be disconnected @@ -463,8 +463,8 @@ impl P2PSession { /// - Returns [`InvalidRequest`] if the handle not referring to a remote player or spectator. /// - Returns [`NotSynchronized`] if the session is not connected to other clients yet. /// - /// [`InvalidRequest`]: GGRSError::InvalidRequest - /// [`NotSynchronized`]: GGRSError::NotSynchronized + /// [`InvalidRequest`]: GgrsError::InvalidRequest + /// [`NotSynchronized`]: GgrsError::NotSynchronized pub fn network_stats(&self, player_handle: PlayerHandle) -> Result { match self.player_reg.handles.get(&player_handle) { Some(PlayerType::Remote(addr)) => self diff --git a/src/sessions/p2p_spectator_session.rs b/src/sessions/p2p_spectator_session.rs index 1c0f00c..df54032 100644 --- a/src/sessions/p2p_spectator_session.rs +++ b/src/sessions/p2p_spectator_session.rs @@ -87,7 +87,7 @@ impl SpectatorSession { /// # Errors /// - Returns [`NotSynchronized`] if the session is not connected to other clients yet. /// - /// [`NotSynchronized`]: GGRSError::NotSynchronized + /// [`NotSynchronized`]: GgrsError::NotSynchronized pub fn network_stats(&self) -> Result { self.host.network_stats() } @@ -98,14 +98,14 @@ impl SpectatorSession { } /// You should call this to notify GGRS that you are ready to advance your gamestate by a single frame. - /// Returns an order-sensitive [`Vec`]. You should fulfill all requests in the exact order they are provided. + /// Returns an order-sensitive [`Vec`]. You should fulfill all requests in the exact order they are provided. /// Failure to do so will cause panics later. /// # Errors /// - Returns [`NotSynchronized`] if the session is not yet ready to accept input. /// In this case, you either need to start the session or wait for synchronization between clients. /// - /// [`Vec`]: GGRSRequest - /// [`NotSynchronized`]: GGRSError::NotSynchronized + /// [`Vec`]: GgrsRequest + /// [`NotSynchronized`]: GgrsError::NotSynchronized pub fn advance_frame(&mut self) -> Result>, GgrsError> { // receive info from host, trigger events and send messages self.poll_remote_clients(); diff --git a/src/sessions/sync_test_session.rs b/src/sessions/sync_test_session.rs index 02d0f34..b9deaea 100644 --- a/src/sessions/sync_test_session.rs +++ b/src/sessions/sync_test_session.rs @@ -57,7 +57,7 @@ impl SyncTestSession { /// - Returns [`InvalidRequest`] when the given handle is not valid (i.e. not between 0 and num_players). /// /// [`advance_frame()`]: Self#method.advance_frame - /// [`InvalidRequest`]: GGRSError::InvalidRequest + /// [`InvalidRequest`]: GgrsError::InvalidRequest pub fn add_local_input( &mut self, player_handle: PlayerHandle, @@ -74,14 +74,14 @@ impl SyncTestSession { } /// In a sync test, this will advance the state by a single frame and afterwards rollback `check_distance` amount of frames, - /// resimulate and compare checksums with the original states. Returns an order-sensitive [`Vec`]. + /// resimulate and compare checksums with the original states. Returns an order-sensitive [`Vec`]. /// You should fulfill all requests in the exact order they are provided. Failure to do so will cause panics later. /// /// # Errors /// - Returns [`MismatchedChecksum`] if checksums don't match after resimulation. /// - /// [`Vec`]: GGRSRequest - /// [`MismatchedChecksum`]: GGRSError::MismatchedChecksum + /// [`Vec`]: GgrsRequest + /// [`MismatchedChecksum`]: GgrsError::MismatchedChecksum pub fn advance_frame(&mut self) -> Result>, GgrsError> { let mut requests = Vec::new(); diff --git a/src/sync_layer.rs b/src/sync_layer.rs index 3e1582e..58c514f 100644 --- a/src/sync_layer.rs +++ b/src/sync_layer.rs @@ -8,7 +8,7 @@ use crate::input_queue::InputQueue; use crate::network::messages::ConnectionStatus; use crate::{Config, Frame, GgrsRequest, InputStatus, PlayerHandle, NULL_FRAME}; -/// An [`Arc`] that you can [`save()`]/[`load()`] a `T` to/from. These will be handed to the user as part of a [`GGRSRequest`]. +/// An [`Arc`] that you can [`save()`]/[`load()`] a `T` to/from. These will be handed to the user as part of a [`GgrsRequest`]. /// /// [`save()`]: GameStateCell#method.save /// [`load()`]: GameStateCell#method.load From 2dfc0bb1b4e4c0812816f0f4951aa43a40581e1c Mon Sep 17 00:00:00 2001 From: Georg Friedrich Schuppe Date: Fri, 10 Nov 2023 00:24:28 -0800 Subject: [PATCH 7/8] doc: missing whitespace Co-authored-by: Johan Klokkhammer Helsing --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 0ad9881..643f33e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -6,7 +6,7 @@ use crate::Frame; /// This enum contains all error messages this library can return. Most API functions will generally return a [`Result<(),GgrsError>`]. /// -/// [`Result<(),GgrsError>`]: std::result::Result +/// [`Result<(), GgrsError>`]: std::result::Result #[derive(Debug, Clone, PartialEq, Hash)] pub enum GgrsError { /// When the prediction threshold has been reached, we cannot accept more inputs from the local player. From d3f9417dbdb826eef3713caf44e4a9a73aeaaea9 Mon Sep 17 00:00:00 2001 From: Georg Friedrich Schuppe Date: Fri, 10 Nov 2023 00:24:36 -0800 Subject: [PATCH 8/8] doc: missing whitespace Co-authored-by: Johan Klokkhammer Helsing --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 643f33e..6c1726a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,7 +4,7 @@ use std::fmt::Display; use crate::Frame; -/// This enum contains all error messages this library can return. Most API functions will generally return a [`Result<(),GgrsError>`]. +/// This enum contains all error messages this library can return. Most API functions will generally return a [`Result<(), GgrsError>`]. /// /// [`Result<(), GgrsError>`]: std::result::Result #[derive(Debug, Clone, PartialEq, Hash)]