cards/server/src/game_handler.rs

258 lines
9.3 KiB
Rust
Raw Normal View History

2024-08-24 16:15:19 -04:00
use crate::game::*;
2024-08-08 05:29:32 -04:00
use crate::user_handler::*;
use crate::AppState;
2024-08-22 17:05:26 -04:00
use crate::DmUserMethod::*;
2024-08-14 20:38:19 -04:00
use crate::GameHandlerMessage::*;
use crate::SendUserMessage::*;
use crate::UserHandlerMessage::*;
2024-08-09 02:57:27 -04:00
use lib::*;
2024-08-12 15:10:48 -04:00
use std::{
net::SocketAddr,
sync::{Arc, RwLock},
};
2024-08-08 05:29:32 -04:00
2024-08-15 00:34:36 -04:00
/// For interacting with the game handler
2024-08-14 20:38:19 -04:00
pub enum GameHandlerMessage {
2024-08-22 16:15:18 -04:00
NewGame(NewGameRequest, SocketAddr),
JoinGame(String, SocketAddr),
2024-08-18 18:48:37 -04:00
MoveRequest(PlayerMoveRequest, SocketAddr),
2024-08-20 22:25:39 -04:00
JudgeDecision(JudgeDecisionRequest, SocketAddr),
2024-08-22 16:15:18 -04:00
DeleteGame(GameDeleteRequest),
2024-08-14 20:38:19 -04:00
}
2024-08-15 00:34:36 -04:00
/// Handles game stuff
2024-08-14 20:38:19 -04:00
pub struct GameHandler {
2024-08-15 01:56:11 -04:00
/// Global state pointer
2024-08-14 20:38:19 -04:00
state: Arc<AppState>,
}
2024-08-12 17:14:27 -04:00
2024-08-14 20:38:19 -04:00
impl GameHandler {
2024-08-15 00:34:36 -04:00
/// Returns a new game handler
2024-08-14 20:38:19 -04:00
pub fn new(state: Arc<AppState>) -> Self {
GameHandler { state }
}
2024-08-12 17:14:27 -04:00
2024-08-15 00:34:36 -04:00
/// Handles incoming messages
2024-08-14 20:38:19 -04:00
pub async fn handle(&self, message: GameHandlerMessage) {
match message {
2024-08-22 16:15:18 -04:00
NewGame(request, addr) => self.create_new_game(request, addr).await,
JoinGame(request, addr) => self.join_game(request, addr).await,
2024-08-18 18:48:37 -04:00
MoveRequest(request, addr) => self.handle_player_move(request, addr).await,
2024-08-20 22:25:39 -04:00
JudgeDecision(request, addr) => self.handle_judging(request, addr).await,
2024-08-22 16:15:18 -04:00
DeleteGame(request) => self.delete_game(request).await,
2024-08-20 22:25:39 -04:00
}
}
2024-08-22 16:15:18 -04:00
/// Delete game
async fn delete_game(&self, request: GameDeleteRequest) {
// TODO: add auth lol
if self
2024-08-22 16:15:18 -04:00
.state
.games
.write()
.unwrap()
.remove(&request.delete_game_id)
.is_some()
{
// Broadcast game browser update
self.state
.broadcast_tx
.send(meta_games_browser_update(&self.state))
.unwrap();
} else {
tracing::error!("User tried to delete a nonexistent game!");
}
2024-08-22 16:15:18 -04:00
}
2024-08-20 22:25:39 -04:00
/// 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) {
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, player_user_id);
self.send_game_state_update(game_id);
} else {
tracing::error!("Received judge request for nonexistent judge player!");
}
} else {
tracing::error!("Received judge request for nonexistent game!");
}
2024-08-17 21:55:15 -04:00
}
/// Process player move request
2024-08-18 18:48:37 -04:00
async fn handle_player_move(&self, request: PlayerMoveRequest, addr: SocketAddr) {
if let Some(this_game) = self.state.games.read().unwrap().get(&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, player_user_id)
{
Err(err) => {
let message = ChatMessage { text: err };
let tx = self.state.users_tx.clone();
tokio::spawn(async move {
let _ = tx.send(DmUser(SendChatMessage(message), Addr(addr))).await;
})
}
Ok(None) => tokio::spawn(async move { tracing::debug!("None") }),
Ok(Some((judge_round, czar_id))) => {
let tx = self.state.users_tx.clone();
tokio::spawn(async move {
let _ = tx
.send(DmUser(SendJudgeRound(judge_round), Id(czar_id)))
.await;
})
}
};
} else {
tracing::error!("Nonexistent player tried to submit move for game!");
2024-08-20 22:25:39 -04:00
}
} else {
tracing::error!("Player tried to submit move for nonexistent game!");
}
2024-08-14 20:38:19 -04:00
}
2024-08-12 17:14:27 -04:00
2024-08-15 00:34:36 -04:00
/// Puts a user in a game
2024-08-22 16:15:18 -04:00
async fn join_game(&self, id: String, addr: SocketAddr) {
if let Some(this_game) = self.state.games.read().unwrap().get(&id) {
if let Some(this_user) = self.state.online_users.read().unwrap().get(&addr) {
// Create player
this_game.write().unwrap().create_player(this_user.clone());
} else {
tracing::error!("Tried to add a nonexistent user to game!");
return;
}
} else {
tracing::error!("User tried to join a nonexistent game!");
return;
}
2024-08-14 20:38:19 -04:00
// Send updates for all players
self.send_game_state_update(id);
2024-08-21 22:05:13 -04:00
// Broadcast game browser update
self.state
.broadcast_tx
.send(meta_games_browser_update(&self.state))
.unwrap();
// Broadcast server meta update
self.state
.broadcast_tx
.send(meta_server_summary_update(&self.state))
.unwrap();
}
/// Send game state update for all players of a game
fn send_game_state_update(&self, game_id: String) {
if let Some(this_game) = self.state.games.read().unwrap().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(),
})
.collect::<Vec<GamePlayerMeta>>();
for player in this_game.read().unwrap().players.values() {
// Create update for user's game view
let meta = GameStateMeta {
uuid: game_id.clone(),
name: this_game.read().unwrap().name.clone(),
host: this_game.read().unwrap().host.read().unwrap().name.clone(),
players: players.clone(),
czar: this_game.read().unwrap().czar.read().unwrap().name.clone(),
black: (
this_game.read().unwrap().current_black.text.clone(),
this_game.read().unwrap().current_black.pick,
),
white: player
.white
.iter()
.map(|card| WhiteCardMeta {
uuid: card.uuid.to_string(),
text: card.text.clone(),
})
.collect(),
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(),
};
// Send user's update
let msg = serde_json::to_string(&meta).unwrap();
let user_tx = player.user.read().unwrap().tx.clone();
tokio::spawn(async move { user_tx.send(msg).await });
}
} else {
tracing::error!("Attempted to create game state update for nonexistent game!");
2024-08-12 17:14:27 -04:00
}
}
2024-08-15 00:34:36 -04:00
/// Creates a new game
2024-08-22 16:15:18 -04:00
async fn create_new_game(&self, new_game: NewGameRequest, addr: SocketAddr) {
2024-08-14 20:38:19 -04:00
if new_game.packs.is_empty() {
tracing::error!("New game cards are empty!");
2024-08-14 20:38:19 -04:00
return;
} else if new_game.name.is_empty() {
tracing::error!("New game name is empty!");
2024-08-14 20:38:19 -04:00
return;
}
2024-08-12 17:14:27 -04:00
if let Some(host) = self.state.online_users.read().unwrap().get(&addr) {
// Create manifest
let manifest = NewGameManifest {
name: new_game.name,
host: host.clone(),
packs: new_game.packs,
};
2024-08-15 00:14:47 -04:00
// Create game using manifest
let mut new_game_object = Game::new(self.state.clone(), manifest);
2024-08-12 17:14:27 -04:00
// Don't forget to create the host player!!!
new_game_object.create_player(host.clone());
2024-08-17 15:57:18 -04:00
let game_id = new_game_object.uuid.to_string();
2024-08-15 00:14:47 -04:00
// Add game to active list
self.state.games.write().unwrap().insert(
new_game_object.uuid.to_string(),
Arc::new(RwLock::new(new_game_object)),
);
2024-08-12 17:14:27 -04:00
self.send_game_state_update(game_id);
2024-08-15 00:14:47 -04:00
// Broadcast game browser update
self.state
.broadcast_tx
.send(meta_games_browser_update(&self.state))
.unwrap();
2024-08-21 22:05:13 -04:00
// Broadcast server meta update
self.state
.broadcast_tx
.send(meta_server_summary_update(&self.state))
.unwrap();
} else {
tracing::error!("Attempted to create game for nonexistent player!");
}
2024-08-14 20:38:19 -04:00
}
2024-08-12 17:14:27 -04:00
}