cards/server/src/game_handler.rs

551 lines
16 KiB
Rust
Raw Normal View History

2024-08-08 05:29:32 -04:00
use crate::user_handler::*;
use crate::AppState;
2024-08-14 20:38:19 -04:00
use crate::GameHandlerMessage::*;
2024-08-09 01:21:04 -04:00
use crate::User;
2024-08-12 17:14:27 -04:00
use anyhow::{Context, Result};
2024-08-09 02:57:27 -04:00
use lib::*;
2024-08-12 15:10:48 -04:00
use rand::prelude::IteratorRandom;
use rand::thread_rng;
use serde::Deserialize;
use std::{
collections::HashMap,
2024-08-12 17:14:27 -04:00
fs::read_to_string,
2024-08-12 15:10:48 -04:00
net::SocketAddr,
sync::{Arc, RwLock},
};
use uuid::Uuid;
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 {
NewGame {
addr: SocketAddr,
new_game: NewGameRequest,
},
JoinGame {
addr: SocketAddr,
id: String,
},
2024-08-18 18:48:37 -04:00
MoveRequest(PlayerMoveRequest, SocketAddr),
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-17 21:55:15 -04:00
NewGame { addr, new_game } => self.create_new_game(addr, new_game).await,
2024-08-14 20:38:19 -04:00
JoinGame { addr, id } => self.join_game(addr, id).await,
2024-08-18 18:48:37 -04:00
MoveRequest(request, addr) => self.handle_player_move(request, addr).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-17 21:55:15 -04:00
let this_player_id = self
.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();
if this_game
.read()
.unwrap()
.czar
.read()
.unwrap()
.uuid
.to_string()
== this_player_id
{
tracing::error!("No! User id is same as current czar");
} else {
tracing::error!("Ok, but i have nothing to do");
2024-08-14 20:38:19 -04:00
}
2024-08-17 21:55:15 -04:00
tracing::debug!(
2024-08-18 18:48:37 -04:00
"Player move received:\nCards: {:#?}\nGame: {}\nPlayer: {}",
request.card_ids,
request.game_id,
2024-08-17 21:55:15 -04:00
this_player_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-08-14 20:38:19 -04:00
async fn join_game(&self, addr: SocketAddr, id: String) {
// 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-14 20:38:19 -04:00
// Create player
2024-08-14 23:59:06 -04:00
this_game.write().unwrap().create_player(this_user);
2024-08-12 17:14:27 -04:00
2024-08-14 20:38:19 -04:00
// Send updates for all players
for player in this_game.read().unwrap().players.values() {
// Create update for user's game view
let meta = GameStateMeta {
uuid: id.clone(),
name: this_game.read().unwrap().name.clone(),
host: this_game.read().unwrap().host.read().unwrap().name.clone(),
players: this_game
.read()
.unwrap()
.players
.values()
.map(|player| player.user.read().unwrap().name.clone())
.collect(),
czar: this_game.read().unwrap().host.read().unwrap().name.clone(),
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-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-14 20:38:19 -04:00
// Broadcast game browser update
self.state
.broadcast_tx
.send(meta_games_browser_update(&self.state))
.unwrap();
2024-08-12 17:14:27 -04:00
2024-08-14 20:38:19 -04:00
// Broadcast server meta update
self.state
.broadcast_tx
.send(meta_server_summary_update(&self.state))
.unwrap();
2024-08-12 17:14:27 -04:00
}
2024-08-15 00:34:36 -04:00
/// Creates a new game
2024-08-17 21:55:15 -04:00
async fn create_new_game(&self, addr: SocketAddr, new_game: NewGameRequest) {
2024-08-14 20:38:19 -04:00
if new_game.packs.is_empty() {
tracing::error!("New game cards are empty!");
2024-08-14 20:38:19 -04:00
return;
} else if new_game.name.is_empty() {
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
// Create update for user's game view
let meta = GameStateMeta {
uuid: new_game_object.uuid.to_string(),
name: new_game_object.name.clone(),
host: new_game_object.host.read().unwrap().name.clone(),
players: new_game_object
.players
.iter()
.map(|player| {
self.state
2024-08-17 21:55:15 -04:00
.users_by_id
2024-08-15 00:14:47 -04:00
.read()
.unwrap()
.get(player.0)
.unwrap()
.read()
.unwrap()
.name
.clone()
})
.collect(),
czar: new_game_object.host.read().unwrap().name.clone(),
black: (
new_game_object.current_black.text.clone(),
new_game_object.current_black.pick,
),
white: new_game_object
.players
.get(&new_game_object.host.read().unwrap().uuid)
2024-08-14 20:38:19 -04:00
.unwrap()
2024-08-15 00:14:47 -04:00
.white
.iter()
2024-08-17 21:55:15 -04:00
.map(|card| WhiteCardMeta {
uuid: card.uuid.to_string(),
text: card.text.clone(),
})
2024-08-15 00:14:47 -04:00
.collect(),
packs: new_game_object.packs.clone(),
};
2024-08-12 17:14:27 -04:00
2024-08-15 00:14:47 -04:00
// Send user's update
let tx = host.read().unwrap().tx.clone();
tx.send(serde_json::to_string(&meta).unwrap())
.await
.unwrap();
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)),
);
// 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
}
2024-08-08 05:29:32 -04:00
2024-08-12 15:10:48 -04:00
/// Card Set
#[derive(Debug)]
2024-08-12 17:14:27 -04:00
struct CardSet {
2024-08-17 15:57:18 -04:00
white: Option<Vec<Arc<CardWhiteWithID>>>,
black: Option<Vec<Arc<CardBlackWithID>>>,
2024-08-12 15:10:48 -04:00
}
/// Card Packs
#[derive(Debug)]
pub struct CardPacks {
2024-08-12 17:14:27 -04:00
official: HashMap<u8, CardSet>,
unofficial: HashMap<u8, CardSet>,
2024-08-12 15:10:48 -04:00
}
2024-08-17 15:57:18 -04:00
/// A raw white card as it exists in the source json
2024-08-15 00:34:36 -04:00
#[derive(Debug, Deserialize)]
2024-08-17 15:57:18 -04:00
struct CardWhiteFromJSON {
2024-08-12 15:10:48 -04:00
/// Card text
2024-08-12 17:14:27 -04:00
text: String,
2024-08-12 15:10:48 -04:00
/// ID of the pack it came from
2024-08-12 17:14:27 -04:00
pack: u8,
2024-08-12 15:10:48 -04:00
}
2024-08-17 15:57:18 -04:00
/// A raw black card as it exists in the source json
2024-08-15 00:34:36 -04:00
#[derive(Debug, Deserialize)]
2024-08-17 15:57:18 -04:00
struct CardBlackFromJSON {
2024-08-12 15:10:48 -04:00
/// Card text
2024-08-12 17:14:27 -04:00
text: String,
2024-08-12 15:10:48 -04:00
/// Amount of cards to submit for judging
2024-08-12 17:14:27 -04:00
pick: u8,
2024-08-12 15:10:48 -04:00
/// ID of the pack it came from
2024-08-12 17:14:27 -04:00
pack: u8,
2024-08-12 15:10:48 -04:00
}
2024-08-17 15:57:18 -04:00
/// A processed white card for use server-side
#[derive(Debug)]
struct CardWhiteWithID {
/// Unique identifier
uuid: Uuid,
/// Card text
text: String,
}
/// A processed black card for use server-side
#[derive(Debug)]
struct CardBlackWithID {
/// Unique identifier
uuid: Uuid,
/// Card text
text: String,
/// Amount of cards to submit for judging
pick: u8,
}
2024-08-12 15:10:48 -04:00
/// A card pack
#[derive(Debug, Deserialize)]
2024-08-12 17:14:27 -04:00
struct CardPack {
2024-08-12 15:10:48 -04:00
/// Name of the pack
2024-08-12 17:14:27 -04:00
name: String,
2024-08-12 15:10:48 -04:00
/// Whether or not this is an official card pack
2024-08-12 17:14:27 -04:00
official: bool,
2024-08-12 15:10:48 -04:00
/// White card data
2024-08-17 15:57:18 -04:00
white: Option<Vec<CardWhiteFromJSON>>,
2024-08-12 15:10:48 -04:00
/// Black card data
2024-08-17 15:57:18 -04:00
black: Option<Vec<CardBlackFromJSON>>,
2024-08-12 15:10:48 -04:00
}
2024-08-15 00:34:36 -04:00
/// Internal manifest for making a new game
2024-08-12 15:10:48 -04:00
#[derive(Debug)]
2024-08-12 17:14:27 -04:00
struct NewGameManifest {
2024-08-12 15:10:48 -04:00
/// Game name
2024-08-12 17:14:27 -04:00
name: String,
2024-08-12 15:10:48 -04:00
/// Game host
2024-08-12 17:14:27 -04:00
host: Arc<RwLock<User>>,
2024-08-12 15:10:48 -04:00
/// Selected game packs
2024-08-12 17:14:27 -04:00
packs: Vec<u8>,
2024-08-12 15:10:48 -04:00
}
2024-08-15 00:34:36 -04:00
/// A player
2024-08-12 15:10:48 -04:00
#[derive(Debug)]
2024-08-13 18:16:31 -04:00
pub struct Player {
2024-08-14 18:01:43 -04:00
/// Pointer to user
user: Arc<RwLock<User>>,
2024-08-12 15:10:48 -04:00
/// The player's hand
2024-08-17 15:57:18 -04:00
white: Vec<Arc<CardWhiteWithID>>,
2024-08-12 15:10:48 -04:00
/// The player's wins
2024-08-17 15:57:18 -04:00
black: Vec<Arc<CardBlackWithID>>,
2024-08-12 15:10:48 -04:00
}
2024-08-15 00:34:36 -04:00
/// The game object
2024-08-12 15:10:48 -04:00
#[derive(Debug)]
pub struct Game {
2024-08-13 18:16:31 -04:00
/// Game's UUID
pub uuid: Uuid,
2024-08-12 15:10:48 -04:00
/// The name of the game
pub name: String,
/// The host user of the game
pub host: Arc<RwLock<User>>,
/// White draw pile
2024-08-17 22:42:20 -04:00
white: Vec<Arc<CardWhiteWithID>>,
2024-08-17 21:55:15 -04:00
/// Current card czar
pub czar: Arc<RwLock<User>>,
2024-08-12 15:10:48 -04:00
/// Black draw pile
2024-08-17 15:57:18 -04:00
black: Vec<Arc<CardBlackWithID>>,
2024-08-13 18:16:31 -04:00
pub players: HashMap<Uuid, Player>,
2024-08-12 15:10:48 -04:00
/// Black card for the current round
2024-08-17 15:57:18 -04:00
current_black: Arc<CardBlackWithID>,
2024-08-13 18:16:31 -04:00
pub packs: Vec<u8>,
2024-08-12 15:10:48 -04:00
}
impl Game {
2024-08-15 00:34:36 -04:00
/// Returns a new game object
2024-08-15 00:14:47 -04:00
fn new(state: Arc<AppState>, request: NewGameManifest) -> Self {
2024-08-14 23:59:06 -04:00
// Build the decks
let mut white = vec![];
let mut black = vec![];
for pack_num in &request.packs {
2024-08-12 17:14:27 -04:00
if let Some(pack) = state.packs.official.get(&pack_num) {
2024-08-14 23:59:06 -04:00
if let Some(card) = &pack.white {
white.extend(card.clone())
2024-08-12 17:14:27 -04:00
}
2024-08-14 23:59:06 -04:00
if let Some(card) = &pack.black {
black.extend(card.clone())
2024-08-12 17:14:27 -04:00
}
} else if let Some(pack) = state.packs.unofficial.get(&pack_num) {
2024-08-14 23:59:06 -04:00
if let Some(card) = &pack.white {
white.extend(card.clone())
2024-08-12 17:14:27 -04:00
}
2024-08-14 23:59:06 -04:00
if let Some(card) = &pack.black {
black.extend(card.clone())
2024-08-12 17:14:27 -04:00
}
}
}
2024-08-12 15:10:48 -04:00
2024-08-15 00:34:36 -04:00
// Draw first black card
2024-08-17 15:57:18 -04:00
let current_black = black.swap_remove(
(0..black.len())
.choose(&mut thread_rng())
.expect("No black cards to draw from!"),
);
2024-08-15 00:34:36 -04:00
// These are at the largest size they should ever be
2024-08-14 23:59:06 -04:00
white.shrink_to_fit();
black.shrink_to_fit();
2024-08-15 00:34:36 -04:00
// Return game object
2024-08-15 00:14:47 -04:00
Game {
2024-08-14 23:59:06 -04:00
uuid: Uuid::now_v7(),
name: request.name,
host: request.host.clone(),
2024-08-17 21:55:15 -04:00
czar: request.host.clone(),
2024-08-14 23:59:06 -04:00
white,
black,
players: HashMap::new(),
current_black,
packs: request.packs.clone(),
2024-08-15 00:14:47 -04:00
}
2024-08-12 15:10:48 -04:00
}
/// Draw one white card at random from play deck.
2024-08-17 15:57:18 -04:00
fn draw_one_white(&mut self) -> Option<Arc<CardWhiteWithID>> {
2024-08-12 15:10:48 -04:00
let deck = &mut self.white;
if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) {
Some(deck.swap_remove(index))
2024-08-12 15:10:48 -04:00
} else {
tracing::error!("Tried to draw white card that doesn't exist!");
None
2024-08-12 15:10:48 -04:00
}
}
/// Create a new player and add them to the game.
2024-08-14 23:59:06 -04:00
pub fn create_player(&mut self, user: Arc<RwLock<User>>) {
// Build hand of 10 white cards
let mut white = vec![];
2024-08-12 15:10:48 -04:00
for _ in 0..10 {
if let Some(card) = self.draw_one_white() {
2024-08-14 23:59:06 -04:00
white.push(card);
}
2024-08-12 15:10:48 -04:00
}
2024-08-14 23:59:06 -04:00
// New player object
let new_player = Player {
user: user.clone(),
white,
black: vec![],
};
2024-08-12 15:10:48 -04:00
2024-08-14 23:59:06 -04:00
// Add player to game
2024-08-12 15:10:48 -04:00
self.players
.insert(user.read().unwrap().uuid.clone(), new_player);
}
}
2024-08-14 20:38:19 -04:00
/// Parse json for card data
pub fn load_cards_from_json(path: &str) -> Result<(CardPacks, CardPacksMeta)> {
2024-08-15 00:34:36 -04:00
// Load in json
2024-08-14 20:38:19 -04:00
let data: String =
read_to_string(path).with_context(|| format!("Invalid JSON path: \"{}\"", path))?;
let jayson: Vec<CardPack> = serde_json::from_str(&data)
.with_context(|| format!("The contents of \"{path}\" is not valid JSON."))?;
2024-08-08 05:29:32 -04:00
2024-08-15 00:34:36 -04:00
// For global state
2024-08-14 20:38:19 -04:00
let mut official: HashMap<u8, CardSet> = HashMap::new();
let mut unofficial: HashMap<u8, CardSet> = HashMap::new();
let mut official_meta: Vec<CardPackMeta> = vec![];
let mut unofficial_meta: Vec<CardPackMeta> = vec![];
2024-08-09 01:21:04 -04:00
2024-08-15 00:34:36 -04:00
// Unpack the json
2024-08-17 15:57:18 -04:00
for sets in jayson {
2024-08-14 20:38:19 -04:00
let mut num_white = 0;
let mut num_black = 0;
2024-08-14 18:01:43 -04:00
2024-08-14 20:38:19 -04:00
let mut newset = CardSet {
white: Option::None,
black: Option::None,
};
2024-08-14 00:16:54 -04:00
2024-08-14 20:38:19 -04:00
// No safe default for this so make it an Option
let mut pack: Option<u8> = Option::None;
2024-08-14 18:01:43 -04:00
2024-08-15 00:34:36 -04:00
// Process white cards if there are any
2024-08-17 15:57:18 -04:00
if let Some(ref white) = sets.white {
2024-08-14 20:38:19 -04:00
num_white = white.len();
if num_white > 0 {
pack = Some(white[0].pack);
2024-08-17 15:57:18 -04:00
let mut white_buf = vec![];
for card in sets.white.unwrap() {
white_buf.push(Arc::new(CardWhiteWithID {
uuid: Uuid::now_v7(),
text: card.text,
}));
}
newset.white = Some(white_buf);
2024-08-14 20:38:19 -04:00
}
2024-08-14 00:16:54 -04:00
}
2024-08-15 00:34:36 -04:00
// Process black cards if there are any
2024-08-17 15:57:18 -04:00
if let Some(ref black) = sets.black {
2024-08-14 20:38:19 -04:00
num_black = black.len();
if num_black > 0 {
pack = Some(black[0].pack);
2024-08-17 15:57:18 -04:00
let mut black_buf = vec![];
for card in sets.black.unwrap() {
black_buf.push(Arc::new(CardBlackWithID {
uuid: Uuid::now_v7(),
text: card.text,
pick: card.pick,
}));
}
newset.black = Some(black_buf);
2024-08-14 20:38:19 -04:00
}
2024-08-09 01:21:04 -04:00
}
2024-08-15 00:34:36 -04:00
// Start repackaging
2024-08-14 20:38:19 -04:00
let meta = CardPackMeta {
2024-08-17 15:57:18 -04:00
name: sets.name,
2024-08-14 20:38:19 -04:00
pack: pack.expect("No card pack number!"),
num_white,
num_black,
2024-08-08 05:29:32 -04:00
};
2024-08-17 15:57:18 -04:00
if sets.official {
2024-08-14 20:38:19 -04:00
official_meta.push(meta);
official.insert(pack.unwrap(), newset);
} else {
unofficial_meta.push(meta);
unofficial.insert(pack.unwrap(), newset);
}
}
2024-08-09 02:57:27 -04:00
2024-08-15 00:34:36 -04:00
// These are now the largest size they should ever be
2024-08-14 20:38:19 -04:00
official.shrink_to_fit();
unofficial.shrink_to_fit();
official_meta.shrink_to_fit();
unofficial_meta.shrink_to_fit();
2024-08-14 00:16:54 -04:00
2024-08-15 00:34:36 -04:00
// Package for export
2024-08-14 20:38:19 -04:00
let packs = CardPacks {
official,
unofficial,
};
let packs_meta = CardPacksMeta {
official_meta,
unofficial_meta,
};
Ok((packs, packs_meta))
2024-08-08 05:29:32 -04:00
}