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::*;
|
2024-08-18 19:11:38 -04:00
|
|
|
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
|
|
|
|
let _ = self
|
|
|
|
.state
|
|
|
|
.games
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.remove(&request.delete_game_id)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Broadcast game browser update
|
|
|
|
self.state
|
|
|
|
.broadcast_tx
|
|
|
|
.send(meta_games_browser_update(&self.state))
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-08-20 22:25:39 -04:00
|
|
|
/// Process judging
|
|
|
|
async fn handle_judging(&self, request: JudgeDecisionRequest, addr: SocketAddr) {
|
|
|
|
// Get pointers
|
|
|
|
let this_user_id = self
|
|
|
|
.state
|
|
|
|
.online_users
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(&addr)
|
|
|
|
.unwrap()
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.uuid
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
let this_game = self
|
|
|
|
.state
|
|
|
|
.games
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(&request.game_id)
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
|
|
|
|
// Check if this player is czar
|
|
|
|
// Check if player is currently Czar
|
|
|
|
if this_game
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.czar
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.uuid
|
|
|
|
.to_string()
|
|
|
|
== this_user_id
|
|
|
|
{
|
|
|
|
// Find user who submitted the card
|
2024-08-22 21:19:34 -04:00
|
|
|
let winning_player_id = this_game
|
2024-08-20 22:25:39 -04:00
|
|
|
.read()
|
|
|
|
.unwrap()
|
2024-08-24 21:24:58 -04:00
|
|
|
.judge_pile_meta
|
2024-08-20 22:25:39 -04:00
|
|
|
.get(&request.winning_cards)
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
|
2024-08-22 21:19:34 -04:00
|
|
|
this_game
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.finish_round(winning_player_id.clone());
|
|
|
|
|
|
|
|
let this_game_id = this_game.read().unwrap().uuid.to_string();
|
|
|
|
self.send_game_state_update(this_game_id).await
|
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) {
|
2024-08-20 22:25:39 -04:00
|
|
|
// Get pointers
|
2024-08-24 18:39:11 -04:00
|
|
|
let player_user_id = self
|
2024-08-17 21:55:15 -04:00
|
|
|
.state
|
|
|
|
.online_users
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(&addr)
|
|
|
|
.unwrap()
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.uuid
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
let this_game = self
|
|
|
|
.state
|
|
|
|
.games
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2024-08-18 18:48:37 -04:00
|
|
|
.get(&request.game_id)
|
2024-08-17 21:55:15 -04:00
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
|
2024-08-20 22:25:39 -04:00
|
|
|
// Do the stuff
|
2024-08-24 18:39:11 -04:00
|
|
|
match this_game
|
|
|
|
.write()
|
2024-08-17 21:55:15 -04:00
|
|
|
.unwrap()
|
2024-08-24 18:39:11 -04:00
|
|
|
.player_move(request, player_user_id)
|
2024-08-17 21:55:15 -04:00
|
|
|
{
|
2024-08-24 18:39:11 -04:00
|
|
|
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;
|
|
|
|
})
|
2024-08-20 22:25:39 -04:00
|
|
|
}
|
2024-08-24 18:39:11 -04:00
|
|
|
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;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
};
|
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) {
|
2024-08-14 20:38:19 -04:00
|
|
|
// Get pointers
|
|
|
|
let this_game = self.state.games.read().unwrap().get(&id).unwrap().clone();
|
|
|
|
let this_user = self
|
|
|
|
.state
|
|
|
|
.online_users
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(&addr)
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
2024-08-12 17:14:27 -04:00
|
|
|
|
2024-08-21 22:05:13 -04:00
|
|
|
// Check if player already exists
|
2024-08-18 19:51:45 -04:00
|
|
|
if !this_game
|
2024-08-18 19:11:38 -04:00
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.players
|
|
|
|
.contains_key(&this_user.read().unwrap().uuid)
|
|
|
|
{
|
2024-08-18 19:51:45 -04:00
|
|
|
// Create player
|
|
|
|
this_game.write().unwrap().create_player(this_user);
|
2024-08-18 19:11:38 -04:00
|
|
|
}
|
|
|
|
|
2024-08-14 20:38:19 -04:00
|
|
|
// Send updates for all players
|
2024-08-21 22:05:13 -04:00
|
|
|
self.send_game_state_update(id).await;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
async fn send_game_state_update(&self, game_id: String) {
|
|
|
|
let this_game = self
|
|
|
|
.state
|
|
|
|
.games
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(&game_id)
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
|
2024-08-22 21:19:34 -04:00
|
|
|
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>>();
|
|
|
|
|
2024-08-14 20:38:19 -04:00
|
|
|
for player in this_game.read().unwrap().players.values() {
|
|
|
|
// Create update for user's game view
|
|
|
|
let meta = GameStateMeta {
|
2024-08-21 22:05:13 -04:00
|
|
|
uuid: game_id.clone(),
|
2024-08-14 20:38:19 -04:00
|
|
|
name: this_game.read().unwrap().name.clone(),
|
|
|
|
host: this_game.read().unwrap().host.read().unwrap().name.clone(),
|
2024-08-22 21:19:34 -04:00
|
|
|
players: players.clone(),
|
2024-08-24 22:02:05 -04:00
|
|
|
czar: this_game.read().unwrap().czar.read().unwrap().name.clone(),
|
2024-08-14 23:14:57 -04:00
|
|
|
black: (
|
|
|
|
this_game.read().unwrap().current_black.text.clone(),
|
|
|
|
this_game.read().unwrap().current_black.pick,
|
|
|
|
),
|
2024-08-17 21:55:15 -04:00
|
|
|
white: player
|
|
|
|
.white
|
|
|
|
.iter()
|
|
|
|
.map(|card| WhiteCardMeta {
|
|
|
|
uuid: card.uuid.to_string(),
|
|
|
|
text: card.text.clone(),
|
|
|
|
})
|
|
|
|
.collect(),
|
2024-08-14 20:38:19 -04:00
|
|
|
packs: this_game.read().unwrap().packs.clone(),
|
2024-08-24 21:45:15 -04:00
|
|
|
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(),
|
2024-08-14 20:38:19 -04:00
|
|
|
};
|
2024-08-12 17:14:27 -04:00
|
|
|
|
2024-08-14 20:38:19 -04:00
|
|
|
// 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 });
|
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() {
|
2024-08-14 23:14:57 -04:00
|
|
|
tracing::error!("New game cards are empty!");
|
2024-08-14 20:38:19 -04:00
|
|
|
return;
|
|
|
|
} else if new_game.name.is_empty() {
|
2024-08-14 23:14:57 -04:00
|
|
|
tracing::error!("New game name is empty!");
|
2024-08-14 20:38:19 -04:00
|
|
|
return;
|
|
|
|
}
|
2024-08-12 17:14:27 -04:00
|
|
|
|
2024-08-15 00:14:47 -04:00
|
|
|
// Get host pointer
|
|
|
|
let host = self
|
|
|
|
.state
|
|
|
|
.online_users
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(&addr)
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
|
|
|
|
// Create manifest
|
2024-08-14 20:38:19 -04:00
|
|
|
let manifest = NewGameManifest {
|
|
|
|
name: new_game.name,
|
2024-08-15 00:14:47 -04:00
|
|
|
host: host.clone(),
|
2024-08-14 20:38:19 -04:00
|
|
|
packs: new_game.packs,
|
|
|
|
};
|
2024-08-12 17:14:27 -04:00
|
|
|
|
2024-08-15 00:14:47 -04:00
|
|
|
// Create game using manifest
|
2024-08-17 15:57:18 -04:00
|
|
|
let mut new_game_object = Game::new(self.state.clone(), manifest);
|
|
|
|
|
|
|
|
// Don't forget to create the host player!!!
|
|
|
|
new_game_object.create_player(host.clone());
|
2024-08-15 00:14:47 -04:00
|
|
|
|
2024-08-21 22:05:13 -04:00
|
|
|
let game_id = new_game_object.uuid.to_string();
|
2024-08-12 17:14:27 -04:00
|
|
|
|
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-21 22:05:13 -04:00
|
|
|
self.send_game_state_update(game_id).await;
|
|
|
|
|
2024-08-15 00:14:47 -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();
|
2024-08-14 20:38:19 -04:00
|
|
|
}
|
2024-08-12 17:14:27 -04:00
|
|
|
}
|