crude card pack selection

This commit is contained in:
Adam 2024-08-04 03:13:34 -04:00
parent e0e02bcf83
commit 44ff6adb8a
9 changed files with 192 additions and 34 deletions

View file

@ -41,6 +41,7 @@ pub fn Auth() -> impl IntoView {
placeholder=move || username.get()
node_ref=username_input_ref
/>
handle empty
<br/>
<input
class="py-2 px-4 pl-4 font-bold text-white rounded border-b-4 bg-slate-600 border-slate-800 hover:bg-slate-700 hover:border-slate-500"

View file

@ -1,7 +1,10 @@
use std::collections::BTreeSet;
use crate::components::websocket::WebSocketContext;
use leptos::html::Input;
use leptos::*;
use leptos_use::core::ConnectionReadyState;
use leptos_use::signal_throttled_with_options;
use lib::models::*;
use serde_json::to_string;
@ -11,19 +14,28 @@ pub fn Browser() -> impl IntoView {
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let game_update_context = expect_context::<ReadSignal<Option<GamesUpdate>>>();
let card_packs = expect_context::<ReadSignal<CardPacksMeta>>();
let (active_games, set_active_games) = create_signal::<Vec<String>>(vec![]);
let new_game_input_ref = create_node_ref::<Input>();
let new_game_name_ref = create_node_ref::<Input>();
let (selected_packs, set_selected_packs) = create_signal::<BTreeSet<u8>>(BTreeSet::new());
// create_effect(move |_| {
// logging::log!("{:#?}", selected_packs().iter().collect::<Vec<_>>());
// });
// Game stuff
let new_game = move |_| {
(websocket.send)(
&to_string(&NewGameRequest {
name: new_game_input_ref.get().unwrap().value(),
name: new_game_name_ref.get().unwrap().value(),
packs: selected_packs()
.into_iter()
.map(|n| n.clone()) // hax
.collect::<Vec<_>>(),
})
.unwrap(),
);
new_game_input_ref.get().unwrap().set_value("");
new_game_name_ref.get().unwrap().set_value("");
};
create_effect(move |_| {
@ -40,20 +52,128 @@ pub fn Browser() -> impl IntoView {
set_active_games(vec![]);
}
});
let (show_packs, set_show_packs) = create_signal(false);
let show_packs_button = move |_| set_show_packs(!show_packs());
view! {
<div class="p-1">
<h2 class="text-2xl">Game Browser</h2>
<ul>
<h2 class="text-2xl">Game Browser</h2>
{move || active_games().into_iter().map(|n| view! { <li>{n}</li> }).collect_view()}
</ul>
</div>
<hr/>
<div class="flex p-1">
<form onsubmit="return false" on:submit=new_game>
<h2 class="text-2xl">Create Game</h2>
<input
class="w-80 h-11 font-mono rounded-sm bg-slate-900 text-slate-200"
placeholder="Name"
disabled=move || !connected()
node_ref=new_game_input_ref
node_ref=new_game_name_ref
/>
handle empty
<h2 class="text-2xl">Packs</h2>
<div class="p-2">
<button type="button" class="bg-slate-600">
<input type="checkbox" id="all"/>
<label for="all">All</label>
</button>
<button type="button" class="bg-slate-600">
<input type="checkbox" id="official" checked/>
<label for="official">Official</label>
</button>
<button type="button" class="bg-slate-600" on:click=show_packs_button>
<label>Custom</label>
</button>
finish this
</div>
<Show when=move || show_packs()>
<span class="flex">
<div>
<h2 class="text-xl">Official</h2>
{move || {
card_packs()
.official_meta
.into_iter()
.map(|n| {
view! {
<input
type="checkbox"
value=n.pack
id=n.pack
checked
on:change=move |e| {
if event_target_checked(&e) {
logging::log!("insert");
set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})
} else {
logging::log!("remove");
set_selected_packs
.update(|packs| {
packs.remove(&n.pack);
})
}
}
/>
<label for=n.pack>{n.name}</label>
<br/>
{set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})}
}
})
.collect_view()
}}
</div>
<div>
<h2 class="text-xl">Unofficial</h2>
{move || {
card_packs()
.unofficial_meta
.into_iter()
.map(|n| {
view! {
<input
type="checkbox"
value=n.pack
id=n.pack
on:change=move |e| {
if event_target_checked(&e) {
logging::log!("insert");
set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})
} else {
logging::log!("remove");
set_selected_packs
.update(|packs| {
packs.remove(&n.pack);
})
}
}
/>
<label for=n.pack>{n.name}</label>
<br/>
}
})
.collect_view()
}}
</div>
</span>
</Show>
<input
class="py-2 px-4 pl-4 font-bold text-white rounded border-b-4 bg-slate-600 border-slate-800 hover:bg-slate-700 hover:border-slate-500"
type="submit"

