Browse Source
Merge pull request 'misc refactorings to make things easier' (#100) from refactor_some_things into master
pbs
Merge pull request 'misc refactorings to make things easier' (#100) from refactor_some_things into master
pbs
jake
5 years ago
15 changed files with 785 additions and 511 deletions
-
11src/entity/item/mod.rs
-
20src/ship/drops/box_drop_table.rs
-
18src/ship/drops/generic_armor.rs
-
16src/ship/drops/generic_shield.rs
-
20src/ship/drops/generic_unit.rs
-
46src/ship/drops/generic_weapon.rs
-
12src/ship/drops/mod.rs
-
6src/ship/drops/rare_drop_table.rs
-
16src/ship/drops/tech_table.rs
-
8src/ship/drops/tool_table.rs
-
44src/ship/items.rs
-
674src/ship/location.rs
-
180src/ship/map.rs
-
4src/ship/room.rs
-
221src/ship/ship.rs
@ -1,305 +1,519 @@ |
|||
use std::collections::HashMap;
|
|||
use std::sync::{Arc, RwLock};
|
|||
use std::convert::Into;
|
|||
|
|||
use std::time::SystemTime;
|
|||
use crate::common::serverstate::ClientId;
|
|||
// TODO: room passwords?
|
|||
// TODO: remove clients from areas (or upon insert, remove that id from anywhere else)
|
|||
|
|||
pub const MAX_ROOMS: usize = 128;
|
|||
|
|||
#[derive(Copy, Clone)]
|
|||
pub struct AreaClient {
|
|||
client_id: ClientId,
|
|||
time_join: SystemTime,
|
|||
}
|
|||
|
|||
#[derive(Copy, Clone)]
|
|||
pub struct InnerClientArea<const N: usize> {
|
|||
clients: [Option<AreaClient>; N],
|
|||
pub enum AreaType {
|
|||
Room,
|
|||
Lobby,
|
|||
}
|
|||
|
|||
impl<const N: usize> InnerClientArea<{N}> {
|
|||
pub fn new() -> InnerClientArea<{N}> {
|
|||
let mut clients: [std::mem::MaybeUninit<Option<AreaClient>>; N] = unsafe {
|
|||
std::mem::MaybeUninit::uninit().assume_init()
|
|||
};
|
|||
for i in clients.iter_mut() {
|
|||
i.write(None);
|
|||
}
|
|||
|
|||
InnerClientArea {
|
|||
clients: unsafe { (&clients as *const _ as *const [Option<AreaClient>; N]).read()}
|
|||
}
|
|||
}
|
|||
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
pub struct LobbyId(pub usize);
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
pub struct RoomId(pub usize);
|
|||
|
|||
fn add(&mut self, id: ClientId) -> Option<usize> {
|
|||
for (i, client) in self.clients.iter_mut().enumerate() {
|
|||
if client.is_none() {
|
|||
*client = Some(AreaClient{
|
|||
client_id: id,
|
|||
time_join: SystemTime::now(),
|
|||
});
|
|||
return Some(i);
|
|||
}
|
|||
}
|
|||
return None;
|
|||
}
|
|||
fn remove(&mut self, id: ClientId) -> bool {
|
|||
for areaclient in self.clients.iter_mut() {
|
|||
if let Some(client) = *areaclient {
|
|||
if client.client_id == id {
|
|||
*areaclient = None;
|
|||
return true;
|
|||
}
|
|||
}
|
|||
}
|
|||
false
|
|||
}
|
|||
|
|||
fn contains(&self, id: ClientId) -> bool {
|
|||
self.clients.iter()
|
|||
.filter(|k| k.is_some())
|
|||
.map(|k| k.unwrap() )
|
|||
.fold(false, |acc, k| {
|
|||
if acc {
|
|||
acc
|
|||
}
|
|||
else if k.client_id == id {
|
|||
true
|
|||
}
|
|||
else {
|
|||
false
|
|||
}
|
|||
})
|
|||
impl LobbyId {
|
|||
pub fn id(&self) -> u8 {
|
|||
self.0 as u8
|
|||
}
|
|||
}
|
|||
|
|||
pub struct LobbyId(pub usize);
|
|||
pub struct RoomId(pub usize);
|
|||
|
|||
pub type Lobby = InnerClientArea<12>;
|
|||
pub type Room = InnerClientArea<4>;
|
|||
|
|||
trait ClientArea {
|
|||
fn clients(&self) -> std::slice::Iter<'_, Option<AreaClient>>;
|
|||
fn remove(&mut self, id: ClientId) -> bool;
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum CreateRoomError {
|
|||
NoOpenSlots,
|
|||
ClientInAreaAlready,
|
|||
JoinError,
|
|||
}
|
|||
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum JoinRoomError {
|
|||
RoomDoesNotExist,
|
|||
RoomFull,
|
|||
ClientInAreaAlready,
|
|||
}
|
|||
|
|||
impl ClientArea for Lobby {
|
|||
fn clients(& self) -> std::slice::Iter<'_, Option<AreaClient>> {
|
|||
self.clients.iter()
|
|||
}
|
|||
|
|||
fn remove(&mut self, id: ClientId) -> bool {
|
|||
self.remove(id)
|
|||
}
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum JoinLobbyError {
|
|||
LobbyDoesNotExist,
|
|||
LobbyFull,
|
|||
ClientInAreaAlready,
|
|||
}
|
|||
|
|||
impl<'a> ClientArea for Room {
|
|||
fn clients(& self) -> std::slice::Iter<'_, Option<AreaClient>> {
|
|||
self.clients.iter()
|
|||
}
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
pub struct LocalClientId(usize);
|
|||
|
|||
fn remove(&mut self, id: ClientId) -> bool {
|
|||
self.remove(id)
|
|||
impl LocalClientId {
|
|||
pub fn id(&self) -> u8 {
|
|||
self.0 as u8
|
|||
}
|
|||
}
|
|||
|
|||
pub enum AreaType {
|
|||
Lobby,
|
|||
Room,
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
pub struct AreaClient {
|
|||
pub client: ClientId,
|
|||
pub local_client: LocalClientId,
|
|||
time_join: SystemTime,
|
|||
}
|
|||
|
|||
#[derive(Debug)]
|
|||
pub struct ClientAtLocation {
|
|||
pub client_id: ClientId,
|
|||
pub index: usize,
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
struct Lobby([Option<AreaClient>; 12]);
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
struct Room([Option<AreaClient>; 4]);
|
|||
|
|||
#[derive(Debug, Copy, Clone, PartialEq)]
|
|||
pub enum RoomLobby {
|
|||
Room(RoomId),
|
|||
Lobby(LobbyId),
|
|||
}
|
|||
|
|||
pub struct Area {
|
|||
pub area_type: AreaType,
|
|||
area: Arc<RwLock<dyn ClientArea>>,
|
|||
index: usize,
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum GetAreaError {
|
|||
InvalidClient,
|
|||
}
|
|||
|
|||
impl Area {
|
|||
fn new(area_type: AreaType, area: Arc<RwLock<dyn ClientArea>>, index: usize) -> Area {
|
|||
Area {
|
|||
area_type: area_type,
|
|||
area: area,
|
|||
index: index,
|
|||
}
|
|||
}
|
|||
pub fn clients(&self) -> Vec<ClientAtLocation> {
|
|||
self.area.read().unwrap().clients()
|
|||
.enumerate()
|
|||
.filter(|(_i, k)| k.is_some())
|
|||
.map(|(i, k)| (i, k.unwrap()) )
|
|||
.map(|(i, k)| ClientAtLocation {
|
|||
client_id: k.client_id,
|
|||
index: i
|
|||
}).collect()
|
|||
}
|
|||
// TODO: Result in cases where no one is in the area?
|
|||
pub fn leader(&self) -> ClientAtLocation {
|
|||
self.area.read().unwrap().clients()
|
|||
.enumerate()
|
|||
.filter(|(_i, k)| k.is_some())
|
|||
.map(|(i, k)| (i, k.unwrap()) )
|
|||
.fold((ClientAtLocation {
|
|||
client_id: ClientId(0),
|
|||
index: 0
|
|||
}, SystemTime::UNIX_EPOCH),
|
|||
|(acc, time), (i, k)| {
|
|||
if time > k.time_join {
|
|||
(ClientAtLocation {
|
|||
client_id: k.client_id,
|
|||
index: i,
|
|||
}, k.time_join)
|
|||
}
|
|||
else {
|
|||
(acc, time)
|
|||
}
|
|||
}).0
|
|||
}
|
|||
|
|||
pub fn remove(&mut self, id: ClientId) -> bool {
|
|||
self.area.write().unwrap().remove(id)
|
|||
}
|
|||
|
|||
pub fn id(&self) -> usize {
|
|||
self.index
|
|||
}
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum ClientRemovalError {
|
|||
ClientNotInArea,
|
|||
InvalidArea,
|
|||
}
|
|||
|
|||
#[derive(Debug)]
|
|||
pub enum CreateRoomError {
|
|||
NoOpenSlots,
|
|||
ClientInAreaAlready,
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum GetClientsError {
|
|||
InvalidClient,
|
|||
InvalidArea,
|
|||
}
|
|||
|
|||
#[derive(Debug)]
|
|||
pub enum JoinRoomError {
|
|||
RoomDoesNotExist,
|
|||
RoomFull,
|
|||
ClientInAreaAlready,
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum GetNeighborError {
|
|||
InvalidClient,
|
|||
InvalidArea,
|
|||
}
|
|||
|
|||
#[derive(Debug)]
|
|||
pub enum JoinLobbyError {
|
|||
LobbyDoesNotExist,
|
|||
LobbyFull,
|
|||
ClientInAreaAlready,
|
|||
#[derive(Debug, PartialEq)]
|
|||
pub enum GetLeaderError {
|
|||
InvalidClient,
|
|||
InvalidArea,
|
|||
NoClientInArea,
|
|||
}
|
|||
|
|||
pub struct ClientLocation {
|
|||
lobbies: [Arc<RwLock<Lobby>>; 15],
|
|||
rooms: [Option<Arc<RwLock<Room>>>; MAX_ROOMS],
|
|||
lobbies: [Lobby; 15],
|
|||
rooms: [Option<Room>; MAX_ROOMS],
|
|||
client_location: HashMap<ClientId, RoomLobby>,
|
|||
}
|
|||
|
|||
impl ClientLocation {
|
|||
pub fn new() -> ClientLocation {
|
|||
ClientLocation {
|
|||
//lobbies: [Arc::new(RwLock::new(Lobby::new())); 15],
|
|||
lobbies: crate::init_array!(Arc<RwLock<Lobby>>, 15, Arc::new(RwLock::new(Lobby::new()))),
|
|||
lobbies: [Lobby([None; 12]); 15],
|
|||
rooms: [None; MAX_ROOMS],
|
|||
client_location: HashMap::new(),
|
|||
}
|
|||
}
|
|||
|
|||
fn err_if_client_is_in_area<E>(&mut self, id: ClientId, err: E) -> Result<(), E> {
|
|||
let in_lobby = self.lobbies.iter()
|
|||
.any(|k| k.read().unwrap().contains(id));
|
|||
let in_room = self.rooms.iter()
|
|||
.filter(|k| k.is_some())
|
|||
.map(|k| k.as_ref().unwrap())
|
|||
.any(|k| k.read().unwrap().contains(id));
|
|||
|
|||
if in_lobby || in_room {
|
|||
Err(err)
|
|||
}
|
|||
else {
|
|||
Ok(())
|
|||
}
|
|||
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)?;
|
|||
let (index, empty_slot) = l.0.iter_mut()
|
|||
.enumerate()
|
|||
.filter(|(_, k)| k.is_none())
|
|||
.nth(0)
|
|||
.ok_or(JoinLobbyError::LobbyFull)?;
|
|||
*empty_slot = Some(AreaClient {
|
|||
client: id,
|
|||
local_client: LocalClientId(index),
|
|||
time_join: SystemTime::now(),
|
|||
});
|
|||
self.remove_client_from_area(id);
|
|||
self.client_location.insert(id, RoomLobby::Lobby(lobby));
|
|||
Ok(())
|
|||
}
|
|||
|
|||
pub fn add_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<usize, JoinLobbyError> {
|
|||
self.err_if_client_is_in_area(id, JoinLobbyError::ClientInAreaAlready)?;
|
|||
self.lobbies.get_mut(lobby.0)
|
|||
.ok_or(JoinLobbyError::LobbyDoesNotExist)?
|
|||
.write().unwrap()
|
|||
.add(id)
|
|||
.ok_or(JoinLobbyError::LobbyFull)
|
|||
|
|||
pub fn add_client_to_next_available_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<LobbyId, JoinLobbyError> {
|
|||
let l = (0..15)
|
|||
.map(|lobby_index| {
|
|||
let new_lobby = LobbyId((lobby.0 + lobby_index) % 15);
|
|||
(new_lobby, self.add_client_to_lobby(id, new_lobby))
|
|||
})
|
|||
.filter(|(_, lobby_option)| {
|
|||
lobby_option.is_ok()
|
|||
})
|
|||
.nth(0)
|
|||
.ok_or(JoinLobbyError::LobbyFull)?;
|
|||
|
|||
Ok(l.0)
|
|||
}
|
|||
|
|||
pub fn new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
|
|||
let (room_id, empty_room) = self.rooms.iter_mut()
|
|||
pub fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
|
|||
let (index, empty_slot) = self.rooms.iter_mut()
|
|||
.enumerate()
|
|||
.filter(|(_, k)| k.is_none())
|
|||
.filter(|(_, r)| r.is_none())
|
|||
.nth(0)
|
|||
.ok_or(CreateRoomError::NoOpenSlots)?;
|
|||
*empty_slot = Some(Room([None; 4]));
|
|||
self.add_client_to_room(id, RoomId(index)).map_err(|err| CreateRoomError::JoinError)?;
|
|||
|
|||
let mut new_room = Room::new();
|
|||
new_room.add(id);
|
|||
*empty_room = Some(Arc::new(RwLock::new(new_room)));
|
|||
self.remove_from_location(id);
|
|||
|
|||
Ok(RoomId(room_id))
|
|||
Ok(RoomId(index))
|
|||
}
|
|||
|
|||
pub fn add_to_room(&mut self, id: ClientId, room: RoomId) -> Result<usize, JoinRoomError> {
|
|||
self.err_if_client_is_in_area(id, JoinRoomError::ClientInAreaAlready)?;
|
|||
self.rooms.get_mut(room.0)
|
|||
pub fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> {
|
|||
let r = self.rooms.get_mut(room.0)
|
|||
.ok_or(JoinRoomError::RoomDoesNotExist)?
|
|||
.as_mut()
|
|||
.ok_or(JoinRoomError::RoomDoesNotExist)?
|
|||
.write().unwrap()
|
|||
.add(id)
|
|||
.ok_or(JoinRoomError::RoomFull)
|
|||
.ok_or(JoinRoomError::RoomDoesNotExist)?;
|
|||
let (index, empty_slot) = r.0.iter_mut()
|
|||
.enumerate()
|
|||
.filter(|(_, k)| k.is_none())
|
|||
.nth(0)
|
|||
.ok_or(JoinRoomError::RoomFull)?;
|
|||
*empty_slot = Some(AreaClient {
|
|||
client: id,
|
|||
local_client: LocalClientId(index),
|
|||
time_join: SystemTime::now(),
|
|||
});
|
|||
self.remove_client_from_area(id);
|
|||
self.client_location.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)?;
|
|||
match area {
|
|||
RoomLobby::Room(room) => {
|
|||
Ok(self.get_clients_in_room(*room).map_err(|_| GetNeighborError::InvalidArea)?
|
|||
.into_iter()
|
|||
.collect())
|
|||
},
|
|||
RoomLobby::Lobby(lobby) => {
|
|||
Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)?
|
|||
.into_iter()
|
|||
.collect())
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
pub fn get_area_by_user(&mut self, id: ClientId) -> Area {
|
|||
for (i, lobby) in self.lobbies.iter().enumerate() {
|
|||
if lobby.read().unwrap().contains(id) {
|
|||
return Area::new(AreaType::Lobby, lobby.clone(), i);
|
|||
pub fn get_client_neighbors(&self, id: ClientId) -> Result<Vec<AreaClient>, GetNeighborError> {
|
|||
let area = self.client_location.get(&id).ok_or(GetNeighborError::InvalidClient)?;
|
|||
match area {
|
|||
RoomLobby::Room(room) => {
|
|||
Ok(self.get_clients_in_room(*room).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)?
|
|||
.into_iter()
|
|||
.filter(|c| c.client != id)
|
|||
.collect())
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
pub fn get_room_leader(&self, room: RoomId) -> Result<AreaClient, GetLeaderError> {
|
|||
let mut r = self.rooms[room.0]
|
|||
.as_ref()
|
|||
.ok_or(GetLeaderError::InvalidArea)?
|
|||
.0.iter().flat_map(|k| k)
|
|||
.collect::<Vec<_>>();
|
|||
r.sort_by_key(|k| k.time_join);
|
|||
let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?;
|
|||
Ok(**c)
|
|||
}
|
|||
|
|||
for (i, room) in self.rooms.iter().enumerate() {
|
|||
if let Some(room) = room {
|
|||
if room.read().unwrap().contains(id){
|
|||
return Area::new(AreaType::Room, room.clone(), i);
|
|||
}
|
|||
pub fn get_lobby_leader(&self, lobby: LobbyId) -> Result<AreaClient, GetLeaderError> {
|
|||
let mut l = self.lobbies[lobby.0]
|
|||
.0.iter().flat_map(|k| k)
|
|||
.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> {
|
|||
match roomlobby {
|
|||
RoomLobby::Room(room) => {
|
|||
self.get_room_leader(room)
|
|||
},
|
|||
RoomLobby::Lobby(lobby) => {
|
|||
self.get_lobby_leader(lobby)
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
pub fn get_leader_by_client(&self, id: ClientId) -> Result<AreaClient, GetLeaderError> {
|
|||
let area = self.client_location.get(&id).ok_or(GetLeaderError::InvalidClient)?;
|
|||
match area {
|
|||
RoomLobby::Room(room) => {
|
|||
self.get_room_leader(*room)
|
|||
},
|
|||
RoomLobby::Lobby(lobby) => {
|
|||
self.get_lobby_leader(*lobby)
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
pub fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result<Vec<AreaClient>, GetClientsError> {
|
|||
Ok(self.lobbies.get(lobby.0).ok_or(GetClientsError::InvalidArea)?.0
|
|||
.iter()
|
|||
.filter_map(|client| {
|
|||
client.map(|c| {
|
|||
c
|
|||
})
|
|||
}).collect())
|
|||
}
|
|||
|
|||
pub 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
|
|||
.iter()
|
|||
.filter_map(|client| {
|
|||
client.map(|c| {
|
|||
c
|
|||
})
|
|||
}).collect())
|
|||
}
|
|||
|
|||
pub fn get_local_client(&self, id: ClientId) -> Result<AreaClient, GetClientsError> {
|
|||
let area = self.client_location.get(&id).ok_or(GetClientsError::InvalidClient)?;
|
|||
match area {
|
|||
RoomLobby::Room(room) => {
|
|||
self.get_clients_in_room(*room).map_err(|_| GetClientsError::InvalidArea)?
|
|||
.into_iter()
|
|||
.filter(|c| c.client == id)
|
|||
.nth(0)
|
|||
.ok_or(GetClientsError::InvalidClient)
|
|||
},
|
|||
RoomLobby::Lobby(lobby) => {
|
|||
self.get_clients_in_lobby(*lobby).map_err(|_| GetClientsError::InvalidArea)?
|
|||
.into_iter()
|
|||
.filter(|c| c.client == id)
|
|||
.nth(0)
|
|||
.ok_or(GetClientsError::InvalidClient)
|
|||
}
|
|||
}
|
|||
}
|
|||
|
|||
pub fn get_area(&self, id: ClientId) -> Result<RoomLobby, GetAreaError> {
|
|||
self.client_location.get(&id)
|
|||
.ok_or(GetAreaError::InvalidClient)
|
|||
.map(Clone::clone)
|
|||
}
|
|||
|
|||
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_or(None, |r| {
|
|||
Some(r.0.iter_mut())
|
|||
})
|
|||
},
|
|||
RoomLobby::Lobby(lobby) => {
|
|||
Some(self.lobbies[lobby.0].0.iter_mut())
|
|||
}
|
|||
};
|
|||
|
|||
client_list
|
|||
.ok_or(ClientRemovalError::InvalidArea)?
|
|||
.filter(|client| {
|
|||
client.map_or(false, |c| {
|
|||
c.client == id
|
|||
})
|
|||
})
|
|||
.for_each(|client| {
|
|||
*client = None
|
|||
});
|
|||
Ok(())
|
|||
}
|
|||
}
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
panic!("client is not in a room/lobby")
|
|||
|
|||
#[cfg(test)]
|
|||
mod test {
|
|||
use super::*;
|
|||
|
|||
#[test]
|
|||
fn test_add_client_to_lobby() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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));
|
|||
|
|||
assert!(cl.get_clients_in_lobby(LobbyId(0)).into_iter().flatten().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
|
|||
(ClientId(12), LocalClientId(0)),
|
|||
(ClientId(14), LocalClientId(1)),
|
|||
]);
|
|||
}
|
|||
|
|||
pub fn remove_from_location(&mut self, id: ClientId) {
|
|||
let in_lobby = self.lobbies.iter_mut()
|
|||
.map(|lobby| lobby.write().unwrap().remove(id))
|
|||
.any(|k| k);
|
|||
#[test]
|
|||
fn test_add_client_to_full_lobby() {
|
|||
let mut cl = ClientLocation::new();
|
|||
(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));
|
|||
}
|
|||
|
|||
if in_lobby {
|
|||
return;
|
|||
#[test]
|
|||
fn test_add_client_to_next_available_lobby() {
|
|||
let mut cl = ClientLocation::new();
|
|||
(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)));
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_add_to_lobby_when_all_are_full() {
|
|||
let mut cl = ClientLocation::new();
|
|||
(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));
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_new_room() {
|
|||
let mut cl = ClientLocation::new();
|
|||
assert!(cl.create_new_room(ClientId(12)) == Ok(RoomId(0)));
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_add_client_to_room() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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![
|
|||
(ClientId(12), LocalClientId(0)),
|
|||
(ClientId(234), LocalClientId(1)),
|
|||
]);
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_no_new_room_slots() {
|
|||
let mut cl = ClientLocation::new();
|
|||
for i in 0..128 {
|
|||
cl.create_new_room(ClientId(i));
|
|||
}
|
|||
assert!(cl.create_new_room(ClientId(234)) == Err(CreateRoomError::NoOpenSlots));
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_joining_full_room() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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));
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_adding_client_to_room_removes_from_lobby() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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![
|
|||
(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![
|
|||
(ClientId(51), LocalClientId(0)),
|
|||
(ClientId(93), LocalClientId(1)),
|
|||
]);
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_getting_neighbors() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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));
|
|||
|
|||
assert!(cl.get_client_neighbors(ClientId(23)).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::new();
|
|||
(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)),
|
|||
]);
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_get_leader() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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));
|
|||
|
|||
assert!(cl.get_leader_by_client(ClientId(51)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0))));
|
|||
}
|
|||
|
|||
#[test]
|
|||
fn test_remove_client_from_room() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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);
|
|||
|
|||
assert!(cl.get_clients_in_room(room).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)),
|
|||
]);
|
|||
}
|
|||
|
|||
self.rooms.iter_mut()
|
|||
.filter(|lobby| lobby.is_some())
|
|||
.map(|lobby| lobby.as_ref().unwrap())
|
|||
.map(|lobby| lobby.write().unwrap().remove(id))
|
|||
.any(|k| k);
|
|||
}
|
|||
|
|||
pub fn get_client_count_in_room(&self, room_id: RoomId) -> u8 {
|
|||
self.rooms[room_id.0].as_ref()
|
|||
.unwrap()
|
|||
.read()
|
|||
.unwrap()
|
|||
.clients()
|
|||
.filter(|k| k.is_some())
|
|||
.count() as u8
|
|||
#[test]
|
|||
fn test_leader_changes_on_leader_leaving() {
|
|||
let mut cl = ClientLocation::new();
|
|||
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))));
|
|||
}
|
|||
}
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue