diff --git a/src/ship/location.rs b/src/ship/location.rs index 6d91fc7..a852dce 100644 --- a/src/ship/location.rs +++ b/src/ship/location.rs @@ -3,6 +3,8 @@ 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, @@ -42,14 +44,16 @@ impl InnerClientArea<{N}> { } return None; } - fn remove(&mut self, id: ClientId) { + 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 { @@ -70,17 +74,12 @@ impl InnerClientArea<{N}> { } } -pub type LobbyId = usize; -pub type RoomId = usize; +pub struct LobbyId(pub usize); +pub struct RoomId(pub usize); pub type Lobby = InnerClientArea<12>; pub type Room = InnerClientArea<4>; -pub struct ClientLocation { - lobbies: [Lobby; 15], - rooms: [Option; 128], -} - trait ClientArea<'a> { fn clients(&'a self) -> std::slice::Iter<'_, Option>; } @@ -156,35 +155,81 @@ impl<'a> Area<'a> { } } +#[derive(Debug)] +pub enum CreateRoomError { + NoOpenSlots, + ClientInAreaAlready, +} + #[derive(Debug)] pub enum JoinRoomError { RoomDoesNotExist, RoomFull, + ClientInAreaAlready, } #[derive(Debug)] pub enum JoinLobbyError { LobbyDoesNotExist, LobbyFull, + ClientInAreaAlready, +} + +pub struct ClientLocation { + lobbies: [Lobby; 15], + rooms: [Option; MAX_ROOMS], } impl ClientLocation { pub fn new() -> ClientLocation { ClientLocation { lobbies: [Lobby::new(); 15], - rooms: [None; 128], + rooms: [None; MAX_ROOMS], + } + } + + fn err_if_client_is_in_area(&mut self, id: ClientId, err: E) -> Result<(), E> { + let in_lobby = self.lobbies.iter() + .any(|k| k.contains(id)); + let in_room = self.rooms.iter() + .filter(|k| k.is_none()) + .map(|k| k.unwrap()) + .any(|k| k.contains(id)); + + if in_lobby || in_room { + Err(err) + } + else { + Ok(()) } } pub fn add_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result { - self.lobbies.get_mut(lobby) + self.err_if_client_is_in_area(id, JoinLobbyError::ClientInAreaAlready)?; + self.lobbies.get_mut(lobby.0) .ok_or(JoinLobbyError::LobbyDoesNotExist)? .add(id) .ok_or(JoinLobbyError::LobbyFull) } + pub fn new_room(&mut self, id: ClientId) -> Result { + self.err_if_client_is_in_area(id, CreateRoomError::ClientInAreaAlready)?; + let (room_id, empty_room) = self.rooms.iter_mut() + .enumerate() + .filter(|(_, k)| k.is_none()) + .nth(0) + .ok_or(CreateRoomError::NoOpenSlots)?; + + let mut new_room = Room::new(); + new_room.add(id); + *empty_room = Some(new_room); + + Ok(RoomId(room_id)) + } + pub fn add_to_room(&mut self, id: ClientId, room: RoomId) -> Result { - self.rooms.get_mut(room) + self.err_if_client_is_in_area(id, JoinRoomError::ClientInAreaAlready)?; + self.rooms.get_mut(room.0) .ok_or(JoinRoomError::RoomDoesNotExist)? .as_mut() .ok_or(JoinRoomError::RoomDoesNotExist)? @@ -209,4 +254,20 @@ impl ClientLocation { panic!("client is not in a room/lobby") } + + pub fn remove_from_location(&mut self, id: ClientId) { + let in_lobby = self.lobbies.iter_mut() + .map(|lobby| lobby.remove(id)) + .any(|k| k); + + if in_lobby { + return; + } + + self.rooms.iter_mut() + .filter(|lobby| lobby.is_none()) + .map(|lobby| lobby.unwrap()) + .map(|mut lobby| lobby.remove(id)) + .any(|k| k); + } } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 847ba34..cd9f84b 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -19,7 +19,7 @@ use crate::entity::account::{UserAccount, UserSettings, USERFLAG_NEWCHAR, USERFL use crate::entity::character::Character; use crate::entity::item::ItemLocation; use crate::login::login::get_login_status; -use crate::ship::location::ClientLocation; +use crate::ship::location::{ClientLocation, LobbyId, RoomId}; use crate::ship::character::{CharacterBuilder, FullCharacterBuilder}; pub const SHIP_PORT: u16 = 23423; @@ -197,7 +197,7 @@ impl ShipServerState { } fn send_player_to_lobby(&mut self, id: ClientId, _pkt: &CharData) -> Result, ShipError> { - self.client_location.add_to_lobby(id, 0).unwrap(); + self.client_location.add_to_lobby(id, LobbyId(0)).unwrap(); let lobby = self.client_location.get_area_by_user(id); let clients = lobby.clients();