1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::time::Duration;
mod protocol;
mod backend;
mod input;
mod sync;
mod time_sync;
pub use backend::*;
pub use backroll_transport as transport;
pub use input::GameInput;
pub(crate) use bevy_tasks::TaskPool;
pub const MAX_PLAYERS_PER_MATCH: 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 BackrollPlayerHandle(pub usize);
pub enum BackrollPlayer {
Local,
Spectator(transport::Peer),
Remote(transport::Peer),
}
impl BackrollPlayer {
pub(crate) fn is_local(&self) -> bool {
if let Self::Local = self {
true
} else {
false
}
}
}
pub trait BackrollConfig: 'static {
type Input: Default + Eq + Clone + bytemuck::Pod + Send + Sync;
type State: 'static + Send + Sync;
const MAX_PLAYERS_PER_MATCH: usize;
const RECOMMENDATION_INTERVAL: u32;
}
pub trait SessionCallbacks<T>
where
T: BackrollConfig,
{
fn save_state(&mut self) -> (T::State, Option<u64>);
fn load_state(&mut self, state: &T::State);
fn advance_frame(&mut self, input: GameInput<T::Input>);
fn handle_event(&mut self, event: BackrollEvent);
}
pub enum BackrollError {
MultipleLocalPlayers,
InRollback,
NotSynchronized,
ReachedPredictionBarrier,
InvalidPlayer(BackrollPlayerHandle),
PlayerDisconnected(BackrollPlayerHandle),
}
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,
}
pub enum BackrollEvent {
Connected(BackrollPlayerHandle),
Synchronizing {
player: BackrollPlayerHandle,
count: u8,
total: u8,
},
Synchronized(BackrollPlayerHandle),
Running,
Disconnected(BackrollPlayerHandle),
TimeSync { frames_ahead: u8 },
ConnectionInterrupted {
player: BackrollPlayerHandle,
disconnect_timeout: Duration,
},
ConnectionResumed(BackrollPlayerHandle),
}