library

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

run.rs (6296B)


      1 use std::{net::SocketAddr, sync::mpsc::channel, thread};
      2 
      3 use crate::{
      4     game::{
      5         CONFY_APP_NAME, CONFY_CONFIG_NAME, ClientState, ViewMode, handle_drop_book_input,
      6         handle_movement_input, handle_pick_up_book_input,
      7     },
      8     net::handle_connection,
      9     render::{follow_local_player, render_game},
     10 };
     11 
     12 use common::game::{Action, Response};
     13 use macroquad::{
     14     prelude::*,
     15     ui::{
     16         hash, root_ui,
     17         widgets::{Button, InputText, Label},
     18     },
     19 };
     20 
     21 impl ClientState {
     22     pub(crate) fn run_menu_frame(&mut self) {
     23         clear_background(MAGENTA);
     24         const ELEMENT_SIZE: Vec2 = Vec2::new(420., 24.);
     25         const NUM_ELEMENTS: usize = 4;
     26         const MENU_SIZE: Vec2 = Vec2::new(ELEMENT_SIZE.x, ELEMENT_SIZE.y * NUM_ELEMENTS as f32);
     27         const ELEMENT_PITCH: Vec2 = Vec2::new(0., ELEMENT_SIZE.y);
     28         let screen_size = vec2(screen_width(), screen_height());
     29         let menu_top_left = screen_size / 2. - MENU_SIZE / 2.;
     30         let mut ui = root_ui();
     31         let name_input_token = hash!();
     32         InputText::new(name_input_token)
     33             .label("name")
     34             .position(menu_top_left)
     35             .size(ELEMENT_SIZE)
     36             .margin(Vec2::ZERO)
     37             .ui(&mut ui, &mut self.config.player_name);
     38         InputText::new(hash!())
     39             .label("server")
     40             .position(menu_top_left)
     41             .size(ELEMENT_SIZE)
     42             .margin(Vec2::ZERO)
     43             .ui(&mut ui, &mut self.config.server);
     44         let connect_button_clicked = Button::new("connect")
     45             .position(menu_top_left + ELEMENT_PITCH * 2.)
     46             .size(ELEMENT_SIZE)
     47             .ui(&mut ui);
     48         let addr = if connect_button_clicked || is_key_pressed(KeyCode::Enter) {
     49             if let Ok(addr) = self.config.server.parse::<SocketAddr>() {
     50                 Some(addr)
     51             } else if self.config.player_name.is_empty() {
     52                 self.menu_error = "enter your name pls".to_string();
     53                 None
     54             } else {
     55                 self.menu_error = "invalid server :-\\".to_string();
     56                 None
     57             }
     58         } else {
     59             None
     60         };
     61         Label::new(self.menu_error.as_str())
     62             .position(menu_top_left + ELEMENT_PITCH * 3.)
     63             .size(ELEMENT_SIZE)
     64             .ui(&mut ui);
     65         if self.first_frame {
     66             ui.set_input_focus(name_input_token);
     67             self.first_frame = false;
     68         }
     69         if let Some(addr) = addr {
     70             let _ = confy::store(CONFY_APP_NAME, Some(CONFY_CONFIG_NAME), self.config.clone());
     71             let (client_to_server_tx, client_to_server_rx) = channel();
     72             let (server_to_client_tx, server_to_client_rx) = channel();
     73             thread::spawn(move || {
     74                 handle_connection(addr, server_to_client_tx, client_to_server_rx)
     75             });
     76             self.tx = Some(client_to_server_tx);
     77             self.rx = Some(server_to_client_rx);
     78             self.mode = ViewMode::Game;
     79         }
     80     }
     81     pub(crate) fn run_game_frame(&mut self) {
     82         // Update frame timer so we move the player at the right speed
     83         self.tick();
     84 
     85         // Process any new responses from the server
     86         let mut response_count: u8 = 0;
     87         let mut latest_sequence_number = 0;
     88         if let Some(ref rx) = self.rx {
     89             for response in rx.try_iter().collect::<Vec<Response>>() {
     90                 response_count = response_count.saturating_add(1);
     91                 // If this is the first response that we're processing during this tick,
     92                 // then we need to copy the current game state so we can interpolate against
     93                 // it below
     94                 if response_count == 1 {
     95                     self.advance_game_state();
     96                 }
     97                 self.handle_response(&response);
     98                 latest_sequence_number = latest_sequence_number.max(response.sequence_number());
     99             }
    100         }
    101 
    102         // If there were any server responses, then do server reconciliation and client
    103         // prediction
    104         if response_count > 0 {
    105             self.reconcile(latest_sequence_number);
    106             self.predict();
    107         }
    108 
    109         if let Some(id) = self.local_player_id
    110             && let Some(local_player) = self.game.get_player(&id).cloned()
    111         {
    112             // Collect and send actions based on user input this frame
    113             let mut new_actions = [None, None, None];
    114 
    115             new_actions[0] = handle_movement_input(&local_player, &self.dt);
    116             new_actions[1] = handle_pick_up_book_input(&local_player, self.game.floor_books());
    117             new_actions[2] = handle_drop_book_input(&local_player, self.selected_book);
    118 
    119             for new_action in new_actions.iter().filter_map(|na| na.clone()) {
    120                 let action = Action::new(self.sequence_number, id, new_action);
    121                 self.game.apply_action(&action);
    122                 self.send_action(&action);
    123             }
    124 
    125             // Center local player on the screen
    126             follow_local_player(&mut self.camera, &self.game, &id);
    127 
    128             // Entity interpolation
    129             let interpolated_game = self.interpolate();
    130 
    131             // Toggle debug view if requested
    132             if is_key_pressed(KeyCode::F3) {
    133                 self.debug_view = !self.debug_view;
    134             }
    135 
    136             // Set selected book
    137             let books_count = local_player.books().len();
    138             if self.selected_book > books_count.saturating_sub(1) {
    139                 self.selected_book = books_count.saturating_sub(1);
    140             }
    141             if is_key_pressed(KeyCode::Key1) {
    142                 self.selected_book = 0;
    143             } else if is_key_pressed(KeyCode::Key2) {
    144                 self.selected_book = 1;
    145             } else if is_key_pressed(KeyCode::Key3) {
    146                 self.selected_book = 2;
    147             } else if is_key_pressed(KeyCode::Key4) {
    148                 self.selected_book = 3;
    149             } else if is_key_pressed(KeyCode::Key5) {
    150                 self.selected_book = 4;
    151             }
    152 
    153             // Draw the frame
    154             render_game(
    155                 &self.camera,
    156                 &interpolated_game,
    157                 self.debug_view,
    158                 &id,
    159                 self.selected_book,
    160             );
    161         }
    162     }
    163 }