diff options
Diffstat (limited to 'games/rstnode/src/lobby.rs')
-rw-r--r-- | games/rstnode/src/lobby.rs | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/games/rstnode/src/lobby.rs b/games/rstnode/src/lobby.rs new file mode 100644 index 000000000000..496f98bd7b6f --- /dev/null +++ b/games/rstnode/src/lobby.rs @@ -0,0 +1,191 @@ +//! The code that handles the lobby logic + +use crate::{ + data::{Color, ColorPalette}, + users::MetaUser, + wire::{Lobby, LobbyErr, LobbyId, LobbyUpdate, LobbyUser, User, UserId}, +}; +use async_std::sync::{Arc, RwLock}; +use std::{ + collections::BTreeMap, + sync::atomic::{AtomicUsize, Ordering}, +}; + +/// A list of all the lobbies on the server +pub struct LobbyList { + max: AtomicUsize, + lobbies: RwLock<BTreeMap<LobbyId, MetaLobby>>, +} + +impl LobbyList { + pub fn new() -> Self { + Self { + max: 0.into(), + lobbies: Default::default(), + } + } + + /// Create a new lobby + pub async fn create(&self, map: String) -> LobbyId { + let id = self.max.fetch_add(1, Ordering::Relaxed); + self.lobbies + .write() + .await + .insert(id, MetaLobby::create(id, map)); + id + } + + /// Remove a lobby by ID + pub async fn destroy(&self, id: LobbyId) -> Result<(), LobbyErr> { + self.consume(id).await.map(|_| ()) + } + + /// Remove and return the lobby + pub async fn consume(&self, id: LobbyId) -> Result<MetaLobby, LobbyErr> { + self.lobbies + .write() + .await + .remove(&id) + .map_or(Err(LobbyErr::NoSuchRoom), |l| Ok(l)) + } + + /// Get mutable access to a lobby + pub async fn get_mut<F, T>(&self, id: LobbyId, cb: F) -> Result<T, LobbyErr> + where + F: Fn(&mut MetaLobby) -> T, + { + self.lobbies + .write() + .await + .get_mut(&id) + .map_or(Err(LobbyErr::OtherError), |ref mut l| Ok(cb(l))) + } +} + +/// Additional state held by the server +/// +/// The meta lobby will also sync updates to all connected users, when updates are made to the lobby +pub struct MetaLobby { + pub palette: Vec<Color>, + pub inner: Lobby, +} + +impl MetaLobby { + pub fn create(id: LobbyId, map: String) -> Self { + Self { + palette: Vec::palette(), + inner: Lobby { + id, + map, + players: vec![], + settings: vec![], + }, + } + } + + pub fn join(&mut self, user: &MetaUser) -> Lobby { + let color = if &user.name == "spacekookie" { + let color = Color::blue(); + self.palette.without(&color); + + if let Some(user) = self + .inner + .players + .iter_mut() + .find(|u| u.color == Color::blue()) + { + user.color = self.palette.remove(0); + } + + color + } else { + self.palette.remove(0) + }; + + self.inner.players.push(LobbyUser { + admin: false, + id: user.id, + name: user.name.clone(), + ready: false, + color, + }); + + self.inner.clone() + } + + pub fn leave(&mut self, user: &MetaUser) { + let (pos, user) = self + .inner + .players + .iter() + .enumerate() + .find_map(|(num, u)| { + if u.id == user.id { + Some((num, u)) + } else { + None + } + }) + .unwrap(); + self.palette.remix(user.color); + self.inner.players.remove(pos); + } + + /// Check if a user is even present in a lobby + /// + /// Perform this prerequisite check before making other user-specific changes to the lobby + pub fn in_lobby(&self, user: UserId) -> bool { + self.inner + .players + .iter() + .find(|u| u.id == user) + .map(|_| true) + .unwrap_or(false) + } + + /// Set the ready state for a user + pub fn ready(&mut self, user: User, ready: bool) -> LobbyUpdate { + if let Some(user) = self + .inner + .players + .iter_mut() + .find(|u| u.id == user.id) + .as_mut() + { + user.ready = ready; + } + + LobbyUpdate::Ready( + self.inner + .players + .iter() + .filter_map(|u| if u.ready { Some(u.id) } else { None }) + .collect(), + ) + } + + /// Try to start a game, if the user can and everybody is ready + pub fn start(&mut self, user: UserId) -> Result<(), LobbyErr> { + if let Some(_) = self + .inner + .players + .iter() + .filter(|u| u.admin) + .find(|u| u.id == user) + { + return Err(LobbyErr::NotAuthorized); + }; + + match self + .inner + .players + .iter() + .filter(|u| !u.ready) + .collect::<Vec<_>>() + .len() + { + 0 => Err(LobbyErr::NotAllReady), + _ => Ok(()), + } + } +} |