update games in real time of user change
This commit is contained in:
parent
54fa246229
commit
aee5bcdefb
4 changed files with 138 additions and 61 deletions
|
@ -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,52 +196,54 @@ 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>) {
|
||||||
if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) {
|
for game_id in game_ids {
|
||||||
let players = this_game
|
if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) {
|
||||||
.read()
|
let players = this_game
|
||||||
.unwrap()
|
.read()
|
||||||
.players
|
.unwrap()
|
||||||
.values()
|
.players
|
||||||
.map(|player| GamePlayerMeta {
|
.values()
|
||||||
name: player.user.read().unwrap().name.clone(),
|
.map(|player| GamePlayerMeta {
|
||||||
score: player.black.len(),
|
name: player.user.read().unwrap().name.clone(),
|
||||||
})
|
score: player.black.len(),
|
||||||
.collect::<Vec<GamePlayerMeta>>();
|
})
|
||||||
|
.collect::<Vec<GamePlayerMeta>>();
|
||||||
|
|
||||||
for player in this_game.read().unwrap().players.values() {
|
for player in this_game.read().unwrap().players.values() {
|
||||||
// Create update for user's game view
|
// Create update for user's game view
|
||||||
let meta = GameStateMeta {
|
let meta = GameStateMeta {
|
||||||
uuid: game_id.clone(),
|
uuid: game_id.clone(),
|
||||||
name: this_game.read().unwrap().name.clone(),
|
name: this_game.read().unwrap().name.clone(),
|
||||||
host: this_game.read().unwrap().host.read().unwrap().name.clone(),
|
host: this_game.read().unwrap().host.read().unwrap().name.clone(),
|
||||||
players: players.clone(),
|
players: players.clone(),
|
||||||
czar: this_game.read().unwrap().czar.read().unwrap().name.clone(),
|
czar: this_game.read().unwrap().czar.read().unwrap().name.clone(),
|
||||||
black: (
|
black: (
|
||||||
this_game.read().unwrap().current_black.text.clone(),
|
this_game.read().unwrap().current_black.text.clone(),
|
||||||
this_game.read().unwrap().current_black.pick,
|
this_game.read().unwrap().current_black.pick,
|
||||||
),
|
),
|
||||||
white: player
|
white: player
|
||||||
.white
|
.white
|
||||||
.iter()
|
.iter()
|
||||||
.map(|card| WhiteCardMeta {
|
.map(|card| WhiteCardMeta {
|
||||||
uuid: card.uuid.to_string(),
|
uuid: card.uuid.to_string(),
|
||||||
text: card.text.clone(),
|
text: card.text.clone(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
packs: this_game.read().unwrap().packs.clone(),
|
packs: this_game.read().unwrap().packs.clone(),
|
||||||
white_count: this_game.read().unwrap().white.len(),
|
white_count: this_game.read().unwrap().white.len(),
|
||||||
black_count: this_game.read().unwrap().black.len(),
|
black_count: this_game.read().unwrap().black.len(),
|
||||||
white_discard_count: this_game.read().unwrap().white_discard.len(),
|
white_discard_count: this_game.read().unwrap().white_discard.len(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send user's update
|
// Send user's update
|
||||||
let msg = serde_json::to_string(&meta).unwrap();
|
let msg = serde_json::to_string(&meta).unwrap();
|
||||||
let user_tx = player.user.read().unwrap().tx.clone();
|
let user_tx = player.user.read().unwrap().tx.clone();
|
||||||
tokio::spawn(async move { user_tx.send(msg).await });
|
tokio::spawn(async move { user_tx.send(msg).await });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracing::error!("Attempted to create game state update for nonexistent game!");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
tracing::error!("Attempted to create game state update for nonexistent game!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue