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 }