This commit is contained in:
Adam 2024-08-12 17:14:27 -04:00
parent dcc427dc55
commit 032b031d6e
8 changed files with 168 additions and 206 deletions

View file

@ -11,7 +11,7 @@ pub fn Game() -> impl IntoView {
let (game_host, set_game_host) = create_signal("".to_string());
let (game_players, set_game_players) = create_signal(vec![]);
let (game_czar, set_game_czar) = create_signal("".to_string());
let (game_black, set_game_black) = create_signal("".to_string());
let (game_black, set_game_black) = create_signal(("".to_string(), 0u8));
let (game_white, set_game_white) = create_signal(vec![]);
create_effect(move |_| {
@ -28,12 +28,12 @@ pub fn Game() -> impl IntoView {
view! {
<div class="p-1">
<h2 class="text-2xl">Game</h2>
<p>Name: {move || game_name}</p>
<p>Host: {move || game_host}</p>
<p>Players: {move || game_players}</p>
<p>Czar: {move || game_czar}</p>
<p>Black Card: {move || game_black}</p>
<p>Your Cards: {move || game_white}</p>
<p>Name: {move || game_name()}</p>
<p>Host: {move || game_host()}</p>
<p>Players: {move || game_players()}</p>
<p>Czar: {move || game_czar()}</p>
<p>Black Card: {move || game_black().0} Pick: {move || game_black().1}</p>
<p>Your Cards: {move || game_white()}</p>
</div>
}
}

View file

@ -7,7 +7,7 @@ pub struct GameMeta {
pub host: String,
pub players: Vec<String>,
pub czar: String,
pub black: String,
pub black: (String, u8),
pub white: Vec<String>,
}

View file

@ -1,87 +1,171 @@
use crate::user_handler::*;
use crate::AppState;
use crate::User;
use anyhow::Result;
use anyhow::{Context, Result};
use lib::*;
use rand::prelude::IteratorRandom;
use rand::thread_rng;
use serde::Deserialize;
use std::{
collections::HashMap,
fs::read_to_string,
net::SocketAddr,
sync::{Arc, RwLock},
};
use uuid::Uuid;
// This file is disgusting, don't look at it
/// Parse json for card data
pub fn load_cards_from_json(path: &str) -> Result<(CardPacks, CardPacksMeta)> {
// TODO: Repack these cards so every card is stored once and pointers are passed around instead of
// cloning stuff
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."))?;
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![];
for set in jayson {
let mut num_white = 0;
let mut num_black = 0;
let mut newset = CardSet {
white: Option::None,
black: Option::None,
};
// No safe default for this so make it an Option
let mut pack: Option<u8> = Option::None;
if let Some(ref white) = set.white {
num_white = white.len();
if num_white > 0 {
pack = Some(white[0].pack);
newset.white = Some(set.white.unwrap());
}
}
if let Some(ref black) = set.black {
num_black = black.len();
if num_black > 0 {
pack = Some(black[0].pack);
newset.black = Some(set.black.unwrap());
}
}
let meta = CardPackMeta {
name: set.name,
pack: pack.expect("No card pack number!"),
num_white,
num_black,
};
if set.official {
official_meta.push(meta);
official.insert(pack.unwrap(), newset);
} else {
unofficial_meta.push(meta);
unofficial.insert(pack.unwrap(), newset);
}
}
official.shrink_to_fit();
unofficial.shrink_to_fit();
official_meta.shrink_to_fit();
unofficial_meta.shrink_to_fit();
tracing::debug!("{} official", official.len());
tracing::debug!("{} official meta", official_meta.len());
tracing::debug!("{} unofficial", unofficial.len());
tracing::debug!("{} unofficial meta", unofficial_meta.len());
tracing::debug!("{:#?}", official_meta[0]);
tracing::debug!("{:#?}", unofficial_meta[0]);
let packs = CardPacks {
official,
unofficial,
};
let packs_meta = CardPacksMeta {
official_meta,
unofficial_meta,
};
Ok((packs, packs_meta))
}
/// Card Set
#[derive(Debug)]
pub struct CardSet {
pub white: Option<Vec<CardWhite>>,
pub black: Option<Vec<CardBlack>>,
struct CardSet {
white: Option<Vec<CardWhite>>,
black: Option<Vec<CardBlack>>,
}
/// Card Packs
#[derive(Debug)]
pub struct CardPacks {
pub official: HashMap<u8, CardSet>,
pub unofficial: HashMap<u8, CardSet>,
official: HashMap<u8, CardSet>,
unofficial: HashMap<u8, CardSet>,
}
/// A white card
#[derive(Debug, Deserialize)]
pub struct CardWhite {
// TODO: Remove this clone!
#[derive(Debug, Deserialize, Clone)]
struct CardWhite {
/// Card text
pub text: String,
text: String,
/// ID of the pack it came from
pub pack: u8,
pack: u8,
}
/// A black card
#[derive(Debug, Deserialize)]
pub struct CardBlack {
// TODO: Remove this clone!
#[derive(Debug, Deserialize, Clone)]
struct CardBlack {
/// Card text
pub text: String,
text: String,
/// Amount of cards to submit for judging
pub pick: u8,
pick: u8,
/// ID of the pack it came from
pub pack: u8,
pack: u8,
}
/// A card pack
#[derive(Debug, Deserialize)]
pub struct CardPack {
struct CardPack {
/// Name of the pack
pub name: String,
name: String,
/// Whether or not this is an official card pack
pub official: bool,
official: bool,
/// White card data
pub white: Option<Vec<CardWhite>>,
white: Option<Vec<CardWhite>>,
/// Black card data
pub black: Option<Vec<CardBlack>>,
black: Option<Vec<CardBlack>>,
}
/// New game request structure
#[derive(Debug)]
pub struct NewGameManifest {
struct NewGameManifest {
/// Game name
pub name: String,
name: String,
/// Game host
pub host: Arc<RwLock<User>>,
host: Arc<RwLock<User>>,
/// Selected game packs
pub packs: Vec<u8>,
packs: Vec<u8>,
}
/// A struct that represents a player
#[derive(Debug)]
pub struct Player {
/// Player's user's uuid
pub user_uuid: Uuid,
struct Player {
/// The player's hand
pub white: Vec<CardWhite>,
white: Vec<CardWhite>,
/// The player's wins
pub black: Vec<CardBlack>,
black: Vec<CardBlack>,
}
/// The game master
@ -92,47 +176,21 @@ pub struct Game {
/// The host user of the game
pub host: Arc<RwLock<User>>,
/// White draw pile
pub white: Vec<CardWhite>,
white: Vec<CardWhite>,
/// Black draw pile
pub black: Vec<CardBlack>,
/// White discard pile
pub white_discard: Vec<CardWhite>,
/// Black discard pile
pub black_discard: Vec<CardBlack>,
/// List of current players
pub players: HashMap<Uuid, Player>,
// /// Reference to current card czar
// czar: &Player,
black: Vec<CardBlack>,
players: HashMap<Uuid, Player>,
/// Black card for the current round
pub current_black: Option<CardBlack>,
current_black: Option<CardBlack>,
}
impl Game {
/// Build game decks from input data for game start.
/// This should only run once and at startup.
fn build_decks(&mut self, selected_packs: Vec<u8>) -> Result<()> {
// for pack in selected_packs {
// for pack in card_packs {
// if let Some(white) = pack.white {
// self.white.extend(white)
// }
// if let Some(black) = pack.black {
// self.black.extend(black)
// }
// }
// }
Ok(())
}
pub fn new(request: NewGameManifest) -> Result<Self> {
fn new(state: Arc<AppState>, request: NewGameManifest) -> Result<Self> {
let mut game = Game {
name: request.host.read().unwrap().name.clone(),
host: request.host.clone(),
white: vec![],
black: vec![],
white_discard: vec![],
black_discard: vec![],
players: HashMap::new(),
current_black: Option::None,
};
@ -144,30 +202,43 @@ impl Game {
game.name = request.name;
game.host = request.host.clone();
game.build_decks(request.packs)?;
game.build_decks(state, request.packs)?;
game.create_player(request.host)?;
game.deal_black()?;
Ok(game)
}
// pub fn join(request:GameJoinRequest)
/// Build game decks from input data for game start.
/// This should only run once and at startup.
fn build_decks(&mut self, state: Arc<AppState>, selected_packs: Vec<u8>) -> Result<()> {
// TODO: Make this right -- remove the clones, use references to single cards
for pack_num in selected_packs {
if let Some(pack) = state.packs.official.get(&pack_num) {
if let Some(white) = &pack.white {
self.white.extend(white.clone())
}
if let Some(black) = &pack.black {
self.black.extend(black.clone())
}
} else if let Some(pack) = state.packs.unofficial.get(&pack_num) {
if let Some(white) = &pack.white {
self.white.extend(white.clone())
}
if let Some(black) = &pack.black {
self.black.extend(black.clone())
}
}
}
/// Log counts of current drawable cards
/// For testing
pub fn deck_counts(&self) {
tracing::debug!(
"Deck Counts:\n {} White cards\n {} Black cards",
self.white.len(),
self.black.len()
);
Ok(())
}
/// Draw one white card at random from play deck.
fn draw_one_white(&mut self) -> Result<CardWhite> {
let deck = &mut self.white;
// this feels sloppy
// TODO: this feels sloppy
if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) {
Ok(deck.swap_remove(index))
} else {
@ -182,7 +253,7 @@ impl Game {
fn draw_one_black(&mut self) -> Result<CardBlack> {
let deck = &mut self.black;
// this feels sloppy
// TODO: this feels sloppy
if let Some(index) = (0..deck.len()).choose(&mut thread_rng()) {
Ok(deck.swap_remove(index))
} else {
@ -202,9 +273,8 @@ impl Game {
}
/// Create a new player and add them to the game.
pub fn create_player(&mut self, user: Arc<RwLock<User>>) -> Result<()> {
fn create_player(&mut self, user: Arc<RwLock<User>>) -> Result<()> {
let mut new_player = Player {
user_uuid: user.read().unwrap().uuid.clone(),
white: vec![],
black: vec![],
};
@ -225,16 +295,6 @@ impl Game {
Ok(())
}
pub fn game_start(&mut self) -> Result<()> {
if let Some(black) = &self.current_black {
tracing::debug!("{}", black.text);
} else {
tracing::debug!("YOU DONE FUCKED UP (no current black card)");
}
Ok(())
}
}
pub enum GameHandlerMessage {
@ -288,7 +348,7 @@ impl GameHandler {
};
// create game
if let Ok(new_game_object) = Game::new(manifest) {
if let Ok(new_game_object) = Game::new(self.state.clone(), manifest) {
let tx = self
.state
.online_users
@ -301,9 +361,9 @@ impl GameHandler {
.tx
.clone();
let mut black_text = "Error".to_string();
let mut black_card = ("Error".to_string(), 0u8);
if let Some(ref current_black) = new_game_object.current_black {
black_text = current_black.text.to_owned()
black_card = (current_black.text.to_owned(), current_black.pick)
}
let meta = GameMeta {
@ -326,7 +386,7 @@ impl GameHandler {
})
.collect(),
czar: new_game_object.host.read().unwrap().name.clone(),
black: black_text,
black: black_card,
white: new_game_object
.players
.get(&new_game_object.host.read().unwrap().uuid)

View file

@ -7,7 +7,7 @@ use game_handler::GameHandlerMessage;
use lib::*;
use std::{
collections::{HashMap, HashSet},
fs::{read_to_string, File},
fs::File,
io::{BufRead, BufReader},
net::SocketAddr,
sync::{Arc, RwLock},
@ -44,89 +44,6 @@ impl User {
}
}
/// Parse json for card data
pub fn load_cards_from_json(path: &str) -> Result<(CardPacks, CardPacksMeta)> {
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."))?;
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![];
for set in jayson {
let mut num_white = 0;
let mut num_black = 0;
let mut newset = CardSet {
white: Option::None,
black: Option::None,
};
// No safe default for this so make it an Option
let mut pack: Option<u8> = Option::None;
if let Some(ref white) = set.white {
num_white = white.len();
if num_white > 0 {
pack = Some(white[0].pack);
newset.white = Some(set.white.unwrap());
}
}
if let Some(ref black) = set.black {
num_black = black.len();
if num_black > 0 {
pack = Some(black[0].pack);
newset.black = Some(set.black.unwrap());
}
}
let meta = CardPackMeta {
name: set.name,
pack: pack.expect("No card pack number!"),
num_white,
num_black,
};
if set.official {
official_meta.push(meta);
official.insert(pack.unwrap(), newset);
} else {
unofficial_meta.push(meta);
unofficial.insert(pack.unwrap(), newset);
}
}
official.shrink_to_fit();
unofficial.shrink_to_fit();
official_meta.shrink_to_fit();
unofficial_meta.shrink_to_fit();
tracing::debug!("{} official", official.len());
tracing::debug!("{} official meta", official_meta.len());
tracing::debug!("{} unofficial", unofficial.len());
tracing::debug!("{} unofficial meta", unofficial_meta.len());
tracing::debug!("{:#?}", official_meta[0]);
tracing::debug!("{:#?}", unofficial_meta[0]);
let packs = CardPacks {
official,
unofficial,
};
let packs_meta = CardPacksMeta {
official_meta,
unofficial_meta,
};
Ok((packs, packs_meta))
}
/// Parse name list
pub fn load_names(path: &str) -> Result<Vec<String>> {
let f = File::open(path).with_context(|| format!("Invalid names path: \"{}\"", path))?;

View file

@ -64,16 +64,7 @@ async fn main() -> Result<()> {
}
});
// Make an outgoing message handler handler
// DO it
// DO it
// DO it
// DO it
// DO it
// DO it
// DO it
// DO it
// DO it
// TODO: Make an outgoing message handler handler
// Spawn task to handle User things
let user_handler = UserHandler::new(app_state.clone());

View file

@ -7,9 +7,6 @@ use serde_json::{from_str, to_string};
use std::net::SocketAddr;
use std::sync::Arc;
// Handle incoming messages over the WebSocket, and probably do more than we should.
// Also with lots of unwrapping
pub struct MessageHandler {
state: Arc<AppState>,
}
@ -23,7 +20,7 @@ impl MessageHandler {
match message {
Message::Text(text) => match text {
_chat_message if let Ok(chat_message) = from_str::<ChatMessage>(&text) => {
// This should be delegated to user handler and an outgoing message and/or chat handler
// TODO: This should be delegated to user handler and an outgoing message and/or chat handler
let msg = format! {"{0}: {1}", self.state.online_users.read().unwrap().get(&addr).unwrap().read().unwrap().name, chat_message.text};
tracing::debug!("{msg}");
self.state

View file

@ -5,8 +5,6 @@ use serde_json::to_string;
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};
// This file is a mess, don't read it
pub enum UserHandlerMessage {
NewUser { user: User, addr: SocketAddr },
UserLogIn { username: String, addr: SocketAddr },
@ -24,7 +22,7 @@ impl UserHandler {
pub async fn handle(&self, message: UserHandlerMessage) {
match message {
UserHandlerMessage::NewUser { user, addr } => {
// make this not async
// TODO: make this not async
self.set_up_new_user(user, addr).await
}
UserHandlerMessage::UserLogIn { username, addr } => self.login(username, addr).await,
@ -65,7 +63,7 @@ impl UserHandler {
.unwrap();
// Broadcast new user's existence
// this should probably be combined and sent as one
// TODO: this should probably be combined and sent as one
let _ = &self
.state
.broadcast_tx
@ -82,8 +80,7 @@ impl UserHandler {
.send(meta_chat_update(&self.state))
.unwrap();
// this races the broadcasts but if it's done last it'll probably show up
// last
// TODO: this races the broadcasts but if it's done last it'll probably show up last
tx.send(meta_motd()).await.unwrap();
}
@ -245,7 +242,7 @@ pub fn user_client_self_update(new_user: &Arc<RwLock<User>>) -> String {
/// Generate chatroom metadata update
pub fn meta_chat_update(state: &Arc<AppState>) -> String {
// this may get expensive if there are many users
// TODO: this may get expensive if there are many users
let mut names = vec![];
for user in state.online_users.read().unwrap().iter() {
@ -285,7 +282,7 @@ pub fn meta_server_summary_update(state: &Arc<AppState>) -> String {
/// Generate games list update
pub fn meta_games_browser_update(state: &Arc<AppState>) -> String {
// this may get expensive if there are many games
// TODO: this may get expensive if there are many games
let mut names = vec![];
for game in state.games.read().unwrap().values() {

View file

@ -37,9 +37,8 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc<AppState>, ad
let mut map = HashMap::new();
map.insert(addr, dm_tx.clone());
let _ = state
state
.users_tx
// add tx
.send(UserHandlerMessage::NewUser {
user: User::new(
format!(
@ -51,7 +50,8 @@ pub async fn websocket_on_connection(stream: WebSocket, state: Arc<AppState>, ad
),
addr,
})
.await;
.await
.unwrap();
// Subscribe to receive from global broadcast channel
let mut rx = state.broadcast_tx.subscribe();