add player for host
This commit is contained in:
parent
08db7f9bfc
commit
11bc54f996
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
player::PlayerId,
|
player::PlayerId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CharacterState, PlayerState};
|
use super::{CharacterState, PlayerState, PublicIdentity};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum HostMessage {
|
pub enum HostMessage {
|
||||||
|
|
@ -55,6 +55,7 @@ impl From<HostDayMessage> for HostGameMessage {
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum HostLobbyMessage {
|
pub enum HostLobbyMessage {
|
||||||
GetState,
|
GetState,
|
||||||
|
ManufacturePlayer(PublicIdentity),
|
||||||
Kick(PlayerId),
|
Kick(PlayerId),
|
||||||
SetPlayerNumber(PlayerId, NonZeroU8),
|
SetPlayerNumber(PlayerId, NonZeroU8),
|
||||||
GetGameSettings,
|
GetGameSettings,
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,18 @@ impl Lobby {
|
||||||
|
|
||||||
async fn next_inner(&mut self, msg: Message) -> Result<Option<GameRunner>, GameError> {
|
async fn next_inner(&mut self, msg: Message) -> Result<Option<GameRunner>, GameError> {
|
||||||
match msg {
|
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))) => {
|
Message::Host(HostMessage::Lobby(HostLobbyMessage::SetQrMode(mode))) => {
|
||||||
self.qr_mode = mode;
|
self.qr_mode = mode;
|
||||||
self.send_lobby_info_to_host().await.log_debug();
|
self.send_lobby_info_to_host().await.log_debug();
|
||||||
|
|
@ -235,7 +247,7 @@ impl Lobby {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
if let Some(sender) = self.joined_players.get_sender(identity.player_id).await {
|
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_clients().await;
|
||||||
self.send_lobby_info_to_host().await?;
|
self.send_lobby_info_to_host().await?;
|
||||||
}
|
}
|
||||||
|
|
@ -321,10 +333,10 @@ impl Lobby {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LobbyPlayers(Vec<(Identification, Sender<ServerMessage>)>);
|
pub struct LobbyPlayers(Vec<(Identification, Option<Sender<ServerMessage>>)>);
|
||||||
|
|
||||||
impl Deref for LobbyPlayers {
|
impl Deref for LobbyPlayers {
|
||||||
type Target = Vec<(Identification, Sender<ServerMessage>)>;
|
type Target = Vec<(Identification, Option<Sender<ServerMessage>>)>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
|
|
@ -339,8 +351,6 @@ impl DerefMut for LobbyPlayers {
|
||||||
|
|
||||||
impl LobbyPlayers {
|
impl LobbyPlayers {
|
||||||
pub fn with_dummies(dummy_count: NonZeroU8) -> Self {
|
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(
|
Self(
|
||||||
(0..dummy_count.get())
|
(0..dummy_count.get())
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
|
|
@ -353,7 +363,7 @@ impl LobbyPlayers {
|
||||||
number: NonZeroU8::new(p + 1),
|
number: NonZeroU8::new(p + 1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
send.clone(),
|
None,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
@ -361,6 +371,7 @@ impl LobbyPlayers {
|
||||||
}
|
}
|
||||||
pub fn find(&self, player_id: PlayerId) -> Option<&Sender<ServerMessage>> {
|
pub fn find(&self, player_id: PlayerId) -> Option<&Sender<ServerMessage>> {
|
||||||
self.iter()
|
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))
|
.find_map(|(id, s)| (id.player_id == player_id).then_some(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,8 +201,7 @@ nav.debug-nav {
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenu {
|
.submenu {
|
||||||
background-color: black;
|
// border: 1px solid rgba(255, 255, 255, 0.7);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.7);
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
// position: fixed;
|
// position: fixed;
|
||||||
|
|
@ -829,25 +828,6 @@ input {
|
||||||
margin: 10px;
|
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 {
|
.info-update {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
align-content: stretch;
|
align-content: stretch;
|
||||||
|
|
@ -997,11 +977,17 @@ input {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
|
|
||||||
&>p {
|
&>label {
|
||||||
height: 100%;
|
// height: 100%;
|
||||||
width: 100%;
|
// width: 100%;
|
||||||
|
flex-grow: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&>button {
|
||||||
|
width: max-content;
|
||||||
|
font-size: 3rem;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.setup-slot {
|
.setup-slot {
|
||||||
|
|
@ -1013,15 +999,23 @@ input {
|
||||||
}
|
}
|
||||||
|
|
||||||
&>.submenu {
|
&>.submenu {
|
||||||
min-width: 5cm;
|
min-width: 30vw;
|
||||||
|
|
||||||
.assign-list {
|
.assign-list {
|
||||||
min-width: 5cm;
|
// min-width: 5cm;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
& .submenu button {
|
& .submenu button {
|
||||||
width: inherit;
|
width: 5cm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.assignees {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1324,3 +1318,31 @@ input {
|
||||||
|
|
||||||
& .next {}
|
& .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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use werewolves_proto::{
|
||||||
error::GameError,
|
error::GameError,
|
||||||
game::{GameOver, GameSettings},
|
game::{GameOver, GameSettings},
|
||||||
message::{
|
message::{
|
||||||
CharacterIdentity, CharacterState, PlayerState,
|
CharacterIdentity, CharacterState, PlayerState, PublicIdentity,
|
||||||
host::{
|
host::{
|
||||||
HostDayMessage, HostGameMessage, HostLobbyMessage, HostMessage, HostNightMessage,
|
HostDayMessage, HostGameMessage, HostLobbyMessage, HostMessage, HostNightMessage,
|
||||||
ServerToHostMessage,
|
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! {
|
html! {
|
||||||
<Settings
|
<Settings
|
||||||
settings={settings}
|
settings={settings}
|
||||||
on_start={on_start}
|
on_start={on_start}
|
||||||
on_update={on_changed}
|
on_update={on_changed}
|
||||||
players_in_lobby={players.clone()}
|
players_in_lobby={players.clone()}
|
||||||
|
on_add_player={on_add_player}
|
||||||
qr_mode_button={qr_mode_toggle}
|
qr_mode_button={qr_mode_toggle}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ use convert_case::{Case, Casing};
|
||||||
use werewolves_proto::{
|
use werewolves_proto::{
|
||||||
error::GameError,
|
error::GameError,
|
||||||
game::{GameSettings, OrRandom, SetupRole, SetupSlot, SlotId},
|
game::{GameSettings, OrRandom, SetupRole, SetupSlot, SlotId},
|
||||||
message::{Identification, PlayerState},
|
message::{Identification, PlayerState, PublicIdentity},
|
||||||
role::RoleTitle,
|
role::RoleTitle,
|
||||||
};
|
};
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
use crate::components::{Button, ClickableField, Identity};
|
use crate::components::{Button, ClickableField, Identity, client::Signin};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Properties)]
|
#[derive(Debug, PartialEq, Properties)]
|
||||||
pub struct SettingsProps {
|
pub struct SettingsProps {
|
||||||
|
|
@ -18,6 +18,7 @@ pub struct SettingsProps {
|
||||||
pub players_in_lobby: Rc<[PlayerState]>,
|
pub players_in_lobby: Rc<[PlayerState]>,
|
||||||
pub on_update: Callback<GameSettings>,
|
pub on_update: Callback<GameSettings>,
|
||||||
pub on_start: Callback<()>,
|
pub on_start: Callback<()>,
|
||||||
|
pub on_add_player: Callback<PublicIdentity>,
|
||||||
pub qr_mode_button: Html,
|
pub qr_mode_button: Html,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -28,6 +29,7 @@ pub fn Settings(
|
||||||
players_in_lobby,
|
players_in_lobby,
|
||||||
on_update,
|
on_update,
|
||||||
on_start,
|
on_start,
|
||||||
|
on_add_player,
|
||||||
qr_mode_button,
|
qr_mode_button,
|
||||||
}: &SettingsProps,
|
}: &SettingsProps,
|
||||||
) -> Html {
|
) -> Html {
|
||||||
|
|
@ -72,6 +74,7 @@ pub fn Settings(
|
||||||
.map(|slot| {
|
.map(|slot| {
|
||||||
html! {
|
html! {
|
||||||
<SettingsSlot
|
<SettingsSlot
|
||||||
|
all_players={players.clone()}
|
||||||
players_for_assign={players_for_assign.clone()}
|
players_for_assign={players_for_assign.clone()}
|
||||||
roles_in_setup={roles_in_setup.clone()}
|
roles_in_setup={roles_in_setup.clone()}
|
||||||
slot={slot.clone()}
|
slot={slot.clone()}
|
||||||
|
|
@ -248,6 +251,11 @@ pub fn Settings(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let add_player_open = use_state(|| false);
|
||||||
|
let add_player_opts = html! {
|
||||||
|
<Signin callback={on_add_player.clone()}/>
|
||||||
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class="settings">
|
<div class="settings">
|
||||||
<div class="top-settings">
|
<div class="top-settings">
|
||||||
|
|
@ -257,6 +265,12 @@ pub fn Settings(
|
||||||
{clear_all_assignments}
|
{clear_all_assignments}
|
||||||
{clear_bad_assigned}
|
{clear_bad_assigned}
|
||||||
</div>
|
</div>
|
||||||
|
<ClickableField
|
||||||
|
options={add_player_opts}
|
||||||
|
state={add_player_open}
|
||||||
|
>
|
||||||
|
{"add player"}
|
||||||
|
</ClickableField>
|
||||||
<p>{format!("min roles for setup: {}", settings.min_players_needed())}</p>
|
<p>{format!("min roles for setup: {}", settings.min_players_needed())}</p>
|
||||||
<p>{format!("current role count: {}", settings.slots().len())}</p>
|
<p>{format!("current role count: {}", settings.slots().len())}</p>
|
||||||
<div class="roles-add-list">
|
<div class="roles-add-list">
|
||||||
|
|
@ -291,6 +305,7 @@ pub struct SettingsSlotProps {
|
||||||
pub roles_in_setup: Rc<[RoleTitle]>,
|
pub roles_in_setup: Rc<[RoleTitle]>,
|
||||||
pub slot: SetupSlot,
|
pub slot: SetupSlot,
|
||||||
pub update: Callback<SettingSlotAction>,
|
pub update: Callback<SettingSlotAction>,
|
||||||
|
pub all_players: Rc<[Identification]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
|
|
@ -300,6 +315,7 @@ pub fn SettingsSlot(
|
||||||
roles_in_setup,
|
roles_in_setup,
|
||||||
slot,
|
slot,
|
||||||
update,
|
update,
|
||||||
|
all_players,
|
||||||
}: &SettingsSlotProps,
|
}: &SettingsSlotProps,
|
||||||
) -> Html {
|
) -> Html {
|
||||||
let open = use_state(|| false);
|
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 assign_to = assign_to_submenu(players_for_assign, slot, &update, &open.setter());
|
||||||
let options =
|
let options =
|
||||||
setup_options_for_slot(slot, &update, roles_in_setup, apprentice_open, open.clone());
|
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! {
|
||||||
|
<>
|
||||||
|
<span>{"assigned to"}</span>
|
||||||
|
<Identity ident={assign_to.public.clone()} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| html! {{"assign"}});
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<Button on_click={on_kick}>
|
<Button on_click={on_kick}>
|
||||||
|
|
@ -331,7 +360,7 @@ pub fn SettingsSlot(
|
||||||
state={assign_open}
|
state={assign_open}
|
||||||
class={classes!("assign-list")}
|
class={classes!("assign-list")}
|
||||||
>
|
>
|
||||||
{"assign"}
|
{assign_text}
|
||||||
</ClickableField>
|
</ClickableField>
|
||||||
{options}
|
{options}
|
||||||
</>
|
</>
|
||||||
|
|
@ -357,7 +386,7 @@ fn assign_to_submenu(
|
||||||
update: &Callback<SettingSlotAction>,
|
update: &Callback<SettingSlotAction>,
|
||||||
assign_setter: &UseStateSetter<bool>,
|
assign_setter: &UseStateSetter<bool>,
|
||||||
) -> Html {
|
) -> Html {
|
||||||
players
|
let buttons = players
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let slot = slot.clone();
|
let slot = slot.clone();
|
||||||
|
|
@ -376,7 +405,13 @@ fn assign_to_submenu(
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect::<Html>();
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div class="assignees">
|
||||||
|
{buttons}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_options_for_slot(
|
fn setup_options_for_slot(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue