|
|
@ -4,6 +4,10 @@ use std::time::SystemTime; |
|
|
|
use thiserror::Error;
|
|
|
|
use crate::common::serverstate::ClientId;
|
|
|
|
|
|
|
|
use async_std::sync::{Arc, RwLock};
|
|
|
|
use futures::{stream, StreamExt};
|
|
|
|
use std::pin::pin;
|
|
|
|
|
|
|
|
pub const MAX_ROOMS: usize = 128;
|
|
|
|
|
|
|
|
pub enum AreaType {
|
|
|
@ -133,33 +137,48 @@ pub enum RoomLobby { |
|
|
|
Lobby(LobbyId),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct ClientLocation {
|
|
|
|
lobbies: [Lobby; 15],
|
|
|
|
rooms: [Option<Room>; MAX_ROOMS],
|
|
|
|
client_location: HashMap<ClientId, RoomLobby>,
|
|
|
|
lobbies: [Arc<RwLock<Lobby>>; 15],
|
|
|
|
rooms: [Option<Arc<RwLock<Room>>>; MAX_ROOMS],
|
|
|
|
client_location: Arc<RwLock<HashMap<ClientId, RoomLobby>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ClientLocation {
|
|
|
|
fn default() -> ClientLocation {
|
|
|
|
//const RNONE: Option<Arc<RwLock<Room>>> = None;
|
|
|
|
//const LINIT: Arc<RwLock<Lobby>> = Arc::new(RwLock::new(Lobby([None; 12])));
|
|
|
|
ClientLocation {
|
|
|
|
lobbies: [Lobby([None; 12]); 15],
|
|
|
|
rooms: [None; MAX_ROOMS],
|
|
|
|
client_location: HashMap::new(),
|
|
|
|
//lobbies: [LINIT; 15],
|
|
|
|
lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))),
|
|
|
|
rooms: core::array::from_fn(|_| None),
|
|
|
|
//rooms: [RNONE; MAX_ROOMS],
|
|
|
|
client_location: Arc::new(RwLock::new(HashMap::new())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl ClientLocation {
|
|
|
|
pub fn add_client_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<(), JoinLobbyError> {
|
|
|
|
let l = self.lobbies.get_mut(lobby.0).ok_or(JoinLobbyError::LobbyDoesNotExist)?;
|
|
|
|
if l.0.iter().filter(|c| c.is_none()).count() == 0 {
|
|
|
|
pub async fn add_client_to_lobby(&self, id: ClientId, lobby_id: LobbyId) -> Result<(), JoinLobbyError> {
|
|
|
|
{
|
|
|
|
let lobby = self.lobbies
|
|
|
|
.get(lobby_id.0)
|
|
|
|
.ok_or(JoinLobbyError::LobbyDoesNotExist)?
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
if lobby.0.iter().all(|c| c.is_some()) {
|
|
|
|
return Err(JoinLobbyError::LobbyFull);
|
|
|
|
}
|
|
|
|
self.remove_client_from_area(id);
|
|
|
|
}
|
|
|
|
self.remove_client_from_area(id).await;
|
|
|
|
|
|
|
|
let l = self.lobbies.get_mut(lobby.0).ok_or(JoinLobbyError::LobbyDoesNotExist)?;
|
|
|
|
let (index, empty_slot) = l.0.iter_mut()
|
|
|
|
let mut lobby = self.lobbies
|
|
|
|
.get(lobby_id.0)
|
|
|
|
.ok_or(JoinLobbyError::LobbyDoesNotExist)?
|
|
|
|
.write()
|
|
|
|
.await;
|
|
|
|
let (index, empty_slot) = lobby.0.iter_mut()
|
|
|
|
.enumerate()
|
|
|
|
.find(|(_, k)| k.is_none())
|
|
|
|
.ok_or(JoinLobbyError::LobbyFull)?;
|
|
|
@ -168,40 +187,45 @@ impl ClientLocation { |
|
|
|
local_client: LocalClientId(index),
|
|
|
|
time_join: SystemTime::now(),
|
|
|
|
});
|
|
|
|
self.client_location.insert(id, RoomLobby::Lobby(lobby));
|
|
|
|
self.client_location
|
|
|
|
.write()
|
|
|
|
.await
|
|
|
|
.insert(id, RoomLobby::Lobby(lobby_id));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_client_to_next_available_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<LobbyId, JoinLobbyError> {
|
|
|
|
let l = (0..15)
|
|
|
|
.map(|lobby_index| {
|
|
|
|
pub async fn add_client_to_next_available_lobby(&self, id: ClientId, lobby: LobbyId) -> Result<LobbyId, JoinLobbyError> {
|
|
|
|
pin!(stream::iter(0..15)
|
|
|
|
.filter_map(|lobby_index| async move {
|
|
|
|
let new_lobby = LobbyId((lobby.0 + lobby_index) % 15);
|
|
|
|
(new_lobby, self.add_client_to_lobby(id, new_lobby))
|
|
|
|
})
|
|
|
|
.find(|(_, lobby_option)| {
|
|
|
|
lobby_option.is_ok()
|
|
|
|
})
|
|
|
|
.ok_or(JoinLobbyError::LobbyFull)?;
|
|
|
|
|
|
|
|
Ok(l.0)
|
|
|
|
Some((new_lobby, self.add_client_to_lobby(id, new_lobby).await.ok()?))
|
|
|
|
}))
|
|
|
|
.next()
|
|
|
|
.await
|
|
|
|
.map(|l| l.0)
|
|
|
|
.ok_or(JoinLobbyError::LobbyFull)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
|
|
|
|
pub async fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
|
|
|
|
let (index, empty_slot) = self.rooms.iter_mut()
|
|
|
|
.enumerate()
|
|
|
|
.find(|(_, r)| r.is_none())
|
|
|
|
.ok_or(CreateRoomError::NoOpenSlots)?;
|
|
|
|
*empty_slot = Some(Room([None; 4]));
|
|
|
|
self.add_client_to_room(id, RoomId(index)).map_err(|_err| CreateRoomError::JoinError)?;
|
|
|
|
*empty_slot = Some(Arc::new(RwLock::new(Room([None; 4]))));
|
|
|
|
self.add_client_to_room(id, RoomId(index))
|
|
|
|
.await
|
|
|
|
.map_err(|_err| CreateRoomError::JoinError)?;
|
|
|
|
|
|
|
|
Ok(RoomId(index))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> {
|
|
|
|
let r = self.rooms.get_mut(room.0)
|
|
|
|
pub async fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> {
|
|
|
|
let mut r = self.rooms.get(room.0)
|
|
|
|
.ok_or(JoinRoomError::RoomDoesNotExist)?
|
|
|
|
.as_mut()
|
|
|
|
.ok_or(JoinRoomError::RoomDoesNotExist)?;
|
|
|
|
.as_ref()
|
|
|
|
.ok_or(JoinRoomError::RoomDoesNotExist)?
|
|
|
|
.write()
|
|
|
|
.await;
|
|
|
|
let (index, empty_slot) = r.0.iter_mut()
|
|
|
|
.enumerate()
|
|
|
|
.find(|(_, k)| k.is_none())
|
|
|
@ -211,38 +235,51 @@ impl ClientLocation { |
|
|
|
local_client: LocalClientId(index),
|
|
|
|
time_join: SystemTime::now(),
|
|
|
|
});
|
|
|
|
self.remove_client_from_area(id);
|
|
|
|
self.client_location.insert(id, RoomLobby::Room(room));
|
|
|
|
self.remove_client_from_area(id).await;
|
|
|
|
self.client_location
|
|
|
|
.write()
|
|
|
|
.await
|
|
|
|
.insert(id, RoomLobby::Room(room));
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_all_clients_by_client(&self, id: ClientId) -> Result<Vec<AreaClient>, GetNeighborError> {
|
|
|
|
let area = self.client_location.get(&id).ok_or(GetNeighborError::InvalidClient)?;
|
|
|
|
pub async fn get_all_clients_by_client(&self, id: ClientId) -> Result<Vec<AreaClient>, GetNeighborError> {
|
|
|
|
let area = self.client_location
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
let area = area
|
|
|
|
.get(&id)
|
|
|
|
.ok_or(GetNeighborError::InvalidClient)?;
|
|
|
|
match area {
|
|
|
|
RoomLobby::Room(room) => {
|
|
|
|
Ok(self.get_clients_in_room(*room).map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
.into_iter()
|
|
|
|
.collect())
|
|
|
|
},
|
|
|
|
RoomLobby::Lobby(lobby) => {
|
|
|
|
Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
.into_iter()
|
|
|
|
.collect())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_client_neighbors(&self, id: ClientId) -> Result<Vec<AreaClient>, GetNeighborError> {
|
|
|
|
let area = self.client_location.get(&id).ok_or(GetNeighborError::InvalidClient)?;
|
|
|
|
pub async fn get_client_neighbors(&self, id: ClientId) -> Result<Vec<AreaClient>, GetNeighborError> {
|
|
|
|
let area = self.client_location
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
let area = area
|
|
|
|
.get(&id)
|
|
|
|
.ok_or(GetNeighborError::InvalidClient)?;
|
|
|
|
match area {
|
|
|
|
RoomLobby::Room(room) => {
|
|
|
|
Ok(self.get_clients_in_room(*room).map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
Ok(self.get_clients_in_room(*room).await.map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
.into_iter()
|
|
|
|
.filter(|c| c.client != id)
|
|
|
|
.collect())
|
|
|
|
},
|
|
|
|
RoomLobby::Lobby(lobby) => {
|
|
|
|
Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
Ok(self.get_clients_in_lobby(*lobby).await.map_err(|_| GetNeighborError::InvalidArea)?
|
|
|
|
.into_iter()
|
|
|
|
.filter(|c| c.client != id)
|
|
|
|
.collect())
|
|
|
@ -250,51 +287,72 @@ impl ClientLocation { |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_room_leader(&self, room: RoomId) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
let mut r = self.rooms[room.0]
|
|
|
|
pub async fn get_room_leader(&self, room: RoomId) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
let r = self.rooms[room.0]
|
|
|
|
.as_ref()
|
|
|
|
.ok_or(GetLeaderError::InvalidArea)?
|
|
|
|
.0.iter().flatten()
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
let mut r = r
|
|
|
|
.0
|
|
|
|
.iter()
|
|
|
|
.flatten()
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
r.sort_by_key(|k| k.time_join);
|
|
|
|
let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?;
|
|
|
|
let c = r.get(0)
|
|
|
|
.ok_or(GetLeaderError::NoClientInArea)?;
|
|
|
|
Ok(**c)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_lobby_leader(&self, lobby: LobbyId) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
let mut l = self.lobbies[lobby.0]
|
|
|
|
.0.iter().flatten()
|
|
|
|
pub async fn get_lobby_leader(&self, lobby: LobbyId) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
let l = self.lobbies[lobby.0]
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
let mut l = l
|
|
|
|
.0
|
|
|
|
.iter()
|
|
|
|
.flatten()
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
l.sort_by_key(|k| k.time_join);
|
|
|
|
let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?;
|
|
|
|
Ok(**c)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_area_leader(&self, roomlobby: RoomLobby) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
pub async fn get_area_leader(&self, roomlobby: RoomLobby) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
match roomlobby {
|
|
|
|
RoomLobby::Room(room) => {
|
|
|
|
self.get_room_leader(room)
|
|
|
|
self.get_room_leader(room).await
|
|
|
|
},
|
|
|
|
RoomLobby::Lobby(lobby) => {
|
|
|
|
self.get_lobby_leader(lobby)
|
|
|
|
self.get_lobby_leader(lobby).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_leader_by_client(&self, id: ClientId) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
let area = self.client_location.get(&id).ok_or(GetLeaderError::InvalidClient)?;
|
|
|
|
pub async fn get_leader_by_client(&self, id: ClientId) -> Result<AreaClient, GetLeaderError> {
|
|
|
|
let area = self.client_location
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
let area = area
|
|
|
|
.get(&id)
|
|
|
|
.ok_or(GetLeaderError::InvalidClient)?;
|
|
|
|
match area {
|
|
|
|
RoomLobby::Room(room) => {
|
|
|
|
self.get_room_leader(*room)
|
|
|
|
self.get_room_leader(*room).await
|
|
|
|
},
|
|
|
|
RoomLobby::Lobby(lobby) => {
|
|
|
|
self.get_lobby_leader(*lobby)
|
|
|
|
self.get_lobby_leader(*lobby).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result<Vec<AreaClient>, GetClientsError> {
|
|
|
|
Ok(self.lobbies.get(lobby.0).ok_or(GetClientsError::InvalidArea)?.0
|
|
|
|
pub async fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result<Vec<AreaClient>, GetClientsError> {
|
|
|
|
Ok(self.lobbies
|
|
|
|
.get(lobby.0)
|
|
|
|
.ok_or(GetClientsError::InvalidArea)?
|
|
|
|
.read()
|
|
|
|
.await
|
|
|
|
.0
|
|
|
|
.iter()
|
|
|
|
.filter_map(|client| {
|
|
|
|
client.map(|c| {
|
|
|
@ -303,10 +361,14 @@ impl ClientLocation { |
|
|
|
}).collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_clients_in_room(&self, room: RoomId) -> Result<Vec<AreaClient>, GetClientsError> {
|
|
|
|
pub async fn get_clients_in_room(&self, room: RoomId) -> Result<Vec<AreaClient>, GetClientsError> {
|
|
|
|
Ok(self.rooms.get(room.0)
|
|
|
|
.ok_or(GetClientsError::InvalidArea)?
|
|
|
|
.ok_or(GetClientsError::InvalidArea)?.0
|
|
|
|
.as_ref()
|
|
|
|
.ok_or(GetClientsError::InvalidArea)?
|
|
|
|
.read()
|
|
|
|
.await
|
|
|
|
.0
|
|
|
|
.iter()
|
|
|
|
.filter_map(|client| {
|
|
|
|
client.map(|c| {
|
|
|
@ -315,17 +377,26 @@ impl ClientLocation { |
|
|
|
}).collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_local_client(&self, id: ClientId) -> Result<AreaClient, GetClientsError> {
|
|
|
|
let area = self.client_location.get(&id).ok_or(GetClientsError::InvalidClient)?;
|
|
|
|
pub async fn get_local_client(&self, id: ClientId) -> Result<AreaClient, GetClientsError> {
|
|
|
|
let area = self.client_location
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
let area = area
|
|
|
|
.get(&id)
|
|
|
|
.ok_or(GetClientsError::InvalidClient)?;
|
|
|
|
match area {
|
|
|
|
RoomLobby::Room(room) => {
|
|
|
|
self.get_clients_in_room(*room).map_err(|_| GetClientsError::InvalidArea)?
|
|
|
|
self.get_clients_in_room(*room)
|
|
|
|
.await
|
|
|
|
.map_err(|_| GetClientsError::InvalidArea)?
|
|
|
|
.into_iter()
|
|
|
|
.find(|c| c.client == id)
|
|
|
|
.ok_or(GetClientsError::InvalidClient)
|
|
|
|
},
|
|
|
|
RoomLobby::Lobby(lobby) => {
|
|
|
|
self.get_clients_in_lobby(*lobby).map_err(|_| GetClientsError::InvalidArea)?
|
|
|
|
self.get_clients_in_lobby(*lobby)
|
|
|
|
.await
|
|
|
|
.map_err(|_| GetClientsError::InvalidArea)?
|
|
|
|
.into_iter()
|
|
|
|
.find(|c| c.client == id)
|
|
|
|
.ok_or(GetClientsError::InvalidClient)
|
|
|
@ -333,14 +404,17 @@ impl ClientLocation { |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_area(&self, id: ClientId) -> Result<RoomLobby, GetAreaError> {
|
|
|
|
self.client_location.get(&id)
|
|
|
|
pub async fn get_area(&self, id: ClientId) -> Result<RoomLobby, GetAreaError> {
|
|
|
|
self.client_location
|
|
|
|
.read()
|
|
|
|
.await
|
|
|
|
.get(&id)
|
|
|
|
.ok_or(GetAreaError::InvalidClient)
|
|
|
|
.map(Clone::clone)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_room(&self, id: ClientId) -> Result<RoomId, GetAreaError> {
|
|
|
|
if let RoomLobby::Room(room) = self.client_location.get(&id).ok_or(GetAreaError::InvalidClient)? {
|
|
|
|
pub async fn get_room(&self, id: ClientId) -> Result<RoomId, GetAreaError> {
|
|
|
|
if let RoomLobby::Room(room) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? {
|
|
|
|
Ok(*room)
|
|
|
|
}
|
|
|
|
else {
|
|
|
@ -348,8 +422,8 @@ impl ClientLocation { |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_lobby(&self, id: ClientId) -> Result<LobbyId, GetAreaError> {
|
|
|
|
if let RoomLobby::Lobby(lobby) = self.client_location.get(&id).ok_or(GetAreaError::InvalidClient)? {
|
|
|
|
pub async fn get_lobby(&self, id: ClientId) -> Result<LobbyId, GetAreaError> {
|
|
|
|
if let RoomLobby::Lobby(lobby) = self.client_location.read().await.get(&id).ok_or(GetAreaError::InvalidClient)? {
|
|
|
|
Ok(*lobby)
|
|
|
|
}
|
|
|
|
else {
|
|
|
@ -357,23 +431,10 @@ impl ClientLocation { |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_client_from_area(&mut self, id: ClientId) -> Result<(), ClientRemovalError> {
|
|
|
|
let area = self.client_location.get_mut(&id).ok_or(ClientRemovalError::ClientNotInArea)?;
|
|
|
|
let client_list = match area {
|
|
|
|
RoomLobby::Room(room) => {
|
|
|
|
self.rooms[room.0]
|
|
|
|
.as_mut()
|
|
|
|
.map(|r| {
|
|
|
|
r.0.iter_mut()
|
|
|
|
})
|
|
|
|
},
|
|
|
|
RoomLobby::Lobby(lobby) => {
|
|
|
|
Some(self.lobbies[lobby.0].0.iter_mut())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pub async fn remove_client_from_area(&self, id: ClientId) -> Result<(), ClientRemovalError> {
|
|
|
|
fn remove_client<const N: usize>(id: ClientId, client_list : &mut [Option<AreaClient>; N]) {
|
|
|
|
client_list
|
|
|
|
.ok_or(ClientRemovalError::InvalidArea)?
|
|
|
|
.iter_mut()
|
|
|
|
.filter(|client| {
|
|
|
|
client.map_or(false, |c| {
|
|
|
|
c.client == id
|
|
|
@ -382,6 +443,29 @@ impl ClientLocation { |
|
|
|
.for_each(|client| {
|
|
|
|
*client = None
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let area = self.client_location
|
|
|
|
.read()
|
|
|
|
.await;
|
|
|
|
let area = area
|
|
|
|
.get(&id)
|
|
|
|
.ok_or(ClientRemovalError::ClientNotInArea)?;
|
|
|
|
match area {
|
|
|
|
RoomLobby::Room(room) => {
|
|
|
|
let r = self.rooms.get(room.0).ok_or(ClientRemovalError::InvalidArea)?;
|
|
|
|
if let Some(r) = r {
|
|
|
|
remove_client(id, &mut r.write().await.0)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return Err(ClientRemovalError::InvalidArea)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
RoomLobby::Lobby(lobby) => {
|
|
|
|
remove_client(id, &mut self.lobbies[lobby.0].write().await.0)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -397,173 +481,174 @@ impl ClientLocation { |
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_client_to_lobby() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(13), LobbyId(1));
|
|
|
|
cl.add_client_to_lobby(ClientId(14), LobbyId(0));
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_add_client_to_lobby() {
|
|
|
|
let cl = ClientLocation::default();
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap();
|
|
|
|
cl.add_client_to_lobby(ClientId(13), LobbyId(1)).await.unwrap();
|
|
|
|
cl.add_client_to_lobby(ClientId(14), LobbyId(0)).await.unwrap();
|
|
|
|
|
|
|
|
assert!(cl.get_clients_in_lobby(LobbyId(0)).into_iter().flatten().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
assert!(cl.get_clients_in_lobby(LobbyId(0)).await.into_iter().flatten().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
(ClientId(12), LocalClientId(0)),
|
|
|
|
(ClientId(14), LocalClientId(1)),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_client_to_full_lobby() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
(0..12).for_each(|i| {
|
|
|
|
cl.add_client_to_lobby(ClientId(i), LobbyId(0));
|
|
|
|
});
|
|
|
|
assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)) == Err(JoinLobbyError::LobbyFull));
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_add_client_to_full_lobby() {
|
|
|
|
let cl = ClientLocation::default();
|
|
|
|
for i in 0..12 {
|
|
|
|
cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap();
|
|
|
|
}
|
|
|
|
assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await == Err(JoinLobbyError::LobbyFull));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_client_to_next_available_lobby() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
(1..4).for_each(|lobby| {
|
|
|
|
(0..12).for_each(|i| {
|
|
|
|
cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)) == Ok(LobbyId(4)));
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_add_client_to_next_available_lobby() {
|
|
|
|
let cl = ClientLocation::default();
|
|
|
|
for lobby in 1..4 {
|
|
|
|
for i in 0..12 {
|
|
|
|
cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await == Ok(LobbyId(4)));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_to_lobby_when_all_are_full() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
(0..15).for_each(|lobby| {
|
|
|
|
(0..12).for_each(|i| {
|
|
|
|
cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
assert!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)) == Err(JoinLobbyError::LobbyFull));
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_add_to_lobby_when_all_are_full() {
|
|
|
|
let cl = ClientLocation::default();
|
|
|
|
for lobby in 0..15 {
|
|
|
|
for i in 0..12 {
|
|
|
|
cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby)).await.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert_eq!(cl.add_client_to_next_available_lobby(ClientId(99), LobbyId(1)).await, Err(JoinLobbyError::LobbyFull));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_new_room() {
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_new_room() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
assert!(cl.create_new_room(ClientId(12)) == Ok(RoomId(0)));
|
|
|
|
assert!(cl.create_new_room(ClientId(12)).await == Ok(RoomId(0)));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_client_to_room() {
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_add_client_to_room() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
let room = cl.create_new_room(ClientId(12)).unwrap();
|
|
|
|
assert!(cl.add_client_to_room(ClientId(234), room) == Ok(()));
|
|
|
|
assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
let room = cl.create_new_room(ClientId(12)).await.unwrap();
|
|
|
|
assert!(cl.add_client_to_room(ClientId(234), room).await == Ok(()));
|
|
|
|
assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
(ClientId(12), LocalClientId(0)),
|
|
|
|
(ClientId(234), LocalClientId(1)),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_no_new_room_slots() {
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_no_new_room_slots() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
for i in 0..128 {
|
|
|
|
cl.create_new_room(ClientId(i));
|
|
|
|
cl.create_new_room(ClientId(i)).await;
|
|
|
|
}
|
|
|
|
assert!(cl.create_new_room(ClientId(234)) == Err(CreateRoomError::NoOpenSlots));
|
|
|
|
assert!(cl.create_new_room(ClientId(234)).await == Err(CreateRoomError::NoOpenSlots));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_joining_full_room() {
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_joining_full_room() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
let room = cl.create_new_room(ClientId(0)).unwrap();
|
|
|
|
assert!(cl.add_client_to_room(ClientId(1), room) == Ok(()));
|
|
|
|
assert!(cl.add_client_to_room(ClientId(2), room) == Ok(()));
|
|
|
|
assert!(cl.add_client_to_room(ClientId(3), room) == Ok(()));
|
|
|
|
assert!(cl.add_client_to_room(ClientId(234), room) == Err(JoinRoomError::RoomFull));
|
|
|
|
let room = cl.create_new_room(ClientId(0)).await.unwrap();
|
|
|
|
assert!(cl.add_client_to_room(ClientId(1), room).await == Ok(()));
|
|
|
|
assert!(cl.add_client_to_room(ClientId(2), room).await == Ok(()));
|
|
|
|
assert!(cl.add_client_to_room(ClientId(3), room).await == Ok(()));
|
|
|
|
assert!(cl.add_client_to_room(ClientId(234), room).await == Err(JoinRoomError::RoomFull));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_adding_client_to_room_removes_from_lobby() {
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_adding_client_to_room_removes_from_lobby() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
cl.add_client_to_lobby(ClientId(93), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(23), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(51), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0));
|
|
|
|
|
|
|
|
let room = cl.create_new_room(ClientId(51)).unwrap();
|
|
|
|
assert!(cl.add_client_to_room(ClientId(93), room) == Ok(()));
|
|
|
|
assert!(cl.get_clients_in_lobby(LobbyId(0)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await;
|
|
|
|
cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await;
|
|
|
|
cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await;
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await;
|
|
|
|
|
|
|
|
let room = cl.create_new_room(ClientId(51)).await.unwrap();
|
|
|
|
assert!(cl.add_client_to_room(ClientId(93), room).await == Ok(()));
|
|
|
|
assert!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
(ClientId(23), LocalClientId(1)),
|
|
|
|
(ClientId(12), LocalClientId(3)),
|
|
|
|
]);
|
|
|
|
assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
(ClientId(51), LocalClientId(0)),
|
|
|
|
(ClientId(93), LocalClientId(1)),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_getting_neighbors() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
cl.add_client_to_lobby(ClientId(93), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(23), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(51), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0));
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_getting_neighbors() {
|
|
|
|
let cl = ClientLocation::default();
|
|
|
|
cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await.unwrap();
|
|
|
|
cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await.unwrap();
|
|
|
|
cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await.unwrap();
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await.unwrap();
|
|
|
|
|
|
|
|
assert!(cl.get_client_neighbors(ClientId(23)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
assert!(cl.get_client_neighbors(ClientId(23)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
(ClientId(93), LocalClientId(0)),
|
|
|
|
(ClientId(51), LocalClientId(2)),
|
|
|
|
(ClientId(12), LocalClientId(3)),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_failing_to_join_lobby_does_not_remove_from_current_area() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
(0..12).for_each(|i| {
|
|
|
|
cl.add_client_to_lobby(ClientId(i), LobbyId(0));
|
|
|
|
});
|
|
|
|
cl.add_client_to_lobby(ClientId(99), LobbyId(1));
|
|
|
|
cl.add_client_to_lobby(ClientId(99), LobbyId(0));
|
|
|
|
assert!(cl.get_clients_in_lobby(LobbyId(0)).unwrap().len() == 12);
|
|
|
|
assert!(cl.get_clients_in_lobby(LobbyId(1)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
(ClientId(99), LocalClientId(0)),
|
|
|
|
]);
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_failing_to_join_lobby_does_not_remove_from_current_area() {
|
|
|
|
let cl = ClientLocation::default();
|
|
|
|
for i in 0..12 {
|
|
|
|
cl.add_client_to_lobby(ClientId(i), LobbyId(0)).await.unwrap();
|
|
|
|
}
|
|
|
|
assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(1)).await.is_ok());
|
|
|
|
assert!(cl.add_client_to_lobby(ClientId(99), LobbyId(0)).await.is_err());
|
|
|
|
assert_eq!(cl.get_clients_in_lobby(LobbyId(0)).await.unwrap().len(), 12);
|
|
|
|
assert_eq!(
|
|
|
|
cl.get_clients_in_lobby(LobbyId(1)).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>(),
|
|
|
|
vec![(ClientId(99), LocalClientId(0))]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_leader() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
cl.add_client_to_lobby(ClientId(93), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(23), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(51), LobbyId(0));
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0));
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_get_leader() {
|
|
|
|
let cl = ClientLocation::default();
|
|
|
|
cl.add_client_to_lobby(ClientId(93), LobbyId(0)).await;
|
|
|
|
cl.add_client_to_lobby(ClientId(23), LobbyId(0)).await;
|
|
|
|
cl.add_client_to_lobby(ClientId(51), LobbyId(0)).await;
|
|
|
|
cl.add_client_to_lobby(ClientId(12), LobbyId(0)).await;
|
|
|
|
|
|
|
|
assert!(cl.get_leader_by_client(ClientId(51)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0))));
|
|
|
|
assert!(cl.get_leader_by_client(ClientId(51)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0))));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_remove_client_from_room() {
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_remove_client_from_room() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
let room = cl.create_new_room(ClientId(51)).unwrap();
|
|
|
|
cl.add_client_to_room(ClientId(93), room);
|
|
|
|
cl.add_client_to_room(ClientId(23), room);
|
|
|
|
cl.remove_client_from_area(ClientId(51));
|
|
|
|
cl.add_client_to_room(ClientId(12), room);
|
|
|
|
let room = cl.create_new_room(ClientId(51)).await.unwrap();
|
|
|
|
cl.add_client_to_room(ClientId(93), room).await;
|
|
|
|
cl.add_client_to_room(ClientId(23), room).await;
|
|
|
|
cl.remove_client_from_area(ClientId(51)).await;
|
|
|
|
cl.add_client_to_room(ClientId(12), room).await;
|
|
|
|
|
|
|
|
assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
assert!(cl.get_clients_in_room(room).await.unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|
|
|
(ClientId(12), LocalClientId(0)),
|
|
|
|
(ClientId(93), LocalClientId(1)),
|
|
|
|
(ClientId(23), LocalClientId(2)),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_leader_changes_on_leader_leaving() {
|
|
|
|
#[async_std::test]
|
|
|
|
async fn test_leader_changes_on_leader_leaving() {
|
|
|
|
let mut cl = ClientLocation::default();
|
|
|
|
let room = cl.create_new_room(ClientId(51)).unwrap();
|
|
|
|
cl.add_client_to_room(ClientId(93), room);
|
|
|
|
cl.add_client_to_room(ClientId(23), room);
|
|
|
|
cl.remove_client_from_area(ClientId(51));
|
|
|
|
cl.add_client_to_room(ClientId(12), room);
|
|
|
|
cl.remove_client_from_area(ClientId(23));
|
|
|
|
cl.add_client_to_room(ClientId(99), room);
|
|
|
|
|
|
|
|
assert!(cl.get_leader_by_client(ClientId(12)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1))));
|
|
|
|
let room = cl.create_new_room(ClientId(51)).await.unwrap();
|
|
|
|
cl.add_client_to_room(ClientId(93), room).await.unwrap();
|
|
|
|
cl.add_client_to_room(ClientId(23), room).await.unwrap();
|
|
|
|
cl.remove_client_from_area(ClientId(51)).await.unwrap();
|
|
|
|
cl.add_client_to_room(ClientId(12), room).await.unwrap();
|
|
|
|
cl.remove_client_from_area(ClientId(23)).await.unwrap();
|
|
|
|
cl.add_client_to_room(ClientId(99), room).await.unwrap();
|
|
|
|
|
|
|
|
assert!(cl.get_leader_by_client(ClientId(12)).await.map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1))));
|
|
|
|
}
|
|
|
|
}
|