diff --git a/src/api/mod.rs b/src/api/mod.rs index b36fcc4..53f1b2c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -63,6 +63,7 @@ pub enum Request { GetScene { id: usize, }, + /// TODO: Perhaps remove it, as the client should auto get it on login and on scene list updates GetSceneList, GetTokens { scene: usize, diff --git a/src/lib.rs b/src/lib.rs index 48a0e78..ff07bea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,7 @@ impl GameServer { pub async fn server_loop( mut self, mut msgs: mpsc::Receiver<(String, api::Request)>, - broadcast: broadcast::Sender<(Option, api::Response)>, + broadcast: broadcast::Sender<(SendTo, api::Response)>, ) { while let Some(req) = msgs.recv().await { let (id, req) = req; @@ -98,18 +98,18 @@ impl GameServer { self.users.insert(login.username.clone(), admin); // Send login confirmation _ = broadcast.send(( - Some(id.clone()), + SendTo::User(id.clone()), api::Response::Login(api::login::LoginResult { success: true, username: login.username.clone(), }), )); // Send the list of scenes and chat history and such - _ = broadcast.send((Some(login.username.clone()), self.get_scene_list(admin))); - _ = broadcast.send((Some(login.username.clone()), self.get_last_messages(50))); + _ = broadcast.send((SendTo::User(login.username.clone()), self.get_scene_list(admin))); + _ = broadcast.send((SendTo::User(login.username.clone()), self.get_last_messages(50))); } else { _ = broadcast.send(( - Some(id.clone()), + SendTo::User(id.clone()), api::Response::Login(api::login::LoginResult { success: false, username: login.username, @@ -131,15 +131,18 @@ impl GameServer { self.chat.push((id.clone(), msg.clone())); if msg.whisper.is_some() { - _ = broadcast.send((Some(id.clone()), api::Response::Message(msg.clone()))); + _ = broadcast.send((SendTo::User(id.clone()), api::Response::Message(msg.clone()))); } - _ = broadcast.send((msg.whisper.clone(), api::Response::Message(msg))); + _ = broadcast.send(( + msg.whisper.clone().map(|id| SendTo::User(id)).unwrap_or_default(), + api::Response::Message(msg), + )); } api::Request::GetChatHistory { amount, from } => { - _ = broadcast.send((Some(id), self.get_chat_history(amount, from))); + _ = broadcast.send((SendTo::User(id), self.get_chat_history(amount, from))); } api::Request::GetLastMessages { amount } => { - _ = broadcast.send((Some(id), self.get_last_messages(amount))); + _ = broadcast.send((SendTo::User(id), self.get_last_messages(amount))); } api::Request::GetTokens { scene } => { for token_id in self.game.available_tokens(scene, self.is_admin(&id)) { @@ -147,7 +150,7 @@ impl GameServer { (ti.visible_to_players) { _ = broadcast.send(( - Some(id.clone()), + SendTo::User(id.clone()), api::Response::SpawnToken(SpawnToken { token_id: token_id, x: ti.x, @@ -160,14 +163,14 @@ impl GameServer { } api::Request::GetScene { id: scene_id } => { if let Some(response) = self.get_scene(&id, scene_id) { - _ = broadcast.send((Some(id), response)); + _ = broadcast.send((SendTo::User(id), response)); } } api::Request::CreateScene { title } => { if self.is_admin(&id) { self.game.create_scene(title); let scenes = self.get_scene_list(true); - _ = broadcast.send((Some(id), scenes)); + _ = broadcast.send((SendTo::User(id), scenes)); } } api::Request::SetSceneGrid { @@ -180,7 +183,11 @@ impl GameServer { if let Some(map) = s.map.as_mut() { map.grid_cell_size = grid_cell_size; map.grid_offset = grid_offset; - let return_id = if s.visible_to_users { None } else { Some(id.clone()) }; + let return_id = if s.visible_to_users { + SendTo::All + } else { + SendTo::User(id.clone()) + }; if let Some(scene) = self.get_scene(&id, scene) { _ = broadcast.send((return_id, scene)); } @@ -191,12 +198,12 @@ impl GameServer { api::Request::SceneSetVisible { scene, visible } => { if self.is_admin(&id) { self.game.scene_visible(scene, visible); - _ = broadcast.send((None, self.get_scene_list(false))); - _ = broadcast.send((Some(id), self.get_scene_list(true))); + _ = broadcast.send((SendTo::AllBut(id.clone()), self.get_scene_list(false))); + _ = broadcast.send((SendTo::User(id), self.get_scene_list(true))); } } api::Request::GetSceneList => { - _ = broadcast.send((Some(id.clone()), self.get_scene_list(self.is_admin(&id)))); + _ = broadcast.send((SendTo::User(id.clone()), self.get_scene_list(self.is_admin(&id)))); } api::Request::SpawnToken { map_id, @@ -213,9 +220,9 @@ impl GameServer { .create_token(map_id, character, img_path.clone(), x, y, visible_to_players); _ = broadcast.send(( if visible_to_players && scene_visible { - None + SendTo::All } else { - Some(id) + SendTo::User(id) }, api::Response::SpawnToken(SpawnToken { token_id, @@ -231,7 +238,7 @@ impl GameServer { if self.game.move_token(0, token_id, x, y) { // TODO: maybe chage move_token to return optional x,y values if succeeded to make sure the token is where it was going to be // TODO: Check if the token is visible to players and if not, only update it's position to admins or something - _ = broadcast.send((None, api::Response::MoveToken { token_id, x, y })); + _ = broadcast.send((SendTo::All, api::Response::MoveToken { token_id, x, y })); } } api::Request::ActionResult(result) => { @@ -249,27 +256,27 @@ impl GameServer { .targets(Some(result.targets)) .id(self.chat.len() + 1); self.chat.push((id, msg.clone())); - _ = broadcast.send((None, api::Response::Message(msg))); + _ = broadcast.send((SendTo::All, api::Response::Message(msg))); } api::Request::CreateCharacter => { // check if user is admin if self.is_admin(&id) { let new_id = self.game.create_character(); // return the new id with the character i think - _ = broadcast.send((Some(id), api::Response::CharacterCreated(new_id))); + _ = broadcast.send((SendTo::User(id), api::Response::CharacterCreated(new_id))); } } api::Request::Quit => { if self.users.contains_key(&id) { self.users.remove(&id); } - _ = broadcast.send((None, api::Response::Quit { id })); + _ = broadcast.send((SendTo::All, api::Response::Quit { id })); } api::Request::Kick(id) => { if self.users.contains_key(&id) { self.users.remove(&id); } - _ = broadcast.send((Some(id), api::Response::Shutdown)); + _ = broadcast.send((SendTo::User(id), api::Response::Shutdown)); } api::Request::Shutdown => { if self.is_admin(&id) { @@ -292,7 +299,7 @@ impl GameServer { self.save().await; } } - _ = broadcast.send((None, api::Response::Shutdown)); + _ = broadcast.send((SendTo::All, api::Response::Shutdown)); self.save().await; // Save the game one last time :) } @@ -369,3 +376,20 @@ impl GameServer { self.users.get(id).map(|a| *a).unwrap_or(false) } } + +#[derive(Default, Clone, Debug)] +pub enum SendTo { + #[default] + All, + User(String), + AllBut(String), +} +impl SendTo { + pub fn should_send(&self, to: &str) -> bool { + match self { + SendTo::All => true, + SendTo::User(user) => user == to, + SendTo::AllBut(user) => user != to, + } + } +} diff --git a/src/main.rs b/src/main.rs index d02a96c..27c08b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,10 @@ use futures_util::{ SinkExt, StreamExt, stream::{SplitSink, SplitStream}, }; -use open_tavern::api::{Request, RequestError, Response}; +use open_tavern::{ + SendTo, + api::{Request, RequestError, Response}, +}; use tokio::sync::{broadcast, mpsc}; use tokio_util::io::ReaderStream; @@ -55,7 +58,7 @@ async fn run_web_server(listener: tokio::net::TcpListener, app: Router) { async fn ws_handler( ws: ws::WebSocketUpgrade, msend: mpsc::Sender<(String, Request)>, - brecv: broadcast::Receiver<(Option, Response)>, + brecv: broadcast::Receiver<(SendTo, Response)>, ) -> impl axum::response::IntoResponse { ws.on_upgrade(|w| handle_socket(w, msend, brecv)) } @@ -89,10 +92,10 @@ async fn socket_receiver(mut recv: SplitStream, msend: mpsc::Send async fn socket_sender( id: String, mut send: SplitSink, - mut brecv: broadcast::Receiver<(Option, Response)>, + mut brecv: broadcast::Receiver<(SendTo, Response)>, ) { while let Ok((to_id, msg)) = brecv.recv().await { - if to_id.is_none() || to_id.map(|t| t == id).unwrap_or(false) { + if to_id.should_send(&id) { println!("Sending a message to {}: {:?}", &id, &msg); let err = send .send(ws::Message::Text(serde_json::to_string(&msg).unwrap().into())) @@ -110,7 +113,7 @@ async fn socket_sender( async fn handle_socket( mut socket: ws::WebSocket, msend: mpsc::Sender<(String, Request)>, - mut brecv: broadcast::Receiver<(Option, Response)>, + mut brecv: broadcast::Receiver<(SendTo, Response)>, ) { let mut id: Option = None; // this is a temp id, and as long as 2 people dont try to connect to the socket at the same milisecond and to the same user it would be fine (i hope) @@ -128,7 +131,7 @@ async fn handle_socket( println!("{} trying to log in: {:?}", &temp_id, &b); if let Ok((to_id, msg)) = b { if let Response::Login(open_tavern::api::login::LoginResult { success, username }) = &msg { - let to_id = to_id.map(|ti| ti == temp_id).unwrap_or(false); + let to_id = to_id.should_send(&temp_id); if to_id && *success && id.as_ref().map(|id| id == username).unwrap_or(false) { _ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default().into())).await; break;