diff --git a/werewolves-proto/src/error.rs b/werewolves-proto/src/error.rs index 4e51fa1..8c1df18 100644 --- a/werewolves-proto/src/error.rs +++ b/werewolves-proto/src/error.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::{player::CharacterId, role::RoleTitle}; +use crate::role::RoleTitle; #[derive(Debug, Clone, PartialEq, Error, Serialize, Deserialize)] pub enum GameError { diff --git a/werewolves-proto/src/game/kill.rs b/werewolves-proto/src/game/kill.rs index ff78ebb..608c40d 100644 --- a/werewolves-proto/src/game/kill.rs +++ b/werewolves-proto/src/game/kill.rs @@ -1,13 +1,10 @@ -use core::{ - num::NonZeroU8, - ops::{Deref, Not}, -}; +use core::{num::NonZeroU8, ops::Not}; use super::Result; use crate::{ diedto::DiedTo, error::GameError, - game::{Village, kill::taken::Taken, night::NightChange}, + game::{Village, night::NightChange}, player::{CharacterId, Protection}, }; @@ -26,10 +23,13 @@ pub enum KillOutcome { impl KillOutcome { pub fn apply_to_village(self, village: &mut Village) -> Result<()> { match self { - KillOutcome::Single(character_id, died_to) => Ok(village - .character_by_id_mut(&character_id) - .ok_or(GameError::InvalidTarget)? - .kill(died_to)), + KillOutcome::Single(character_id, died_to) => { + village + .character_by_id_mut(&character_id) + .ok_or(GameError::InvalidTarget)? + .kill(died_to); + Ok(()) + } KillOutcome::Guarding { original_killer, original_target, @@ -146,7 +146,7 @@ pub fn resolve_kill( None => return Ok(Some(KillOutcome::Single(target.clone(), died_to.clone()))), }; - match protection.deref() { + match protection { Protection::Guardian { source, guarding: true, @@ -188,17 +188,7 @@ impl<'a> ChangesLookup<'a> { }) } - pub fn release(&mut self, taken: Taken<'a, T>) { - self.1.swap_remove( - self.1 - .iter() - .enumerate() - .find_map(|(idx, c)| (*c == taken.idx()).then_some(idx)) - .unwrap(), - ); - } - - pub fn protected_take(&mut self, target: &CharacterId) -> Option> { + pub fn protected_take(&mut self, target: &CharacterId) -> Option { if let Some((idx, c)) = self.0.iter().enumerate().find_map(|(idx, c)| { self.1 .contains(&idx) @@ -213,7 +203,7 @@ impl<'a> ChangesLookup<'a> { .flatten() }) { self.1.push(idx); - Some(Taken::new(idx, c)) + Some(c.clone()) } else { None } @@ -267,26 +257,3 @@ impl<'a> ChangesLookup<'a> { }) } } - -mod taken { - use core::ops::Deref; - - pub struct Taken<'a, T>(usize, &'a T); - impl<'a, T> Taken<'a, T> { - pub const fn new(idx: usize, item: &'a T) -> Self { - Self(idx, item) - } - - pub const fn idx(&self) -> usize { - self.0 - } - } - - impl<'a, T> Deref for Taken<'a, T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.1 - } - } -} diff --git a/werewolves-proto/src/game/mod.rs b/werewolves-proto/src/game/mod.rs index 60fd4b2..55f5934 100644 --- a/werewolves-proto/src/game/mod.rs +++ b/werewolves-proto/src/game/mod.rs @@ -18,7 +18,6 @@ use crate::{ message::{ CharacterState, Identification, host::{HostDayMessage, HostGameMessage, HostNightMessage, ServerToHostMessage}, - night::ActionResponse, }, player::CharacterId, }; @@ -193,6 +192,7 @@ impl Game { } } +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum GameState { Day { diff --git a/werewolves-proto/src/game/night.rs b/werewolves-proto/src/game/night.rs index 064ef1c..daeaffb 100644 --- a/werewolves-proto/src/game/night.rs +++ b/werewolves-proto/src/game/night.rs @@ -12,7 +12,7 @@ use crate::{ DateTime, Village, kill::{self, ChangesLookup}, }, - message::night::{ActionPrompt, ActionResponse, ActionResult, ActionType}, + message::night::{ActionPrompt, ActionResponse, ActionResult}, player::{Character, CharacterId, Protection}, role::{PreviousGuardianAction, Role, RoleBlock, RoleTitle}, }; diff --git a/werewolves-proto/src/game/village.rs b/werewolves-proto/src/game/village.rs index 0c0f748..c10e2a5 100644 --- a/werewolves-proto/src/game/village.rs +++ b/werewolves-proto/src/game/village.rs @@ -61,7 +61,7 @@ impl Village { .map(|(player, role)| { let player_str = player.public.to_string(); Character::new(player, role) - .ok_or_else(|| GameError::PlayerNotAssignedNumber(player_str)) + .ok_or(GameError::PlayerNotAssignedNumber(player_str)) }) .collect::>>()?, date_time: DateTime::Night { number: 0 }, diff --git a/werewolves-proto/src/game_test/mod.rs b/werewolves-proto/src/game_test/mod.rs index 66d2d18..7033293 100644 --- a/werewolves-proto/src/game_test/mod.rs +++ b/werewolves-proto/src/game_test/mod.rs @@ -50,7 +50,6 @@ trait GameExt { fn next(&mut self) -> ActionPrompt; fn next_expect_day(&mut self) -> (Box<[CharacterState]>, Box<[CharacterId]>, NonZeroU8); fn response(&mut self, resp: ActionResponse) -> ActionResult; - fn get_state(&mut self) -> ServerToHostMessage; fn execute(&mut self) -> ActionPrompt; fn mark_for_execution( &mut self, @@ -111,10 +110,6 @@ impl GameExt for Game { .unwrap() .prompt() } - - fn get_state(&mut self) -> ServerToHostMessage { - self.process(HostGameMessage::GetState).unwrap() - } } fn init_log() { diff --git a/werewolves-proto/src/lib.rs b/werewolves-proto/src/lib.rs index 3309e21..7ab5568 100644 --- a/werewolves-proto/src/lib.rs +++ b/werewolves-proto/src/lib.rs @@ -1,9 +1,5 @@ #![allow(clippy::new_without_default)] -use error::GameError; -use serde::{Deserialize, Serialize}; -use thiserror::Error; -// pub mod action; pub mod diedto; pub mod error; pub mod game; diff --git a/werewolves-proto/src/message.rs b/werewolves-proto/src/message.rs index 9e42bda..8dff05c 100644 --- a/werewolves-proto/src/message.rs +++ b/werewolves-proto/src/message.rs @@ -2,18 +2,12 @@ pub mod host; mod ident; pub mod night; -use core::{fmt::Display, num::NonZeroU8}; +use core::num::NonZeroU8; pub use ident::*; -use night::{ActionPrompt, ActionResponse, ActionResult}; use serde::{Deserialize, Serialize}; -use crate::{ - error::GameError, - game::GameOver, - player::{Character, CharacterId}, - role::RoleTitle, -}; +use crate::{game::GameOver, player::CharacterId, role::RoleTitle}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum ClientMessage { diff --git a/werewolves-proto/src/message/host.rs b/werewolves-proto/src/message/host.rs index a78cbd5..0d63df5 100644 --- a/werewolves-proto/src/message/host.rs +++ b/werewolves-proto/src/message/host.rs @@ -6,7 +6,7 @@ use crate::{ error::GameError, game::{GameOver, GameSettings}, message::{ - CharacterIdentity, PublicIdentity, + CharacterIdentity, night::{ActionPrompt, ActionResponse, ActionResult}, }, player::{CharacterId, PlayerId}, diff --git a/werewolves-server/src/client.rs b/werewolves-server/src/client.rs index 5647ced..a252078 100644 --- a/werewolves-server/src/client.rs +++ b/werewolves-server/src/client.rs @@ -58,7 +58,7 @@ pub async fn handler( recv, connection_id.clone(), ident.public.name.clone(), - ident.public.number.clone(), + ident.public.number, ident.public.pronouns.clone(), ), ) @@ -161,11 +161,7 @@ impl Client { } } - async fn on_recv( - &mut self, - msg: Result, - conn_id: ConnectionId, - ) -> Result<(), anyhow::Error> { + async fn on_recv(&mut self, msg: Result) -> Result<(), anyhow::Error> { use crate::LogError; let msg = match msg { @@ -231,7 +227,7 @@ impl Client { if let Err(err) = tokio::select! { msg = self.socket.recv() => { match msg { - Some(msg) => self.on_recv(msg, self.connection_id.clone()).await, + Some(msg) => self.on_recv(msg).await, None => { return; }, diff --git a/werewolves-server/src/communication/host.rs b/werewolves-server/src/communication/host.rs index a098576..6c67f44 100644 --- a/werewolves-server/src/communication/host.rs +++ b/werewolves-server/src/communication/host.rs @@ -22,10 +22,7 @@ impl HostComms { #[cfg(debug_assertions)] pub async fn recv(&mut self) -> Option { - match self.recv.recv().await { - Some(msg) => Some(msg), - None => None, - } + self.recv.recv().await } #[cfg(not(debug_assertions))] diff --git a/werewolves-server/src/communication/lobby.rs b/werewolves-server/src/communication/lobby.rs index 831144d..7f4a94e 100644 --- a/werewolves-server/src/communication/lobby.rs +++ b/werewolves-server/src/communication/lobby.rs @@ -22,6 +22,7 @@ impl LobbyComms { (self.comms, self.connect_recv) } + #[allow(unused)] pub const fn player(&mut self) -> &mut PlayerIdComms { self.comms.player() } diff --git a/werewolves-server/src/communication/mod.rs b/werewolves-server/src/communication/mod.rs index 865ea84..7d57d55 100644 --- a/werewolves-server/src/communication/mod.rs +++ b/werewolves-server/src/communication/mod.rs @@ -23,6 +23,7 @@ impl Comms { &mut self.host } + #[allow(unused)] pub const fn player(&mut self) -> &mut PlayerIdComms { &mut self.player } diff --git a/werewolves-server/src/communication/player.rs b/werewolves-server/src/communication/player.rs index 8b7da99..2f22c46 100644 --- a/werewolves-server/src/communication/player.rs +++ b/werewolves-server/src/communication/player.rs @@ -1,8 +1,8 @@ use colored::Colorize; use tokio::sync::broadcast::Receiver; -use werewolves_proto::{error::GameError, player::PlayerId}; +use werewolves_proto::error::GameError; -use crate::{connection::JoinedPlayers, runner::IdentifiedClientMessage}; +use crate::runner::IdentifiedClientMessage; pub struct PlayerIdComms { // joined_players: JoinedPlayers, diff --git a/werewolves-server/src/connection.rs b/werewolves-server/src/connection.rs index 02b9a97..8cdddf8 100644 --- a/werewolves-server/src/connection.rs +++ b/werewolves-server/src/connection.rs @@ -9,7 +9,6 @@ use tokio::{ time::Instant, }; use werewolves_proto::{ - error::GameError, message::{PublicIdentity, ServerMessage}, player::PlayerId, }; @@ -142,30 +141,6 @@ impl JoinedPlayers { None } - pub async fn start_game_with(&self, players: &[PlayerId]) -> Result { - let mut map = self.players.lock().await; - - for player in players { - if let Some(player) = map.get_mut(player) { - player.in_game = true; - }; - } - - Ok(InGameToken::new( - self.clone(), - players.iter().cloned().collect(), - )) - } - - pub async fn release_from_game(&self, players: &[PlayerId]) { - self.players - .lock() - .await - .iter_mut() - .filter(|(p, _)| players.contains(*p)) - .for_each(|(_, p)| p.in_game = false) - } - pub async fn get_sender(&self, player_id: &PlayerId) -> Option> { self.players .lock() @@ -196,27 +171,3 @@ impl JoinedPlayers { } } } - -pub struct InGameToken { - joined_players: JoinedPlayers, - players_in_game: Option>, -} -impl InGameToken { - const fn new(joined_players: JoinedPlayers, players_in_game: Box<[PlayerId]>) -> Self { - Self { - joined_players, - players_in_game: Some(players_in_game), - } - } -} -impl Drop for InGameToken { - fn drop(&mut self) { - let joined_players = self.joined_players.clone(); - if let Some(players) = self.players_in_game.take() { - tokio::spawn(async move { - let players_in_game = players; - joined_players.release_from_game(&players_in_game).await; - }); - } - } -} diff --git a/werewolves-server/src/game.rs b/werewolves-server/src/game.rs index df174b8..de4743a 100644 --- a/werewolves-server/src/game.rs +++ b/werewolves-server/src/game.rs @@ -7,7 +7,6 @@ use crate::{ lobby::{Lobby, LobbyPlayers}, runner::{IdentifiedClientMessage, Message}, }; -use futures::SinkExt; use tokio::{sync::broadcast::Receiver, time::Instant}; use werewolves_proto::{ error::GameError, @@ -53,7 +52,6 @@ impl GameRunner { } pub fn into_lobby(self) -> Lobby { - // core::mem::drop(self._release_token); let mut lobby = Lobby::new( self.joined_players, LobbyComms::new(self.comms, self.connect_recv), @@ -214,6 +212,12 @@ impl GameRunner { } } + for char in self.game.village().characters() { + if let Some(sender) = self.joined_players.get_sender(char.player_id()).await { + let _ = sender.send(ServerMessage::Disconnect); + } + } + self.roles_revealed = true; } diff --git a/werewolves-server/src/lobby.rs b/werewolves-server/src/lobby.rs index 15d69ad..860e121 100644 --- a/werewolves-server/src/lobby.rs +++ b/werewolves-server/src/lobby.rs @@ -1,18 +1,11 @@ -use core::{ - num::NonZeroU8, - ops::{Deref, DerefMut}, - time::Duration, -}; -use std::{collections::HashMap, os::unix::raw::pid_t}; +use core::ops::{Deref, DerefMut}; -use serde::{Deserialize, Serialize}; use tokio::sync::broadcast::Sender; use werewolves_proto::{ error::GameError, - game::{Game, GameSettings, Village}, + game::{Game, GameSettings}, message::{ - CharacterState, ClientMessage, DayCharacter, Identification, PlayerState, ServerMessage, - UpdateSelf, + ClientMessage, Identification, PlayerState, ServerMessage, host::{HostLobbyMessage, HostMessage, ServerToHostMessage}, }, player::PlayerId, @@ -353,10 +346,4 @@ impl LobbyPlayers { Ok(()) } } - - pub fn drain(&mut self) -> Self { - let mut swapped = Self(vec![]); - core::mem::swap(&mut swapped, self); - swapped - } } diff --git a/werewolves-server/src/main.rs b/werewolves-server/src/main.rs index a9b9c69..c374216 100644 --- a/werewolves-server/src/main.rs +++ b/werewolves-server/src/main.rs @@ -17,13 +17,9 @@ use axum_extra::headers; use communication::lobby::LobbyComms; use connection::JoinedPlayers; use core::{fmt::Display, net::SocketAddr, str::FromStr}; -use log::Record; use runner::IdentifiedClientMessage; use std::{env, io::Write, path::Path}; -use tokio::{ - sync::{broadcast, mpsc}, - time::Instant, -}; +use tokio::sync::{broadcast, mpsc}; use crate::{ communication::{Comms, host::HostComms, player::PlayerIdComms}, @@ -114,7 +110,7 @@ async fn main() { let path = Path::new(option_env!("SAVE_PATH").unwrap_or(DEFAULT_SAVE_DIR)); - if let Err(err) = std::fs::create_dir(&path) + if let Err(err) = std::fs::create_dir(path) && !matches!(err.kind(), std::io::ErrorKind::AlreadyExists) { panic!("creating save dir at [{path:?}]: {err}") diff --git a/werewolves/index.scss b/werewolves/index.scss index d1ccfd4..f40b65c 100644 --- a/werewolves/index.scss +++ b/werewolves/index.scss @@ -586,7 +586,7 @@ clients { margin-left: 5vw; margin-right: 5vw; margin-top: 30px; - display: flexbox; + display: flex; flex-basis: content; } diff --git a/werewolves/src/clients/client/client.rs b/werewolves/src/clients/client/client.rs index 09c2ab9..6258757 100644 --- a/werewolves/src/clients/client/client.rs +++ b/werewolves/src/clients/client/client.rs @@ -1,32 +1,17 @@ -use core::{num::NonZeroU8, sync::atomic::AtomicBool, time::Duration}; -use std::{collections::VecDeque, rc::Rc}; +use std::rc::Rc; -use futures::{ - SinkExt, StreamExt, - channel::mpsc::{Receiver, Sender}, -}; -use gloo::{ - net::websocket::{self, futures::WebSocket}, - storage::{LocalStorage, Storage, errors::StorageError}, -}; -use instant::Instant; -use serde::Serialize; +use gloo::storage::errors::StorageError; use werewolves_proto::{ - error::GameError, - game::GameOver, - message::{ - ClientMessage, DayCharacter, Identification, PlayerUpdate, PublicIdentity, ServerMessage, - night::{ActionPrompt, ActionResponse, ActionResult}, - }, + message::{ClientMessage, Identification, PublicIdentity}, player::PlayerId, role::RoleTitle, }; -use yew::{html::Scope, prelude::*, suspense::use_future}; +use yew::prelude::*; use crate::{ clients::client::connection::{Connection2, ConnectionError}, components::{ - Button, Identity, Notification, + Button, Identity, client::{ClientNav, Signin}, }, storage::StorageKey, @@ -34,197 +19,10 @@ use crate::{ use crate::WerewolfError; -#[derive(Debug)] -pub enum Message { - SetErrorCallback(Callback>), - SetPublicIdentity(PublicIdentity), - RecvServerMessage(ServerMessage), - Connect, - ForceIdentity(Identification), -} - -pub struct Connection { - scope: Scope, - ident: Identification, - recv: Receiver, -} - -fn url() -> String { - format!( - "{}client", - option_env!("LOCAL") - .map(|_| crate::clients::DEBUG_URL) - .unwrap_or(crate::clients::LIVE_URL) - ) -} - -impl Connection { - async fn connect_ws() -> WebSocket { - let url = url(); - loop { - match WebSocket::open(&url) { - Ok(ws) => break ws, - Err(err) => { - log::error!("connect: {err}"); - yew::platform::time::sleep(Duration::from_secs(1)).await; - } - } - } - } - - fn encode_message(msg: &impl Serialize) -> websocket::Message { - #[cfg(feature = "json")] - { - websocket::Message::Text(serde_json::to_string(msg).expect("message serialization")) - } - #[cfg(feature = "cbor")] - { - websocket::Message::Bytes({ - let mut v = Vec::new(); - ciborium::into_writer(msg, &mut v).expect("serializing message"); - v - }) - } - } - - async fn run(mut self) { - const CONNECT_WAIT: Duration = Duration::from_secs(3); - let url = url(); - let mut last_connect: Option = None; - 'outer: loop { - if let Some(last_connect) = last_connect.as_ref() { - let time_since_last = Instant::now() - *last_connect; - if time_since_last <= CONNECT_WAIT { - yew::platform::time::sleep(CONNECT_WAIT.saturating_sub(time_since_last)).await; - continue; - } - } - last_connect = Some(Instant::now()); - log::info!("connecting to {url}"); - let mut ws = Self::connect_ws().await.fuse(); - log::info!("connected to {url}"); - - if let Err(err) = ws.send(Self::encode_message(&self.ident)).await { - log::error!("websocket identification send: {err}"); - continue 'outer; - }; - - if let Err(err) = ws - .send(Self::encode_message(&ClientMessage::GetState)) - .await - { - log::error!("websocket identification send: {err}"); - continue 'outer; - }; - - loop { - let msg = futures::select! { - r = ws.next() => { - match r { - Some(Ok(msg)) => msg, - Some(Err(err)) => { - log::error!("websocket recv: {err}"); - continue 'outer; - }, - None => { - log::warn!("websocket closed"); - continue 'outer; - }, - } - } - r = self.recv.next() => { - match r { - Some(msg) => { - log::info!("sending message: {msg:?}"); - if let Err(err) = ws.send( - Self::encode_message(&msg) - ).await { - log::error!("websocket send error: {err}"); - continue 'outer; - } - continue; - }, - None => { - log::info!("recv channel closed"); - return; - }, - } - }, - }; - let parse = { - #[cfg(feature = "json")] - { - match msg { - websocket::Message::Text(text) => { - serde_json::from_str::(&text) - } - websocket::Message::Bytes(items) => serde_json::from_slice(&items), - } - } - #[cfg(feature = "cbor")] - { - match msg { - websocket::Message::Text(_) => { - log::error!("text messages not supported in cbor mode; discarding"); - continue; - } - websocket::Message::Bytes(bytes) => { - ciborium::from_reader::(bytes.as_slice()) - } - } - } - }; - match parse { - Ok(msg) => self.scope.send_message(Message::RecvServerMessage(msg)), - Err(err) => { - log::error!("parsing server message: {err}; ignoring.") - } - } - } - } - } -} - -#[derive(PartialEq, Debug, Clone)] -pub enum ClientEvent { - Disconnected, - Waiting, - ShowRole(RoleTitle), - NotInLobby(Box<[PublicIdentity]>), - InLobby(Box<[PublicIdentity]>), - GameInProgress, - GameOver(GameOver), -} - -impl TryFrom for ClientEvent { - type Error = ServerMessage; - - fn try_from(msg: ServerMessage) -> Result { - Ok(match msg { - ServerMessage::Disconnect => Self::Disconnected, - ServerMessage::LobbyInfo { - joined, - mut players, - } => { - const LAST: NonZeroU8 = NonZeroU8::new(0xFF).unwrap(); - players.sort_by(|l, r| l.number.unwrap_or(LAST).cmp(&r.number.unwrap_or(LAST))); - let players = players.into_iter().collect(); - match joined { - true => Self::InLobby(players), - false => Self::NotInLobby(players), - } - } - ServerMessage::GameInProgress => Self::GameInProgress, - _ => return Err(msg), - }) - } -} - #[derive(PartialEq, Debug, Clone)] pub enum ClientEvent2 { Disconnected, Connecting, - Waiting, ShowRole(RoleTitle), Lobby { @@ -299,7 +97,6 @@ pub fn Client2(ClientProps { auto_join }: &ClientProps) -> Html { } html! {

