let game handler own the games

This commit is contained in:
Adam 2024-10-13 17:04:28 -04:00
parent 3fb3d2f521
commit c8375d1b15
4 changed files with 60 additions and 84 deletions

View file

@ -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<Option<(JudgeRound, String)>, String> {
if self.czar.read().unwrap().uuid == player_user_id {

View file

@ -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<AppState>,
games: HashMap<String, Game>,
}
impl GameHandler {
/// Returns a new game handler
pub fn new(state: Arc<AppState>) -> 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<String>) {
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::<Vec<&String>>()
@ -227,18 +211,18 @@ impl GameHandler {
})
.collect::<Vec<GamePlayerMeta>>();
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<String>) {
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::<Vec<GameBrowserMeta>>();
@ -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) });
}

View file

@ -76,7 +76,6 @@ pub struct AppState {
pub offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>,
pub packs: CardPacks,
pub packs_meta: CardPacksMeta,
pub games: RwLock<HashMap<String, Arc<RwLock<Game>>>>,
}
/// Card Set

View file

@ -80,7 +80,6 @@ async fn main() -> Result<()> {
let online_users = RwLock::new(HashMap::<SocketAddr, Arc<RwLock<User>>>::new());
let offline_users = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::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 {