From 11bc54f9967d2b7d61def1fe3c304091f7778bee Mon Sep 17 00:00:00 2001 From: emilis Date: Fri, 10 Oct 2025 18:34:59 +0100 Subject: [PATCH] add player for host --- werewolves-proto/src/message/host.rs | 3 +- werewolves-server/src/lobby.rs | 23 +++++--- werewolves/index.scss | 76 +++++++++++++++++---------- werewolves/src/clients/host/host.rs | 7 ++- werewolves/src/components/settings.rs | 45 ++++++++++++++-- 5 files changed, 114 insertions(+), 40 deletions(-) diff --git a/werewolves-proto/src/message/host.rs b/werewolves-proto/src/message/host.rs index 481dd28..fe983ba 100644 --- a/werewolves-proto/src/message/host.rs +++ b/werewolves-proto/src/message/host.rs @@ -13,7 +13,7 @@ use crate::{ player::PlayerId, }; -use super::{CharacterState, PlayerState}; +use super::{CharacterState, PlayerState, PublicIdentity}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum HostMessage { @@ -55,6 +55,7 @@ impl From for HostGameMessage { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum HostLobbyMessage { GetState, + ManufacturePlayer(PublicIdentity), Kick(PlayerId), SetPlayerNumber(PlayerId, NonZeroU8), GetGameSettings, diff --git a/werewolves-server/src/lobby.rs b/werewolves-server/src/lobby.rs index 83391bb..c5a4cd7 100644 --- a/werewolves-server/src/lobby.rs +++ b/werewolves-server/src/lobby.rs @@ -155,6 +155,18 @@ impl Lobby { async fn next_inner(&mut self, msg: Message) -> Result, GameError> { match msg { + Message::Host(HostMessage::Lobby(HostLobbyMessage::ManufacturePlayer(public))) => { + log::info!("adding player {public:?} by host request"); + self.players_in_lobby.push(( + Identification { + player_id: PlayerId::new(), + public, + }, + None, + )); + self.send_lobby_info_to_clients().await; + self.send_lobby_info_to_host().await.log_debug(); + } Message::Host(HostMessage::Lobby(HostLobbyMessage::SetQrMode(mode))) => { self.qr_mode = mode; self.send_lobby_info_to_host().await.log_debug(); @@ -235,7 +247,7 @@ impl Lobby { return Ok(None); } if let Some(sender) = self.joined_players.get_sender(identity.player_id).await { - self.players_in_lobby.push((identity, sender.clone())); + self.players_in_lobby.push((identity, Some(sender.clone()))); self.send_lobby_info_to_clients().await; self.send_lobby_info_to_host().await?; } @@ -321,10 +333,10 @@ impl Lobby { } #[derive(Clone)] -pub struct LobbyPlayers(Vec<(Identification, Sender)>); +pub struct LobbyPlayers(Vec<(Identification, Option>)>); impl Deref for LobbyPlayers { - type Target = Vec<(Identification, Sender)>; + type Target = Vec<(Identification, Option>)>; fn deref(&self) -> &Self::Target { &self.0 @@ -339,8 +351,6 @@ impl DerefMut for LobbyPlayers { impl LobbyPlayers { pub fn with_dummies(dummy_count: NonZeroU8) -> Self { - let (send, mut recv) = broadcast::channel(100); - tokio::spawn(async move { while recv.recv().await.is_ok() {} }); Self( (0..dummy_count.get()) .map(|p| { @@ -353,7 +363,7 @@ impl LobbyPlayers { number: NonZeroU8::new(p + 1), }, }, - send.clone(), + None, ) }) .collect(), @@ -361,6 +371,7 @@ impl LobbyPlayers { } pub fn find(&self, player_id: PlayerId) -> Option<&Sender> { self.iter() + .filter_map(|(id, s)| s.as_ref().map(|s| (id, s))) .find_map(|(id, s)| (id.player_id == player_id).then_some(s)) } diff --git a/werewolves/index.scss b/werewolves/index.scss index d40ae40..6681d10 100644 --- a/werewolves/index.scss +++ b/werewolves/index.scss @@ -201,8 +201,7 @@ nav.debug-nav { } .submenu { - background-color: black; - border: 1px solid rgba(255, 255, 255, 0.7); + // border: 1px solid rgba(255, 255, 255, 0.7); padding: 10px; position: relative; // position: fixed; @@ -829,25 +828,6 @@ input { margin: 10px; } -.signin { - @extend .row-list; - justify-content: center; - text-align: center; - - & label { - font-size: 1.5rem; - } - - & input { - height: 2rem; - text-align: center; - - &#number { - font-size: 2rem; - } - } -} - .info-update { font-size: 2rem; align-content: stretch; @@ -997,11 +977,17 @@ input { align-items: center; align-content: center; - &>p { - height: 100%; - width: 100%; + &>label { + // height: 100%; + // width: 100%; + flex-grow: 3; } + &>button { + width: max-content; + font-size: 3rem; + flex-grow: 1; + } } .setup-slot { @@ -1013,15 +999,23 @@ input { } &>.submenu { - min-width: 5cm; + min-width: 30vw; .assign-list { - min-width: 5cm; + // min-width: 5cm; + gap: 10px; & .submenu button { - width: inherit; + width: 5cm; } } + + .assignees { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 5px; + } } } @@ -1324,3 +1318,31 @@ input { & .next {} } + +.signin { + @extend .row-list; + justify-content: center; + text-align: center; + + & label { + font-size: 1.5rem; + } + + & input { + height: 2rem; + text-align: center; + + &#number { + font-size: 2rem; + } + } +} + +.submenu:has(.signin) { + position: absolute; + width: max-content; + + & input { + font-size: 1rem !important; + } +} diff --git a/werewolves/src/clients/host/host.rs b/werewolves/src/clients/host/host.rs index 1d7ac15..5fbb7e4 100644 --- a/werewolves/src/clients/host/host.rs +++ b/werewolves/src/clients/host/host.rs @@ -13,7 +13,7 @@ use werewolves_proto::{ error::GameError, game::{GameOver, GameSettings}, message::{ - CharacterIdentity, CharacterState, PlayerState, + CharacterIdentity, CharacterState, PlayerState, PublicIdentity, host::{ HostDayMessage, HostGameMessage, HostLobbyMessage, HostMessage, HostNightMessage, ServerToHostMessage, @@ -662,12 +662,17 @@ impl Host { } }); }); + let on_add_player = crate::callback::send_fn( + |msg: PublicIdentity| HostMessage::Lobby(HostLobbyMessage::ManufacturePlayer(msg)), + self.send.clone(), + ); html! { } diff --git a/werewolves/src/components/settings.rs b/werewolves/src/components/settings.rs index 3638741..85c3313 100644 --- a/werewolves/src/components/settings.rs +++ b/werewolves/src/components/settings.rs @@ -5,12 +5,12 @@ use convert_case::{Case, Casing}; use werewolves_proto::{ error::GameError, game::{GameSettings, OrRandom, SetupRole, SetupSlot, SlotId}, - message::{Identification, PlayerState}, + message::{Identification, PlayerState, PublicIdentity}, role::RoleTitle, }; use yew::prelude::*; -use crate::components::{Button, ClickableField, Identity}; +use crate::components::{Button, ClickableField, Identity, client::Signin}; #[derive(Debug, PartialEq, Properties)] pub struct SettingsProps { @@ -18,6 +18,7 @@ pub struct SettingsProps { pub players_in_lobby: Rc<[PlayerState]>, pub on_update: Callback, pub on_start: Callback<()>, + pub on_add_player: Callback, pub qr_mode_button: Html, } @@ -28,6 +29,7 @@ pub fn Settings( players_in_lobby, on_update, on_start, + on_add_player, qr_mode_button, }: &SettingsProps, ) -> Html { @@ -72,6 +74,7 @@ pub fn Settings( .map(|slot| { html! { + }; + html! {
@@ -257,6 +265,12 @@ pub fn Settings( {clear_all_assignments} {clear_bad_assigned}
+ + {"add player"} +

{format!("min roles for setup: {}", settings.min_players_needed())}

{format!("current role count: {}", settings.slots().len())}

@@ -291,6 +305,7 @@ pub struct SettingsSlotProps { pub roles_in_setup: Rc<[RoleTitle]>, pub slot: SetupSlot, pub update: Callback, + pub all_players: Rc<[Identification]>, } #[function_component] @@ -300,6 +315,7 @@ pub fn SettingsSlot( roles_in_setup, slot, update, + all_players, }: &SettingsSlotProps, ) -> Html { let open = use_state(|| false); @@ -321,6 +337,19 @@ pub fn SettingsSlot( let assign_to = assign_to_submenu(players_for_assign, slot, &update, &open.setter()); let options = setup_options_for_slot(slot, &update, roles_in_setup, apprentice_open, open.clone()); + let assign_text = slot + .assign_to + .as_ref() + .and_then(|assign_to| all_players.iter().find(|p| p.player_id == *assign_to)) + .map(|assign_to| { + html! { + <> + {"assigned to"} + + + } + }) + .unwrap_or_else(|| html! {{"assign"}}); html! { <> } }) - .collect() + .collect::(); + + html! { +
+ {buttons} +
+ } } fn setup_options_for_slot(