crude card pack selection
This commit is contained in:
parent
e0e02bcf83
commit
44ff6adb8a
9 changed files with 192 additions and 34 deletions
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -124,6 +124,7 @@ pub fn Chat() -> impl IntoView {
|
|||
type="submit"
|
||||
value="Send"
|
||||
/>
|
||||
handle empty
|
||||
</form>
|
||||
</span>
|
||||
<br/>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue