Merge pull request 'roominfo' (#112) from roominfo into master
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			Reviewed-on: #112
This commit is contained in:
		
						commit
						7219481aa2
					
				| @ -3,6 +3,7 @@ use serde::{Serialize, Deserialize}; | ||||
| use std::collections::HashMap; | ||||
| use thiserror::Error; | ||||
| use crate::ship::room::Episode; | ||||
| use std::fmt; | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] | ||||
| pub enum MapArea { | ||||
| @ -256,6 +257,60 @@ impl MapArea { | ||||
|             MapArea::SaintMillion => Episode::Four, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn as_string(&self) -> &str{ | ||||
|         match self { | ||||
|             MapArea::Pioneer2Ep1 => "Pioneer 2", | ||||
|             MapArea::Forest1 => "Forest 1", | ||||
|             MapArea::Forest2 => "Forest 2", | ||||
|             MapArea::Caves1 => "Caves 1", | ||||
|             MapArea::Caves2 => "Caves 2", | ||||
|             MapArea::Caves3 => "Caves 3", | ||||
|             MapArea::Mines1 => "Mines 1", | ||||
|             MapArea::Mines2 => "Mines 2", | ||||
|             MapArea::Ruins1 => "Ruins 1", | ||||
|             MapArea::Ruins2 => "Ruins 2", | ||||
|             MapArea::Ruins3 => "Ruins 3", | ||||
|             MapArea::Dragon => "Dragon", | ||||
|             MapArea::DeRolLe => "De Rol Le", | ||||
|             MapArea::VolOpt => "Vol Opt", | ||||
|             MapArea::DarkFalz => "Dark Falz", | ||||
|             MapArea::Pioneer2Ep2 => "Pioneer 2", | ||||
|             MapArea::VrTempleAlpha => "Vr Temple Alpha", | ||||
|             MapArea::VrTempleBeta => "Vr Temple Beta", | ||||
|             MapArea::VrSpaceshipAlpha => "Vr Spaceship Alpha", | ||||
|             MapArea::VrSpaceshipBeta => "Vr Spaceship Beta", | ||||
|             MapArea::Cca => "CCA", | ||||
|             MapArea::JungleAreaNorth => "Jungle Area North", | ||||
|             MapArea::JungleAreaEast => "Jungle Area East", | ||||
|             MapArea::Mountain => "Mountain", | ||||
|             MapArea::Seaside => "Seaside", | ||||
|             MapArea::SeabedUpper => "Seabed Upper", | ||||
|             MapArea::SeabedLower => "Seabed Lower", | ||||
|             MapArea::GalGryphon => "Gal Gryphon", | ||||
|             MapArea::OlgaFlow => "Olga Flow", | ||||
|             MapArea::BarbaRay => "Barba Ray", | ||||
|             MapArea::GolDragon => "Gol Dragon", | ||||
|             MapArea::SeasideNight => "Seaside Night", | ||||
|             MapArea::Tower => "Tower", | ||||
|             MapArea::Pioneer2Ep4 => "Pioneer 2", | ||||
|             MapArea::CraterEast => "Crater East", | ||||
|             MapArea::CraterWest => "Crater West", | ||||
|             MapArea::CraterSouth => "Crater South", | ||||
|             MapArea::CraterNorth => "Crater North", | ||||
|             MapArea::CraterInterior => "Crater Interior", | ||||
|             MapArea::SubDesert1 => "Sub Desert 1", | ||||
|             MapArea::SubDesert2 => "Sub Desert 2", | ||||
|             MapArea::SubDesert3 => "Sub Desert 3", | ||||
|             MapArea::SaintMillion => "Saint Million", | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for MapArea { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         write!(f, "{}", self.as_string()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -3,11 +3,11 @@ use crate::common::serverstate::ClientId; | ||||
| use crate::common::leveltable::CharacterLevelTable; | ||||
| use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms}; | ||||
| use crate::ship::character::{FullCharacterBytesBuilder}; | ||||
| use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError}; | ||||
| //use crate::ship::items::;
 | ||||
| use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; | ||||
| use crate::ship::packet; | ||||
| use crate::ship::items::state::ItemState; | ||||
| use crate::entity::gateway::EntityGateway; | ||||
| use crate::ship::map::MapArea; | ||||
| 
 | ||||
| // this function needs a better home
 | ||||
| pub fn block_selected(id: ClientId, | ||||
| @ -129,3 +129,30 @@ pub fn remove_from_lobby(id: ClientId, | ||||
|         (n.client, leave_lobby_pkt.clone()) | ||||
|     }).collect()) | ||||
| } | ||||
| 
 | ||||
| pub fn get_room_tab_info(id: ClientId, | ||||
|                                 pkt: &MenuDetail, | ||||
|                                 client_location: &mut ClientLocation, | ||||
|                                 clients: &Clients, | ||||
|                                 rooms: &mut Rooms) | ||||
|                                 -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { | ||||
|     let room_id = RoomId(pkt.item as usize); | ||||
|     if let Some(_room) = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))? { | ||||
|         let mut room_info = String::new(); | ||||
|         let clients_in_room = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
|         for client in clients_in_room { | ||||
|             let cs = clients.get(&client.client).ok_or(ShipError::ClientNotFound(client.client))?; | ||||
|             let gc = cs.user.guildcard; | ||||
|             let name = &cs.character.name; | ||||
|             let cc = cs.character.char_class; | ||||
|             let leveltable = CharacterLevelTable::default(); | ||||
|             let lv = leveltable.get_level_from_exp(cc, cs.character.exp); | ||||
|             let floor = cs.area.unwrap_or(MapArea::Pioneer2Ep1); | ||||
| 
 | ||||
|             room_info += format!("{} Lv{} {}\n{} {}\n", gc,lv,name,cc,floor).as_str(); | ||||
|         } | ||||
|         Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new(room_info)))]) | ||||
|     } else  { | ||||
|         Ok(vec![(id, SendShipPacket::SmallLeftDialog(SmallLeftDialog::new("Game is no longer active".into())))]) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -86,62 +86,66 @@ pub fn join_room(id: ClientId, | ||||
|                  -> Result<Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send>, ShipError> { | ||||
|     let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
|     let level = level_table.get_level_from_exp(client.character.char_class, client.character.exp); | ||||
|     let room = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.as_ref().unwrap(); // clippy look what you made me do
 | ||||
|     // let room = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.as_ref().unwrap(); // clippy look what you made me do
 | ||||
|     if let Some(room) = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))? { | ||||
| 
 | ||||
|     match room.mode.difficulty() { | ||||
|         room::Difficulty::Ultimate => { | ||||
|             if level < 80 { | ||||
|                 return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto join Ultimate rooms.".into())))].into_iter())) | ||||
|             } | ||||
|         }, | ||||
|         room::Difficulty::VeryHard => { | ||||
|             if level < 40 { | ||||
|                 return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto join Very Hard rooms.".into())))].into_iter())) | ||||
|             } | ||||
|         }, | ||||
|         room::Difficulty::Hard => { | ||||
|             if level < 20 { | ||||
|                 return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto join Hard rooms.".into())))].into_iter())) | ||||
|             } | ||||
|         }, | ||||
|         _ => {}, | ||||
|     }; | ||||
|         match room.mode.difficulty() { | ||||
|             room::Difficulty::Ultimate => { | ||||
|                 if level < 80 { | ||||
|                     return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto join Ultimate rooms.".into())))].into_iter())) | ||||
|                 } | ||||
|             }, | ||||
|             room::Difficulty::VeryHard => { | ||||
|                 if level < 40 { | ||||
|                     return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto join Very Hard rooms.".into())))].into_iter())) | ||||
|                 } | ||||
|             }, | ||||
|             room::Difficulty::Hard => { | ||||
|                 if level < 20 { | ||||
|                     return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto join Hard rooms.".into())))].into_iter())) | ||||
|                 } | ||||
|             }, | ||||
|             _ => {}, | ||||
|         }; | ||||
| 
 | ||||
|     let original_area = client_location.get_area(id).unwrap(); | ||||
|     let original_neighbors = client_location.get_client_neighbors(id).unwrap(); | ||||
|     if room.bursting { | ||||
|         return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))].into_iter())) | ||||
|         let original_area = client_location.get_area(id).unwrap(); | ||||
|         let original_neighbors = client_location.get_client_neighbors(id).unwrap(); | ||||
|         if room.bursting { | ||||
|             return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))].into_iter())) | ||||
|         } | ||||
|         let room_id = RoomId(pkt.item as usize); | ||||
|         let original_room_clients = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
|         client_location.add_client_to_room(id, room_id).unwrap(); // TODO: show room full error or whatever
 | ||||
