diff --git a/client/src/components/game.rs b/client/src/components/game.rs index 50514d9..158b416 100644 --- a/client/src/components/game.rs +++ b/client/src/components/game.rs @@ -11,7 +11,7 @@ pub fn Game() -> impl IntoView { let (game_host, set_game_host) = create_signal("".to_string()); let (game_players, set_game_players) = create_signal(vec![]); let (game_czar, set_game_czar) = create_signal("".to_string()); - let (game_black, set_game_black) = create_signal("".to_string()); + let (game_black, set_game_black) = create_signal(("".to_string(), 0u8)); let (game_white, set_game_white) = create_signal(vec![]); create_effect(move |_| { @@ -28,12 +28,12 @@ pub fn Game() -> impl IntoView { view! {

Game

-

Name: {move || game_name}

-

Host: {move || game_host}

-

Players: {move || game_players}

-

Czar: {move || game_czar}

-

Black Card: {move || game_black}

-

Your Cards: {move || game_white}

+

Name: {move || game_name()}

+

Host: {move || game_host()}

+

Players: {move || game_players()}

+

Czar: {move || game_czar()}

+

Black Card: {move || game_black().0} Pick: {move || game_black().1}

+

Your Cards: {move || game_white()}

} } diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 02a2fc8..3b03501 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -7,7 +7,7 @@ pub struct GameMeta { pub host: String, pub players: Vec, pub czar: String, - pub black: String, + pub black: (String, u8), pub white: Vec, } diff --git a/server/src/game_handler.rs b/server/src/game_handler.rs index 48ef034..0012fed 100644 --- a/server/src/game_handler.rs +++ b/server/src/game_handler.rs @@ -1,87 +1,171 @@ use crate::user_handler::*; use crate::AppState; use crate::User; -use anyhow::Result; +use anyhow::{Context, Result}; use lib::*; use rand::prelude::IteratorRandom; use rand::thread_rng; use serde::Deserialize; use std::{ collections::HashMap, + fs::read_to_string, net::SocketAddr, sync::{Arc, RwLock}, }; use uuid::Uuid; -// This file is disgusting, don't look at it +/// Parse json for card data +pub fn load_cards_from_json(path: &str) -> Result<(CardPacks, CardPacksMeta)> { + // TODO: Repack these cards so every card is stored once and pointers are passed around instead of + // cloning stuff + let data: String = + read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?; + let jayson: Vec = serde_json::from_str(&data) + .with_context(|| format!("The contents of \"{path}\" is not valid JSON."))?; + + let mut official: HashMap = HashMap::new(); + let mut unofficial: HashMap = HashMap::new(); + + let mut official_meta: Vec = vec![]; + let mut unofficial_meta: Vec = vec![]; + + for set in jayson { + let mut num_white = 0; + let mut num_black = 0; + + let mut newset = CardSet { + white: Option::None, + black: Option::None, + }; + + // No safe default for this so make it an Option + let mut pack: Option = Option::None; + + if let Some(ref white) = set.white { + num_white = white.len(); + if num_white > 0 { + pack = Some(white[0].pack); + newset.white = Some(set.white.unwrap()); + } + } + + if let Some(ref black) = set.black { + num_black = black.len(); + if num_black > 0 { + pack = Some(black[0].pack); + newset.black = Some(set.black.unwrap()); + } + } + + let meta = CardPackMeta { + name: set.name, + pack: pack.expect("No card pack number!"), + num_white, + num_black, + }; + + if set.official { + official_meta.push(meta); + official.insert(pack.unwrap(), newset); + } else { + unofficial_meta.push(meta); + unofficial.insert(pack.unwrap(), newset); + } + } + + official.shrink_to_fit(); + unofficial.shrink_to_fit(); + + official_meta.shrink_to_fit(); + unofficial_meta.shrink_to_fit(); + + tracing::debug!("{} official", official.len()); + tracing::debug!("{} official meta", official_meta.len()); + tracing::debug!("{} unofficial", unofficial.len()); + tracing::debug!("{} unofficial meta", unofficial_meta.len()); + tracing::debug!("{:#?}", official_meta[0]); + tracing::debug!("{:#?}", unofficial_meta[0]); + + let packs = CardPacks { + official, + unofficial, + }; + + let packs_meta = CardPacksMeta { + official_meta, + unofficial_meta, + }; + + Ok((packs, packs_meta)) +} /// Card Set #[derive(Debug)] -pub struct CardSet { - pub white: Option>, - pub black: Option>, +struct CardSet { + white: Option>, + black: Option>, } /// Card Packs #[derive(Debug)] pub struct CardPacks { - pub official: HashMap, - pub unofficial: HashMap, + official: HashMap, + unofficial: HashMap, } /// A white card -#[derive(Debug, Deserialize)] -pub struct CardWhite { +// TODO: Remove this clone! +#[derive(Debug, Deserialize, Clone)] +struct CardWhite { /// Card text - pub text: String, + text: String, /// ID of the pack it came from - pub pack: u8, + pack: u8, } /// A black card -#[derive(Debug, Deserialize)] -pub struct CardBlack { +// TODO: Remove this clone! +#[derive(Debug, Deserialize, Clone)] +struct CardBlack { /// Card text - pub text: String, + text: String, /// Amount of cards to submit for judging - pub pick: u8, + pick: u8, /// ID of the pack it came from - pub pack: u8, + pack: u8, } /// A card pack #[derive(Debug, Deserialize)] -pub struct CardPack { +struct CardPack { /// Name of the pack - pub name: String, + name: String, /// Whether or not this is an official card pack - pub official: bool, + official: bool, /// White card data - pub white: Option>, + white: Option>, /// Black card data - pub black: Option>, + black: Option>, } /// New game request structure #[derive(Debug)] -pub struct NewGameManifest { +struct NewGameManifest { /// Game name - pub name: String, + name: String, /// Game host - pub host: Arc>, + host: Arc>, /// Selected game packs - pub packs: Vec, + packs: Vec, } /// A struct that represents a player #[derive(Debug)] -pub struct Player { - /// Player's user's uuid - pub user_uuid: Uuid, +struct Player { /// The player's hand - pub white: Vec, + white: Vec, /// The player's wins - pub black: Vec, + black: Vec, } /// The game master @@ -92,47 +176,21 @@ pub struct Game { /// The host user of the game pub host: Arc>, /// White draw pile - pub white: Vec, + white: Vec, /// Black draw pile - pub black: Vec, - /// White discard pile - pub white_discard: Vec, - /// Black discard pile - pub black_discard: Vec, - /// List of current players - pub players: HashMap, - // /// Reference to current card czar - // czar: &Player, + black: Vec, + players: HashMap, /// Black card for the current round - pub current_black: Option, + current_black: Option, } impl Game { - /// Build game decks from input data for game start. - /// This should only run once and at startup. - fn build_decks(&mut self, selected_packs: Vec) -> Result<()> { - // for pack in selected_packs { - // for pack in card_packs { - // if let Some(white) = pack.white { - // self.white.extend(white) - // } - // if let Some(black) = pack.black { - // self.black.extend(black) - // } - // } - // } - - Ok(()) - } - - pub fn new(request: NewGameManifest) -> Result { + fn new(state: Arc, request: NewGameManifest) -> Result { let mut game = Game { name: request.host.read().unwrap().name.clone(), host: request.host.clone(), white: vec![], black: vec![], - white_discard: vec![], - black_discard: vec![], players: HashMap::new(), current_black: Option::None, }; @@ -144,30 +202,43 @@ impl Game { game.name = request.name; game.host = request.host.clone(); - game.build_decks(request.packs)?; + game.build_decks(state, request.packs)?; game.create_player(request.host)?; game.deal_black()?; Ok(game) } - // pub fn join(request:GameJoinRequest) + /// Build game decks from input data for game start. + /// This should only run once and at startup. + fn build_decks(&mut self, state: Arc, selected_packs: Vec) -> Result<()> { + // TODO: Make this right -- remove the clones, use references to single cards + for pack_num in selected_packs { + if let Some(pack) = state.packs.official.get(&pack_num) { + if let Some(white) = &pack.white { + self.white.extend(white.clone()) + } + if let Some(black) = &pack.black { + self.black.extend(black.clone()) + } + } else if let Some(pack) = state.packs.unofficial.get(&pack_num) { + if let Some(white) = &pack.white { + self.white.extend(white.clone()) + } + if let Some(black) = &pack.black { + self.black.extend(black.clone()) + } + } + } - /// Log counts of current drawable cards - /// For testing - pub fn deck_counts(&self) { - tracing::debug!( - "Deck Counts:\n {} White cards\n {} Black cards", - self.white.len(), - self.black.len() - ); + Ok(()) } /// Draw one white card at random from play deck. fn draw_one_white(&mut self) -> Result { let deck = &mut self.white; - // this feels sloppy + // TODO: this feels sloppy if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { Ok(deck.swap_remove(index)) } else { @@ -182,7 +253,7 @@ impl Game { fn draw_one_black(&mut self) -> Result { let deck = &mut self.black; - // this feels sloppy + // TODO: this feels sloppy if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { Ok(deck.swap_remove(index)) } else { @@ -202,9 +273,8 @@ impl Game { } /// Create a new player and add them to the game. - pub fn create_player(&mut self, user: Arc>) -> Result<()> { + fn create_player(&mut self, user: Arc>) -> Result<()> { let mut new_player = Player { - user_uuid: user.read().unwrap().uuid.clone(), white: vec![], black: vec![], }; @@ -225,16 +295,6 @@ impl Game { Ok(()) } - - pub fn game_start(&mut self) -> Result<()> { - if let Some(black) = &self.current_black { - tracing::debug!("{}", black.text); - } else { - tracing::debug!("YOU DONE FUCKED UP (no current black card)"); - } - - Ok(()) - } } pub enum GameHandlerMessage { @@ -288,7 +348,7 @@ impl GameHandler { }; // create game - if let Ok(new_game_object) = Game::new(manifest) { + if let Ok(new_game_object) = Game::new(self.state.clone(), manifest) { let tx = self .state .online_users @@ -301,9 +361,9 @@ impl GameHandler { .tx .clone(); - let mut black_text = "Error".to_string(); + let mut black_card = ("Error".to_string(), 0u8); if let Some(ref current_black) = new_game_object.current_black { - black_text = current_black.text.to_owned() + black_card = (current_black.text.to_owned(), current_black.pick) } let meta = GameMeta { @@ -326,7 +386,7 @@ impl GameHandler { }) .collect(), czar: new_game_object.host.read().unwrap().name.clone(), - black: black_text, + black: black_card, white: new_game_object .players .get(&new_game_object.host.read().unwrap().uuid) diff --git a/server/src/lib.rs b/server/src/lib.rs index ac57564..3589631 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -7,7 +7,7 @@ use game_handler::GameHandlerMessage; use lib::*; use std::{ collections::{HashMap, HashSet}, - fs::{read_to_string, File}, + fs::File, io::{BufRead, BufReader}, net::SocketAddr, sync::{Arc, RwLock}, @@ -44,89 +44,6 @@ impl User { } } -/// Parse json for card data -pub fn load_cards_from_json(path: &str) -> Result<(CardPacks, CardPacksMeta)> { - let data: String = - read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?; - let jayson: Vec = serde_json::from_str(&data) - .with_context(|| format!("The contents of \"{path}\" is not valid JSON."))?; - - let mut official: HashMap = HashMap::new(); - let mut unofficial: HashMap = HashMap::new(); - - let mut official_meta: Vec = vec![]; - let mut unofficial_meta: Vec = vec![]; - - for set in jayson { - let mut num_white = 0; - let mut num_black = 0; - - let mut newset = CardSet { - white: Option::None, - black: Option::None, - }; - - // No safe default for this so make it an Option - let mut pack: Option = Option::None; - - if let Some(ref white) = set.white { - num_white = white.len(); - if num_white > 0 { - pack = Some(white[0].pack); - newset.white = Some(set.white.unwrap()); - } - } - - if let Some(ref black) = set.black { - num_black = black.len(); - if num_black > 0 { - pack = Some(black[0].pack); - newset.black = Some(set.black.unwrap()); - } - } - - let meta = CardPackMeta { - name: set.name, - pack: pack.expect("No card pack number!"), - num_white, - num_black, - }; - - if set.official { - official_meta.push(meta); - official.insert(pack.unwrap(), newset); - } else { - unofficial_meta.push(meta); - unofficial.insert(pack.unwrap(), newset); - } - } - - official.shrink_to_fit(); - unofficial.shrink_to_fit(); - - official_meta.shrink_to_fit(); - unofficial_meta.shrink_to_fit(); - - tracing::debug!("{} official", official.len()); - tracing::debug!("{} official meta", official_meta.len()); - tracing::debug!("{} unofficial", unofficial.len()); - tracing::debug!("{} unofficial meta", unofficial_meta.len()); - tracing::debug!("{:#?}", official_meta[0]); - tracing::debug!("{:#?}", unofficial_meta[0]); - - let packs = CardPacks { - official, - unofficial, - }; - - let packs_meta = CardPacksMeta { - official_meta, - unofficial_meta, - }; - - Ok((packs, packs_meta)) -} - /// Parse name list pub fn load_names(path: &str) -> Result> { let f = File::open(path).with_context(|| format!("Invalid names path: \"{}\"", path))?; diff --git a/server/src/main.rs b/server/src/main.rs index 8e49896..598a682 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -64,16 +64,7 @@ async fn main() -> Result<()> { } }); - // Make an outgoing message handler handler - // DO it - // DO it - // DO it - // DO it - // DO it - // DO it - // DO it - // DO it - // DO it + // TODO: Make an outgoing message handler handler // Spawn task to handle User things let user_handler = UserHandler::new(app_state.clone()); diff --git a/server/src/message_handler.rs b/server/src/message_handler.rs index 20b5915..1de58a8 100644 --- a/server/src/message_handler.rs +++ b/server/src/message_handler.rs @@ -7,9 +7,6 @@ use serde_json::{from_str, to_string}; use std::net::SocketAddr; use std::sync::Arc; -// Handle incoming messages over the WebSocket, and probably do more than we should. -// Also with lots of unwrapping - pub struct MessageHandler { state: Arc, } @@ -23,7 +20,7 @@ impl MessageHandler { match message { Message::Text(text) => match text { _chat_message if let Ok(chat_message) = from_str::(&text) => { - // This should be delegated to user handler and an outgoing message and/or chat handler + // TODO: This should be delegated to user handler and an outgoing message and/or chat handler let msg = format! {"{0}: {1}", self.state.online_users.read().unwrap().get(&addr).unwrap().read().unwrap().name, chat_message.text}; tracing::debug!("{msg}"); self.state diff --git a/server/src/user_handler.rs b/server/src/user_handler.rs index 82a21e0..e9730e6 100644 --- a/server/src/user_handler.rs +++ b/server/src/user_handler.rs @@ -5,8 +5,6 @@ use serde_json::to_string; use std::net::SocketAddr; use std::sync::{Arc, RwLock}; -// This file is a mess, don't read it - pub enum UserHandlerMessage { NewUser { user: User, addr: SocketAddr }, UserLogIn { username: String, addr: SocketAddr }, @@ -24,7 +22,7 @@ impl UserHandler { pub async fn handle(&self, message: UserHandlerMessage) { match message { UserHandlerMessage::NewUser { user, addr } => { - // make this not async + // TODO: make this not async self.set_up_new_user(user, addr).await } UserHandlerMessage::UserLogIn { username, addr } => self.login(username, addr).await, @@ -65,7 +63,7 @@ impl UserHandler { .unwrap(); // Broadcast new user's existence - // this should probably be combined and sent as one + // TODO: this should probably be combined and sent as one let _ = &self .state .broadcast_tx @@ -82,8 +80,7 @@ impl UserHandler { .send(meta_chat_update(&self.state)) .unwrap(); - // this races the broadcasts but if it's done last it'll probably show up - // last + // TODO: this races the broadcasts but if it's done last it'll probably show up last tx.send(meta_motd()).await.unwrap(); } @@ -245,7 +242,7 @@ pub fn user_client_self_update(new_user: &Arc>) -> String { /// Generate chatroom metadata update pub fn meta_chat_update(state: &Arc) -> String { - // this may get expensive if there are many users + // TODO: this may get expensive if there are many users let mut names = vec![]; for user in state.online_users.read().unwrap().iter() { @@ -285,7 +282,7 @@ pub fn meta_server_summary_update(state: &Arc) -> String { /// Generate games list update pub fn meta_games_browser_update(state: &Arc) -> String { - // this may get expensive if there are many games + // TODO: this may get expensive if there are many games let mut names = vec![]; for game in state.games.read().unwrap().values() { diff --git a/server/src/websocket.rs b/server/src/websocket.rs index 9deb6c9..86838ed 100644 --- a/server/src/websocket.rs +++ b/server/src/websocket.rs @@ -37,9 +37,8 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc, ad let mut map = HashMap::new(); map.insert(addr, dm_tx.clone()); - let _ = state + state .users_tx - // add tx .send(UserHandlerMessage::NewUser { user: User::new( format!( @@ -51,7 +50,8 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc, ad ), addr, }) - .await; + .await + .unwrap(); // Subscribe to receive from global broadcast channel let mut rx = state.broadcast_tx.subscribe();