remove player from area when they leave
This commit is contained in:
		
							parent
							
								
									a7cb592471
								
							
						
					
					
						commit
						e451eb88b5
					
				| @ -5,3 +5,17 @@ pub mod client; | ||||
| pub mod clientpool; | ||||
| pub mod mainloop; | ||||
| pub mod leveltable; | ||||
| 
 | ||||
| // https://www.reddit.com/r/rust/comments/33xhhu/how_to_create_an_array_of_structs_that_havent/
 | ||||
| #[macro_export] | ||||
| macro_rules! init_array( | ||||
|     ($ty:ty, $len:expr, $val:expr) => ( | ||||
|         { | ||||
|             let mut array: [$ty; $len] = unsafe { std::mem::uninitialized() }; | ||||
|             for i in array.iter_mut() { | ||||
|                 unsafe { ::std::ptr::write(i, $val); } | ||||
|             } | ||||
|             array | ||||
|         } | ||||
|     ) | ||||
| ); | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| use std::sync::{Arc, RwLock}; | ||||
| 
 | ||||
| use std::time::SystemTime; | ||||
| use crate::common::serverstate::ClientId; | ||||
| // TODO: room passwords?
 | ||||
| @ -11,7 +13,6 @@ pub struct AreaClient { | ||||
|     time_join: SystemTime, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Copy, Clone)] | ||||
| pub struct InnerClientArea<const N: usize> { | ||||
|     clients: [Option<AreaClient>; N], | ||||
| @ -80,23 +81,36 @@ pub struct RoomId(pub usize); | ||||
| pub type Lobby = InnerClientArea<12>; | ||||
| pub type Room = InnerClientArea<4>; | ||||
| 
 | ||||
| trait ClientArea<'a> { | ||||
|     fn clients(&'a self) -> std::slice::Iter<'_, Option<AreaClient>>; | ||||
| trait ClientArea { | ||||
|     fn clients(&self) -> std::slice::Iter<'_, Option<AreaClient>>; | ||||
|     fn remove(&mut self, id: ClientId) -> bool; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| impl<'a> ClientArea<'a> for Lobby { | ||||
|     fn clients(&'a self) -> std::slice::Iter<'_, Option<AreaClient>> { | ||||
| 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) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a> ClientArea<'a> for Room { | ||||
|     fn clients(&'a self) -> std::slice::Iter<'_, Option<AreaClient>> { | ||||
| impl<'a> ClientArea for Room { | ||||
|     fn clients(& self) -> std::slice::Iter<'_, Option<AreaClient>> { | ||||
|         self.clients.iter() | ||||
|     } | ||||
| 
 | ||||
|     fn remove(&mut self, id: ClientId) -> bool { | ||||
|         self.remove(id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub enum AreaType { | ||||
|     Lobby, | ||||
|     Room, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct ClientAtLocation { | ||||
| @ -104,21 +118,22 @@ pub struct ClientAtLocation { | ||||
|     pub index: usize, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub struct Area<'a> { | ||||
|     area: &'a dyn ClientArea<'a>, | ||||
| pub struct Area { | ||||
|     pub area_type: AreaType, | ||||
|     area: Arc<RwLock<dyn ClientArea>>, | ||||
|     index: usize, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Area<'a> { | ||||
|     fn new(area: &'a dyn ClientArea<'a>, index: usize) -> Area<'a> { | ||||
| 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(&'a self) -> Vec<ClientAtLocation> { | ||||
|         self.area.clients() | ||||
|     pub fn clients(&self) -> Vec<ClientAtLocation> { | ||||
|         self.area.read().unwrap().clients() | ||||
|             .enumerate() | ||||
|             .filter(|(_i, k)| k.is_some()) | ||||
|             .map(|(i, k)| (i, k.unwrap()) ) | ||||
| @ -129,9 +144,9 @@ impl<'a> Area<'a> { | ||||
|     } | ||||
|     // TODO: Result in cases where no one is in the area?
 | ||||
|     pub fn leader(&self) -> ClientAtLocation { | ||||
|         self.area.clients() | ||||
|         self.area.read().unwrap().clients() | ||||
|             .enumerate() | ||||
|             .filter(|(i, k)| k.is_some()) | ||||
|             .filter(|(_i, k)| k.is_some()) | ||||
|             .map(|(i, k)| (i, k.unwrap()) ) | ||||
|             .fold((ClientAtLocation { | ||||
|                 client_id: ClientId(0), | ||||
| @ -150,6 +165,10 @@ impl<'a> Area<'a> { | ||||
|                   }).0 | ||||
|     } | ||||
| 
 | ||||
|     pub fn remove(&mut self, id: ClientId) -> bool { | ||||
|         self.area.write().unwrap().remove(id) | ||||
|     } | ||||
| 
 | ||||
|     pub fn id(&self) -> usize { | ||||
|         self.index | ||||
|     } | ||||
| @ -176,25 +195,26 @@ pub enum JoinLobbyError { | ||||
| } | ||||
| 
 | ||||
| pub struct ClientLocation { | ||||
|     lobbies: [Lobby; 15], | ||||
|     rooms: [Option<Room>; MAX_ROOMS], | ||||
|     lobbies: [Arc<RwLock<Lobby>>; 15], | ||||
|     rooms: [Option<Arc<RwLock<Room>>>; MAX_ROOMS], | ||||
| } | ||||
| 
 | ||||
| impl ClientLocation { | ||||
|     pub fn new() -> ClientLocation { | ||||
|         ClientLocation { | ||||
|             lobbies: [Lobby::new(); 15], | ||||
|             //lobbies: [Arc::new(RwLock::new(Lobby::new())); 15],
 | ||||
|             lobbies: crate::init_array!(Arc<RwLock<Lobby>>, 15, Arc::new(RwLock::new(Lobby::new()))), | ||||
|             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() | ||||
|             .any(|k| k.contains(id)); | ||||
|             .any(|k| k.read().unwrap().contains(id)); | ||||
|         let in_room = self.rooms.iter() | ||||
|             .filter(|k| k.is_some()) | ||||
|             .map(|k| k.unwrap()) | ||||
|             .any(|k| k.contains(id)); | ||||
|             .map(|k| k.as_ref().unwrap()) | ||||
|             .any(|k| k.read().unwrap().contains(id)); | ||||
| 
 | ||||
|         if in_lobby || in_room { | ||||
|             Err(err) | ||||
| @ -208,6 +228,7 @@ impl ClientLocation { | ||||
|         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) | ||||
|     } | ||||
| @ -222,7 +243,7 @@ impl ClientLocation { | ||||
| 
 | ||||
|         let mut new_room = Room::new(); | ||||
|         new_room.add(id); | ||||
|         *empty_room = Some(new_room); | ||||
|         *empty_room = Some(Arc::new(RwLock::new(new_room))); | ||||
| 
 | ||||
|         Ok(RoomId(room_id)) | ||||
|     } | ||||
| @ -233,21 +254,22 @@ impl ClientLocation { | ||||
|             .ok_or(JoinRoomError::RoomDoesNotExist)? | ||||
|             .as_mut() | ||||
|             .ok_or(JoinRoomError::RoomDoesNotExist)? | ||||
|             .write().unwrap() | ||||
|             .add(id) | ||||
|             .ok_or(JoinRoomError::RoomFull) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_area_by_user(&self, id: ClientId) -> Area { | ||||
|     pub fn get_area_by_user(&mut self, id: ClientId) -> Area { | ||||
|         for (i, lobby) in self.lobbies.iter().enumerate() { | ||||
|             if lobby.contains(id) { | ||||
|                 return Area::new(lobby, i); | ||||
|             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.contains(id){ | ||||
|                     return Area::new(room, i); | ||||
|                 if room.read().unwrap().contains(id){ | ||||
|                     return Area::new(AreaType::Room, room.clone(), i); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @ -257,7 +279,7 @@ impl ClientLocation { | ||||
| 
 | ||||
|     pub fn remove_from_location(&mut self, id: ClientId) { | ||||
|         let in_lobby = self.lobbies.iter_mut() | ||||
|             .map(|lobby| lobby.remove(id)) | ||||
|             .map(|lobby| lobby.write().unwrap().remove(id)) | ||||
|             .any(|k| k); | ||||
| 
 | ||||
|         if in_lobby { | ||||
| @ -266,8 +288,8 @@ impl ClientLocation { | ||||
| 
 | ||||
|         self.rooms.iter_mut() | ||||
|             .filter(|lobby| lobby.is_some()) | ||||
|             .map(|lobby| lobby.unwrap()) | ||||
|             .map(|mut lobby| lobby.remove(id)) | ||||
|             .map(|lobby| lobby.as_ref().unwrap()) | ||||
|             .map(|mut lobby| lobby.write().unwrap().remove(id)) | ||||
|             .any(|k| k); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -20,7 +20,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, LobbyId, RoomId}; | ||||
| use crate::ship::location::{ClientLocation, LobbyId, RoomId, AreaType}; | ||||
| use crate::ship::character::{CharacterBuilder, FullCharacterBuilder}; | ||||
| use crate::ship::room; | ||||
| 
 | ||||
| @ -59,7 +59,7 @@ impl RecvServerPacket for RecvShipPacket { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum SendShipPacket { | ||||
|     ShipWelcome(ShipWelcome), | ||||
|     LoginResponse(LoginResponse), | ||||
| @ -74,6 +74,8 @@ pub enum SendShipPacket { | ||||
|     SmallDialog(SmallDialog), | ||||
|     JoinRoom(JoinRoom), | ||||
|     AddToRoom(AddToRoom), | ||||
|     LeaveLobby(LeaveLobby), | ||||
|     LeaveRoom(LeaveRoom), | ||||
| } | ||||
| 
 | ||||
| impl SendServerPacket for SendShipPacket { | ||||
| @ -92,6 +94,8 @@ impl SendServerPacket for SendShipPacket { | ||||
|             SendShipPacket::SmallDialog(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::JoinRoom(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::AddToRoom(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::LeaveLobby(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::LeaveRoom(pkt) => pkt.as_bytes(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -430,7 +434,25 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> { | ||||
|     } | ||||
| 
 | ||||
|     fn on_disconnect(&mut self, id: ClientId) -> Vec<(ClientId, SendShipPacket)> { | ||||
|         warn!("disconnected!"); | ||||
|         Vec::new() | ||||
|         let mut area = self.client_location.get_area_by_user(id); | ||||
|         let client = area.clients().into_iter().filter(|client| { | ||||
|             client.client_id == id | ||||
|         //}).collect::<Vec<_>>()[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)), | ||||
|         }; | ||||
| 
 | ||||
|         other_clients.map(|client| { | ||||
|             (client.client_id, pkt.clone()) | ||||
|         }).collect() | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user