elseware/src/ship/location.rs

213 lines
5.4 KiB
Rust
Raw Normal View History

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?
// TODO: remove clients from areas (or upon insert, remove that id from anywhere else)
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;
}
fn remove(&mut self, id: ClientId) {
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;
}
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
pub type LobbyId = usize;
pub type RoomId = usize;
2019-12-15 23:18:21 -08:00
pub type Lobby = InnerClientArea<12>;
pub type Room = InnerClientArea<4>;
2019-11-23 19:01:03 -08:00
pub struct ClientLocation {
lobbies: [Lobby; 15],
rooms: [Option<Room>; 128],
}
2019-12-15 23:18:21 -08:00
trait ClientArea<'a> {
fn clients(&'a self) -> std::slice::Iter<'_, Option<AreaClient>>;
}
impl<'a> ClientArea<'a> for Lobby {
fn clients(&'a self) -> std::slice::Iter<'_, Option<AreaClient>> {
self.clients.iter()
}
}
impl<'a> ClientArea<'a> for Room {
fn clients(&'a self) -> std::slice::Iter<'_, Option<AreaClient>> {
self.clients.iter()
}
}
#[derive(Debug)]
pub struct ClientAtLocation {
pub client_id: ClientId,
pub index: usize,
}
pub struct Area<'a> {
area: &'a dyn ClientArea<'a>,
index: usize,
}
2019-11-23 19:01:03 -08:00
2019-12-15 23:18:21 -08:00
impl<'a> Area<'a> {
fn new(area: &'a dyn ClientArea<'a>, index: usize) -> Area<'a> {
Area {
area: area,
index: index,
}
}
pub fn clients(&'a self) -> Vec<ClientAtLocation> {
self.area.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.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 id(&self) -> usize {
self.index
}
}
#[derive(Debug)]
pub enum JoinRoomError {
2019-11-23 19:01:03 -08:00
RoomDoesNotExist,
RoomFull,
}
2019-12-15 23:18:21 -08:00
#[derive(Debug)]
pub enum JoinLobbyError {
2019-11-23 19:01:03 -08:00
LobbyDoesNotExist,
LobbyFull,
}
impl ClientLocation {
pub fn new() -> ClientLocation {
ClientLocation {
lobbies: [Lobby::new(); 15],
rooms: [None; 128],
}
}
pub fn add_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<usize, JoinLobbyError> {
self.lobbies.get_mut(lobby)
.ok_or(JoinLobbyError::LobbyDoesNotExist)?
.add(id)
.ok_or(JoinLobbyError::LobbyFull)
}
pub fn add_to_room(&mut self, id: ClientId, room: RoomId) -> Result<usize, JoinRoomError> {
self.rooms.get_mut(room)
.ok_or(JoinRoomError::RoomDoesNotExist)?
.as_mut()
.ok_or(JoinRoomError::RoomDoesNotExist)?
.add(id)
.ok_or(JoinRoomError::RoomFull)
}
2019-12-15 23:18:21 -08:00
pub fn get_area_by_user(&self, id: ClientId) -> Area {
for (i, lobby) in self.lobbies.iter().enumerate() {
if lobby.contains(id) {
return Area::new(lobby, 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 {
2019-12-15 23:18:21 -08:00
if room.contains(id){
return Area::new(room, 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
}
}