let game handler own the games
This commit is contained in:
parent
3fb3d2f521
commit
c8375d1b15
4 changed files with 60 additions and 84 deletions
|
@ -142,7 +142,7 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Judge Game
|
/// Judge Game
|
||||||
pub fn judge_round(&mut self, request: JudgeDecisionRequest, player_user_id: String) {
|
pub fn judge_round(&mut self, request: &JudgeDecisionRequest, player_user_id: String) {
|
||||||
// Check if player is czar
|
// Check if player is czar
|
||||||
if self.czar.read().unwrap().uuid.to_string() == player_user_id {
|
if self.czar.read().unwrap().uuid.to_string() == player_user_id {
|
||||||
if let Some(winner_id) = self.judge_pile_meta.get(&request.winning_cards) {
|
if let Some(winner_id) = self.judge_pile_meta.get(&request.winning_cards) {
|
||||||
|
@ -158,7 +158,7 @@ impl Game {
|
||||||
/// Process player move
|
/// Process player move
|
||||||
pub fn player_move(
|
pub fn player_move(
|
||||||
&mut self,
|
&mut self,
|
||||||
request: PlayerMoveRequest,
|
request: &PlayerMoveRequest,
|
||||||
player_user_id: String,
|
player_user_id: String,
|
||||||
) -> Result<Option<(JudgeRound, String)>, String> {
|
) -> Result<Option<(JudgeRound, String)>, String> {
|
||||||
if self.czar.read().unwrap().uuid == player_user_id {
|
if self.czar.read().unwrap().uuid == player_user_id {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::game::*;
|
use crate::game::*;
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use crate::DmUserMethod::*;
|
use crate::DmUserMethod::*;
|
||||||
use crate::GameHandlerMessage::*;
|
use crate::GameHandlerMessage::*;
|
||||||
|
@ -6,10 +7,8 @@ use crate::SendUserMessage::*;
|
||||||
use crate::UserHandlerMessage::*;
|
use crate::UserHandlerMessage::*;
|
||||||
use lib::*;
|
use lib::*;
|
||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
use std::{
|
use std::collections::HashMap;
|
||||||
net::SocketAddr,
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
sync::{Arc, RwLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// For interacting with the game handler
|
/// For interacting with the game handler
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -28,20 +27,22 @@ pub enum GameHandlerMessage {
|
||||||
pub struct GameHandler {
|
pub struct GameHandler {
|
||||||
/// Global state pointer
|
/// Global state pointer
|
||||||
state: Arc<AppState>,
|
state: Arc<AppState>,
|
||||||
|
games: HashMap<String, Game>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameHandler {
|
impl GameHandler {
|
||||||
/// Returns a new game handler
|
/// Returns a new game handler
|
||||||
pub fn new(state: Arc<AppState>) -> Self {
|
pub fn new(state: Arc<AppState>) -> Self {
|
||||||
GameHandler { state }
|
let games = HashMap::new();
|
||||||
|
GameHandler { state, games }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles incoming messages
|
/// Handles incoming messages
|
||||||
pub async fn handle(&self, message: GameHandlerMessage) {
|
pub async fn handle(&mut self, message: GameHandlerMessage) {
|
||||||
match message {
|
match message {
|
||||||
NewGame(request, addr) => self.create_new_game(request, addr).await,
|
NewGame(request, addr) => self.create_new_game(request, addr).await,
|
||||||
JoinGame(request, addr) => self.join_game(request, addr).await,
|
JoinGame(request, addr) => self.join_game(request, addr).await,
|
||||||
MoveRequest(request, addr) => self.handle_player_move(request, addr).await,
|
MoveRequest(request, addr) => self.handle_player_move(request, addr),
|
||||||
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,
|
||||||
SendGameStateUpdate(game_ids) => self.send_game_state_update_all(game_ids),
|
SendGameStateUpdate(game_ids) => self.send_game_state_update_all(game_ids),
|
||||||
|
@ -51,16 +52,9 @@ impl GameHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete game
|
/// Delete game
|
||||||
async fn delete_game(&self, request: GameDeleteRequest) {
|
async fn delete_game(&mut self, request: GameDeleteRequest) {
|
||||||
// TODO: add auth lol
|
// TODO: add auth lol
|
||||||
if self
|
if self.games.remove(&request.delete_game_id).is_some() {
|
||||||
.state
|
|
||||||
.games
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.remove(&request.delete_game_id)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
self.broadcast_game_browser_update();
|
self.broadcast_game_browser_update();
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("User tried to delete a nonexistent game!");
|
tracing::error!("User tried to delete a nonexistent game!");
|
||||||
|
@ -68,17 +62,14 @@ impl GameHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process judging
|
/// Process judging
|
||||||
async fn handle_judging(&self, request: JudgeDecisionRequest, addr: SocketAddr) {
|
async fn handle_judging(&mut self, request: JudgeDecisionRequest, addr: SocketAddr) {
|
||||||
if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) {
|
if let Some(this_game) = self.games.get_mut(&request.game_id) {
|
||||||
if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) {
|
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 player_user_id = player_user.read().unwrap().uuid.to_string();
|
||||||
let game_id = request.game_id.to_string();
|
let game_id = request.game_id.to_string();
|
||||||
|
|
||||||
// Send to game
|
// Send to game
|
||||||
this_game
|
this_game.judge_round(&request, player_user_id);
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.judge_round(request.clone(), player_user_id);
|
|
||||||
|
|
||||||
self.send_game_state_update_all(vec![game_id.clone()]);
|
self.send_game_state_update_all(vec![game_id.clone()]);
|
||||||
self.send_game_meta_update(vec![game_id]);
|
self.send_game_meta_update(vec![game_id]);
|
||||||
|
@ -95,44 +86,38 @@ impl GameHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process player move request
|
/// Process player move request
|
||||||
async fn handle_player_move(&self, request: PlayerMoveRequest, addr: SocketAddr) {
|
fn handle_player_move(&mut self, request: PlayerMoveRequest, addr: SocketAddr) {
|
||||||
if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) {
|
if let Some(this_game) = self.games.get_mut(&request.game_id) {
|
||||||
if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) {
|
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 player_user_id = player_user.read().unwrap().uuid.to_string();
|
||||||
|
|
||||||
// Do the stuff
|
// Do the stuff
|
||||||
match this_game
|
match this_game.player_move(&request, player_user_id) {
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.player_move(request.clone(), player_user_id)
|
|
||||||
{
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let message = ChatMessage { text: err };
|
let message = ChatMessage { text: err };
|
||||||
let tx = self.state.users_tx.clone();
|
let users_tx = self.state.users_tx.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) =
|
if let Err(e) = users_tx
|
||||||
tx.send(DmUser(SendChatMessage(message), Addr(addr))).await
|
.send(DmUser(SendChatMessage(message), Addr(addr)))
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
tracing::error!("Could not send message: {}", e);
|
tracing::error!("Could not send message: {}", e);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
tokio::spawn(
|
tracing::debug!("TODO: whatever i'm supposed to do")
|
||||||
async move { tracing::debug!("TODO: whatever i'm supposed to do") },
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Ok(Some((judge_round, czar_id))) => {
|
Ok(Some((judge_round, czar_id))) => {
|
||||||
let tx = self.state.users_tx.clone();
|
let users_tx = self.state.users_tx.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = tx
|
if let Err(e) = users_tx
|
||||||
.send(DmUser(SendJudgeRound(judge_round), Id(czar_id)))
|
.send(DmUser(SendJudgeRound(judge_round), Id(czar_id)))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
tracing::error!("Could not send message: {}", e);
|
tracing::error!("Could not send message: {}", e);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,8 +161,8 @@ impl GameHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Puts a user in a game
|
/// Puts a user in a game
|
||||||
async fn join_game(&self, game_id: String, addr: SocketAddr) {
|
async fn join_game(&mut self, game_id: String, addr: SocketAddr) {
|
||||||
if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) {
|
if self.games.contains_key(&game_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();
|
let this_user_id = this_user.read().unwrap().uuid.clone();
|
||||||
|
|
||||||
|
@ -185,7 +170,10 @@ impl GameHandler {
|
||||||
self.register_user_in_game(game_id.clone(), this_user_id.clone());
|
self.register_user_in_game(game_id.clone(), this_user_id.clone());
|
||||||
|
|
||||||
// Create player
|
// Create player
|
||||||
this_game.write().unwrap().create_player(this_user.clone());
|
self.games
|
||||||
|
.get_mut(&game_id)
|
||||||
|
.unwrap()
|
||||||
|
.create_player(this_user.clone());
|
||||||
|
|
||||||
// Send cards
|
// Send cards
|
||||||
self.send_game_state_update_single(this_user_id, game_id.clone())
|
self.send_game_state_update_single(this_user_id, game_id.clone())
|
||||||
|
@ -208,18 +196,14 @@ impl GameHandler {
|
||||||
/// Send game meta update for all players of a game
|
/// Send game meta update for all players of a game
|
||||||
fn send_game_meta_update(&self, game_ids: Vec<String>) {
|
fn send_game_meta_update(&self, game_ids: Vec<String>) {
|
||||||
for game_id in game_ids {
|
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.games.get(&game_id) {
|
||||||
let players = this_game
|
let players = this_game
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.players
|
.players
|
||||||
.values()
|
.values()
|
||||||
.map(|player| GamePlayerMeta {
|
.map(|player| GamePlayerMeta {
|
||||||
name: player.user.read().unwrap().name.clone(),
|
name: player.user.read().unwrap().name.clone(),
|
||||||
score: player.black.len(),
|
score: player.black.len(),
|
||||||
submitted: this_game
|
submitted: this_game
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.judge_pile_meta
|
.judge_pile_meta
|
||||||
.values()
|
.values()
|
||||||
.collect::<Vec<&String>>()
|
.collect::<Vec<&String>>()
|
||||||
|
@ -227,18 +211,18 @@ impl GameHandler {
|
||||||
})
|
})
|
||||||
.collect::<Vec<GamePlayerMeta>>();
|
.collect::<Vec<GamePlayerMeta>>();
|
||||||
|
|
||||||
for player in this_game.read().unwrap().players.values() {
|
for player in this_game.players.values() {
|
||||||
// Create update for user's game view
|
// Create update for user's game view
|
||||||
let meta = GameMeta {
|
let meta = GameMeta {
|
||||||
uuid: game_id.clone(),
|
uuid: game_id.clone(),
|
||||||
name: this_game.read().unwrap().name.clone(),
|
name: this_game.name.clone(),
|
||||||
host: this_game.read().unwrap().host.read().unwrap().name.clone(),
|
host: this_game.host.read().unwrap().name.clone(),
|
||||||
players: players.clone(),
|
players: players.clone(),
|
||||||
czar: this_game.read().unwrap().czar.read().unwrap().name.clone(),
|
czar: this_game.czar.read().unwrap().name.clone(),
|
||||||
packs: this_game.read().unwrap().packs.clone(),
|
packs: this_game.packs.clone(),
|
||||||
white_count: this_game.read().unwrap().white.len(),
|
white_count: this_game.white.len(),
|
||||||
black_count: this_game.read().unwrap().black.len(),
|
black_count: this_game.black.len(),
|
||||||
white_discard_count: this_game.read().unwrap().white_discard.len(),
|
white_discard_count: this_game.white_discard.len(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send user's update
|
// Send user's update
|
||||||
|
@ -263,13 +247,13 @@ 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_all(&self, game_ids: Vec<String>) {
|
fn send_game_state_update_all(&self, game_ids: Vec<String>) {
|
||||||
for game_id in game_ids {
|
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.games.get(&game_id) {
|
||||||
for player in this_game.read().unwrap().players.values() {
|
for player in this_game.players.values() {
|
||||||
// Create update for user's game view
|
// Create update for user's game view
|
||||||
let meta = GameStateMeta {
|
let meta = GameStateMeta {
|
||||||
black: (
|
black: (
|
||||||
this_game.read().unwrap().current_black.text.clone(),
|
this_game.current_black.text.clone(),
|
||||||
this_game.read().unwrap().current_black.pick,
|
this_game.current_black.pick,
|
||||||
),
|
),
|
||||||
white: player
|
white: player
|
||||||
.white
|
.white
|
||||||
|
@ -294,13 +278,13 @@ impl GameHandler {
|
||||||
|
|
||||||
/// Send game state update for a single user
|
/// Send game state update for a single user
|
||||||
fn send_game_state_update_single(&self, user_id: String, game_id: String) {
|
fn send_game_state_update_single(&self, user_id: String, game_id: String) {
|
||||||
if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) {
|
if let Some(this_game) = self.games.get(&game_id) {
|
||||||
if let Some(player) = this_game.read().unwrap().players.get(&user_id) {
|
if let Some(player) = this_game.players.get(&user_id) {
|
||||||
// Create update for user's game view
|
// Create update for user's game view
|
||||||
let meta = GameStateMeta {
|
let meta = GameStateMeta {
|
||||||
black: (
|
black: (
|
||||||
this_game.read().unwrap().current_black.text.clone(),
|
this_game.current_black.text.clone(),
|
||||||
this_game.read().unwrap().current_black.pick,
|
this_game.current_black.pick,
|
||||||
),
|
),
|
||||||
white: player
|
white: player
|
||||||
.white
|
.white
|
||||||
|
@ -325,7 +309,7 @@ impl GameHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new game
|
/// Creates a new game
|
||||||
async fn create_new_game(&self, new_game: NewGameRequest, addr: SocketAddr) {
|
async fn create_new_game(&mut self, new_game: NewGameRequest, addr: SocketAddr) {
|
||||||
if new_game.packs.is_empty() {
|
if new_game.packs.is_empty() {
|
||||||
tracing::error!("New game cards are empty!");
|
tracing::error!("New game cards are empty!");
|
||||||
return;
|
return;
|
||||||
|
@ -364,10 +348,8 @@ impl GameHandler {
|
||||||
let game_id = new_game_object.uuid.to_string();
|
let game_id = new_game_object.uuid.to_string();
|
||||||
|
|
||||||
// Add game to active list
|
// Add game to active list
|
||||||
self.state.games.write().unwrap().insert(
|
self.games
|
||||||
new_game_object.uuid.to_string(),
|
.insert(new_game_object.uuid.to_string(), new_game_object);
|
||||||
Arc::new(RwLock::new(new_game_object)),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Register game to user
|
// Register game to user
|
||||||
self.register_user_in_game(game_id.clone(), host.read().unwrap().uuid.clone());
|
self.register_user_in_game(game_id.clone(), host.read().unwrap().uuid.clone());
|
||||||
|
@ -386,17 +368,14 @@ impl GameHandler {
|
||||||
// TODO: this may get expensive if there are many games
|
// TODO: this may get expensive if there are many games
|
||||||
|
|
||||||
let games = self
|
let games = self
|
||||||
.state
|
|
||||||
.games
|
.games
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.values()
|
.values()
|
||||||
.map(|game| GameBrowserMeta {
|
.map(|game| GameBrowserMeta {
|
||||||
uuid: game.read().unwrap().uuid.to_string(),
|
uuid: game.uuid.to_string(),
|
||||||
name: game.read().unwrap().name.clone(),
|
name: game.name.clone(),
|
||||||
host: game.read().unwrap().host.read().unwrap().name.clone(),
|
host: game.host.read().unwrap().name.clone(),
|
||||||
players: game.read().unwrap().players.len(),
|
players: game.players.len(),
|
||||||
packs: game.read().unwrap().packs.clone(),
|
packs: game.packs.clone(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<GameBrowserMeta>>();
|
.collect::<Vec<GameBrowserMeta>>();
|
||||||
|
|
||||||
|
@ -412,7 +391,7 @@ impl GameHandler {
|
||||||
/// Broadcast updated game count
|
/// Broadcast updated game count
|
||||||
fn broadcast_game_count(&self) {
|
fn broadcast_game_count(&self) {
|
||||||
let tx = self.state.broadcast_tx.clone();
|
let tx = self.state.broadcast_tx.clone();
|
||||||
let active_games = self.state.games.read().unwrap().len();
|
let active_games = self.games.len();
|
||||||
let msg = to_string(&ServerActiveGames { active_games }).unwrap();
|
let msg = to_string(&ServerActiveGames { active_games }).unwrap();
|
||||||
tokio::spawn(async move { tx.send(msg) });
|
tokio::spawn(async move { tx.send(msg) });
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,6 @@ pub struct AppState {
|
||||||
pub offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>,
|
pub offline_users: RwLock<HashMap<String, Arc<RwLock<User>>>>,
|
||||||
pub packs: CardPacks,
|
pub packs: CardPacks,
|
||||||
pub packs_meta: CardPacksMeta,
|
pub packs_meta: CardPacksMeta,
|
||||||
pub games: RwLock<HashMap<String, Arc<RwLock<Game>>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Card Set
|
/// Card Set
|
||||||
|
|
|
@ -80,7 +80,6 @@ async fn main() -> Result<()> {
|
||||||
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")?;
|
||||||
let games = RwLock::new(HashMap::new());
|
|
||||||
|
|
||||||
let app_state = Arc::new(AppState {
|
let app_state = Arc::new(AppState {
|
||||||
white_cards_by_id,
|
white_cards_by_id,
|
||||||
|
@ -97,7 +96,6 @@ async fn main() -> Result<()> {
|
||||||
offline_users,
|
offline_users,
|
||||||
packs,
|
packs,
|
||||||
packs_meta,
|
packs_meta,
|
||||||
games,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Spawn task to handle incoming messages, also handles outging messages
|
// Spawn task to handle incoming messages, also handles outging messages
|
||||||
|
@ -126,7 +124,7 @@ async fn main() -> Result<()> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Spawn task to handle Game things
|
// Spawn task to handle Game things
|
||||||
let game_handler = GameHandler::new(app_state.clone());
|
let mut game_handler = GameHandler::new(app_state.clone());
|
||||||
tokio::task::Builder::new()
|
tokio::task::Builder::new()
|
||||||
.name("Game Handler")
|
.name("Game Handler")
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
|
|
Loading…
Add table
Reference in a new issue