{"connecting..."}

} } - ClientEvent2::Waiting => html! {

{"waiting..."}

}, ClientEvent2::ShowRole(role_title) => { let send = (*send).clone(); let error_cb = error_cb.clone(); @@ -386,346 +183,8 @@ pub fn Client2(ClientProps { auto_join }: &ClientProps) -> Html { } } -pub struct Client { - player: Option, - send: Sender, - recv: Option>, - current_event: Option, - auto_join: bool, - - error_callback: Callback>, -} - -impl Client { - fn error(&self, err: WerewolfError) { - self.error_callback.emit(Some(err)) - } - - fn clear_error(&self) { - self.error_callback.emit(None) - } - - fn bug(&self, msg: &str) { - log::warn!("BUG: {msg}") - } -} - #[derive(Debug, Clone, PartialEq, Copy, Properties)] pub struct ClientProps { #[prop_or_default] pub auto_join: bool, } - -impl Component for Client { - type Message = Message; - - type Properties = ClientProps; - - fn create(ctx: &Context) -> Self { - gloo::utils::document().set_title("Werewolves Player"); - let player = PlayerId::load_from_storage() - .ok() - .and_then(|p| PublicIdentity::load_from_storage().ok().map(|n| (p, n))) - .map(|(player_id, public)| Identification { player_id, public }); - - let (send, recv) = futures::channel::mpsc::channel::(100); - - Self { - player, - send, - recv: Some(recv), - auto_join: ctx.props().auto_join, - error_callback: Callback::from(|err| { - if let Some(err) = err { - log::error!("{err}") - } - }), - current_event: None, - } - } - - fn view(&self, ctx: &Context) -> Html { - if self.player.is_none() { - let scope = ctx.link().clone(); - let callback = Callback::from(move |public: PublicIdentity| { - scope.send_message(Message::SetPublicIdentity(public)); - }); - return html! { - - }; - } else if self.recv.is_some() { - // Player info loaded, but connection isn't started - ctx.link().send_message(Message::Connect); - return html! {}; - } - - let msg = match self.current_event.as_ref() { - Some(msg) => msg, - None => { - return html! { -
-