View file

@ -124,6 +124,7 @@ pub fn Chat() -> impl IntoView {
type="submit"
value="Send"
/>
handle empty
</form>
</span>
<br/>

View file

@ -1,9 +1,8 @@
use std::rc::Rc;
use leptos::*;
use leptos_use::{core::ConnectionReadyState, use_websocket, UseWebsocketReturn};
use lib::models::*;
use serde_json::from_str;
use std::rc::Rc;
#[derive(Clone)]
pub struct WebSocketContext {
@ -74,12 +73,17 @@ pub fn Websocket() -> impl IntoView {
let (chat_update, set_chat_update) = create_signal::<Option<ChatUpdate>>(Option::None);
let (chat_message, set_chat_message) = create_signal::<Option<ChatMessage>>(Option::None);
let (active_games, set_active_games) = create_signal::<Option<GamesUpdate>>(Option::None);
let (card_packs_meta, set_card_packs_meta) = create_signal::<CardPacksMeta>(CardPacksMeta {
official_meta: vec![],
unofficial_meta: vec![],
});
// provide_context::<ReadSignal<Option<Game>>>(game_object);
provide_context::<ReadSignal<Option<UserUpdate>>>(user_update);
provide_context::<ReadSignal<Option<ChatUpdate>>>(chat_update);
provide_context::<ReadSignal<Option<ChatMessage>>>(chat_message);
provide_context::<ReadSignal<Option<GamesUpdate>>>(active_games);
provide_context::<ReadSignal<CardPacksMeta>>(card_packs_meta);
provide_context::<ReadSignal<Option<ServerStateSummary>>>(state_summary);
// Message handler
@ -101,6 +105,8 @@ pub fn Websocket() -> impl IntoView {
set_chat_update(Some(chat_update));
} else if let Ok(games_update) = from_str::<GamesUpdate>(message) {
set_active_games(Some(games_update));
} else if let Ok(packs_meta_update) = from_str::<CardPacksMeta>(message) {
set_card_packs_meta(packs_meta_update);
} else {
logging::log!("Unhandled message: {}", message);
}

View file

@ -8,7 +8,7 @@ use crate::models::*;
impl Game {
/// Build game decks from input data for game start.
/// This should only run once and at startup.
fn _build_decks(&mut self, cards_json: Vec<CardSet>) -> Result<()> {
fn _build_decks(&mut self, cards_json: Vec<CardPack>) -> Result<()> {
for pack in cards_json {
if let Some(white) = pack.white {
self.white.extend(white)

View file

@ -1,6 +1,27 @@
use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock};
/// Card Pack Meta
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CardPackMeta {
pub name: String,
pub pack: u8,
pub num_white: usize,
pub num_black: usize,
}
/// Card Packs Meta
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CardPacksMeta {
pub official_meta: Vec<CardPackMeta>,
pub unofficial_meta: Vec<CardPackMeta>,
}
/// Card Packs Meta
#[derive(Debug, Serialize, Deserialize)]
pub struct CardPacks {
pub official: Vec<CardPack>,
pub unofficial: Vec<CardPack>,
}
/// Games update
#[derive(Serialize, Deserialize, Debug)]
pub struct GamesUpdate {
@ -56,6 +77,7 @@ impl User {
pub struct NewGameRequest {
/// Game name
pub name: String,
pub packs: Vec<u8>,
}
/// New game request structure
@ -97,13 +119,11 @@ pub struct CardBlack {
pub pack: u8,
}
/// A card set
/// A card pack
#[derive(Debug, Serialize, Deserialize)]
pub struct CardSet {
pub struct CardPack {
/// Name of the pack
pub name: String,
/// Pack Description
pub description: Option<String>,
/// Whether or not this is an official card pack
pub official: bool,
/// White card data

View file

@ -93,6 +93,7 @@ async fn handle_new_user(
.send(Message::Text(server_summary_update(state)))
.await?;
sender.send(Message::Text(games_update(state))).await?;
sender.send(Message::Text(cards_meta_update(state))).await?;
// Broadcast new user's existence
// this should probably be combined and sent as one
@ -138,6 +139,12 @@ fn chat_meta_update(state: &Arc<AppState>) -> String {
.unwrap()
}
/// Generage cards meta message
fn cards_meta_update(state: &Arc<AppState>) -> String {
tracing::debug!("sending cards meta");
to_string::<CardPacksMeta>(&state.packs_meta).unwrap()
}
/// Generate message-of-the-day server greeting
fn motd() -> String {
to_string::<ChatMessage>(&ChatMessage {

View file

@ -64,6 +64,7 @@ fn handle_new_game(
.unwrap()
.clone(),
};
tracing::debug!("Game Packs {:?}", new_game.packs);
// create game
if let Ok(new_game_object) = Game::new(manifest) {

View file

@ -16,27 +16,17 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
pub mod api;
use crate::api::*;
/// Card Pack Meta
#[derive(Debug)]
pub struct CardPackMeta {
name: String,
description: Option<String>,
pack: u8,
num_white: usize,
num_black: usize,
}
/// Parse json for card data
fn load_cards_from_json(path: &str) -> Result<Vec<CardSet>> {
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<CardSet> =
serde_json::from_str(&data).with_context(|| format!("\"{path}\" is invalid json"))?;
let jayson: Vec<CardPack> = serde_json::from_str(&data)
.with_context(|| format!("The contents of \"{path}\" is not valid JSON."))?;
let mut official: Vec<CardPack> = vec![];
let mut unofficial: Vec<CardPack> = vec![];
let mut official: Vec<CardSet> = vec![];
let mut official_meta: Vec<CardPackMeta> = vec![];
let mut unofficial: Vec<CardSet> = vec![];
let mut unofficial_meta: Vec<CardPackMeta> = vec![];
for set in jayson {
@ -59,7 +49,6 @@ fn load_cards_from_json(path: &str) -> Result<Vec<CardSet>> {
let meta = CardPackMeta {
name: set.name,
description: set.description,
pack: pack.expect("No card pack number!"),
num_white,
num_black,
@ -80,11 +69,22 @@ fn load_cards_from_json(path: &str) -> Result<Vec<CardSet>> {
tracing::debug!("{:#?}", unofficial_meta[0]);
official.shrink_to_fit();
official_meta.shrink_to_fit();
unofficial.shrink_to_fit();
let packs = CardPacks {
official,
unofficial,
};
official_meta.shrink_to_fit();
unofficial_meta.shrink_to_fit();
Ok(official)
let packs_meta = CardPacksMeta {
official_meta,
unofficial_meta,
};
Ok((packs, packs_meta))
}
/// Parse name list
@ -109,7 +109,8 @@ pub struct AppState {
// Channel used to send messages to all connected clients.
tx: broadcast::Sender<String>,
// Master card decks
all_cards: Vec<CardSet>,
packs: CardPacks,
packs_meta: CardPacksMeta,
// Games list
games: RwLock<Vec<Game>>,
// chatrooms: Mutex<HashMap<String, ChatRoom<'user>>>,
@ -133,7 +134,7 @@ async fn main() -> Result<()> {
let (tx, _rx) = broadcast::channel(100);
let online_users = RwLock::new(HashMap::<SocketAddr, Arc<RwLock<User>>>::new());
let offline_users = RwLock::new(HashMap::<String, Arc<RwLock<User>>>::new());
let all_cards = load_cards_from_json("data/cah-cards-full.json")?;
let (packs, packs_meta) = load_cards_from_json("data/cah-cards-full.json")?;
let games = RwLock::new(vec![]);
let first_names = load_names("data/first.txt")?;
let last_names = load_names("data/last.txt")?;
@ -142,7 +143,8 @@ async fn main() -> Result<()> {
online_users,
offline_users,
tx,
all_cards,
packs,
packs_meta,
games,
first_names,
last_names,