library

Online co-op book organization video game
git clone https://git.bradleygannon.com/library.git
Log | Files | Refs

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 }