2024-11-21 12:41:17 -05:00
|
|
|
use crate::card_loader::*;
|
2024-08-24 16:15:19 -04:00
|
|
|
use crate::game::*;
|
2024-08-08 05:29:32 -04:00
|
|
|
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-12-02 22:50:49 -05:00
|
|
|
use crate::OutgoingMessageHandlerMessage::*;
|
2024-08-18 19:11:38 -04:00
|
|
|
use crate::SendUserMessage::*;
|
2024-12-13 04:38:14 -05:00
|
|
|
use crate::User;
|
|
|
|
use crate::UserHandlerMessage;
|
2024-11-19 01:32:06 -05:00
|
|
|
use axum::extract::ws::Message;
|
2024-08-09 02:57:27 -04:00
|
|
|
use lib::*;
|
2024-12-13 04:38:14 -05:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
};
|
2024-11-21 13:56:03 -05:00
|
|
|
use tokio::sync::mpsc::Sender;
|
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-12-13 04:38:14 -05:00
|
|
|
NewGame(NewGameRequest, Arc<RwLock<User>>),
|
|
|
|
JoinGame(String, Arc<RwLock<User>>),
|
|
|
|
MoveRequest(PlayerMoveRequest, Arc<RwLock<User>>),
|
|
|
|
JudgeDecision(JudgeDecisionRequest, String),
|
2024-08-22 16:15:18 -04:00
|
|
|
DeleteGame(GameDeleteRequest),
|
2024-09-03 14:02:14 -04:00
|
|
|
SendGameStateUpdate(Vec<String>),
|
|
|
|
SendGameMetaUpdate(Vec<String>),
|
2024-12-11 23:20:44 -05:00
|
|
|
SendGameUserUpdate(String),
|
2024-10-11 23:09:19 -04:00
|
|
|
BroadcastGamesUpdate(),
|
2024-11-21 12:41:17 -05:00
|
|
|
SendCardPacks(Sender<Message>),
|
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-10-13 17:04:28 -04:00
|
|
|
games: HashMap<String, Game>,
|
2024-11-21 12:41:17 -05:00
|
|
|
packs: CardPacks,
|
|
|
|
packs_meta: CardPacksMeta,
|
2024-12-11 23:20:44 -05:00
|
|
|
game_id_by_user_id: HashMap<String, Vec<String>>,
|
2024-08-14 20:38:19 -04:00
|
|
|
}
|
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 {
|
2024-10-13 17:04:28 -04:00
|
|
|
let games = HashMap::new();
|
2024-11-21 12:41:17 -05:00
|
|
|
let (packs, packs_meta) = card_loader("data/cah-cards-full.json").unwrap();
|
2024-12-11 23:20:44 -05:00
|
|
|
let game_id_by_user_id = HashMap::<String, Vec<String>>::new();
|
|
|
|
|
2024-11-21 12:41:17 -05:00
|
|
|
GameHandler {
|
|
|
|
state,
|
|
|
|
games,
|
|
|
|
packs,
|
|
|
|
packs_meta,
|
2024-12-11 23:20:44 -05:00
|
|
|
game_id_by_user_id,
|
2024-11-21 12:41:17 -05:00
|
|
|
}
|
2024-08-14 20:38:19 -04:00
|
|
|
}
|
2024-08-12 17:14:27 -04:00
|
|
|
|
2024-08-15 00:34:36 -04:00
|
|
|
/// Handles incoming messages
|
2024-10-13 17:04:28 -04:00
|
|
|
pub async fn handle(&mut self, message: GameHandlerMessage) {
|
2024-08-14 20:38:19 -04:00
|
|
|
match message {
|
2024-12-13 04:38:14 -05:00
|
|
|
NewGame(request, host) => self.create_new_game(request, host).await,
|
|
|
|
JoinGame(request, user) => self.join_game(request, user).await,
|
|
|
|
MoveRequest(move_request, player_user) => {
|
|
|
|
self.handle_player_move(move_request, player_user).await
|
|
|
|
}
|
|
|
|
JudgeDecision(request, player_user_id) => {
|
|
|
|
self.handle_judging(request, player_user_id).await
|
|
|
|
}
|
2024-08-22 16:15:18 -04:00
|
|
|
DeleteGame(request) => self.delete_game(request).await,
|
2024-09-03 14:02:14 -04:00
|
|
|
SendGameStateUpdate(game_ids) => self.send_game_state_update_all(game_ids),
|
|
|
|
SendGameMetaUpdate(game_ids) => self.send_game_meta_update(game_ids),
|
2024-12-11 23:20:44 -05:00
|
|
|
SendGameUserUpdate(user_id) => self.send_game_user_update(user_id),
|
2024-10-11 23:13:35 -04:00
|
|
|
BroadcastGamesUpdate() => self.broadcast_game_browser_update(),
|
2024-11-21 12:41:17 -05:00
|
|
|
SendCardPacks(tx) => self.send_card_packs(tx).await,
|
2024-08-20 22:25:39 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-22 16:15:18 -04:00
|
|
|
/// Delete game
|
2024-10-13 17:04:28 -04:00
|
|
|
async fn delete_game(&mut self, request: GameDeleteRequest) {
|
2024-08-22 16:15:18 -04:00
|
|
|
// TODO: add auth lol
|
2024-10-13 17:04:28 -04:00
|
|
|
if self.games.remove(&request.delete_game_id).is_some() {
|
2024-10-11 23:13:35 -04:00
|
|
|
self.broadcast_game_browser_update();
|
2024-08-27 22:03:27 -04:00
|
|
|
} 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
|
2024-12-13 04:38:14 -05:00
|
|
|
async fn handle_judging(&mut self, request: JudgeDecisionRequest, player_user_id: String) {
|
2024-10-13 17:04:28 -04:00
|
|
|
if let Some(this_game) = self.games.get_mut(&request.game_id) {
|
2024-12-13 04:38:14 -05:00
|
|
|
let game_id = request.game_id.to_string();
|
2024-08-27 22:03:27 -04:00
|
|
|
|
2024-12-13 04:38:14 -05:00
|
|
|
// Send to game
|
|
|
|
this_game.judge_round(&request, player_user_id);
|
2024-08-27 22:03:27 -04:00
|
|
|
|
2024-12-13 04:38:14 -05:00
|
|
|
self.send_game_state_update_all(vec![game_id.clone()]);
|
|
|
|
self.send_game_meta_update(vec![game_id]);
|
2024-08-27 22:03:27 -04:00
|
|
|
} else {
|
|
|
|
tracing::error!("Received judge request for nonexistent game!");
|
|
|
|
}
|
2024-09-03 14:02:14 -04:00
|
|
|
|
|
|
|
// Send updates for all players
|
|
|
|
self.send_game_state_update_all(vec![request.game_id.clone()]);
|
|
|
|
self.send_game_meta_update(vec![request.game_id]);
|
2024-08-17 21:55:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Process player move request
|
2024-12-13 04:38:14 -05:00
|
|
|
async fn handle_player_move(
|
|
|
|
&mut self,
|
|
|
|
request: PlayerMoveRequest,
|
|
|
|
player_user: Arc<RwLock<User>>,
|
|
|
|
) {
|
2024-10-13 17:04:28 -04:00
|
|
|
if let Some(this_game) = self.games.get_mut(&request.game_id) {
|
2024-12-13 04:38:14 -05:00
|
|
|
let player_user_id = player_user.read().unwrap().uuid.to_string();
|
|
|
|
|
|
|
|
// Do the stuff
|
|
|
|
match this_game.player_move(&request, player_user_id.clone()) {
|
|
|
|
Err(err) => {
|
|
|
|
let message = ChatMessage { text: err };
|
|
|
|
let users_tx = self.state.tx_user_handler.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
if let Err(e) = users_tx
|
|
|
|
.send(UserHandlerMessage::DmUser(
|
|
|
|
SendChatMessage(message),
|
|
|
|
Id(player_user_id),
|
|
|
|
))
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
tracing::error!("Could not send message: {}", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Ok(None) => {
|
|
|
|
tracing::debug!("TODO: whatever i'm supposed to do")
|
|
|
|
}
|
|
|
|
Ok(Some((judge_round, czar_id))) => {
|
|
|
|
let users_tx = self.state.tx_user_handler.clone();
|
|
|
|
tokio::spawn(async move {
|
|
|
|
if let Err(e) = users_tx
|
|
|
|
.send(UserHandlerMessage::DmUser(
|
|
|
|
SendJudgeRound(judge_round),
|
|
|
|
Id(czar_id),
|
|
|
|
))
|
|
|
|
.await
|
|
|
|
{
|
|
|
|
tracing::error!("Could not send message: {}", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2024-08-27 22:03:27 -04:00
|
|
|
} else {
|
|
|
|
tracing::error!("Player tried to submit move for nonexistent game!");
|
|
|
|
}
|
2024-09-03 14:02:14 -04:00
|
|
|
self.send_game_meta_update(vec![request.game_id]);
|
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-12-13 04:38:14 -05:00
|
|
|
async fn join_game(&mut self, game_id: String, this_user: Arc<RwLock<User>>) {
|
2024-10-13 17:04:28 -04:00
|
|
|
if self.games.contains_key(&game_id) {
|
2024-12-13 04:38:14 -05:00
|
|
|
let this_user_id = this_user.read().unwrap().uuid.clone();
|
2024-08-30 00:08:49 -04:00
|
|
|
|
2024-12-13 04:38:14 -05:00
|
|
|
// Register game to user
|
|
|
|
if !self.game_id_by_user_id.contains_key(&this_user_id) {
|
|
|
|
self.game_id_by_user_id
|
|
|
|
.insert(this_user_id.clone(), vec![game_id.clone()]);
|
|
|
|
} else if self.game_id_by_user_id.contains_key(&this_user_id) {
|
|
|
|
self.game_id_by_user_id
|
|
|
|
.get_mut(&this_user_id)
|
2024-10-13 17:04:28 -04:00
|
|
|
.unwrap()
|
2024-12-13 04:38:14 -05:00
|
|
|
.extend(vec![game_id.clone()]);
|
2024-08-27 22:03:27 -04:00
|
|
|
}
|
2024-12-13 04:38:14 -05:00
|
|
|
|
|
|
|
// Create player
|
|
|
|
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())
|
2024-08-27 22:03:27 -04:00
|
|
|
} else {
|
|
|
|
tracing::error!("User tried to join a nonexistent game!");
|
|
|
|
return;
|
|
|
|
}
|
2024-08-18 19:11:38 -04:00
|
|
|
|
2024-08-14 20:38:19 -04:00
|
|
|
// Send updates for all players
|
2024-09-03 14:02:14 -04:00
|
|
|
self.send_game_meta_update(vec![game_id.clone()]);
|
2024-08-21 22:05:13 -04:00
|
|
|
|
2024-10-11 23:13:35 -04:00
|
|
|
self.broadcast_game_browser_update();
|
2024-10-12 01:21:42 -04:00
|
|
|
self.broadcast_game_count();
|
2024-08-21 22:05:13 -04:00
|
|
|
}
|
|
|
|
|
2024-09-03 14:02:14 -04:00
|
|
|
/// Send game meta update for all players of a game
|
|
|
|
fn send_game_meta_update(&self, game_ids: Vec<String>) {
|
2024-08-30 00:08:49 -04:00
|
|
|
for game_id in game_ids {
|
2024-10-13 17:04:28 -04:00
|
|
|
if let Some(this_game) = self.games.get(&game_id) {
|
2024-08-30 00:08:49 -04:00
|
|
|
let players = this_game
|
|
|
|
.players
|
|
|
|
.values()
|
|
|
|
.map(|player| GamePlayerMeta {
|
|
|
|
name: player.user.read().unwrap().name.clone(),
|
2024-11-15 19:39:48 -05:00
|
|
|
score: player.black.len().try_into().unwrap(),
|
2024-09-03 14:02:14 -04:00
|
|
|
submitted: this_game
|
|
|
|
.judge_pile_meta
|
|
|
|
.values()
|
|
|
|
.collect::<Vec<&String>>()
|
|
|
|
.contains(&&player.user.read().unwrap().uuid),
|
2024-08-30 00:08:49 -04:00
|
|
|
})
|
|
|
|
.collect::<Vec<GamePlayerMeta>>();
|
2024-08-27 22:03:27 -04:00
|
|
|
|
2024-10-13 17:04:28 -04:00
|
|
|
for player in this_game.players.values() {
|
2024-08-30 00:08:49 -04:00
|
|
|
// Create update for user's game view
|
2024-09-03 14:02:14 -04:00
|
|
|
let meta = GameMeta {
|
2024-08-30 00:08:49 -04:00
|
|
|
uuid: game_id.clone(),
|
2024-10-13 17:04:28 -04:00
|
|
|
name: this_game.name.clone(),
|
|
|
|
host: this_game.host.read().unwrap().name.clone(),
|
2024-08-30 00:08:49 -04:00
|
|
|
players: players.clone(),
|
2024-10-13 17:04:28 -04:00
|
|
|
czar: this_game.czar.read().unwrap().name.clone(),
|
|
|
|
packs: this_game.packs.clone(),
|
2024-11-15 19:39:48 -05:00
|
|
|
white_count: this_game.white.len().try_into().unwrap(),
|
|
|
|
black_count: this_game.black.len().try_into().unwrap(),
|
|
|
|
white_discard_count: this_game.white_discard.len().try_into().unwrap(),
|
2024-09-03 14:02:14 -04:00
|
|
|
};
|
|
|
|
|
2024-12-02 22:50:49 -05:00
|
|
|
let tx = self.state.tx_outgoing_message_handler.clone();
|
2024-09-03 14:02:14 -04:00
|
|
|
let user_tx = player.user.read().unwrap().tx.clone();
|
2024-10-10 01:19:52 -04:00
|
|
|
tokio::spawn(async move {
|
2024-10-10 04:15:25 -04:00
|
|
|
// channel can still close after this point but it'll catch most of it
|
|
|
|
// TODO: handle this later? make this situation impossible to begin with?
|
|
|
|
if !user_tx.is_closed() {
|
2024-12-02 22:50:49 -05:00
|
|
|
if let Err(e) = tx
|
|
|
|
.send(Unicast((user_tx, ServerToClientMessage::GameMeta(meta))))
|
|
|
|
.await
|
|
|
|
{
|
2024-10-10 04:15:25 -04:00
|
|
|
tracing::error!("Error sending user update: {}", e)
|
|
|
|
}
|
2024-10-10 01:19:52 -04:00
|
|
|
}
|
|
|
|
});
|
2024-09-03 14:02:14 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tracing::error!("Attempted to create game meta update for nonexistent game!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-11 23:20:44 -05:00
|
|
|
/// Send game meta update for all players of a game
|
|
|
|
fn send_game_user_update(&self, user_id: String) {
|
|
|
|
if self.game_id_by_user_id.contains_key(&user_id) {
|
|
|
|
let game_ids = self.game_id_by_user_id.get(&user_id).unwrap().to_vec();
|
|
|
|
self.send_game_meta_update(game_ids);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-03 14:02:14 -04:00
|
|
|
/// 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 {
|
2024-10-13 17:04:28 -04:00
|
|
|
if let Some(this_game) = self.games.get(&game_id) {
|
|
|
|
for player in this_game.players.values() {
|
2024-09-03 14:02:14 -04:00
|
|
|
// Create update for user's game view
|
|
|
|
let meta = GameStateMeta {
|
2024-11-15 21:41:21 -05:00
|
|
|
black: Some(BlackCardMeta {
|
|
|
|
text: this_game.current_black.text.clone(),
|
|
|
|
pick: this_game.current_black.pick.try_into().unwrap(),
|
|
|
|
}),
|
2024-08-30 00:08:49 -04:00
|
|
|
white: player
|
|
|
|
.white
|
|
|
|
.iter()
|
|
|
|
.map(|card| WhiteCardMeta {
|
|
|
|
uuid: card.uuid.to_string(),
|
|
|
|
text: card.text.clone(),
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
};
|
2024-08-27 22:03:27 -04:00
|
|
|
|
2024-08-30 00:08:49 -04:00
|
|
|
// Send user's update
|
2024-12-02 22:50:49 -05:00
|
|
|
let tx = self.state.tx_outgoing_message_handler.clone();
|
2024-08-30 00:08:49 -04:00
|
|
|
let user_tx = player.user.read().unwrap().tx.clone();
|
2024-12-02 22:50:49 -05:00
|
|
|
tokio::spawn(async move {
|
|
|
|
tx.send(Unicast((
|
|
|
|
user_tx,
|
|
|
|
ServerToClientMessage::GameStateMeta(meta),
|
|
|
|
)))
|
|
|
|
.await
|
|
|
|
});
|
2024-08-30 00:08:49 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tracing::error!("Attempted to create game state update for nonexistent game!");
|
2024-08-27 22:03:27 -04:00
|
|
|
}
|
2024-08-12 17:14:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-03 14:02:14 -04:00
|
|
|
/// Send game state update for a single user
|
|
|
|
fn send_game_state_update_single(&self, user_id: String, game_id: String) {
|
2024-10-13 17:04:28 -04:00
|
|
|
if let Some(this_game) = self.games.get(&game_id) {
|
|
|
|
if let Some(player) = this_game.players.get(&user_id) {
|
2024-09-03 14:02:14 -04:00
|
|
|
// Create update for user's game view
|
|
|
|
let meta = GameStateMeta {
|
2024-11-15 21:41:21 -05:00
|
|
|
black: Some(BlackCardMeta {
|
|
|
|
text: this_game.current_black.text.clone(),
|
|
|
|
pick: this_game.current_black.pick.try_into().unwrap(),
|
|
|
|
}),
|
2024-09-03 14:02:14 -04:00
|
|
|
white: player
|
|
|
|
.white
|
|
|
|
.iter()
|
|
|
|
.map(|card| WhiteCardMeta {
|
|
|
|
uuid: card.uuid.to_string(),
|
|
|
|
text: card.text.clone(),
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Send user's update
|
2024-12-02 22:50:49 -05:00
|
|
|
let tx = self.state.tx_outgoing_message_handler.clone();
|
2024-09-03 14:02:14 -04:00
|
|
|
let user_tx = player.user.read().unwrap().tx.clone();
|
2024-12-02 22:50:49 -05:00
|
|
|
tokio::spawn(async move {
|
|
|
|
tx.send(Unicast((
|
|
|
|
user_tx,
|
|
|
|
ServerToClientMessage::GameStateMeta(meta),
|
|
|
|
)))
|
|
|
|
.await
|
|
|
|
});
|
2024-09-03 14:02:14 -04:00
|
|
|
} else {
|
|
|
|
tracing::error!("Attempted to create game state update for nonexistent player!");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tracing::error!("Attempted to create game state update for nonexistent game!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-15 00:34:36 -04:00
|
|
|
/// Creates a new game
|
2024-12-13 04:38:14 -05:00
|
|
|
async fn create_new_game(&mut self, new_game: NewGameRequest, host: Arc<RwLock<User>>) {
|
2024-11-16 04:19:21 -05:00
|
|
|
if new_game.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;
|
2024-11-16 04:19:21 -05:00
|
|
|
} else if new_game.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-12-13 04:38:14 -05:00
|
|
|
let new_game_name;
|
|
|
|
let max_game_name_len = 32;
|
2024-08-15 00:14:47 -04:00
|
|
|
|
2024-12-13 04:38:14 -05:00
|
|
|
if new_game.game_name.len() > max_game_name_len {
|
|
|
|
new_game_name = new_game.game_name[..max_game_name_len].to_string()
|
2024-08-27 22:03:27 -04:00
|
|
|
} else {
|
2024-12-13 04:38:14 -05:00
|
|
|
new_game_name = new_game.game_name
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create manifest
|
|
|
|
let manifest = NewGameManifest {
|
|
|
|
name: new_game_name,
|
|
|
|
host: host.clone(),
|
|
|
|
packs: new_game
|
|
|
|
.game_packs
|
|
|
|
.into_iter()
|
|
|
|
.map(|pack| u8::from_str_radix(&pack, 10).unwrap())
|
|
|
|
.collect(),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Create game using manifest
|
|
|
|
let mut new_game_object = Game::new(&self.packs, manifest);
|
|
|
|
|
|
|
|
// Don't forget to create the host player!!!
|
|
|
|
new_game_object.create_player(host.clone());
|
|
|
|
|
|
|
|
let game_id = new_game_object.uuid.to_string();
|
|
|
|
|
|
|
|
// Add game to active list
|
|
|
|
self.games
|
|
|
|
.insert(new_game_object.uuid.to_string(), new_game_object);
|
|
|
|
|
|
|
|
// Register game to user
|
|
|
|
let user_id = host.read().unwrap().uuid.clone();
|
|
|
|
if !self.game_id_by_user_id.contains_key(&user_id) {
|
|
|
|
self.game_id_by_user_id
|
|
|
|
.insert(user_id.clone(), vec![game_id.clone()]);
|
|
|
|
} else if self.game_id_by_user_id.contains_key(&user_id) {
|
|
|
|
self.game_id_by_user_id
|
|
|
|
.get_mut(&user_id)
|
|
|
|
.unwrap()
|
|
|
|
.extend(vec![game_id.clone()]);
|
2024-08-27 22:03:27 -04:00
|
|
|
}
|
2024-12-13 04:38:14 -05:00
|
|
|
self.send_game_state_update_all(vec![game_id.clone()]);
|
|
|
|
self.send_game_meta_update(vec![game_id]);
|
|
|
|
|
|
|
|
self.broadcast_game_browser_update();
|
|
|
|
self.broadcast_game_count();
|
2024-08-14 20:38:19 -04:00
|
|
|
}
|
2024-10-11 23:09:19 -04:00
|
|
|
|
|
|
|
/// Generate games list update
|
2024-10-11 23:13:35 -04:00
|
|
|
fn broadcast_game_browser_update(&self) {
|
2024-10-11 23:09:19 -04:00
|
|
|
// TODO: this may get expensive if there are many games
|
|
|
|
|
|
|
|
let games = self
|
|
|
|
.games
|
|
|
|
.values()
|
|
|
|
.map(|game| GameBrowserMeta {
|
2024-10-13 17:04:28 -04:00
|
|
|
uuid: game.uuid.to_string(),
|
|
|
|
name: game.name.clone(),
|
|
|
|
host: game.host.read().unwrap().name.clone(),
|
2024-11-16 04:19:21 -05:00
|
|
|
players: game.players.len().try_into().unwrap(),
|
2024-10-13 17:04:28 -04:00
|
|
|
packs: game.packs.clone(),
|
2024-10-11 23:09:19 -04:00
|
|
|
})
|
|
|
|
.collect::<Vec<GameBrowserMeta>>();
|
|
|
|
|
2024-12-02 22:50:49 -05:00
|
|
|
let tx = self.state.tx_outgoing_message_handler.clone();
|
2024-10-11 23:09:19 -04:00
|
|
|
tokio::spawn(async move {
|
2024-12-02 22:50:49 -05:00
|
|
|
if let Err(e) = tx
|
2024-12-03 19:40:15 -05:00
|
|
|
.send(Broadcast(ServerToClientMessage::GamesUpdate(GamesUpdate {
|
|
|
|
games,
|
|
|
|
})))
|
2024-12-02 22:50:49 -05:00
|
|
|
.await
|
|
|
|
{
|
2024-10-11 23:09:19 -04:00
|
|
|
tracing::error!("Error broadcasting games update: {}", e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2024-10-12 01:21:42 -04:00
|
|
|
|
|
|
|
/// Broadcast updated game count
|
|
|
|
fn broadcast_game_count(&self) {
|
2024-12-02 22:50:49 -05:00
|
|
|
let tx = self.state.tx_outgoing_message_handler.clone();
|
2024-11-16 04:19:21 -05:00
|
|
|
let active_games: u32 = self.games.len().try_into().unwrap();
|
2024-12-02 22:50:49 -05:00
|
|
|
let msg = ServerActiveGames { active_games };
|
2024-10-13 18:29:13 -04:00
|
|
|
tokio::spawn(async move {
|
2024-12-02 22:50:49 -05:00
|
|
|
if let Err(e) = tx
|
2024-12-03 19:40:15 -05:00
|
|
|
.send(Broadcast(ServerToClientMessage::ServerActiveGames(msg)))
|
2024-12-02 22:50:49 -05:00
|
|
|
.await
|
|
|
|
{
|
2024-10-13 18:29:13 -04:00
|
|
|
tracing::error!("Error broadcasting game count: {}", e);
|
|
|
|
}
|
|
|
|
});
|
2024-10-12 01:21:42 -04:00
|
|
|
}
|
2024-11-21 12:41:17 -05:00
|
|
|
|
|
|
|
/// Send available card packs to a user
|
|
|
|
async fn send_card_packs(&self, tx: Sender<Message>) {
|
2024-12-02 22:50:49 -05:00
|
|
|
let msg = ServerToClientMessage::CardPacksMeta(self.packs_meta.clone());
|
|
|
|
if let Err(e) = self
|
|
|
|
.state
|
|
|
|
.tx_outgoing_message_handler
|
|
|
|
.send(Unicast((tx, msg)))
|
|
|
|
.await
|
|
|
|
{
|
2024-11-21 12:41:17 -05:00
|
|
|
tracing::error!("Error sending card packs: {}", e)
|
|
|
|
}
|
|
|
|
}
|
2024-08-12 17:14:27 -04:00
|
|
|
}
|