| 
 | ||||
|         let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
|         let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
| 
 | ||||
|         item_state.add_character_to_room(room_id, &client.character, area_client); | ||||
| 
 | ||||
|         let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
|         let join_room = builder::room::join_room(id, clients, client_location, room_id, room)?; | ||||
|         let add_to = builder::room::add_to_room(id, client, &area_client, &leader, item_state, level_table, room_id)?; | ||||
| 
 | ||||
|         let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); | ||||
|         room.bursting = true; | ||||
| 
 | ||||
|         let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new( | ||||
|             vec![(id, SendShipPacket::JoinRoom(join_room))] | ||||
|                 .into_iter() | ||||
|                 .chain(original_room_clients.into_iter() | ||||
|                     .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))) | ||||
|                 )); | ||||
| 
 | ||||
|         if let Ok(leader) = client_location.get_area_leader(original_area) { | ||||
|             let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); | ||||
|             result = Box::new(result.chain(original_neighbors.into_iter() | ||||
|                                         .map(move |c| (c.client, leave_lobby.clone())))) | ||||
|         } | ||||
| 
 | ||||
|         Ok(result) | ||||
|     } else { | ||||
|         Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Game is no longer active".into())))].into_iter())) | ||||
|     } | ||||
|     let room_id = RoomId(pkt.item as usize); | ||||
|     let original_room_clients = client_location.get_clients_in_room(room_id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
|     client_location.add_client_to_room(id, room_id).unwrap(); // TODO: show room full error or whatever
 | ||||
| 
 | ||||
|     let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; | ||||
|     let area_client = client_location.get_local_client(id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
| 
 | ||||
|     item_state.add_character_to_room(room_id, &client.character, area_client); | ||||
| 
 | ||||
|     let leader = client_location.get_room_leader(room_id).map_err(|err| -> ClientLocationError { err.into() })?; | ||||
|     let join_room = builder::room::join_room(id, clients, client_location, room_id, room)?; | ||||
|     let add_to = builder::room::add_to_room(id, client, &area_client, &leader, item_state, level_table, room_id)?; | ||||
| 
 | ||||
|     let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); | ||||
|     room.bursting = true; | ||||
| 
 | ||||
|     let mut result: Box<dyn Iterator<Item=(ClientId, SendShipPacket)> + Send> = Box::new( | ||||
|         vec![(id, SendShipPacket::JoinRoom(join_room))] | ||||
|             .into_iter() | ||||
|             .chain(original_room_clients.into_iter() | ||||
|                    .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))) | ||||
|             )); | ||||
| 
 | ||||
