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