diff --git a/src/ship/location.rs b/src/ship/location.rs index a8c23c7..95e4134 100644 --- a/src/ship/location.rs +++ b/src/ship/location.rs @@ -1,79 +1,15 @@ 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 { - clients: [Option; N], -} - -impl InnerClientArea<{N}> { - pub fn new() -> InnerClientArea<{N}> { - let mut clients: [std::mem::MaybeUninit>; 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; N]).read()} - } - } - - - fn add(&mut self, id: ClientId) -> Option { - 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 - } - }) - } +pub enum AreaType { + Room, + Lobby, } @@ -82,101 +18,12 @@ pub struct LobbyId(pub usize); #[derive(Debug, Copy, Clone, PartialEq)] pub struct RoomId(pub usize); -pub type Lobby = InnerClientArea<12>; -pub type Room = InnerClientArea<4>; - -trait ClientArea { - fn clients(&self) -> std::slice::Iter<'_, Option>; - fn remove(&mut self, id: ClientId) -> bool; -} - - -impl ClientArea for Lobby { - fn clients(& self) -> std::slice::Iter<'_, Option> { - self.clients.iter() - } - - fn remove(&mut self, id: ClientId) -> bool { - self.remove(id) +impl LobbyId { + pub fn id(&self) -> u8 { + self.0 as u8 } } -impl<'a> ClientArea for Room { - fn clients(& self) -> std::slice::Iter<'_, Option> { - self.clients.iter() - } - - fn remove(&mut self, id: ClientId) -> bool { - self.remove(id) - } -} - -pub enum AreaType { - Lobby, - Room, -} - -#[derive(Debug)] -pub struct ClientAtLocation { - pub client_id: ClientId, - pub index: usize, -} - -pub struct Area { - pub area_type: AreaType, - area: Arc>, - index: usize, -} - -impl Area { - fn new(area_type: AreaType, area: Arc>, index: usize) -> Area { - Area { - area_type: area_type, - area: area, - index: index, - } - } - pub fn clients(&self) -> Vec { - 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 CreateRoomError { @@ -199,146 +46,38 @@ pub enum JoinLobbyError { ClientInAreaAlready, } -pub struct ClientLocation { - lobbies: [Arc>; 15], - rooms: [Option>>; MAX_ROOMS], -} - -impl ClientLocation { - pub fn new() -> ClientLocation { - ClientLocation { - //lobbies: [Arc::new(RwLock::new(Lobby::new())); 15], - lobbies: crate::init_array!(Arc>, 15, Arc::new(RwLock::new(Lobby::new()))), - 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.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_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result { - 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 new_room(&mut self, id: ClientId) -> Result { - 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(Arc::new(RwLock::new(new_room))); - self.remove_from_location(id); - - Ok(RoomId(room_id)) - } - - pub fn add_to_room(&mut self, id: ClientId, room: RoomId) -> Result { - 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)? - .write().unwrap() - .add(id) - .ok_or(JoinRoomError::RoomFull) - } - - 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); - } - } - - 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); - } - } - } - - 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.write().unwrap().remove(id)) - .any(|k| k); - - if in_lobby { - return; - } - - 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 - } -} - - #[derive(Debug, Copy, Clone, PartialEq)] pub struct LocalClientId(usize); - -#[derive(Debug, Copy, Clone, PartialEq)] -struct RoomClient { - client: ClientId, - local_client: LocalClientId, - time_join: SystemTime, +impl LocalClientId { + pub fn id(&self) -> u8 { + self.0 as u8 + } } #[derive(Debug, Copy, Clone, PartialEq)] -struct AreaClient2 { - client: ClientId, - local_client: LocalClientId, +pub struct AreaClient { + pub client: ClientId, + pub local_client: LocalClientId, time_join: SystemTime, } #[derive(Debug, Copy, Clone, PartialEq)] -struct Lobby2([Option; 12]); +struct Lobby([Option; 12]); #[derive(Debug, Copy, Clone, PartialEq)] -struct Room2([Option; 4]); +struct Room([Option; 4]); #[derive(Debug, Copy, Clone, PartialEq)] -enum RoomLobby { +pub enum RoomLobby { Room(RoomId), Lobby(LobbyId), } +#[derive(Debug, PartialEq)] +pub enum GetAreaError { + InvalidClient, +} + #[derive(Debug, PartialEq)] pub enum ClientRemovalError { ClientNotInArea, @@ -347,6 +86,7 @@ pub enum ClientRemovalError { #[derive(Debug, PartialEq)] pub enum GetClientsError { + InvalidClient, InvalidArea, } @@ -363,16 +103,16 @@ pub enum GetLeaderError { NoClientInArea, } -pub struct ClientLocation2 { - lobbies: [Lobby2; 15], - rooms: [Option; MAX_ROOMS], +pub struct ClientLocation { + lobbies: [Lobby; 15], + rooms: [Option; MAX_ROOMS], client_location: HashMap, } -impl ClientLocation2 { - pub fn new() -> ClientLocation2 { - ClientLocation2 { - lobbies: [Lobby2([None; 12]); 15], +impl ClientLocation { + pub fn new() -> ClientLocation { + ClientLocation { + lobbies: [Lobby([None; 12]); 15], rooms: [None; MAX_ROOMS], client_location: HashMap::new(), } @@ -385,7 +125,7 @@ impl ClientLocation2 { .filter(|(_, k)| k.is_none()) .nth(0) .ok_or(JoinLobbyError::LobbyFull)?; - *empty_slot = Some(AreaClient2 { + *empty_slot = Some(AreaClient { client: id, local_client: LocalClientId(index), time_join: SystemTime::now(), @@ -411,19 +151,19 @@ impl ClientLocation2 { Ok(l.0) } - fn create_new_room(&mut self, id: ClientId) -> Result { + pub fn create_new_room(&mut self, id: ClientId) -> Result { let (index, empty_slot) = self.rooms.iter_mut() .enumerate() .filter(|(_, r)| r.is_none()) .nth(0) .ok_or(CreateRoomError::NoOpenSlots)?; - *empty_slot = Some(Room2([None; 4])); + *empty_slot = Some(Room([None; 4])); self.add_client_to_room(id, RoomId(index)).map_err(|err| CreateRoomError::JoinError)?; Ok(RoomId(index)) } - fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> { + 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() @@ -433,7 +173,7 @@ impl ClientLocation2 { .filter(|(_, k)| k.is_none()) .nth(0) .ok_or(JoinRoomError::RoomFull)?; - *empty_slot = Some(AreaClient2 { + *empty_slot = Some(AreaClient { client: id, local_client: LocalClientId(index), time_join: SystemTime::now(), @@ -444,69 +184,129 @@ impl ClientLocation2 { } - fn get_client_neighbors(&self, id: ClientId) -> Result, GetNeighborError> { + pub fn get_all_clients_by_client(&self, id: ClientId) -> Result, 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.0 != id) - .collect()) + .into_iter() + .collect()) }, RoomLobby::Lobby(lobby) => { Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)? - .into_iter() - .filter(|c| c.0 != id) - .collect()) + .into_iter() + .collect()) } } } - fn get_room_leader_by_client(&self, id: ClientId) -> Result<(ClientId, LocalClientId), GetLeaderError> { + pub fn get_client_neighbors(&self, id: ClientId) -> Result, 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 { + let mut r = self.rooms[room.0] + .as_ref() + .ok_or(GetLeaderError::InvalidArea)? + .0.iter().flat_map(|k| k) + .collect::>(); + r.sort_by_key(|k| k.time_join); + let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?; + Ok(**c) + } + + pub fn get_lobby_leader(&self, lobby: LobbyId) -> Result { + let mut l = self.lobbies[lobby.0] + .0.iter().flat_map(|k| k) + .collect::>(); + 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 { + 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 { let area = self.client_location.get(&id).ok_or(GetLeaderError::InvalidClient)?; match area { RoomLobby::Room(room) => { - let mut r = self.rooms[room.0] - .as_ref() - .ok_or(GetLeaderError::InvalidArea)? - .0.iter().flat_map(|k| k) - .collect::>(); - //r.sort_by(|a, b| a.time_join.cmp(&b.time_join)); - r.sort_by_key(|k| k.time_join); - let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?; - Ok((c.client, c.local_client)) + self.get_room_leader(*room) }, RoomLobby::Lobby(lobby) => { - let mut l = self.lobbies[lobby.0] - .0.iter().flat_map(|k| k) - .collect::>(); - l.sort_by_key(|k| k.time_join); - let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?; - Ok((c.client, c.local_client)) + self.get_lobby_leader(*lobby) } } } - pub fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result, GetClientsError> { + pub fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result, GetClientsError> { Ok(self.lobbies.get(lobby.0).ok_or(GetClientsError::InvalidArea)?.0 .iter() - .filter_map(|client| { - client.map(|c| { - (c.client, c.local_client) - }) - }).collect()) + .filter_map(|client| { + client.map(|c| { + c + }) + }).collect()) } - pub fn get_clients_in_room(&self, room: RoomId) -> Result, GetClientsError> { + pub fn get_clients_in_room(&self, room: RoomId) -> Result, GetClientsError> { Ok(self.rooms.get(room.0) .ok_or(GetClientsError::InvalidArea)? .ok_or(GetClientsError::InvalidArea)?.0 .iter() - .filter_map(|client| { - client.map(|c| { - (c.client, c.local_client) - }) - }).collect()) + .filter_map(|client| { + client.map(|c| { + c + }) + }).collect()) + } + + pub fn get_local_client(&self, id: ClientId) -> Result { + 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 { + self.client_location.get(&id) + .ok_or(GetAreaError::InvalidClient) + .map(Clone::clone) } pub fn remove_client_from_area(&mut self, id: ClientId) -> Result<(), ClientRemovalError> { @@ -549,20 +349,20 @@ mod test { #[test] fn test_add_client_to_lobby() { - let mut cl = ClientLocation2::new(); + 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)) == Ok(vec![ + assert!(cl.get_clients_in_lobby(LobbyId(0)).into_iter().flatten().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(12), LocalClientId(0)), (ClientId(14), LocalClientId(1)), - ])); + ]); } #[test] fn test_add_client_to_full_lobby() { - let mut cl = ClientLocation2::new(); + let mut cl = ClientLocation::new(); (0..12).for_each(|i| { cl.add_client_to_lobby(ClientId(i), LobbyId(0)); }); @@ -571,7 +371,7 @@ mod test { #[test] fn test_add_client_to_next_available_lobby() { - let mut cl = ClientLocation2::new(); + 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)); @@ -582,7 +382,7 @@ mod test { #[test] fn test_add_to_lobby_when_all_are_full() { - let mut cl = ClientLocation2::new(); + 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)); @@ -593,24 +393,24 @@ mod test { #[test] fn test_new_room() { - let mut cl = ClientLocation2::new(); + 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 = ClientLocation2::new(); + 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) == Ok(vec![ + assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(12), LocalClientId(0)), (ClientId(234), LocalClientId(1)), - ])); + ]); } #[test] fn test_no_new_room_slots() { - let mut cl = ClientLocation2::new(); + let mut cl = ClientLocation::new(); for i in 0..128 { cl.create_new_room(ClientId(i)); } @@ -619,7 +419,7 @@ mod test { #[test] fn test_joining_full_room() { - let mut cl = ClientLocation2::new(); + 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(())); @@ -629,7 +429,7 @@ mod test { #[test] fn test_adding_client_to_room_removes_from_lobby() { - let mut cl = ClientLocation2::new(); + 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)); @@ -637,75 +437,75 @@ mod test { 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)) == Ok(vec![ + assert!(cl.get_clients_in_lobby(LobbyId(0)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(23), LocalClientId(1)), (ClientId(12), LocalClientId(3)), - ])); - assert!(cl.get_clients_in_room(room) == Ok(vec![ + ]); + assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(51), LocalClientId(0)), (ClientId(93), LocalClientId(1)), - ])); + ]); } #[test] fn test_getting_neighbors() { - let mut cl = ClientLocation2::new(); + 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)) == Ok(vec![ + assert!(cl.get_client_neighbors(ClientId(23)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == 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 = ClientLocation2::new(); + 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)) == Ok(vec![ + assert!(cl.get_clients_in_lobby(LobbyId(1)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(99), LocalClientId(0)), - ])); + ]); } #[test] - fn test_room_leader() { - let mut cl = ClientLocation2::new(); + 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_room_leader_by_client(ClientId(51)) == Ok((ClientId(93), LocalClientId(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 = ClientLocation2::new(); + 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) == Ok(vec![ + assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::>() == vec![ (ClientId(12), LocalClientId(0)), (ClientId(93), LocalClientId(1)), (ClientId(23), LocalClientId(2)), - ])); + ]); } #[test] - fn test_room_leader_changes_on_leader_leaving() { - let mut cl = ClientLocation2::new(); + 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); @@ -714,6 +514,6 @@ mod test { cl.remove_client_from_area(ClientId(23)); cl.add_client_to_room(ClientId(99), room); - assert!(cl.get_room_leader_by_client(ClientId(12)) == Ok((ClientId(93), LocalClientId(1)))); + assert!(cl.get_leader_by_client(ClientId(12)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1)))); } } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index aa34738..77acc92 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -21,7 +21,7 @@ use crate::entity::account::{UserAccountEntity, UserSettingsEntity, USERFLAG_NEW use crate::entity::character::CharacterEntity; use crate::entity::item::{ItemLocation, ItemEntity}; use crate::login::login::get_login_status; -use crate::ship::location::{ClientLocation, LobbyId, RoomId, AreaType, MAX_ROOMS}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; use crate::ship::items; use crate::ship::room; @@ -33,6 +33,8 @@ pub enum ShipError { ClientNotFound(ClientId), NoCharacterInSlot(ClientId, u32), InvalidSlot(ClientId, u32), + TooManyClients, + ClientError, } #[derive(Debug)] @@ -216,14 +218,11 @@ impl ShipServerState { } fn send_player_to_lobby(&mut self, id: ClientId, _pkt: &CharData) -> Result, ShipError> { - self.client_location.add_to_lobby(id, LobbyId(0)).unwrap(); - - let lobby = self.client_location.get_area_by_user(id); - let clients = lobby.clients(); - println!("clients in lobby: {:?}", clients); + let lobby = self.client_location.add_client_to_next_available_lobby(id, LobbyId(0)).map_err(|_| ShipError::TooManyClients)?; + let clients = self.client_location.get_clients_in_lobby(lobby).map_err(|_| ShipError::ClientError)?; let playerinfo = clients.iter() .map(|room_client| { - let client = self.clients.get(&room_client.client_id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + let client = self.clients.get(&room_client.client).ok_or(ShipError::ClientNotFound(id)).unwrap(); let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); let c = CharacterBytesBuilder::new() .character(&client.character) @@ -235,7 +234,7 @@ impl ShipServerState { tag: 0x100, guildcard: client.user.id.0, _unknown1: [0; 5], - client_id: room_client.index as u32, + client_id: room_client.local_client.id() as u32, name: c.name, _unknown2: 2, }, @@ -249,28 +248,21 @@ impl ShipServerState { character: c, } }); - let client_id = clients.iter() - .fold(0, |acc, k| { - if k.client_id == id { - k.index - } - else { - acc - } - }); + let area_client = self.client_location.get_local_client(id).map_err(|_| ShipError::ClientError)?; + let leader = self.client_location.get_lobby_leader(lobby).map_err(|_| ShipError::ClientError)?; let join_lobby = JoinLobby { - client: client_id as u8, - leader: lobby.leader().index as u8, + client: area_client.local_client.id(), + leader: leader.local_client.id(), one: 1, - lobby: lobby.id() as u8, + lobby: lobby.id(), block: 1, event: 0, padding: 0, playerinfo: playerinfo.collect(), }; - let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); let c = CharacterBytesBuilder::new() .character(&client.character) @@ -279,10 +271,10 @@ impl ShipServerState { .build(); let addto = AddToLobby { flag: 1, - client: client_id as u8, - leader: lobby.leader().index as u8, + client: area_client.local_client.id(), + leader: leader.local_client.id(), one: 1, - lobby: lobby.id() as u8, + lobby: lobby.id(), block: 1, event: 0, padding: 0, @@ -291,7 +283,7 @@ impl ShipServerState { tag: 0x100, guildcard: client.user.id.0, _unknown1: [0; 5], - client_id: client_id as u32, + client_id: area_client.local_client.id() as u32, name: c.name, _unknown2: 2, }, @@ -306,26 +298,40 @@ impl ShipServerState { }, }; - let mut v = Vec::new(); - v.push((id, SendShipPacket::JoinLobby(join_lobby))); - for client in clients { - if client.client_id != id { - v.push((client.client_id, SendShipPacket::AddToLobby(addto.clone())) - )} - } - - Ok(v) + let neighbors = self.client_location.get_client_neighbors(id).unwrap(); + Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] + .into_iter() + .chain(neighbors.into_iter() + .map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))).collect()) } fn message(&mut self, id: ClientId, msg: &Message) -> Box + Send> { + match &msg.msg { + GameMessage::RequestExp(killmonster) => { + match self.client_location.get_area(id).unwrap() { + RoomLobby::Room(room) => { + let r = self.rooms[room.0].as_ref().unwrap(); + warn!("killed a {:?}", r.maps.enemy_by_id(killmonster.enemy_id as usize).monster); + }, + _ => {} + } + }, + _ => {}, + } + let cmsg = msg.clone(); - Box::new(self.client_location.get_area_by_user(id).clients().iter() - .filter(|client| client.client_id != id) + Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter() + .filter(move |client| client.client != id) .map(move |client| { - (client.client_id, SendShipPacket::Message(cmsg.clone())) - }).collect::>().into_iter()) + (client.client, SendShipPacket::Message(cmsg.clone())) + })) } + /*fn generate_item_drop(&mut self, id: ClientId, monster: MonsterType) -> Option { + let room = self.rooms[self.client_location.get_area_by_user(id).index]; + let item_drop = room.drop_table.get_drop() + }*/ + fn direct_message(&mut self, id: ClientId, msg: &DirectMessage) -> Box + Send> { let cmsg = msg.clone(); let client = self.clients.get_mut(&id).unwrap(); @@ -346,50 +352,60 @@ impl ShipServerState { class: client.character.char_class.into(), }), }; - Box::new(self.client_location.get_area_by_user(id).clients().iter() - .filter(|client| client.index == cmsg.flag as usize) - .map(|client| { - (client.client_id, SendShipPacket::DirectMessage(out_msg.clone())) - }).collect::>().into_iter()) + let msg_flag = cmsg.flag as u8; + Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter() + .filter(move |client| client.local_client.id() == msg_flag) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(out_msg.clone())) + })) }, + /*GameMessage::RequestItem(req_item) => { + let item = self.generate_item_drop(id); + Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(ItemDrop { + client: req_item.client, + target: req_item.target, + area: req_item.area, + variety: 0, + unknown: 0, + x: req_item.x, + z: req_item.z, + unknown2: 0, + item_bytes: item[0..12].try_into().unwrap(), + item_id: 0, + item_bytes2: item[12..16].try_into().unwrap(), + unknown3: 0, + }))))].into_iter()) + },*/ _ => { - Box::new(self.client_location.get_area_by_user(id).clients().iter() - .filter(|client| client.index == cmsg.flag as usize) - .map(|client| { - (client.client_id, SendShipPacket::DirectMessage(cmsg.clone())) - }).collect::>().into_iter()) + let msg_flag = cmsg.flag as u8; + Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter() + .filter(move |client| client.local_client.id() == msg_flag) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(cmsg.clone())) + })) }, } - } fn player_chat(&mut self, id: ClientId, msg: &PlayerChat) -> Result + Send>, ShipError> { let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; let cmsg = PlayerChat::new(client.user.id.0, msg.message.clone()); - Ok(Box::new(self.client_location.get_area_by_user(id).clients().iter() + Ok(Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter() .map(move |client| { - (client.client_id, SendShipPacket::PlayerChat(cmsg.clone())) - }).collect::>().into_iter())) + (client.client, SendShipPacket::PlayerChat(cmsg.clone())) + }))) } fn create_room(&mut self, id: ClientId, create_room: &CreateRoom) -> Box + Send> { - let area = self.client_location.get_area_by_user(id); - let area_client = area.clients().into_iter().filter(|client| { - client.client_id == id - }).next().unwrap(); - let other_clients = area.clients().into_iter() - .filter(move |c| { - c.client_id != id - }); - let room_id = match self.client_location.new_room(id) { - Ok(room_id) => room_id, - Err(err) => return Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new(format!("could not create room: {:?}", err))))].into_iter()) - }; - - let room = room::RoomState::from_create_room(create_room).unwrap(); + let area = self.client_location.get_area(id).unwrap(); + let area_client = self.client_location.get_local_client(id).unwrap(); + let neighbors = self.client_location.get_client_neighbors(id).unwrap(); + let room_id = self.client_location.create_new_room(id).unwrap(); let client = self.clients.get_mut(&id).unwrap();//.ok_or(ShipError::ClientNotFound(id)).unwrap(); + let room = room::RoomState::from_create_room(create_room, client.character.section_id).unwrap(); + let players = [PlayerHeader { tag: 0x00010000, guildcard: client.user.id.0, @@ -419,16 +435,22 @@ impl ShipServerState { }; self.rooms[room_id.0] = Some(room); - let leader = area.leader(); - Box::new(vec![(id, SendShipPacket::JoinRoom(join_room))].into_iter().chain(other_clients.map(move |c| { - (c.client_id, SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.index as u8, leader.index as u8))) - }))) + let leader = self.client_location.get_area_leader(area).unwrap(); + Box::new(vec![(id, SendShipPacket::JoinRoom(join_room))] + .into_iter() + .chain(neighbors + .into_iter() + .map(move |c| { + (c.client, SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id()))) + }))) } fn room_name_request(&mut self, id: ClientId) -> Box + Send> { - let area = self.client_location.get_area_by_user(id); - let room_state = self.rooms[area.id()].as_ref().unwrap(); - Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: room_state.name.clone()}))].into_iter()) + let area = self.client_location.get_area(id).unwrap(); + match area { + RoomLobby::Room(room) => Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: self.rooms[room.0].as_ref().unwrap().name.clone()}))].into_iter()), + RoomLobby::Lobby(_) => panic!() + } } fn update_config(&mut self, id: ClientId, update_config: &UpdateConfig) -> Box + Send> { @@ -439,21 +461,17 @@ impl ShipServerState { } fn request_infoboard(&mut self, id: ClientId, request_infoboard: &ViewInfoboardRequest) -> Box + Send> { - let lobby = self.client_location.get_area_by_user(id); - let clients = lobby.clients(); - let r = clients - .iter() - .filter(|c| c.client_id != id) + let clients = self.client_location.get_client_neighbors(id).unwrap(); + let r = clients.iter() .filter_map(|c| { - self.clients.get(&c.client_id) + self.clients.get(&c.client) }) - .map(|c| { + .map(|client| { InfoboardResponse { - name: libpso::utf8_to_utf16_array!(c.character.name, 16), - message: c.character.info_board.as_bytes(), + name: libpso::utf8_to_utf16_array!(client.character.name, 16), + message: client.character.info_board.as_bytes(), } - }) - .collect(); + }).collect(); Box::new(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: r}))].into_iter()) } @@ -473,7 +491,7 @@ impl ShipServerState { menu_id: ROOM_MENU_ID, item_id: i as u32, difficulty: room.get_difficulty_for_room_list(), - players: self.client_location.get_client_count_in_room(RoomId(i)), // TODO + players: self.client_location.get_clients_in_room(RoomId(i)).unwrap().len() as u8, name: libpso::utf8_to_utf16_array!(room.name, 16), episode: room.get_episode_for_room_list(), flags: room.get_flags_for_room_list(), @@ -566,25 +584,24 @@ impl ServerState for ShipServerState { } fn on_disconnect(&mut self, id: ClientId) -> Vec<(ClientId, SendShipPacket)> { - let mut area = self.client_location.get_area_by_user(id); - let client = area.clients().into_iter().filter(|client| { - client.client_id == id - //}).collect::>()[0]; - }).next().unwrap(); - let other_clients = area.clients().into_iter().filter(|client| { - client.client_id != id - }); - //self.client_location.remove_from_location(id); - area.remove(id); - let leader = area.leader(); - - let pkt = match area.area_type { - AreaType::Lobby => SendShipPacket::LeaveLobby(LeaveLobby::new(client.index as u8, leader.index as u8)), - AreaType::Room => SendShipPacket::LeaveRoom(LeaveRoom::new(client.index as u8, leader.index as u8)), + let client = self.client_location.get_local_client(id).unwrap(); + let neighbors = self.client_location.get_client_neighbors(id).unwrap(); + + let pkt = match self.client_location.get_area(id).unwrap() { + RoomLobby::Room(room) => { + let leader = self.client_location.get_room_leader(room).unwrap(); + SendShipPacket::LeaveRoom(LeaveRoom::new(client.local_client.id(), leader.local_client.id())) + }, + RoomLobby::Lobby(lobby) => { + let leader = self.client_location.get_lobby_leader(lobby).unwrap(); + SendShipPacket::LeaveLobby(LeaveLobby::new(client.local_client.id(), leader.local_client.id())) + } }; - other_clients.map(|client| { - (client.client_id, pkt.clone()) + self.client_location.remove_client_from_area(id); + + neighbors.into_iter().map(|n| { + (n.client, pkt.clone()) }).collect() } }