|     if let Ok(leader) = client_location.get_area_leader(original_area) { | ||||
|         let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); | ||||
|         result = Box::new(result.chain(original_neighbors.into_iter() | ||||
|                                        .map(move |c| (c.client, leave_lobby.clone())))) | ||||
|     } | ||||
| 
 | ||||
|     Ok(result) | ||||
| } | ||||
| 
 | ||||
| pub fn done_bursting(id: ClientId, | ||||
|  | ||||
| @ -205,6 +205,7 @@ pub enum SendShipPacket { | ||||
|     DirectMessage(DirectMessage), | ||||
|     PlayerChat(PlayerChat), | ||||
|     SmallDialog(SmallDialog), | ||||
|     SmallLeftDialog(SmallLeftDialog), | ||||
|     JoinRoom(JoinRoom), | ||||
|     AddToRoom(AddToRoom), | ||||
|     LeaveLobby(LeaveLobby), | ||||
| @ -246,6 +247,7 @@ impl SendServerPacket for SendShipPacket { | ||||
|             SendShipPacket::DirectMessage(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::PlayerChat(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::SmallDialog(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::SmallLeftDialog(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::JoinRoom(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::AddToRoom(pkt) => pkt.as_bytes(), | ||||
|             SendShipPacket::LeaveLobby(pkt) => pkt.as_bytes(), | ||||
| @ -665,9 +667,9 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> { | ||||
|                 let block = self.blocks.with_client(id, &self.clients)?; | ||||
|                 handler::quest::player_chose_quest(id, questmenuselect, &mut self.clients, &block.client_location, &mut block.rooms)? | ||||
|             }, | ||||
|             RecvShipPacket::MenuDetail(_menudetail) => { | ||||
|                 //unreachable!();
 | ||||
|                 Box::new(Vec::new().into_iter()) | ||||
|             RecvShipPacket::MenuDetail(menudetail) => { | ||||
|                 let block = self.blocks.with_client(id, &self.clients)?; | ||||
|                 Box::new(handler::lobby::get_room_tab_info(id, menudetail, &mut block.client_location, &self.clients, &mut block.rooms)?.into_iter()) | ||||
|             }, | ||||
|             RecvShipPacket::RoomPasswordReq(room_password_req) => { | ||||
|                 let block = self.blocks.with_client(id, &self.clients)?; | ||||
|  | ||||
| @ -157,3 +157,70 @@ async fn test_set_invalid_quest_group() { | ||||
|         _ => panic!("Wrong quest category"), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[async_std::test] | ||||
| async fn test_get_room_info() { | ||||
|     let mut entity_gateway = InMemoryGateway::default(); | ||||
|     let (_user1, mut _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; | ||||
|     _char1.name = String::from("GODmar"); | ||||
|     entity_gateway.save_character(&_char1).await.unwrap(); | ||||
|     let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; | ||||
|     let mut ship = Box::new(ShipServerState::builder() | ||||
|         .gateway(entity_gateway.clone()) | ||||
|         .build()); | ||||
|     log_in_char(&mut ship, ClientId(1), "a1", "a").await; | ||||
|     log_in_char(&mut ship, ClientId(2), "a2", "a").await; | ||||
|     join_lobby(&mut ship, ClientId(1)).await; | ||||
|     join_lobby(&mut ship, ClientId(2)).await; | ||||
|     create_room(&mut ship, ClientId(1), "room", "").await; | ||||
|     let _expectedmsg = String::from("1 Lv1 GODmar\nHUmar Pioneer 2\n"); | ||||
|     let packets = ship.handle(ClientId(2), &RecvShipPacket::MenuDetail(MenuDetail{menu: 3, item: 0})).await.unwrap().collect::<Vec<_>>(); | ||||
|     assert!(matches!(&packets[0], (ClientId(2), SendShipPacket::SmallLeftDialog(SmallLeftDialog{ | ||||
|         padding: [17664, 1157645568], | ||||
|         msg: _expectedmsg, | ||||
|     })))); | ||||
| } | ||||
| 
 | ||||
| #[async_std::test] | ||||
| async fn test_cannot_get_room_info_after_room_is_closed() { | ||||
|     let mut entity_gateway = InMemoryGateway::default(); | ||||
|     let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; | ||||
|     let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; | ||||
|     let mut ship = Box::new(ShipServerState::builder() | ||||
|         .gateway(entity_gateway.clone()) | ||||
|         .build()); | ||||
|     log_in_char(&mut ship, ClientId(1), "a1", "a").await; | ||||
|     log_in_char(&mut ship, ClientId(2), "a2", "a").await; | ||||
|     join_lobby(&mut ship, ClientId(1)).await; | ||||
|     join_lobby(&mut ship, ClientId(2)).await; | ||||
|     create_room(&mut ship, ClientId(1), "room", "").await; | ||||
|     leave_room(&mut ship, ClientId(1)).await; | ||||
|     let _expectedmsg = String::from("Game is no longer active!\0"); | ||||
|     let packets = ship.handle(ClientId(2), &RecvShipPacket::MenuDetail(MenuDetail{menu: 3, item: 0})).await.unwrap().collect::<Vec<_>>(); | ||||
|     assert!(matches!(&packets[0], (ClientId(2), SendShipPacket::SmallLeftDialog(SmallLeftDialog{ | ||||
|         padding: [17664, 1157645568], | ||||
|         msg: _expectedmsg, | ||||
|     })))); | ||||
| } | ||||
| 
 | ||||
| #[async_std::test] | ||||
| async fn test_cannot_join_room_after_its_closed() { | ||||
|     let mut entity_gateway = InMemoryGateway::default(); | ||||
|     let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a", 1).await; | ||||
|     let (_user2, _char2) = new_user_character(&mut entity_gateway, "a2", "a", 1).await; | ||||
|     let mut ship = Box::new(ShipServerState::builder() | ||||
|         .gateway(entity_gateway.clone()) | ||||
|         .build()); | ||||
|     log_in_char(&mut ship, ClientId(1), "a1", "a").await; | ||||
|     log_in_char(&mut ship, ClientId(2), "a2", "a").await; | ||||
|     join_lobby(&mut ship, ClientId(1)).await; | ||||
|     join_lobby(&mut ship, ClientId(2)).await; | ||||
|     create_room(&mut ship, ClientId(1), "room", "").await; | ||||
|     leave_room(&mut ship, ClientId(1)).await; | ||||
|     let _expectedmsg = String::from("This room no longer exists!\0"); | ||||
|     let packets = ship.handle(ClientId(2), &RecvShipPacket::MenuSelect(MenuSelect{menu: 3, item: 0})).await.unwrap().collect::<Vec<_>>(); | ||||
|     assert!(matches!(&packets[0], (ClientId(2), SendShipPacket::SmallDialog(SmallDialog{ | ||||
|         padding: [0,0], | ||||
|         msg: _expectedmsg, // wow yes cool rust is so great literally the best i can't put a String::from() directly in here.
 | ||||
|     })))); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user