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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
use crate::*; #[cfg(not(target_arch = "wasm32"))] mod load_native; #[cfg(target_arch = "wasm32")] mod load_web; mod save; #[derive(Serialize)] struct State<G: Game, R: Renderer<G>> { game: G, extra_data: R::ExtraData, } impl<G: Game, R: Renderer<G>> State<G, R> { fn diff(&self, other: &Self) -> (G::Delta, <R::ExtraData as Diff>::Delta) { ( Diff::diff(&self.game, &other.game), Diff::diff(&self.extra_data, &other.extra_data), ) } fn update(&mut self, delta: &(G::Delta, <R::ExtraData as Diff>::Delta)) { Diff::update(&mut self.game, &delta.0); Diff::update(&mut self.extra_data, &delta.1); } } impl<G: Game, R: Renderer<G>> Clone for State<G, R> { fn clone(&self) -> Self { Self { game: self.game.clone(), extra_data: self.extra_data.clone(), } } } enum Entry<G: Game, R: Renderer<G>> { Full(State<G, R>), Delta((G::Delta, <R::ExtraData as Diff>::Delta)), } struct SharedState<G: Game, R: Renderer<G>> { entries: Vec<Entry<G, R>>, custom_data: Vec<Arc<HashMap<usize, Vec<G::CustomData>>>>, events: Vec<Vec<G::Event>>, last_state: State<G, R>, last_custom_data: HashMap<usize, Vec<G::CustomData>>, total_latest_delta_size: u64, } impl<G: Game, R: Renderer<G>> SharedState<G, R> { fn push(&mut self, game: &G, events: Vec<G::Event>) { let prev_state = self.last_state.clone(); self.last_state.game = game.clone(); RendererExtraData::update(&mut self.last_state.extra_data, &events, game); let delta = prev_state.diff(&self.last_state); self.total_latest_delta_size += bincode::serialized_size(&delta).expect("Failed to get delta serialized size"); if self.total_latest_delta_size > bincode::serialized_size(&self.last_state) .expect("Failed to get last state serialized size") { self.entries.push(Entry::Full(self.last_state.clone())); self.total_latest_delta_size = 0; } else { self.entries.push(Entry::Delta(delta)); } self.events.push(events); self.custom_data.push(Arc::new(mem::replace( &mut self.last_custom_data, HashMap::new(), ))); } fn push_custom_data(&mut self, player_index: usize, custom_data: G::CustomData) { if !self.last_custom_data.contains_key(&player_index) { self.last_custom_data.insert(player_index, Vec::new()); } self.last_custom_data .get_mut(&player_index) .unwrap() .push(custom_data); } fn len(&self) -> usize { self.entries.len() } } pub struct History<G: Game, R: Renderer<G>> { shared_state: Arc<Mutex<SharedState<G, R>>>, current_tick_timer: Timer, current_tick: usize, current_state: State<G, R>, current_custom_data: Arc<HashMap<usize, Vec<G::CustomData>>>, } impl<G: Game, R: Renderer<G>> History<G, R> { pub fn new(initial_game_state: &G) -> Self { let initial_extra_data = R::ExtraData::new(initial_game_state); let initial_state = State { game: initial_game_state.clone(), extra_data: initial_extra_data, }; Self { shared_state: Arc::new(Mutex::new(SharedState { entries: vec![Entry::Full(initial_state.clone())], events: Vec::new(), last_state: initial_state.clone(), custom_data: Vec::new(), last_custom_data: HashMap::new(), total_latest_delta_size: 0, })), current_state: initial_state.clone(), current_custom_data: Arc::new(HashMap::new()), current_tick_timer: Timer::new(), current_tick: 0, } } pub fn current_state(&self) -> (&G, &R::ExtraData, &HashMap<usize, Vec<G::CustomData>>) { ( &self.current_state.game, &self.current_state.extra_data, &self.current_custom_data, ) } pub fn len(&self) -> usize { self.shared_state.lock().unwrap().len() } pub fn go_to( &mut self, tick: usize, collect_events: bool, ) -> Box<dyn Iterator<Item = G::Event>> { let shared_state = self.shared_state.lock().unwrap(); let tick = tick.min(shared_state.len() - 1); let mut prev_tick = self.current_tick; let mut events = Vec::new(); if collect_events && tick > prev_tick { for tick in prev_tick..tick { events.extend(shared_state.events[tick].iter().cloned()); } } let (last_full_tick, last_full_state) = shared_state.entries[..=tick] .iter() .enumerate() .rev() .find_map(|(tick, entry)| match entry { Entry::Full(game) => Some((tick, game)), Entry::Delta(_) => None, }) .expect("Didn't find full game entry in history"); if tick < prev_tick || prev_tick < last_full_tick { self.current_state = last_full_state.clone(); prev_tick = last_full_tick; } if tick > prev_tick { for entry in &shared_state.entries[prev_tick + 1..=tick] { match entry { Entry::Full(state) => self.current_state = state.clone(), Entry::Delta(delta) => self.current_state.update(delta), } } } if tick != self.current_tick { self.current_tick_timer = Timer::new(); } if let Some(data) = shared_state.custom_data.get(tick) { self.current_custom_data = data.clone(); } else { if tick > 0 && self.current_tick_timer.elapsed() < 0.5 { self.current_custom_data = shared_state.custom_data[tick - 1].clone(); } else { self.current_custom_data = Arc::new(shared_state.last_custom_data.clone()); } } self.current_tick = tick; Box::new(events.into_iter()) } pub fn tick_handler(&self) -> impl FnMut(&G, Vec<G::Event>) + Send + 'static { let shared_state = self.shared_state.clone(); move |game: &G, events: Vec<G::Event>| { shared_state.lock().unwrap().push(game, events); } } pub fn custom_data_handler(&self) -> impl Fn(usize, G::CustomData) + Send + 'static { let shared_state = self.shared_state.clone(); move |player_index, custom_data| { shared_state .lock() .unwrap() .push_custom_data(player_index, custom_data); } } }