update games in real time of user change

This commit is contained in:
Adam 2024-08-30 00:08:49 -04:00
parent 54fa246229
commit aee5bcdefb
4 changed files with 138 additions and 61 deletions

View file

@ -12,12 +12,14 @@ use std::{
}; };
/// For interacting with the game handler /// For interacting with the game handler
#[derive(Debug)]
pub enum GameHandlerMessage { pub enum GameHandlerMessage {
NewGame(NewGameRequest, SocketAddr), NewGame(NewGameRequest, SocketAddr),
JoinGame(String, SocketAddr), JoinGame(String, SocketAddr),
MoveRequest(PlayerMoveRequest, SocketAddr), MoveRequest(PlayerMoveRequest, SocketAddr),
JudgeDecision(JudgeDecisionRequest, SocketAddr), JudgeDecision(JudgeDecisionRequest, SocketAddr),
DeleteGame(GameDeleteRequest), DeleteGame(GameDeleteRequest),
SendGameUpdate(Vec<String>),
} }
/// Handles game stuff /// Handles game stuff
@ -40,6 +42,7 @@ impl GameHandler {
MoveRequest(request, addr) => self.handle_player_move(request, addr).await, MoveRequest(request, addr) => self.handle_player_move(request, addr).await,
JudgeDecision(request, addr) => self.handle_judging(request, addr).await, JudgeDecision(request, addr) => self.handle_judging(request, addr).await,
DeleteGame(request) => self.delete_game(request).await, DeleteGame(request) => self.delete_game(request).await,
SendGameUpdate(game_ids) => self.send_game_state_update(game_ids),
} }
} }
@ -77,7 +80,7 @@ impl GameHandler {
.unwrap() .unwrap()
.judge_round(request, player_user_id); .judge_round(request, player_user_id);
self.send_game_state_update(game_id); self.send_game_state_update(vec![game_id]);
} else { } else {
tracing::error!("Received judge request for nonexistent judge player!"); tracing::error!("Received judge request for nonexistent judge player!");
} }
@ -124,10 +127,46 @@ impl GameHandler {
} }
} }
// Ties game ids to user for easier lookup
fn register_user_in_game(&self, game_id: String, user_id: String) {
if !self
.state
.games_by_user
.read()
.unwrap()
.contains_key(&user_id)
{
self.state
.games_by_user
.write()
.unwrap()
.insert(user_id, vec![game_id]);
} else if self
.state
.games_by_user
.read()
.unwrap()
.contains_key(&user_id)
{
self.state
.games_by_user
.write()
.unwrap()
.get_mut(&user_id)
.unwrap()
.extend(vec![game_id]);
}
}
/// Puts a user in a game /// Puts a user in a game
async fn join_game(&self, id: String, addr: SocketAddr) { 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_game) = self.state.games.read().unwrap().get(&id) {
if let Some(this_user) = self.state.online_users.read().unwrap().get(&addr) { if let Some(this_user) = self.state.online_users.read().unwrap().get(&addr) {
let this_user_id = this_user.read().unwrap().uuid.clone();
// Register game to user
self.register_user_in_game(id.clone(), this_user_id);
// Create player // Create player
this_game.write().unwrap().create_player(this_user.clone()); this_game.write().unwrap().create_player(this_user.clone());
} else { } else {
@ -138,9 +177,10 @@ impl GameHandler {
tracing::error!("User tried to join a nonexistent game!"); tracing::error!("User tried to join a nonexistent game!");
return; return;
} }
tracing::debug!("{:#?}", self.state.games_by_user.read().unwrap());
// Send updates for all players // Send updates for all players
self.send_game_state_update(id); self.send_game_state_update(vec![id]);
// Broadcast game browser update // Broadcast game browser update
self.state self.state
@ -156,7 +196,8 @@ impl GameHandler {
} }
/// Send game state update for all players of a game /// Send game state update for all players of a game
fn send_game_state_update(&self, game_id: String) { fn send_game_state_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.state.games.read().unwrap().get(&game_id) {
let players = this_game let players = this_game
.read() .read()
@ -204,6 +245,7 @@ impl GameHandler {
tracing::error!("Attempted to create game state update for nonexistent game!"); tracing::error!("Attempted to create game state update for nonexistent game!");
} }
} }
}
/// Creates a new game /// Creates a new game
async fn create_new_game(&self, new_game: NewGameRequest, addr: SocketAddr) { async fn create_new_game(&self, new_game: NewGameRequest, addr: SocketAddr) {
@ -237,7 +279,10 @@ impl GameHandler {
Arc::new(RwLock::new(new_game_object)), Arc::new(RwLock::new(new_game_object)),
); );
self.send_game_state_update(game_id); // Register game to user
self.register_user_in_game(game_id.clone(), host.read().unwrap().uuid.clone());
self.send_game_state_update(vec![game_id]);
// Broadcast game browser update // Broadcast game browser update
self.state self.state

View file

@ -71,6 +71,7 @@ pub struct AppState {
pub last_names: Vec<String>, pub last_names: Vec<String>,
pub reserved_names: RwLock<HashSet<String>>, pub reserved_names: RwLock<HashSet<String>>,
pub users_by_id: RwLock<HashMap<String, Arc<RwLock<User>>>>, pub users_by_id: RwLock<HashMap<String, Arc<RwLock<User>>>>,
pub games_by_user: RwLock<HashMap<String, Vec<String>>>,
pub online_users: RwLock<HashMap<SocketAddr, Arc<RwLock<User>>>>, pub online_users: RwLock<HashMap<SocketAddr, Arc<RwLock<User>>>>,
pub offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>, pub offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>,
pub packs: CardPacks, pub packs: CardPacks,

View file

@ -35,6 +35,7 @@ async fn main() -> Result<()> {
let last_names = load_names("data/last.txt")?; let last_names = load_names("data/last.txt")?;
let reserved_names = RwLock::new(HashSet::<String>::new()); let reserved_names = RwLock::new(HashSet::<String>::new());
let users_by_id = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::new()); let users_by_id = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::new());
let games_by_user = RwLock::new(HashMap::<String, Vec<String>>::new());
let online_users = RwLock::new(HashMap::<SocketAddr, Arc<RwLock<User>>>::new()); let online_users = RwLock::new(HashMap::<SocketAddr, Arc<RwLock<User>>>::new());
let offline_users = RwLock::new(HashMap::<String, 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 (packs, packs_meta, white_cards_by_id) = load_cards_from_json("data/cah-cards-full.json")?;
@ -50,6 +51,7 @@ async fn main() -> Result<()> {
last_names, last_names,
reserved_names, reserved_names,
users_by_id, users_by_id,
games_by_user,
online_users, online_users,
offline_users, offline_users,
packs, packs,

View file

@ -3,7 +3,7 @@ use crate::DmUserMethod::*;
use crate::SendUserMessage::*; use crate::SendUserMessage::*;
use crate::User; use crate::User;
use crate::UserHandlerMessage::*; use crate::UserHandlerMessage::*;
use lib::*; use crate::*;
use serde_json::to_string; use serde_json::to_string;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -245,6 +245,35 @@ impl UserHandler {
Addr(addr), Addr(addr),
) )
.await; .await;
// Update games this user is in
if let Some(user) = &self.state.online_users.read().unwrap().get(&addr) {
let user_id = user.read().unwrap().uuid.to_string();
{
if self
.state
.games_by_user
.read()
.unwrap()
.contains_key(&user_id)
{
let msg = GameHandlerMessage::SendGameUpdate(
self.state
.games_by_user
.read()
.unwrap()
.get(&user_id)
.unwrap()
.to_vec(),
);
let tx = self.state.games_tx.clone();
tokio::spawn(async move {
tracing::debug!("msg: {:#?}", &msg);
let _ = tx.send(msg).await;
});
}
}
}
// Send client updates // Send client updates
let _ = broadcast_tx.send(meta_games_browser_update(&self.state)); let _ = broadcast_tx.send(meta_games_browser_update(&self.state));
let _ = broadcast_tx.send(meta_chat_update(&self.state)); let _ = broadcast_tx.send(meta_chat_update(&self.state));
@ -275,6 +304,20 @@ pub fn meta_chat_update(state: &Arc<AppState>) -> String {
.unwrap() .unwrap()
} }
/// Generate chatroom join announcement
pub fn meta_announce_user_join(state: &Arc<AppState>, addr: &SocketAddr) -> String {
let msg = format!("{} joined.", {
if let Some(user) = state.online_users.read().unwrap().get(addr) {
user.read().unwrap().name.clone()
} else {
return Default::default();
}
});
tracing::debug!("{}", &msg);
to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap()
}
/// Generage cards meta message /// Generage cards meta message
pub fn meta_new_game_card_packs(state: &Arc<AppState>) -> String { pub fn meta_new_game_card_packs(state: &Arc<AppState>) -> String {
to_string::<CardPacksMeta>(&state.packs_meta).unwrap() to_string::<CardPacksMeta>(&state.packs_meta).unwrap()
@ -316,17 +359,3 @@ pub fn meta_games_browser_update(state: &Arc<AppState>) -> String {
to_string::<GamesUpdate>(&GamesUpdate { games }).unwrap() to_string::<GamesUpdate>(&GamesUpdate { games }).unwrap()
} }
/// Generate chatroom join announcement
pub fn meta_announce_user_join(state: &Arc<AppState>, addr: &SocketAddr) -> String {
let msg = format!("{} joined.", {
if let Some(user) = state.online_users.read().unwrap().get(addr) {
user.read().unwrap().name.clone()
} else {
return Default::default();
}
});
tracing::debug!("{}", &msg);
to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap()
}