aboutsummaryrefslogtreecommitdiff
path: root/src/lobby.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lobby.rs')
-rw-r--r--src/lobby.rs136
1 files changed, 120 insertions, 16 deletions
diff --git a/src/lobby.rs b/src/lobby.rs
index ac6ab305414a..496f98bd7b6f 100644
--- a/src/lobby.rs
+++ b/src/lobby.rs
@@ -3,7 +3,7 @@
use crate::{
data::{Color, ColorPalette},
users::MetaUser,
- wire::{Lobby, LobbyId, LobbyUser},
+ wire::{Lobby, LobbyErr, LobbyId, LobbyUpdate, LobbyUser, User, UserId},
};
use async_std::sync::{Arc, RwLock};
use std::{
@@ -14,15 +14,60 @@ use std::{
/// A list of all the lobbies on the server
pub struct LobbyList {
max: AtomicUsize,
- users: RwLock<BTreeMap<LobbyId, Arc<MetaLobby>>>,
+ 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 {
- palette: Vec<Color>,
- inner: Lobby,
+ pub palette: Vec<Color>,
+ pub inner: Lobby,
}
impl MetaLobby {
@@ -38,21 +83,19 @@ impl MetaLobby {
}
}
- pub fn join(&mut self, user: MetaUser) {
+ pub fn join(&mut self, user: &MetaUser) -> Lobby {
let color = if &user.name == "spacekookie" {
let color = Color::blue();
+ self.palette.without(&color);
- let num = self.inner.players.len();
- self.palette = Vec::without(&color);
- let in_use = self.palette.split_off(num);
-
- self.inner
+ if let Some(user) = self
+ .inner
.players
.iter_mut()
- .zip(in_use.into_iter())
- .for_each(|(user, color)| {
- user.color = color;
- });
+ .find(|u| u.color == Color::blue())
+ {
+ user.color = self.palette.remove(0);
+ }
color
} else {
@@ -60,14 +103,17 @@ impl MetaLobby {
};
self.inner.players.push(LobbyUser {
+ admin: false,
id: user.id,
- name: user.name,
+ name: user.name.clone(),
ready: false,
color,
});
+
+ self.inner.clone()
}
- pub fn leave(&mut self, user: MetaUser) {
+ pub fn leave(&mut self, user: &MetaUser) {
let (pos, user) = self
.inner
.players
@@ -84,4 +130,62 @@ impl MetaLobby {
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(()),
+ }
+ }
}