From c8375d1b15903b290bd74c4eb2955f05cb70870a Mon Sep 17 00:00:00 2001 From: Adam Doyle Date: Sun, 13 Oct 2024 17:04:28 -0400 Subject: [PATCH] let game handler own the games --- server/src/game.rs | 4 +- server/src/game_handler.rs | 135 ++++++++++++++++--------------------- server/src/lib.rs | 1 - server/src/main.rs | 4 +- 4 files changed, 60 insertions(+), 84 deletions(-) diff --git a/server/src/game.rs b/server/src/game.rs index da849b5..626b782 100644 --- a/server/src/game.rs +++ b/server/src/game.rs @@ -142,7 +142,7 @@ impl Game { } /// Judge Game - pub fn judge_round(&mut self, request: JudgeDecisionRequest, player_user_id: String) { + pub fn judge_round(&mut self, request: &JudgeDecisionRequest, player_user_id: String) { // Check if player is czar if self.czar.read().unwrap().uuid.to_string() == player_user_id { if let Some(winner_id) = self.judge_pile_meta.get(&request.winning_cards) { @@ -158,7 +158,7 @@ impl Game { /// Process player move pub fn player_move( &mut self, - request: PlayerMoveRequest, + request: &PlayerMoveRequest, player_user_id: String, ) -> Result, String> { if self.czar.read().unwrap().uuid == player_user_id { diff --git a/server/src/game_handler.rs b/server/src/game_handler.rs index 931290a..c6b2b5e 100644 --- a/server/src/game_handler.rs +++ b/server/src/game_handler.rs @@ -1,4 +1,5 @@ use crate::game::*; + use crate::AppState; use crate::DmUserMethod::*; use crate::GameHandlerMessage::*; @@ -6,10 +7,8 @@ use crate::SendUserMessage::*; use crate::UserHandlerMessage::*; use lib::*; use serde_json::to_string; -use std::{ - net::SocketAddr, - sync::{Arc, RwLock}, -}; +use std::collections::HashMap; +use std::{net::SocketAddr, sync::Arc}; /// For interacting with the game handler #[derive(Debug)] @@ -28,20 +27,22 @@ pub enum GameHandlerMessage { pub struct GameHandler { /// Global state pointer state: Arc, + games: HashMap, } impl GameHandler { /// Returns a new game handler pub fn new(state: Arc) -> Self { - GameHandler { state } + let games = HashMap::new(); + GameHandler { state, games } } /// Handles incoming messages - pub async fn handle(&self, message: GameHandlerMessage) { + pub async fn handle(&mut self, message: GameHandlerMessage) { match message { NewGame(request, addr) => self.create_new_game(request, addr).await, JoinGame(request, addr) => self.join_game(request, addr).await, - MoveRequest(request, addr) => self.handle_player_move(request, addr).await, + MoveRequest(request, addr) => self.handle_player_move(request, addr), JudgeDecision(request, addr) => self.handle_judging(request, addr).await, DeleteGame(request) => self.delete_game(request).await, SendGameStateUpdate(game_ids) => self.send_game_state_update_all(game_ids), @@ -51,16 +52,9 @@ impl GameHandler { } /// Delete game - async fn delete_game(&self, request: GameDeleteRequest) { + async fn delete_game(&mut self, request: GameDeleteRequest) { // TODO: add auth lol - if self - .state - .games - .write() - .unwrap() - .remove(&request.delete_game_id) - .is_some() - { + if self.games.remove(&request.delete_game_id).is_some() { self.broadcast_game_browser_update(); } else { tracing::error!("User tried to delete a nonexistent game!"); @@ -68,17 +62,14 @@ impl GameHandler { } /// Process judging - async fn handle_judging(&self, request: JudgeDecisionRequest, addr: SocketAddr) { - if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) { + async fn handle_judging(&mut self, request: JudgeDecisionRequest, addr: SocketAddr) { + if let Some(this_game) = self.games.get_mut(&request.game_id) { if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) { let player_user_id = player_user.read().unwrap().uuid.to_string(); let game_id = request.game_id.to_string(); // Send to game - this_game - .write() - .unwrap() - .judge_round(request.clone(), player_user_id); + this_game.judge_round(&request, player_user_id); self.send_game_state_update_all(vec![game_id.clone()]); self.send_game_meta_update(vec![game_id]); @@ -95,44 +86,38 @@ impl GameHandler { } /// Process player move request - async fn handle_player_move(&self, request: PlayerMoveRequest, addr: SocketAddr) { - if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) { + fn handle_player_move(&mut self, request: PlayerMoveRequest, addr: SocketAddr) { + if let Some(this_game) = self.games.get_mut(&request.game_id) { if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) { let player_user_id = player_user.read().unwrap().uuid.to_string(); // Do the stuff - match this_game - .write() - .unwrap() - .player_move(request.clone(), player_user_id) - { + match this_game.player_move(&request, player_user_id) { Err(err) => { let message = ChatMessage { text: err }; - let tx = self.state.users_tx.clone(); + let users_tx = self.state.users_tx.clone(); tokio::spawn(async move { - if let Err(e) = - tx.send(DmUser(SendChatMessage(message), Addr(addr))).await + if let Err(e) = users_tx + .send(DmUser(SendChatMessage(message), Addr(addr))) + .await { tracing::error!("Could not send message: {}", e); } - }) + }); } Ok(None) => { - tokio::spawn( - async move { tracing::debug!("TODO: whatever i'm supposed to do") }, - ) + tracing::debug!("TODO: whatever i'm supposed to do") } Ok(Some((judge_round, czar_id))) => { - let tx = self.state.users_tx.clone(); - + let users_tx = self.state.users_tx.clone(); tokio::spawn(async move { - if let Err(e) = tx + if let Err(e) = users_tx .send(DmUser(SendJudgeRound(judge_round), Id(czar_id))) .await { tracing::error!("Could not send message: {}", e); } - }) + }); } }; } else { @@ -176,8 +161,8 @@ impl GameHandler { } /// Puts a user in a game - async fn join_game(&self, game_id: String, addr: SocketAddr) { - if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) { + async fn join_game(&mut self, game_id: String, addr: SocketAddr) { + if self.games.contains_key(&game_id) { if let Some(this_user) = self.state.online_users.read().unwrap().get(&addr) { let this_user_id = this_user.read().unwrap().uuid.clone(); @@ -185,7 +170,10 @@ impl GameHandler { self.register_user_in_game(game_id.clone(), this_user_id.clone()); // Create player - this_game.write().unwrap().create_player(this_user.clone()); + self.games + .get_mut(&game_id) + .unwrap() + .create_player(this_user.clone()); // Send cards self.send_game_state_update_single(this_user_id, game_id.clone()) @@ -208,18 +196,14 @@ impl GameHandler { /// Send game meta update for all players of a game fn send_game_meta_update(&self, game_ids: Vec) { for game_id in game_ids { - if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) { + if let Some(this_game) = self.games.get(&game_id) { let players = this_game - .read() - .unwrap() .players .values() .map(|player| GamePlayerMeta { name: player.user.read().unwrap().name.clone(), score: player.black.len(), submitted: this_game - .read() - .unwrap() .judge_pile_meta .values() .collect::>() @@ -227,18 +211,18 @@ impl GameHandler { }) .collect::>(); - for player in this_game.read().unwrap().players.values() { + for player in this_game.players.values() { // Create update for user's game view let meta = GameMeta { uuid: game_id.clone(), - name: this_game.read().unwrap().name.clone(), - host: this_game.read().unwrap().host.read().unwrap().name.clone(), + name: this_game.name.clone(), + host: this_game.host.read().unwrap().name.clone(), players: players.clone(), - czar: this_game.read().unwrap().czar.read().unwrap().name.clone(), - packs: this_game.read().unwrap().packs.clone(), - white_count: this_game.read().unwrap().white.len(), - black_count: this_game.read().unwrap().black.len(), - white_discard_count: this_game.read().unwrap().white_discard.len(), + czar: this_game.czar.read().unwrap().name.clone(), + packs: this_game.packs.clone(), + white_count: this_game.white.len(), + black_count: this_game.black.len(), + white_discard_count: this_game.white_discard.len(), }; // Send user's update @@ -263,13 +247,13 @@ impl GameHandler { /// Send game state update for all players of a game fn send_game_state_update_all(&self, game_ids: Vec) { for game_id in game_ids { - if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) { - for player in this_game.read().unwrap().players.values() { + if let Some(this_game) = self.games.get(&game_id) { + for player in this_game.players.values() { // Create update for user's game view let meta = GameStateMeta { black: ( - this_game.read().unwrap().current_black.text.clone(), - this_game.read().unwrap().current_black.pick, + this_game.current_black.text.clone(), + this_game.current_black.pick, ), white: player .white @@ -294,13 +278,13 @@ impl GameHandler { /// Send game state update for a single user fn send_game_state_update_single(&self, user_id: String, game_id: String) { - if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) { - if let Some(player) = this_game.read().unwrap().players.get(&user_id) { + if let Some(this_game) = self.games.get(&game_id) { + if let Some(player) = this_game.players.get(&user_id) { // Create update for user's game view let meta = GameStateMeta { black: ( - this_game.read().unwrap().current_black.text.clone(), - this_game.read().unwrap().current_black.pick, + this_game.current_black.text.clone(), + this_game.current_black.pick, ), white: player .white @@ -325,7 +309,7 @@ impl GameHandler { } /// Creates a new game - async fn create_new_game(&self, new_game: NewGameRequest, addr: SocketAddr) { + async fn create_new_game(&mut self, new_game: NewGameRequest, addr: SocketAddr) { if new_game.packs.is_empty() { tracing::error!("New game cards are empty!"); return; @@ -364,10 +348,8 @@ impl GameHandler { let game_id = new_game_object.uuid.to_string(); // Add game to active list - self.state.games.write().unwrap().insert( - new_game_object.uuid.to_string(), - Arc::new(RwLock::new(new_game_object)), - ); + self.games + .insert(new_game_object.uuid.to_string(), new_game_object); // Register game to user self.register_user_in_game(game_id.clone(), host.read().unwrap().uuid.clone()); @@ -386,17 +368,14 @@ impl GameHandler { // TODO: this may get expensive if there are many games let games = self - .state .games - .read() - .unwrap() .values() .map(|game| GameBrowserMeta { - uuid: game.read().unwrap().uuid.to_string(), - name: game.read().unwrap().name.clone(), - host: game.read().unwrap().host.read().unwrap().name.clone(), - players: game.read().unwrap().players.len(), - packs: game.read().unwrap().packs.clone(), + uuid: game.uuid.to_string(), + name: game.name.clone(), + host: game.host.read().unwrap().name.clone(), + players: game.players.len(), + packs: game.packs.clone(), }) .collect::>(); @@ -412,7 +391,7 @@ impl GameHandler { /// Broadcast updated game count fn broadcast_game_count(&self) { let tx = self.state.broadcast_tx.clone(); - let active_games = self.state.games.read().unwrap().len(); + let active_games = self.games.len(); let msg = to_string(&ServerActiveGames { active_games }).unwrap(); tokio::spawn(async move { tx.send(msg) }); } diff --git a/server/src/lib.rs b/server/src/lib.rs index 0cb79fa..cb59bfd 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -76,7 +76,6 @@ pub struct AppState { pub offline_users: RwLock>>>, pub packs: CardPacks, pub packs_meta: CardPacksMeta, - pub games: RwLock>>>, } /// Card Set diff --git a/server/src/main.rs b/server/src/main.rs index 0944083..e674bd3 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -80,7 +80,6 @@ async fn main() -> Result<()> { let online_users = RwLock::new(HashMap::>>::new()); let offline_users = RwLock::new(HashMap::>>::new()); let (packs, packs_meta, white_cards_by_id) = load_cards_from_json("data/cah-cards-full.json")?; - let games = RwLock::new(HashMap::new()); let app_state = Arc::new(AppState { white_cards_by_id, @@ -97,7 +96,6 @@ async fn main() -> Result<()> { offline_users, packs, packs_meta, - games, }); // Spawn task to handle incoming messages, also handles outging messages @@ -126,7 +124,7 @@ async fn main() -> Result<()> { .unwrap(); // Spawn task to handle Game things - let game_handler = GameHandler::new(app_state.clone()); + let mut game_handler = GameHandler::new(app_state.clone()); tokio::task::Builder::new() .name("Game Handler") .spawn(async move {