state.rs (2835B)
1 use std::time::{Instant, SystemTime}; 2 3 use common::game::{Action, ActionKind, Response, ResponseKind, state::GameState}; 4 use structdiff::StructDiff; 5 6 use crate::ClientState; 7 8 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] 9 pub(crate) enum ViewMode { 10 #[default] 11 Menu, 12 Game, 13 } 14 15 impl ClientState { 16 pub(crate) fn view_mode(&self) -> ViewMode { 17 self.mode 18 } 19 pub(crate) fn tick(&mut self) { 20 self.t0 = self.t1; 21 self.t1 = Instant::now(); 22 self.dt = self.t1.duration_since(self.t0); 23 } 24 pub(crate) fn advance_game_state(&mut self) { 25 self.old_game = self.game.clone(); 26 } 27 pub(crate) fn send_action(&mut self, action: &Action) { 28 if let Some(ref mut tx) = self.tx 29 && tx.send(action.clone()).is_err() 30 { 31 return; 32 } 33 self.unresponded_actions.push_back(action.clone()); 34 self.sequence_number = self.sequence_number.wrapping_add(1); 35 } 36 pub(crate) fn handle_response(&mut self, response: &Response) { 37 match response.kind() { 38 ResponseKind::SetId { id } => { 39 let action = Action::new( 40 self.sequence_number, 41 id, 42 ActionKind::Join { 43 name: self.config.player_name().clone(), 44 }, 45 ); 46 self.send_action(&action); 47 self.local_player_id = Some(id); 48 } 49 ResponseKind::UpdateGameState { diffs } => { 50 self.game.set_timestamp(response.timestamp()); 51 self.game.apply_mut(diffs); 52 } 53 ResponseKind::ReplaceGameState { new_game_state } => self.game = new_game_state, 54 }; 55 } 56 pub(crate) fn reconcile(&mut self, latest_sequence_number: u32) { 57 // Server reconciliation: drop any unresponded actions whose sequence numbers are less than 58 // the number provided 59 if let Some(new_front_index) = self 60 .unresponded_actions 61 .iter() 62 .position(|ua: &Action| ua.sequence_number() >= latest_sequence_number) 63 { 64 for _ in 0..=new_front_index { 65 self.unresponded_actions.pop_front(); 66 } 67 } 68 } 69 pub(crate) fn predict(&mut self) { 70 // Client prediction: apply all unresponded actions to the game state 71 self.interpolation_basis = SystemTime::now(); 72 for unresponded_action in self.unresponded_actions.iter() { 73 self.game.apply_action(unresponded_action); 74 } 75 } 76 pub(crate) fn interpolate(&self) -> GameState { 77 GameState::interpolate( 78 &self.old_game, 79 &self.game, 80 self.interpolation_basis, 81 self.local_player_id, 82 ) 83 } 84 }