This commit is contained in:
Adam 2024-08-13 18:16:31 -04:00
parent dc7b3efd4f
commit 54d16b2c01
6 changed files with 133 additions and 50 deletions

View file

@ -9,11 +9,14 @@ use std::collections::BTreeSet;
#[component]
pub fn Browser() -> impl IntoView {
let websocket = expect_context::<WebSocketContext>();
// TODO: don't do this
let tx = websocket.clone();
let connected = move || websocket.ready_state.get() == ConnectionReadyState::Open;
let game_update_context = expect_context::<ReadSignal<Option<GamesUpdate>>>();
let game_browser_context = expect_context::<ReadSignal<Vec<GameBrowserMeta>>>();
let card_packs = expect_context::<ReadSignal<CardPacksMeta>>();
let (active_games, set_active_games) = create_signal::<Vec<String>>(vec![]);
let new_game_name_ref = create_node_ref::<Input>();
let (selected_packs, set_selected_packs) = create_signal::<BTreeSet<u8>>(BTreeSet::new());
@ -24,18 +27,15 @@ pub fn Browser() -> impl IntoView {
// Game stuff
let new_game = move |_| {
if let Some(input) = new_game_name_ref.get() {
if input.value() == String::from("") {
if input.value() == *"" {
logging::log!("New game name is empty!");
} else if selected_packs().is_empty() {
logging::log!("New game selected packs is empty!");
} else {
(websocket.send)(
tx.send(
&to_string(&NewGameRequest {
name: input.value(),
packs: selected_packs()
.into_iter()
.map(|n| n.clone()) // hax
.collect::<Vec<_>>(),
packs: selected_packs().into_iter().collect::<Vec<_>>(),
})
.unwrap(),
);
@ -44,33 +44,65 @@ pub fn Browser() -> impl IntoView {
}
};
create_effect(move |_| {
game_update_context.with(move |games| {
if let Some(games) = games {
set_active_games(games.games.clone());
}
})
});
// Clear games list on disconnect
create_effect(move |_| {
if !connected() {
set_active_games(vec![]);
}
});
let (show_packs, set_show_packs) = create_signal(false);
let show_packs_button = move |_| set_show_packs(!show_packs());
let (join_id, set_join_id) = create_signal("".to_string());
create_effect(move |_| {
websocket.send(&to_string(&GameJoinRequest { id: join_id() }).unwrap());
});
view! {
<div class="p-1">
<h2 class="text-2xl">Game Browser</h2>
<ul>
{move || active_games().into_iter().map(|n| view! { <li>{n}</li> }).collect_view()}
</ul>
<table class="min-w-full border border-collapse table-auto">
<thead>
<tr>
<th class="border-b">Name</th>
<th class="border-b">Host</th>
<th class="border-b">Players</th>
<th class="border-b">Card Packs</th>
<th class="border-b"></th>
</tr>
</thead>
{move || {
game_browser_context()
.iter()
.map(|game| {
view! {
<tr>
<td class="text-center border-b">{&game.name}</td>
<td class="text-center border-b">{&game.host}</td>
<td class="text-center border-b">
{&game.players.to_string()}
</td>
<td class="text-center border-b">
{&game.packs.len().to_string()}
</td>
<td class="text-center border-b">
<button
type="button"
value=&game.uuid
on:click=move |e| {
set_join_id(event_target_value(&e));
}
>
Join
</button>
<button type="button">Delete</button>
</td>
</tr>
}
})
.collect_view()
}}
</table>
</div>
<hr/>
<div class="flex p-1">
<form onsubmit="return false" on:submit=new_game>
<h2 class="text-2xl">Create Game</h2>
@ -129,6 +161,8 @@ pub fn Browser() -> impl IntoView {
<label for=n.pack>{n.name}</label>
<br/>
// hax
{set_selected_packs
.update(|packs| {
packs.insert(n.pack);
@ -148,6 +182,7 @@ pub fn Browser() -> impl IntoView {
.map(|n| {
view! {
<input
checked
type="checkbox"
value=n.pack
id=n.pack
@ -170,6 +205,12 @@ pub fn Browser() -> impl IntoView {
<label for=n.pack>{n.name}</label>
<br/>
// hax
{set_selected_packs
.update(|packs| {
packs.insert(n.pack);
})}
}
})
.collect_view()

View file

@ -1,10 +1,10 @@
use crate::components::websocket::WebSocketContext;
// use crate::components::websocket::WebSocketContext;
use leptos::*;
use lib::*;
#[component]
pub fn Game() -> impl IntoView {
let websocket = expect_context::<WebSocketContext>();
// let websocket = expect_context::<WebSocketContext>();
let game_meta = expect_context::<ReadSignal<Option<GameMeta>>>();
let (game_name, set_game_name) = create_signal("".to_string());
@ -27,18 +27,31 @@ pub fn Game() -> impl IntoView {
view! {
<div class="p-1">
<div class="relative">
<h2 class="text-2xl">Game</h2>
<span class="flex">
<p class="p-3">Name: {move || game_name()}</p>
<p class="p-3">Host: {move || game_host()}</p>
<p class="p-3">Czar: {move || game_czar()}</p>
<p class="p-3">Players: {move || game_players()}</p>
<span>
<p>Name: {move || game_name()}</p>
<p>Host: {move || game_host()}</p>
<p>Czar: {move || game_czar()}</p>
</span>
<div class="relative w-40 h-60 text-white bg-black rounded-lg">
<span class="absolute top-0 right-0">
<p>Players:</p>
<ul>
{move || {
game_players()
.iter()
.map(|player| view! { <li>{player}</li> })
.collect_view()
}}
</ul>
</span>
</div>
<div class="relative m-auto w-40 h-60 text-white bg-black rounded-lg">
<p class="p-4">{move || game_black().0}</p>
<p class="absolute right-4 bottom-4">Pick: {move || game_black().1}</p>
</div>
<div class="inline-flex flex-wrap">
<div class="inline-flex flex-wrap justify-center">
{move || {
game_white()
.iter()

View file

@ -72,7 +72,7 @@ pub fn Websocket() -> impl IntoView {
let (user_update, set_user_update) = create_signal::<Option<UserUpdate>>(Option::None);
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 (active_games, set_active_games) = create_signal::<Vec<GameBrowserMeta>>(vec![]);
let (current_game, set_current_game) = create_signal::<Option<GameMeta>>(Option::None);
let (card_packs_meta, set_card_packs_meta) = create_signal::<CardPacksMeta>(CardPacksMeta {
official_meta: vec![],
@ -83,7 +83,7 @@ pub fn Websocket() -> impl IntoView {
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<Vec<GameBrowserMeta>>>(active_games);
provide_context::<ReadSignal<Option<GameMeta>>>(current_game);
provide_context::<ReadSignal<CardPacksMeta>>(card_packs_meta);
provide_context::<ReadSignal<Option<ServerStateSummary>>>(state_summary);
@ -106,7 +106,7 @@ pub fn Websocket() -> impl IntoView {
} else if let Ok(chat_update) = from_str::<ChatUpdate>(message) {
set_chat_update(Some(chat_update));
} else if let Ok(games_update) = from_str::<GamesUpdate>(message) {
set_active_games(Some(games_update));
set_active_games(games_update.games);
} else if let Ok(game_update) = from_str::<GameMeta>(message) {
set_current_game(Some(game_update));
} else if let Ok(packs_meta_update) = from_str::<CardPacksMeta>(message) {

View file

@ -1,14 +1,32 @@
use serde::{Deserialize, Serialize};
/// Game join request
#[derive(Debug, Serialize, Deserialize)]
pub struct GameJoinRequest {
pub id: String,
}
/// Game meta
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GameMeta {
pub uuid: String,
pub name: String,
pub host: String,
pub players: Vec<String>,
pub czar: String,
pub black: (String, u8),
pub white: Vec<String>,
pub packs: Vec<u8>,
}
/// Game browser meta
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GameBrowserMeta {
pub uuid: String,
pub name: String,
pub host: String,
pub players: usize,
pub packs: Vec<u8>,
}
/// Card Pack Meta
@ -30,7 +48,7 @@ pub struct CardPacksMeta {
/// Games update
#[derive(Serialize, Deserialize, Debug)]
pub struct GamesUpdate {
pub games: Vec<String>,
pub games: Vec<GameBrowserMeta>,
}
/// Chat update

View file

@ -161,7 +161,7 @@ struct NewGameManifest {
/// A struct that represents a player
#[derive(Debug)]
struct Player {
pub struct Player {
/// The player's hand
white: Vec<CardWhite>,
/// The player's wins
@ -171,6 +171,8 @@ struct Player {
/// The game master
#[derive(Debug)]
pub struct Game {
/// Game's UUID
pub uuid: Uuid,
/// The name of the game
pub name: String,
/// The host user of the game
@ -179,20 +181,25 @@ pub struct Game {
white: Vec<CardWhite>,
/// Black draw pile
black: Vec<CardBlack>,
players: HashMap<Uuid, Player>,
pub players: HashMap<Uuid, Player>,
/// Black card for the current round
current_black: Option<CardBlack>,
pub packs: Vec<u8>,
}
impl Game {
fn new(state: Arc<AppState>, request: NewGameManifest) -> Result<Self> {
tracing::debug!("{:#?}", request.packs);
tracing::debug!("{:#?}", request.packs.len());
let mut game = Game {
uuid: Uuid::now_v7(),
name: request.host.read().unwrap().name.clone(),
host: request.host.clone(),
white: vec![],
black: vec![],
players: HashMap::new(),
current_black: Option::None,
packs: request.packs.clone(),
};
tracing::debug!(
"Creating game {} with {} as host",
@ -367,6 +374,7 @@ impl GameHandler {
}
let meta = GameMeta {
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
@ -377,7 +385,7 @@ impl GameHandler {
.user_uuid
.read()
.unwrap()
.get(&player.0)
.get(player.0)
.unwrap()
.read()
.unwrap()
@ -395,6 +403,7 @@ impl GameHandler {
.iter()
.map(|card| card.text.clone())
.collect(),
packs: new_game_object.packs.clone(),
};
tx.send(serde_json::to_string(&meta).unwrap())

View file

@ -283,17 +283,19 @@ pub fn meta_server_summary_update(state: &Arc<AppState>) -> String {
/// Generate games list update
pub fn meta_games_browser_update(state: &Arc<AppState>) -> String {
// TODO: this may get expensive if there are many games
let mut names = vec![];
let mut games = vec![];
for game in state.games.read().unwrap().values() {
names.push(format!(
"Name: {} Host: {}",
game.read().unwrap().name,
game.read().unwrap().host.read().unwrap().name
));
games.push(GameBrowserMeta {
uuid: game.read().unwrap().uuid.to_string(),
name: game.read().unwrap().name.clone(),
host: game.read().unwrap().host.read().unwrap().name.clone(),
players: game.read().unwrap().players.len(),
packs: game.read().unwrap().packs.clone(),
});
}
to_string::<GamesUpdate>(&GamesUpdate { games: names }).unwrap()
to_string::<GamesUpdate>(&GamesUpdate { games }).unwrap()
}
/// Generate chatroom join announcement