diff --git a/src/bin/macroquad_client.rs b/src/bin/macroquad_client.rs index 07762a1..3c5d61a 100644 --- a/src/bin/macroquad_client.rs +++ b/src/bin/macroquad_client.rs @@ -1,7 +1,8 @@ use checkers::ui::{ macroquad::{ - difficulty_selection::draw_dificulty_selection, main_menu::draw_main_menu, - mode_selection::draw_mode_selection, server_selection::draw_server_selection, + difficulty_selection::draw_dificulty_selection, game::GameClient, + main_menu::draw_main_menu, mode_selection::draw_mode_selection, + server_selection::draw_server_selection, }, state::{GameContext, GuiState}, }; @@ -40,9 +41,16 @@ pub async fn get_general_style() -> Skin { .font_size(32) .build(); + let checkbox_style = root_ui() + .style_builder() + .color(BLACK) + .text_color(BLACK) + .build(); + Skin { label_style, button_style, + checkbox_style, ..root_ui().default_skin() } } @@ -71,7 +79,7 @@ pub async fn main() { }, ); - match &state { + match &mut state { GuiState::MainMenu => { draw_main_menu(&mut state).await; } @@ -95,7 +103,13 @@ pub async fn main() { Ok(client) => { if let Some(client) = client { draw_text("Connected!", 0.0, 0.0, 64.0, BLACK); - state = GuiState::Game(client); + let client = GameClient::new(client, &context); + if let Some(client) = client { + state = GuiState::Game(client); + } else { + // ugly ass code + draw_text("Could not connect!", 0.0, 0.0, 64.0, BLACK); + } } else { draw_text("Could not connect!", 0.0, 0.0, 64.0, BLACK); } @@ -111,7 +125,8 @@ pub async fn main() { } GuiState::Game(client) => { - draw_text("Gamer time", 100.0, 100.0, 64.0, BLACK); + client.update(); + client.draw(); } GuiState::Exit => { diff --git a/src/network/server.rs b/src/network/server.rs index bf6f8dd..f553aaa 100644 --- a/src/network/server.rs +++ b/src/network/server.rs @@ -30,8 +30,9 @@ const MAX_PLAYABLE_CONNECTIONS: usize = 2; // DON'T EVER CHANGE THIS AS GAME OF // There will be a spectator mode, hence the name __PLAYABLE__ connection. You will be able to have // more connections, but they won't be able to play -#[derive(PartialEq)] -enum ServerStage { +#[derive(Debug, PartialEq, Default)] +pub enum ServerStage { + #[default] Lobby, Game, End, diff --git a/src/ui/macroquad/difficulty_selection.rs b/src/ui/macroquad/difficulty_selection.rs index 8e32f5c..5107df1 100644 --- a/src/ui/macroquad/difficulty_selection.rs +++ b/src/ui/macroquad/difficulty_selection.rs @@ -35,17 +35,17 @@ pub async fn draw_dificulty_selection(state: &mut GuiState, context: &mut GameCo if menu_builder.button(ui, "Easy") { context.difficulty = crate::super_advanced_ai::BotDificulty::Easy; - *state = GuiState::Connecting(connect_to_server(context.clone())); + *state = GuiState::Connecting(connect_to_server()); } if menu_builder.button(ui, "Medium") { context.difficulty = crate::super_advanced_ai::BotDificulty::Normal; - *state = GuiState::Connecting(connect_to_server(context.clone())); + *state = GuiState::Connecting(connect_to_server()); } if menu_builder.button(ui, "Hard") { context.difficulty = crate::super_advanced_ai::BotDificulty::Hard; - *state = GuiState::Connecting(connect_to_server(context.clone())); + *state = GuiState::Connecting(connect_to_server()); } if menu_builder.button(ui, "Go back") { diff --git a/src/ui/macroquad/game.rs b/src/ui/macroquad/game.rs index 2862c78..dacd09d 100644 --- a/src/ui/macroquad/game.rs +++ b/src/ui/macroquad/game.rs @@ -1,8 +1,19 @@ -use tokio::sync::mpsc::Receiver; +use log::{error, info}; +use macroquad::{ + color::GRAY, + math::{Rect, Vec2, vec2}, + shapes::draw_rectangle, + ui::{Ui, hash, root_ui, widgets::Checkbox}, + window::{screen_height, screen_width}, +}; +use tokio::sync::mpsc::{Receiver, error::TryRecvError::Disconnected}; use crate::{ logic::board::board_view::BoardView, - network::{client::Client, message::ServerMessage}, + network::{ + client::Client, message::ServerMessage, network_identity::NetworkIdentity, + server::ServerStage, + }, ui::state::GameContext, }; @@ -10,29 +21,182 @@ pub struct GameClient { client: Client, update_receiver: Receiver, + identity: Option, + board: BoardView, player_name: String, enemy_name: String, // TODO! Server should give this info to us (it doesn't rn) + + game_state: ServerStage, + + game_area: Rect, + game_padding: f32, + + lobby: Lobby, + + chat_area: Rect, +} + +#[derive(Default)] +struct Lobby { + is_ready: bool, + checkbox_pos: Vec2, + checkbox_size: Vec2, } impl GameClient { - pub async fn new(context: &GameContext) -> Option { - let Some(mut client) = Client::new(None).await else { - return None; - }; - + pub fn new(mut client: Client, context: &GameContext) -> Option { let Some(update_receiver) = client.get_update_receiver() else { return None; }; let board = BoardView::default(); + let game_stage = ServerStage::default(); + let mut lobby = Lobby::default(); + lobby.checkbox_size = vec2(32.0, 16.0); + + let game_area = Rect { + x: 0.0, + y: 0.0, + w: screen_width() * 0.8, + h: screen_height(), + }; + let game_padding = 25.0; + + let chat_area = Rect { + x: game_area.w, + y: 0.0, + w: screen_width() * 0.2, + h: screen_height(), + }; + Some(Self { client, update_receiver, + identity: None, + board, + lobby, + player_name: "Morbius".to_string(), enemy_name: "Milo".to_string(), + + game_state: game_stage, + + game_area, + game_padding, + + chat_area, }) } + + pub fn draw(&mut self) { + match self.game_state { + ServerStage::Lobby => { + self.draw_lobby(); + } + + ServerStage::Game => { + self.draw_game(); + } + + ServerStage::End => { + self.draw_summary_screen(); + } + } + //self.draw_chat(); // TODO! uncomment this + } + + fn draw_lobby(&mut self) { + let lobby = &self.lobby; + + draw_rectangle( + lobby.checkbox_pos.x, + lobby.checkbox_pos.y, + lobby.checkbox_size.x * 10.0, + lobby.checkbox_size.y * 10.0, + GRAY, + ); + + Checkbox::new(hash!()) + .pos(self.lobby.checkbox_pos) + .label("Ready") + .size(self.lobby.checkbox_size) + .ui(&mut root_ui(), &mut self.lobby.is_ready); + } + + fn draw_game(&self) { + todo!(); + } + + fn draw_summary_screen(&self) { + todo!(); + } + + fn draw_chat(&self) { + todo!(); + } + + /* === UPDATING STUFF ==== */ + + pub fn update(&mut self) { + self.update_rects(); + self.update_network(); + + match self.game_state { + ServerStage::Lobby => self.update_lobby(), + ServerStage::Game => todo!(), + ServerStage::End => todo!(), + } + } + + fn update_network(&mut self) { + match self.update_receiver.try_recv() { + Ok(msg) => match msg { + ServerMessage::GameStart { identity } => { + info!("We go identity!"); + self.identity = Some(identity); + } + + ServerMessage::AvailableCaptures { captures } => todo!(), + ServerMessage::AvailableMoves { moves } => todo!(), + ServerMessage::BroadcastBoardState { board } => todo!(), + ServerMessage::BroadcastCurrentTurn { active_player } => todo!(), + ServerMessage::BroadCastTextMessage { sender, content } => todo!(), + ServerMessage::GameEnd { result } => todo!(), + + _ => {} // ignore things that network client handled by itself + }, + + Err(Disconnected) => { + error!("Connection broken!!!!"); + } + + Err(_) => {} // No messages - nothing wrong (why is this even an error) + } + } + + fn update_lobby(&mut self) { + self.lobby.checkbox_pos = vec2( + self.game_area.w / 2.0 - self.lobby.checkbox_size.x / 2.0, + self.game_area.h / 2.0, + ); + } + + fn update_rects(&mut self) { + self.game_area = Rect { + x: 0.0, + y: 0.0, + w: screen_width() * 0.8, + h: screen_height(), + }; + + self.chat_area = Rect { + x: self.game_area.w, + y: 0.0, + w: screen_width() * 0.2, + h: screen_height(), + }; + } } diff --git a/src/ui/macroquad/server_selection.rs b/src/ui/macroquad/server_selection.rs index 605b451..c7e8491 100644 --- a/src/ui/macroquad/server_selection.rs +++ b/src/ui/macroquad/server_selection.rs @@ -41,7 +41,7 @@ pub async fn draw_server_selection(state: &mut GuiState, context: &mut GameConte if menu_builder.button(ui, "Connect") { context.gamemode = crate::ui::state::GameMode::Multiplayer { is_hosting: false }; - *state = GuiState::Connecting(connect_to_server(context.clone())); + *state = GuiState::Connecting(connect_to_server()); // TODO Validate url before connecting or something like that } diff --git a/src/ui/state.rs b/src/ui/state.rs index a782c16..2502a3e 100644 --- a/src/ui/state.rs +++ b/src/ui/state.rs @@ -1,6 +1,8 @@ use std::sync::mpsc::{self, Receiver}; -use crate::{super_advanced_ai::BotDificulty, ui::macroquad::game::GameClient}; +use crate::{ + network::client::Client, super_advanced_ai::BotDificulty, ui::macroquad::game::GameClient, +}; #[derive(Default)] pub enum GuiState { @@ -11,7 +13,7 @@ pub enum GuiState { DificultySelection, ServerSelection, - Connecting(Receiver>), + Connecting(Receiver>), Settings, Game(GameClient), @@ -35,14 +37,13 @@ pub struct GameContext { } // TODO! Move this -pub fn connect_to_server(context: GameContext) -> Receiver> { - let (tx, rc) = mpsc::channel::>(); - let context_clone = context.clone(); +pub fn connect_to_server() -> Receiver> { + let (tx, rc) = mpsc::channel::>(); let _ = std::thread::spawn(move || { let rt = tokio::runtime::Runtime::new().unwrap(); - let client_option = rt.block_on(async { GameClient::new(&context_clone).await }); + let client_option = rt.block_on(async { Client::new(None).await }); let _ = tx.send(client_option);