{"Connecting..."}

-
- }; - } - }; - - let content = match msg { - ClientEvent::Disconnected => html! { -
-

{"You were disconnected"}

-
- }, - ClientEvent::Waiting => { - html! { -
-

{"Waiting"}

-
- } - } - ClientEvent::ShowRole(role_title) => { - let send = self.send.clone(); - let on_click = - Callback::from( - move |_| { - while send.clone().try_send(ClientMessage::RoleAck).is_err() {} - }, - ); - html! { -
-

{format!("Your role: {role_title}")}

- -
- } - } - ClientEvent::NotInLobby(players) => { - let send = self.send.clone(); - let on_click = - Callback::from( - move |_| { - while send.clone().try_send(ClientMessage::Hello).is_err() {} - }, - ); - html! { -
- -

{format!("Players in lobby: {}", players.len())}

-
    - {players.iter().map(|p| html!{

    {p.to_string()}

    }).collect::()} -
-
- } - } - ClientEvent::InLobby(players) => { - let send = self.send.clone(); - let on_click = - Callback::from( - move |_| { - while send.clone().try_send(ClientMessage::Goodbye).is_err() {} - }, - ); - html! { -
- -

{format!("Players in lobby: {}", players.len())}

-
    - {players.iter().map(|p| html!{

    {p.to_string()}

    }).collect::()} -
-
- } - } - ClientEvent::GameInProgress => html! { -
-

{"game in progress"}

-
- }, - ClientEvent::GameOver(result) => html! { -
-

{"game over"}

-

{ - match result { - GameOver::VillageWins => "village wins", - GameOver::WolvesWin => "wolves win", - }}

-
- }, - }; - - let player = self - .player - .as_ref() - .map(|player| { - html! { - - - } - }) - .unwrap_or(html!()); - - let send = self.send.clone(); - let client_nav_msg_cb = move |msg| { - let mut send = send.clone(); - yew::platform::spawn_local(async move { - if let Err(err) = send.send(msg).await { - log::error!("sending nav message: {err}"); - } - }); - }; - let nav = self.player.as_ref().map(|_| { - html! { - - } - }); - - html! { - <> - {nav} - - {player} - {content} - - - } - } - - fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { - log::info!("update: {msg:?}"); - match msg { - Message::ForceIdentity(id) => { - self.player.replace(id); - true - } - Message::SetErrorCallback(cb) => { - self.error_callback = cb; - false - } - Message::SetPublicIdentity(public) => { - match self.player.as_mut() { - Some(p) => { - if let Err(err) = public.save_to_storage() { - self.error(err.into()); - return false; - } - p.public = public; - } - None => { - let player_id = match PlayerId::load_from_storage() { - Ok(pid) => pid, - Err(StorageError::KeyNotFound(_)) => { - let pid = PlayerId::new(); - if let Err(err) = pid.save_to_storage() { - self.error(err.into()); - return false; - } - pid - } - Err(err) => { - self.error(err.into()); - return false; - } - }; - if let Err(err) = public.save_to_storage() { - self.error(err.into()); - return false; - } - let ident = Identification { player_id, public }; - self.player = Some(ident.clone()); - - if let Some(recv) = self.recv.take() { - yew::platform::spawn_local( - Connection { - recv, - ident, - scope: ctx.link().clone(), - } - .run(), - ); - } - } - } - true - } - Message::RecvServerMessage(msg) => { - if let ServerMessage::LobbyInfo { - joined: false, - players: _, - } = &msg - && self.auto_join - { - let mut send = self.send.clone(); - yew::platform::spawn_local(async move { - if let Err(err) = send.send(ClientMessage::Hello).await { - log::error!("send: {err}"); - } - }); - self.auto_join = false; - return false; - } - let msg = match msg.try_into() { - Ok(event) => { - self.current_event.replace(event); - return true; - } - Err(msg) => msg, - }; - match msg { - ServerMessage::GameStart { role } => { - self.current_event.replace(ClientEvent::ShowRole(role)); - } - ServerMessage::InvalidMessageForGameState => self.error( - WerewolfError::GameError(GameError::InvalidMessageForGameState), - ), - ServerMessage::NoSuchTarget => { - self.error(WerewolfError::InvalidTarget); - } - ServerMessage::GameInProgress - | ServerMessage::LobbyInfo { - joined: _, - players: _, - } - | ServerMessage::Disconnect => return false, - ServerMessage::GameOver(game_over) => { - self.current_event = Some(ClientEvent::GameOver(game_over)); - } - ServerMessage::Reset => { - let mut send = self.send.clone(); - self.current_event = Some(ClientEvent::Disconnected); - yew::platform::spawn_local(async move { - if let Err(err) = send.send(ClientMessage::GetState).await { - log::error!("send: {err}"); - } - }); - } - ServerMessage::Sleep => self.current_event = Some(ClientEvent::Waiting), - ServerMessage::Update(update) => match (update, self.player.as_mut()) { - (PlayerUpdate::Number(num), Some(player)) => { - player.public.number = Some(num); - return true; - } - (_, None) => return false, - }, - }; - true - } - Message::Connect => { - if let Some(player) = self.player.as_ref() - && let Some(recv) = self.recv.take() - { - yew::platform::spawn_local( - Connection { - scope: ctx.link().clone(), - ident: player.clone(), - recv, - } - .run(), - ); - return true; - } - while let Err(err) = self.send.try_send(ClientMessage::GetState) { - log::error!("send IsThereALobby: {err}") - } - false - } - } - } -} diff --git a/werewolves/src/clients/client/connection.rs b/werewolves/src/clients/client/connection.rs index 746877b..b44cf2d 100644 --- a/werewolves/src/clients/client/connection.rs +++ b/werewolves/src/clients/client/connection.rs @@ -94,6 +94,7 @@ impl Connection2 { .map_err(|_| ConnectionError::ConnectionAlreadyActive)?; core::mem::drop(active); let mut conn = self.clone(); + #[allow(clippy::await_holding_refcell_ref)] yew::platform::spawn_local(async move { let active = conn.active.clone(); conn.active = Rc::new(RefCell::new(())); @@ -105,6 +106,7 @@ impl Connection2 { Ok(()) } + #[allow(clippy::await_holding_refcell_ref)] async fn run(&mut self) { const CONNECT_WAIT: Duration = Duration::from_secs(3); let url = url(); @@ -138,7 +140,8 @@ impl Connection2 { }; log::debug!("beginning listening loop"); - loop { + let mut quit = false; + while !quit { let mut recv = self.receiver.borrow_mut(); let msg = futures::select! { r = ws.next() => { @@ -199,6 +202,7 @@ impl Connection2 { }; match parse { Ok(msg) => { + quit = matches!(msg, ServerMessage::Disconnect); if let Some(state) = self.message_to_client_state(msg) { self.state.set(state); } @@ -245,6 +249,7 @@ impl Connection2 { | ServerMessage::Sleep | ServerMessage::Reset | ServerMessage::GameInProgress => { + log::info!("ignoring: {msg:?}"); return None; } }) diff --git a/werewolves/src/components/action/target.rs b/werewolves/src/components/action/target.rs index 0048746..dd0573e 100644 --- a/werewolves/src/components/action/target.rs +++ b/werewolves/src/components/action/target.rs @@ -19,11 +19,10 @@ pub struct TwoTargetProps { pub target_selection: Option>, } -#[derive(ChecksAs, Clone)] +#[derive(Clone)] enum TwoTargetSelection { None, One(CharacterId), - #[checks] Two(CharacterId, CharacterId), } diff --git a/werewolves/src/components/notification.rs b/werewolves/src/components/notification.rs index 4e23274..7f32558 100644 --- a/werewolves/src/components/notification.rs +++ b/werewolves/src/components/notification.rs @@ -1,19 +1,19 @@ use yew::prelude::*; -#[derive(Debug, PartialEq, Properties)] -pub struct NotificationProps { - pub text: String, - pub callback: Callback<()>, -} +// #[derive(Debug, PartialEq, Properties)] +// pub struct NotificationProps { +// pub text: String, +// pub callback: Callback<()>, +// } -#[function_component] -pub fn Notification(props: &NotificationProps) -> Html { - let cb = props.callback.clone(); - let on_click = Callback::from(move |_| cb.clone().emit(())); - html! { - -

{props.text.clone()}

- -
- } -} +// #[function_component] +// pub fn Notification(props: &NotificationProps) -> Html { +// let cb = props.callback.clone(); +// let on_click = Callback::from(move |_| cb.clone().emit(())); +// html! { +// +//

