2020-01-11 01:08:05 -08:00
|
|
|
use std::sync::{Arc, RwLock};
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
use std::time::SystemTime;
|
2019-11-23 19:01:03 -08:00
|
|
|
use crate::common::serverstate::ClientId;
|
|
|
|
// TODO: room passwords?
|
2019-11-24 21:11:52 -08:00
|
|
|
// TODO: remove clients from areas (or upon insert, remove that id from anywhere else)
|
2019-11-23 19:01:03 -08:00
|
|
|
|
2020-01-02 20:24:17 -08:00
|
|
|
pub const MAX_ROOMS: usize = 128;
|
|
|
|
|
2019-11-23 19:01:03 -08:00
|
|
|
#[derive(Copy, Clone)]
|
2019-12-15 23:18:21 -08:00
|
|
|
pub struct AreaClient {
|
|
|
|
client_id: ClientId,
|
|
|
|
time_join: SystemTime,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct InnerClientArea<const N: usize> {
|
|
|
|
clients: [Option<AreaClient>; N],
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
impl<const N: usize> InnerClientArea<{N}> {
|
|
|
|
pub fn new() -> InnerClientArea<{N}> {
|
|
|
|
let mut clients: [std::mem::MaybeUninit<Option<AreaClient>>; N] = unsafe {
|
2019-11-23 19:01:03 -08:00
|
|
|
std::mem::MaybeUninit::uninit().assume_init()
|
|
|
|
};
|
|
|
|
for i in clients.iter_mut() {
|
|
|
|
i.write(None);
|
|
|
|
}
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
InnerClientArea {
|
|
|
|
clients: unsafe { (&clients as *const _ as *const [Option<AreaClient>; N]).read()}
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
}
|
2019-12-15 23:18:21 -08:00
|
|
|
|
|
|
|
|
2019-11-23 19:01:03 -08:00
|
|
|
fn add(&mut self, id: ClientId) -> Option<usize> {
|
|
|
|
for (i, client) in self.clients.iter_mut().enumerate() {
|
|
|
|
if client.is_none() {
|
2019-12-15 23:18:21 -08:00
|
|
|
*client = Some(AreaClient{
|
|
|
|
client_id: id,
|
|
|
|
time_join: SystemTime::now(),
|
|
|
|
});
|
2019-11-23 19:01:03 -08:00
|
|
|
return Some(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return None;
|
|
|
|
}
|
2020-01-02 20:24:17 -08:00
|
|
|
fn remove(&mut self, id: ClientId) -> bool {
|
2019-12-15 23:18:21 -08:00
|
|
|
for areaclient in self.clients.iter_mut() {
|
|
|
|
if let Some(client) = *areaclient {
|
|
|
|
if client.client_id == id {
|
|
|
|
*areaclient = None;
|
2020-01-02 20:24:17 -08:00
|
|
|
return true;
|
2019-12-15 23:18:21 -08:00
|
|
|
}
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
}
|
2020-01-02 20:24:17 -08:00
|
|
|
false
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2019-11-23 19:01:03 -08:00
|
|
|
|
2020-01-02 20:24:17 -08:00
|
|
|
pub struct LobbyId(pub usize);
|
|
|
|
pub struct RoomId(pub usize);
|
2019-11-23 19:01:03 -08:00
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
pub type Lobby = InnerClientArea<12>;
|
|
|
|
pub type Room = InnerClientArea<4>;
|
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
trait ClientArea {
|
|
|
|
fn clients(&self) -> std::slice::Iter<'_, Option<AreaClient>>;
|
|
|
|
fn remove(&mut self, id: ClientId) -> bool;
|
2019-12-15 23:18:21 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
impl ClientArea for Lobby {
|
|
|
|
fn clients(& self) -> std::slice::Iter<'_, Option<AreaClient>> {
|
2019-12-15 23:18:21 -08:00
|
|
|
self.clients.iter()
|
|
|
|
}
|
2020-01-11 01:08:05 -08:00
|
|
|
|
|
|
|
fn remove(&mut self, id: ClientId) -> bool {
|
|
|
|
self.remove(id)
|
|
|
|
}
|
2019-12-15 23:18:21 -08:00
|
|
|
}
|
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
impl<'a> ClientArea for Room {
|
|
|
|
fn clients(& self) -> std::slice::Iter<'_, Option<AreaClient>> {
|
2019-12-15 23:18:21 -08:00
|
|
|
self.clients.iter()
|
|
|
|
}
|
2020-01-11 01:08:05 -08:00
|
|
|
|
|
|
|
fn remove(&mut self, id: ClientId) -> bool {
|
|
|
|
self.remove(id)
|
|
|
|
}
|
2019-12-15 23:18:21 -08:00
|
|
|
}
|
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
pub enum AreaType {
|
|
|
|
Lobby,
|
|
|
|
Room,
|
|
|
|
}
|
2019-12-15 23:18:21 -08:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ClientAtLocation {
|
|
|
|
pub client_id: ClientId,
|
|
|
|
pub index: usize,
|
|
|
|
}
|
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
pub struct Area {
|
|
|
|
pub area_type: AreaType,
|
|
|
|
area: Arc<RwLock<dyn ClientArea>>,
|
2019-12-15 23:18:21 -08:00
|
|
|
index: usize,
|
|
|
|
}
|
2019-11-23 19:01:03 -08:00
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
impl Area {
|
|
|
|
fn new(area_type: AreaType, area: Arc<RwLock<dyn ClientArea>>, index: usize) -> Area {
|
2019-12-15 23:18:21 -08:00
|
|
|
Area {
|
2020-01-11 01:08:05 -08:00
|
|
|
area_type: area_type,
|
2019-12-15 23:18:21 -08:00
|
|
|
area: area,
|
|
|
|
index: index,
|
|
|
|
}
|
|
|
|
}
|
2020-01-11 01:08:05 -08:00
|
|
|
pub fn clients(&self) -> Vec<ClientAtLocation> {
|
|
|
|
self.area.read().unwrap().clients()
|
2019-12-15 23:18:21 -08:00
|
|
|
.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 {
|
2020-01-11 01:08:05 -08:00
|
|
|
self.area.read().unwrap().clients()
|
2019-12-15 23:18:21 -08:00
|
|
|
.enumerate()
|
2020-01-11 01:08:05 -08:00
|
|
|
.filter(|(_i, k)| k.is_some())
|
2019-12-15 23:18:21 -08:00
|
|
|
.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
|
|
|
|
}
|
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
pub fn remove(&mut self, id: ClientId) -> bool {
|
|
|
|
self.area.write().unwrap().remove(id)
|
|
|
|
}
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
pub fn id(&self) -> usize {
|
|
|
|
self.index
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-02 20:24:17 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum CreateRoomError {
|
|
|
|
NoOpenSlots,
|
|
|
|
ClientInAreaAlready,
|
|
|
|
}
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
#[derive(Debug)]
|
2019-11-24 21:11:52 -08:00
|
|
|
pub enum JoinRoomError {
|
2019-11-23 19:01:03 -08:00
|
|
|
RoomDoesNotExist,
|
|
|
|
RoomFull,
|
2020-01-02 20:24:17 -08:00
|
|
|
ClientInAreaAlready,
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
#[derive(Debug)]
|
2019-11-24 21:11:52 -08:00
|
|
|
pub enum JoinLobbyError {
|
2019-11-23 19:01:03 -08:00
|
|
|
LobbyDoesNotExist,
|
|
|
|
LobbyFull,
|
2020-01-02 20:24:17 -08:00
|
|
|
ClientInAreaAlready,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ClientLocation {
|
2020-01-11 01:08:05 -08:00
|
|
|
lobbies: [Arc<RwLock<Lobby>>; 15],
|
|
|
|
rooms: [Option<Arc<RwLock<Room>>>; MAX_ROOMS],
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ClientLocation {
|
|
|
|
pub fn new() -> ClientLocation {
|
|
|
|
ClientLocation {
|
2020-01-11 01:08:05 -08:00
|
|
|
//lobbies: [Arc::new(RwLock::new(Lobby::new())); 15],
|
|
|
|
lobbies: crate::init_array!(Arc<RwLock<Lobby>>, 15, Arc::new(RwLock::new(Lobby::new()))),
|
2020-01-02 20:24:17 -08:00
|
|
|
rooms: [None; MAX_ROOMS],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn err_if_client_is_in_area<E>(&mut self, id: ClientId, err: E) -> Result<(), E> {
|
|
|
|
let in_lobby = self.lobbies.iter()
|
2020-01-11 01:08:05 -08:00
|
|
|
.any(|k| k.read().unwrap().contains(id));
|
2020-01-02 20:24:17 -08:00
|
|
|
let in_room = self.rooms.iter()
|
2020-01-07 21:39:18 -08:00
|
|
|
.filter(|k| k.is_some())
|
2020-01-11 01:08:05 -08:00
|
|
|
.map(|k| k.as_ref().unwrap())
|
|
|
|
.any(|k| k.read().unwrap().contains(id));
|
2020-01-02 20:24:17 -08:00
|
|
|
|
|
|
|
if in_lobby || in_room {
|
|
|
|
Err(err)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Ok(())
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<usize, JoinLobbyError> {
|
2020-01-02 20:24:17 -08:00
|
|
|
self.err_if_client_is_in_area(id, JoinLobbyError::ClientInAreaAlready)?;
|
|
|
|
self.lobbies.get_mut(lobby.0)
|
2019-11-23 19:01:03 -08:00
|
|
|
.ok_or(JoinLobbyError::LobbyDoesNotExist)?
|
2020-01-11 01:08:05 -08:00
|
|
|
.write().unwrap()
|
2019-11-23 19:01:03 -08:00
|
|
|
.add(id)
|
|
|
|
.ok_or(JoinLobbyError::LobbyFull)
|
|
|
|
}
|
|
|
|
|
2020-01-02 20:24:17 -08:00
|
|
|
pub fn new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
|
|
|
|
self.err_if_client_is_in_area(id, CreateRoomError::ClientInAreaAlready)?;
|
|
|
|
let (room_id, empty_room) = self.rooms.iter_mut()
|
|
|
|
.enumerate()
|
2020-01-07 21:39:18 -08:00
|
|
|
.filter(|(_, k)| k.is_some())
|
2020-01-02 20:24:17 -08:00
|
|
|
.nth(0)
|
|
|
|
.ok_or(CreateRoomError::NoOpenSlots)?;
|
|
|
|
|
|
|
|
let mut new_room = Room::new();
|
|
|
|
new_room.add(id);
|
2020-01-11 01:08:05 -08:00
|
|
|
*empty_room = Some(Arc::new(RwLock::new(new_room)));
|
2020-01-02 20:24:17 -08:00
|
|
|
|
|
|
|
Ok(RoomId(room_id))
|
|
|
|
}
|
|
|
|
|
2019-11-23 19:01:03 -08:00
|
|
|
pub fn add_to_room(&mut self, id: ClientId, room: RoomId) -> Result<usize, JoinRoomError> {
|
2020-01-02 20:24:17 -08:00
|
|
|
self.err_if_client_is_in_area(id, JoinRoomError::ClientInAreaAlready)?;
|
|
|
|
self.rooms.get_mut(room.0)
|
2019-11-23 19:01:03 -08:00
|
|
|
.ok_or(JoinRoomError::RoomDoesNotExist)?
|
|
|
|
.as_mut()
|
|
|
|
.ok_or(JoinRoomError::RoomDoesNotExist)?
|
2020-01-11 01:08:05 -08:00
|
|
|
.write().unwrap()
|
2019-11-23 19:01:03 -08:00
|
|
|
.add(id)
|
|
|
|
.ok_or(JoinRoomError::RoomFull)
|
|
|
|
}
|
|
|
|
|
2020-01-11 01:08:05 -08:00
|
|
|
pub fn get_area_by_user(&mut self, id: ClientId) -> Area {
|
2019-12-15 23:18:21 -08:00
|
|
|
for (i, lobby) in self.lobbies.iter().enumerate() {
|
2020-01-11 01:08:05 -08:00
|
|
|
if lobby.read().unwrap().contains(id) {
|
|
|
|
return Area::new(AreaType::Lobby, lobby.clone(), i);
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-15 23:18:21 -08:00
|
|
|
for (i, room) in self.rooms.iter().enumerate() {
|
2019-11-23 19:01:03 -08:00
|
|
|
if let Some(room) = room {
|
2020-01-11 01:08:05 -08:00
|
|
|
if room.read().unwrap().contains(id){
|
|
|
|
return Area::new(AreaType::Room, room.clone(), i);
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-15 23:18:21 -08:00
|
|
|
|
|
|
|
panic!("client is not in a room/lobby")
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|
2020-01-02 20:24:17 -08:00
|
|
|
|
|
|
|
pub fn remove_from_location(&mut self, id: ClientId) {
|
|
|
|
let in_lobby = self.lobbies.iter_mut()
|
2020-01-11 01:08:05 -08:00
|
|
|
.map(|lobby| lobby.write().unwrap().remove(id))
|
2020-01-02 20:24:17 -08:00
|
|
|
.any(|k| k);
|
|
|
|
|
|
|
|
if in_lobby {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.rooms.iter_mut()
|
2020-01-07 21:39:18 -08:00
|
|
|
.filter(|lobby| lobby.is_some())
|
2020-01-11 01:08:05 -08:00
|
|
|
.map(|lobby| lobby.as_ref().unwrap())
|
|
|
|
.map(|mut lobby| lobby.write().unwrap().remove(id))
|
2020-01-02 20:24:17 -08:00
|
|
|
.any(|k| k);
|
|
|
|
}
|
2019-11-23 19:01:03 -08:00
|
|
|
}
|