use crate::user_handler::*; use crate::AppState; use crate::User; use anyhow::Result; use lib::*; use rand::prelude::IteratorRandom; use rand::thread_rng; use serde::Deserialize; use std::{ collections::HashMap, net::SocketAddr, sync::{Arc, RwLock}, }; use uuid::Uuid; // This file is disgusting, don't look at it /// Card Set #[derive(Debug)] pub struct CardSet { pub white: Option>, pub black: Option>, } /// Card Packs #[derive(Debug)] pub struct CardPacks { pub official: HashMap, pub unofficial: HashMap, } /// A white card #[derive(Debug, Deserialize)] pub struct CardWhite { /// Card text pub text: String, /// ID of the pack it came from pub pack: u8, } /// A black card #[derive(Debug, Deserialize)] pub struct CardBlack { /// Card text pub text: String, /// Amount of cards to submit for judging pub pick: u8, /// ID of the pack it came from pub pack: u8, } /// A card pack #[derive(Debug, Deserialize)] pub struct CardPack { /// Name of the pack pub name: String, /// Whether or not this is an official card pack pub official: bool, /// White card data pub white: Option>, /// Black card data pub black: Option>, } /// New game request structure #[derive(Debug)] pub struct NewGameManifest { /// Game name pub name: String, /// Game host pub host: Arc>, /// Selected game packs pub packs: Vec, } /// A struct that represents a player #[derive(Debug)] pub struct Player { /// Player's user's uuid pub user_uuid: Uuid, /// The player's hand pub white: Vec, /// The player's wins pub black: Vec, } /// The game master #[derive(Debug)] pub struct Game { /// The name of the game pub name: String, /// The host user of the game pub host: Arc>, /// White draw pile pub 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 card for the current round pub 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 { 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, }; tracing::debug!( "Creating game {} with {} as host", &request.name, request.host.read().unwrap().name ); game.name = request.name; game.host = request.host.clone(); game.build_decks(request.packs)?; game.create_player(request.host)?; game.deal_black()?; Ok(game) } // pub fn join(request:GameJoinRequest) /// 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() ); } /// Draw one white card at random from play deck. fn draw_one_white(&mut self) -> Result { let deck = &mut self.white; // this feels sloppy if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { Ok(deck.swap_remove(index)) } else { Ok(CardWhite { text: "Error.\n\nbtw if you see this tell me I'm lazy :)".to_string(), pack: 0, }) } } /// Draw one black card at random from play deck. fn draw_one_black(&mut self) -> Result { let deck = &mut self.black; // this feels sloppy if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) { Ok(deck.swap_remove(index)) } else { Ok(CardBlack { text: "Error.\n\nbtw if you see this tell me I'm lazy :)".to_string(), pick: 0, pack: 0, }) } } /// Deal a black card and use it for the current round fn deal_black(&mut self) -> Result<()> { self.current_black = Some(self.draw_one_black()?); Ok(()) } /// Create a new player and add them to the game. pub fn create_player(&mut self, user: Arc>) -> Result<()> { let mut new_player = Player { user_uuid: user.read().unwrap().uuid.clone(), white: vec![], black: vec![], }; let new_player_name = user.read().unwrap().name.clone(); tracing::debug!("Creating player for {}", &new_player_name); let mut hand_buf = vec![]; for _ in 0..10 { hand_buf.push(self.draw_one_white()?); } tracing::debug!("Dealing hand to {}", &new_player_name); new_player.white.extend(hand_buf); self.players .insert(user.read().unwrap().uuid.clone(), new_player); 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 { NewGame { addr: SocketAddr, new_game: NewGameRequest, }, JoinGame { user: Arc, game_name: String, }, } pub struct GameHandler { state: Arc, } impl GameHandler { pub fn new(state: Arc) -> Self { GameHandler { state } } pub async fn handle(&self, message: GameHandlerMessage) { match message { GameHandlerMessage::NewGame { addr, new_game } => self.new_game(addr, new_game).await, _ => { tracing::debug!("Unhandled at game handler"); } } } async fn new_game(&self, addr: SocketAddr, new_game: NewGameRequest) { if new_game.packs.is_empty() { tracing::debug!("Cards are empty"); return; } else if new_game.name.is_empty() { tracing::debug!("Name are empty"); return; } let manifest = NewGameManifest { name: new_game.name, host: self .state .online_users .read() .unwrap() .get(&addr) .unwrap() .clone(), packs: new_game.packs, }; // create game if let Ok(new_game_object) = Game::new(manifest) { let tx = self .state .online_users .read() .unwrap() .get(&addr) .unwrap() .read() .unwrap() .tx .clone(); let mut black_text = "Error".to_string(); if let Some(ref current_black) = new_game_object.current_black { black_text = current_black.text.to_owned() } let meta = GameMeta { name: new_game_object.name.clone(), host: new_game_object.host.read().unwrap().name.clone(), players: new_game_object .players .iter() .map(|player| { self.state .user_uuid .read() .unwrap() .get(&player.0) .unwrap() .read() .unwrap() .name .clone() }) .collect(), czar: new_game_object.host.read().unwrap().name.clone(), black: black_text, white: new_game_object .players .get(&new_game_object.host.read().unwrap().uuid) .unwrap() .white .iter() .map(|card| card.text.clone()) .collect(), }; tx.send(serde_json::to_string(&meta).unwrap()) .await .unwrap(); self.state.games.write().unwrap().insert( new_game_object.name.clone(), Arc::new(RwLock::new(new_game_object)), ); self.state .broadcast_tx .send(meta_games_browser_update(&self.state)) .unwrap(); self.state .broadcast_tx .send(meta_server_summary_update(&self.state)) .unwrap(); } } }