{props.text.clone()}

+// +//
+// } +// } diff --git a/werewolves/src/main.rs b/werewolves/src/main.rs index 86d08a3..87d84e2 100644 --- a/werewolves/src/main.rs +++ b/werewolves/src/main.rs @@ -27,7 +27,7 @@ use werewolves_proto::{ use yew::{context::ContextProviderProps, prelude::*}; use crate::clients::{ - client::{Client, Client2, ClientContext, ClientProps, Message}, + client::{Client2, ClientContext}, host::{Host, HostEvent}, }; @@ -70,7 +70,7 @@ fn main() { clients.append_child(&dupe).unwrap(); } - let client = yew::Renderer::>::with_root_and_props( + yew::Renderer::>::with_root_and_props( dupe, ContextProviderProps { context: ClientContext { @@ -90,25 +90,9 @@ fn main() { }, ) .render(); - - // let client = yew::Renderer::::with_root_and_props( - // dupe, - // ClientProps { auto_join: true }, - // ) - // .render(); - - // client.send_message(Message::ForceIdentity(Identification { - // player_id, - // public: PublicIdentity { - // name: name.to_string(), - // pronouns: Some(String::from("he/him")), - // number: None, - // }, - // })); - // client.send_message(Message::SetErrorCallback(error_callback.clone())); } } else { - let client = yew::Renderer::>::with_root_and_props( + yew::Renderer::>::with_root_and_props( app_element, ContextProviderProps { context: ClientContext { @@ -121,11 +105,5 @@ fn main() { }, ) .render(); - // let client = yew::Renderer::::with_root_and_props( - // app_element, - // ClientProps { auto_join: false }, - // ) - // .render(); - // client.send_message(Message::SetErrorCallback(error_callback)); } }