use std::time::Duration;
use thiserror::Error;
mod backend;
pub mod command;
mod input;
mod protocol;
mod sync;
mod time_sync;
pub use backend::*;
pub use backroll_transport as transport;
pub use input::GameInput;
pub const MAX_PLAYERS: usize = 8;
const MAX_ROLLBACK_FRAMES: usize = 120;
type Frame = i32;
const NULL_FRAME: Frame = -1;
fn is_null(frame: Frame) -> bool {
frame < 0
}
#[derive(Copy, Clone, Debug)]
pub struct PlayerHandle(pub usize);
#[derive(Clone)]
pub enum Player {
Local,
Remote(transport::Peer),
}
impl Player {
pub(crate) fn is_local(&self) -> bool {
matches!(self, Self::Local)
}
}
impl Default for Player {
fn default() -> Self {
Self::Local
}
}
pub trait Config: 'static {
type Input: PartialEq + bytemuck::Pod + bytemuck::Zeroable + Send + Sync;
type State: Clone + Send + Sync + 'static;
}
#[derive(Clone, Debug, Error)]
pub enum BackrollError {
#[error("Multiple players ")]
MultipleLocalPlayers,
#[error("Action cannot be taken while in rollback.")]
InRollback,
#[error("The session has not been synchronized yet.")]
NotSynchronized,
#[error("The simulation has reached the prediction barrier.")]
ReachedPredictionBarrier,
#[error("Invalid player handle: {:?}", .0)]
InvalidPlayer(PlayerHandle),
#[error("Player already disconnected: {:?}", .0)]
PlayerDisconnected(PlayerHandle),
}
pub type BackrollResult<T> = Result<T, BackrollError>;
#[derive(Clone, Debug, Default)]
pub struct NetworkStats {
pub ping: Duration,
pub send_queue_len: usize,
pub recv_queue_len: usize,
pub kbps_sent: u32,
pub local_frames_behind: Frame,
pub remote_frames_behind: Frame,
}
#[derive(Clone, Debug)]
pub enum Event {
Connected(PlayerHandle),
Synchronizing {
player: PlayerHandle,
count: u8,
total: u8,
},
Synchronized(PlayerHandle),
Running,
Disconnected(PlayerHandle),
TimeSync { frames_ahead: u8 },
ConnectionInterrupted {
player: PlayerHandle,
disconnect_timeout: Duration,
},
ConnectionResumed(PlayerHandle),
}