Merge pull request 'holiday rappies (and other events)' (#122) from holidays 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: #122
This commit is contained in:
		
						commit
						32dddfd9bd
					
				
							
								
								
									
										21
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										21
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -609,7 +609,6 @@ dependencies = [ | |||||||
|  "derive_more", |  "derive_more", | ||||||
|  "enum-utils", |  "enum-utils", | ||||||
|  "fern", |  "fern", | ||||||
|  "fix-hidden-lifetime-bug", |  | ||||||
|  "futures", |  "futures", | ||||||
|  "lazy_static", |  "lazy_static", | ||||||
|  "libpso", |  "libpso", | ||||||
| @ -692,26 +691,6 @@ dependencies = [ | |||||||
|  "log", |  "log", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] |  | ||||||
| name = "fix-hidden-lifetime-bug" |  | ||||||
| version = "0.2.5" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "d4ae9c2016a663983d4e40a9ff967d6dcac59819672f0b47f2b17574e99c33c8" |  | ||||||
| dependencies = [ |  | ||||||
|  "fix-hidden-lifetime-bug-proc_macros", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] |  | ||||||
| name = "fix-hidden-lifetime-bug-proc_macros" |  | ||||||
| version = "0.2.5" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "e4c81935e123ab0741c4c4f0d9b8377e5fb21d3de7e062fa4b1263b1fbcba1ea" |  | ||||||
| dependencies = [ |  | ||||||
|  "proc-macro2", |  | ||||||
|  "quote", |  | ||||||
|  "syn", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "foreign-types" | name = "foreign-types" | ||||||
| version = "0.3.2" | version = "0.3.2" | ||||||
|  | |||||||
| @ -33,4 +33,3 @@ sqlx = { version = "0.5.10", features = ["runtime-async-std-native-tls", "postgr | |||||||
| strum = "0.19.5" | strum = "0.19.5" | ||||||
| strum_macros = "0.19" | strum_macros = "0.19" | ||||||
| anyhow = { version = "1.0.47", features = ["backtrace"] } | anyhow = { version = "1.0.47", features = ["backtrace"] } | ||||||
| fix-hidden-lifetime-bug = "0.2.4" |  | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ use elseware::common::interserver::AuthToken; | |||||||
| use elseware::login::login::LoginServerState; | use elseware::login::login::LoginServerState; | ||||||
| use elseware::login::character::CharacterServerState; | use elseware::login::character::CharacterServerState; | ||||||
| use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; | use elseware::patch::patch::{PatchServerState, generate_patch_tree, load_config, load_motd}; | ||||||
| use elseware::ship::ship::ShipServerStateBuilder; | use elseware::ship::ship::{ShipServerStateBuilder, ShipEvent}; | ||||||
| 
 | 
 | ||||||
| #[allow(unused_imports)] | #[allow(unused_imports)] | ||||||
| use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; | use elseware::entity::gateway::{EntityGateway, InMemoryGateway, PostgresGateway}; | ||||||
| @ -364,6 +364,7 @@ fn main() { | |||||||
|             .name("US/Sona-Nyl".into()) |             .name("US/Sona-Nyl".into()) | ||||||
|             .ip(Ipv4Addr::new(127,0,0,1)) |             .ip(Ipv4Addr::new(127,0,0,1)) | ||||||
|             .port(elseware::ship::ship::SHIP_PORT) |             .port(elseware::ship::ship::SHIP_PORT) | ||||||
|  |             .event(ShipEvent::Halloween) | ||||||
|             .gateway(entity_gateway.clone()) |             .gateway(entity_gateway.clone()) | ||||||
|             .build(); |             .build(); | ||||||
|         let sub_ship_state = ship_state.clone(); |         let sub_ship_state = ship_state.clone(); | ||||||
| @ -378,7 +379,8 @@ fn main() { | |||||||
|         let ship_state = ShipServerStateBuilder::default() |         let ship_state = ShipServerStateBuilder::default() | ||||||
|             .name("EU/Dylath-Leen".into()) |             .name("EU/Dylath-Leen".into()) | ||||||
|             .ip(Ipv4Addr::new(127,0,0,1)) |             .ip(Ipv4Addr::new(127,0,0,1)) | ||||||
|             .port(elseware::ship::ship::SHIP_PORT+200) |             .port(elseware::ship::ship::SHIP_PORT+2000) | ||||||
|  |             .event(ShipEvent::Christmas) | ||||||
|             .gateway(entity_gateway.clone()) |             .gateway(entity_gateway.clone()) | ||||||
|             .build(); |             .build(); | ||||||
|         let sub_ship_state = ship_state.clone(); |         let sub_ship_state = ship_state.clone(); | ||||||
|  | |||||||
| @ -205,6 +205,7 @@ where | |||||||
|     loop { |     loop { | ||||||
|         match packet_queue.recv().await { |         match packet_queue.recv().await { | ||||||
|             Ok(pkt) => { |             Ok(pkt) => { | ||||||
|  |                 info!("[send to {:?}] {:#?}", client_id, pkt); | ||||||
|                 if let Err(err) = send_pkt(&mut socket, &mut cipher, &pkt).await { |                 if let Err(err) = send_pkt(&mut socket, &mut cipher, &pkt).await { | ||||||
|                     warn!("error sending pkt {:#?} to {:?} {:?}", pkt, client_id, err); |                     warn!("error sending pkt {:#?} to {:?} {:?}", pkt, client_id, err); | ||||||
|                 } |                 } | ||||||
|  | |||||||
| @ -7,8 +7,6 @@ | |||||||
| #![feature(test)] | #![feature(test)] | ||||||
| 
 | 
 | ||||||
| extern crate test; | extern crate test; | ||||||
| extern crate fix_hidden_lifetime_bug; |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| pub mod common; | pub mod common; | ||||||
| pub mod entity; | pub mod entity; | ||||||
|  | |||||||
| @ -153,13 +153,9 @@ pub struct ClientLocation { | |||||||
| 
 | 
 | ||||||
| impl Default for ClientLocation { | impl Default for ClientLocation { | ||||||
|     fn default() -> ClientLocation { |     fn default() -> ClientLocation { | ||||||
|         //const RNONE: Option<Arc<RwLock<Room>>> = None;
 |  | ||||||
|         //const LINIT: Arc<RwLock<Lobby>> = Arc::new(RwLock::new(Lobby([None; 12])));
 |  | ||||||
|         ClientLocation { |         ClientLocation { | ||||||
|             //lobbies: [LINIT; 15],
 |  | ||||||
|             lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))), |             lobbies: core::array::from_fn(|_| Arc::new(RwLock::new(Lobby([None; 12])))), | ||||||
|             rooms: core::array::from_fn(|_| None), |             rooms: core::array::from_fn(|_| None), | ||||||
|             //rooms: [RNONE; MAX_ROOMS],
 |  | ||||||
|             client_location: Arc::new(RwLock::new(HashMap::new())), |             client_location: Arc::new(RwLock::new(HashMap::new())), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -5,6 +5,7 @@ use std::collections::HashMap; | |||||||
| use byteorder::{LittleEndian, ReadBytesExt}; | use byteorder::{LittleEndian, ReadBytesExt}; | ||||||
| use thiserror::Error; | use thiserror::Error; | ||||||
| 
 | 
 | ||||||
|  | use crate::ship::ship::ShipEvent; | ||||||
| use crate::ship::monster::MonsterType; | use crate::ship::monster::MonsterType; | ||||||
| use crate::ship::room::Episode; | use crate::ship::room::Episode; | ||||||
| 
 | 
 | ||||||
| @ -87,10 +88,9 @@ impl RareMonsterAppearTable { | |||||||
| 
 | 
 | ||||||
|         let appear_rates: HashMap<MonsterType, f32> = cfg |         let appear_rates: HashMap<MonsterType, f32> = cfg | ||||||
|             .into_iter() |             .into_iter() | ||||||
|             .map(|(monster, rate)| { |             .filter_map(|(monster, rate)| { | ||||||
|                 let monster: MonsterType = monster.parse().unwrap(); // TODO: don't unwrap!
 |                 let monster: MonsterType = monster.parse().ok()?; | ||||||
|                 let appear_rate = rate; |                 Some((monster, rate)) | ||||||
|                 (monster, appear_rate) |  | ||||||
|             }) |             }) | ||||||
|             .collect(); |             .collect(); | ||||||
| 
 | 
 | ||||||
| @ -99,11 +99,8 @@ impl RareMonsterAppearTable { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn roll_appearance(&self, monster: &MonsterType) -> bool { |     pub fn roll_is_rare(&self, monster: &MonsterType) -> bool { | ||||||
|         if rand_chacha::ChaChaRng::from_entropy().gen::<f32>() < *self.appear_rate.get(monster).unwrap_or(&0.0f32) { |         rand_chacha::ChaChaRng::from_entropy().gen::<f32>() < *self.appear_rate.get(monster).unwrap_or(&0.0f32) | ||||||
|             return true |  | ||||||
|         } |  | ||||||
|         false |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -324,7 +321,7 @@ impl MapEnemy { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn has_rare_appearance(self) -> bool { |     pub fn can_be_rare(&self) -> bool { | ||||||
|         matches!(self.monster, |         matches!(self.monster, | ||||||
|             MonsterType::RagRappy | MonsterType::Hildebear | |             MonsterType::RagRappy | MonsterType::Hildebear | | ||||||
|             MonsterType::PoisonLily | MonsterType::PofuillySlime | |             MonsterType::PoisonLily | MonsterType::PofuillySlime | | ||||||
| @ -339,32 +336,26 @@ impl MapEnemy { | |||||||
|     guaranteed rare monsters don't count towards the limit |     guaranteed rare monsters don't count towards the limit | ||||||
|     */ |     */ | ||||||
|     #[must_use] |     #[must_use] | ||||||
|     pub fn set_rare_appearance(self) -> MapEnemy { |     pub fn into_rare(self, event: ShipEvent) -> MapEnemy { | ||||||
|         match (self.monster, self.map_area.to_episode()) { |         match (self.monster, self.map_area.to_episode(), event) { | ||||||
|             (MonsterType::RagRappy, Episode::One) => {MapEnemy {monster: MonsterType::AlRappy, shiny:true, ..self}}, |             (MonsterType::RagRappy, Episode::One, _) => {MapEnemy {monster: MonsterType::AlRappy, shiny:true, ..self}}, | ||||||
|             (MonsterType::RagRappy, Episode::Two) => {MapEnemy {monster: MonsterType::EventRappy, shiny:true, ..self}}, |             (MonsterType::RagRappy, Episode::Two, ShipEvent::Easter) => {MapEnemy {monster: MonsterType::EasterRappy, shiny:true, ..self}}, | ||||||
|             (MonsterType::Hildebear, _) => {MapEnemy {monster: MonsterType::Hildeblue, shiny:true, ..self}}, |             (MonsterType::RagRappy, Episode::Two, ShipEvent::Halloween) => {MapEnemy {monster: MonsterType::HalloRappy, shiny:true, ..self}}, | ||||||
|             (MonsterType::PoisonLily, _) => {MapEnemy {monster: MonsterType::NarLily, shiny:true, ..self}}, |             (MonsterType::RagRappy, Episode::Two, ShipEvent::Christmas) => {MapEnemy {monster: MonsterType::StRappy, shiny:true, ..self}}, | ||||||
|             (MonsterType::PofuillySlime, _) => {MapEnemy {monster: MonsterType::PouillySlime, shiny:true, ..self}}, |             (MonsterType::RagRappy, Episode::Two, _) => {MapEnemy {monster: MonsterType::LoveRappy, shiny:true, ..self}}, | ||||||
|             (MonsterType::SandRappyCrater, _) => {MapEnemy {monster: MonsterType::DelRappyCrater, shiny:true, ..self}}, |             (MonsterType::Hildebear, _, _) => {MapEnemy {monster: MonsterType::Hildeblue, shiny:true, ..self}}, | ||||||
|             (MonsterType::ZuCrater, _) => {MapEnemy {monster: MonsterType::PazuzuCrater, shiny:true, ..self}}, |             (MonsterType::PoisonLily, _, _) => {MapEnemy {monster: MonsterType::NarLily, shiny:true, ..self}}, | ||||||
|             (MonsterType::Dorphon, _) => {MapEnemy {monster: MonsterType::DorphonEclair, shiny:true, ..self}}, |             (MonsterType::PofuillySlime, _, _) => {MapEnemy {monster: MonsterType::PouillySlime, shiny:true, ..self}}, | ||||||
|             (MonsterType::SandRappyDesert, _) => {MapEnemy {monster: MonsterType::DelRappyDesert, shiny:true, ..self}}, |             (MonsterType::SandRappyCrater, _, _) => {MapEnemy {monster: MonsterType::DelRappyCrater, shiny:true, ..self}}, | ||||||
|             (MonsterType::ZuDesert, _) => {MapEnemy {monster: MonsterType::PazuzuDesert, shiny:true, ..self}}, |             (MonsterType::ZuCrater, _, _) => {MapEnemy {monster: MonsterType::PazuzuCrater, shiny:true, ..self}}, | ||||||
|             (MonsterType::MerissaA, _) => {MapEnemy {monster: MonsterType::MerissaAA, shiny:true, ..self}}, |             (MonsterType::Dorphon, _, _) => {MapEnemy {monster: MonsterType::DorphonEclair, shiny:true, ..self}}, | ||||||
|             (MonsterType::SaintMillion, _) => {MapEnemy {monster: MonsterType::Kondrieu, shiny:true, ..self}}, |             (MonsterType::SandRappyDesert, _, _) => {MapEnemy {monster: MonsterType::DelRappyDesert, shiny:true, ..self}}, | ||||||
|             (MonsterType::Shambertin, _) => {MapEnemy {monster: MonsterType::Kondrieu, shiny:true, ..self}}, |             (MonsterType::ZuDesert, _, _) => {MapEnemy {monster: MonsterType::PazuzuDesert, shiny:true, ..self}}, | ||||||
|  |             (MonsterType::MerissaA, _, _) => {MapEnemy {monster: MonsterType::MerissaAA, shiny:true, ..self}}, | ||||||
|  |             (MonsterType::SaintMillion, _, _) => {MapEnemy {monster: MonsterType::Kondrieu, shiny:true, ..self}}, | ||||||
|  |             (MonsterType::Shambertin, _, _) => {MapEnemy {monster: MonsterType::Kondrieu, shiny:true, ..self}}, | ||||||
|             _ => {self}, |             _ => {self}, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     
 |  | ||||||
|     // in theory this should only be called on monsters we know can have rare types
 |  | ||||||
|     #[must_use] |  | ||||||
|     pub fn roll_appearance_for_mission(self, rare_monster_table: &RareMonsterAppearTable) -> MapEnemy { |  | ||||||
|         if rare_monster_table.roll_appearance(&self.monster) { |  | ||||||
|             return self.set_rare_appearance() |  | ||||||
|         } |  | ||||||
|         self |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ use std::fs::File; | |||||||
| 
 | 
 | ||||||
| use thiserror::Error; | use thiserror::Error; | ||||||
| 
 | 
 | ||||||
|  | use crate::ship::ship::ShipEvent; | ||||||
| use crate::ship::monster::MonsterType; | use crate::ship::monster::MonsterType; | ||||||
| use crate::ship::room::{Episode, RoomMode}; | use crate::ship::room::{Episode, RoomMode}; | ||||||
| 
 | 
 | ||||||
| @ -186,7 +187,7 @@ pub struct Maps { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Maps { | impl Maps { | ||||||
|     pub fn new(room_mode: RoomMode, rare_monster_table: &enemy::RareMonsterAppearTable) -> Maps { |     pub fn new(room_mode: RoomMode, rare_monster_table: &enemy::RareMonsterAppearTable, event: ShipEvent) -> Maps { | ||||||
|         let map_variants = match (room_mode.episode(), room_mode.single_player()) { |         let map_variants = match (room_mode.episode(), room_mode.single_player()) { | ||||||
|             (Episode::One, 0) => { |             (Episode::One, 0) => { | ||||||
|                 vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online), |                 vec![MapVariant::new(MapArea::Pioneer2Ep1, MapVariantMode::Online), | ||||||
| @ -278,20 +279,19 @@ impl Maps { | |||||||
|             _ => unreachable!() |             _ => unreachable!() | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let mut maps = Maps { |         Maps { | ||||||
|             enemy_data: map_variants.iter() |             enemy_data: map_variants.iter() | ||||||
|                         .fold(Vec::new(), |mut enemy_data, map_variant| { |                 .flat_map(|map_variant| { | ||||||
|                             enemy_data.append(&mut enemy_data_from_map_data(map_variant, &room_mode.episode())); |                     enemy_data_from_map_data(map_variant, &room_mode.episode()) | ||||||
|                             enemy_data |                 }) | ||||||
|                         }), |                 .map(|enemy| apply_rare_enemy(enemy, rare_monster_table, event)) | ||||||
|  |                 .collect(), | ||||||
|             object_data: map_variants.iter() |             object_data: map_variants.iter() | ||||||
|                 .flat_map(|map_variant| { |                 .flat_map(|map_variant| { | ||||||
|                     objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) |                     objects_from_map_data(map_variant.obj_file().into(), &room_mode.episode(), &map_variant.map) | ||||||
|                 }).collect(), |                 }).collect(), | ||||||
|             map_variants, |             map_variants, | ||||||
|         }; |         } | ||||||
|         maps.roll_monster_appearance(rare_monster_table); |  | ||||||
|         maps |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn enemy_by_id(&self, id: usize) -> Result<MapEnemy, MapsError> { |     pub fn enemy_by_id(&self, id: usize) -> Result<MapEnemy, MapsError> { | ||||||
| @ -314,9 +314,16 @@ impl Maps { | |||||||
|             }) |             }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn set_quest_data(&mut self, enemies: Vec<Option<MapEnemy>>, objects: Vec<Option<MapObject>>, rare_monster_appear_table: &RareMonsterAppearTable) { |     pub fn set_quest_data(&mut self, | ||||||
|         self.enemy_data = enemies; |                           enemies: Vec<Option<MapEnemy>>, | ||||||
|         self.roll_monster_appearance(rare_monster_appear_table); |                           objects: Vec<Option<MapObject>>, | ||||||
|  |                           rare_monster_table: &RareMonsterAppearTable, | ||||||
|  |                           event: ShipEvent) | ||||||
|  |     { | ||||||
|  |         self.enemy_data = enemies | ||||||
|  |             .into_iter() | ||||||
|  |             .map(|enemy| apply_rare_enemy(enemy, rare_monster_table, event)) | ||||||
|  |             .collect(); | ||||||
|         self.object_data = objects; |         self.object_data = objects; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -325,10 +332,11 @@ impl Maps { | |||||||
|         let shiny: Vec<(usize, &Option<MapEnemy>)> = self.enemy_data.iter() |         let shiny: Vec<(usize, &Option<MapEnemy>)> = self.enemy_data.iter() | ||||||
|             .enumerate() |             .enumerate() | ||||||
|             .filter(|(_,m)| { |             .filter(|(_,m)| { | ||||||
|                 if m.is_some() { |                 match m { | ||||||
|                     m.unwrap().shiny |                     Some(m) => { | ||||||
|                 } else { |                         m.shiny | ||||||
|                     false |                     }, | ||||||
|  |                     None => false, | ||||||
|                 } |                 } | ||||||
|             }) |             }) | ||||||
|             .collect(); |             .collect(); | ||||||
| @ -341,21 +349,15 @@ impl Maps { | |||||||
|         } |         } | ||||||
|         rare_monsters |         rare_monsters | ||||||
|     } |     } | ||||||
| 
 | } | ||||||
|     pub fn roll_monster_appearance(&mut self, rare_monster_table: &RareMonsterAppearTable) { | 
 | ||||||
|         self.enemy_data = self.enemy_data | fn apply_rare_enemy(enemy: Option<MapEnemy>, rare_enemy_table: &RareMonsterAppearTable, event: ShipEvent) -> Option<MapEnemy> { | ||||||
|                             .iter() |     enemy.map(|enemy| { | ||||||
|                             .map(|&x| |         if enemy.can_be_rare() && rare_enemy_table.roll_is_rare(&enemy.monster) { | ||||||
|                                 if let Some(monster) = x { |             enemy.into_rare(event) | ||||||
|                                     if monster.has_rare_appearance() { |         } | ||||||
|                                         Some(monster.roll_appearance_for_mission(rare_monster_table)) |         else { | ||||||
|                                     } else { |             enemy | ||||||
|                                         Some(monster) |         } | ||||||
|                                     } |     }) | ||||||
|                                 } else { |  | ||||||
|                                     x |  | ||||||
|                                 } |  | ||||||
|                             ) |  | ||||||
|                             .collect(); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| use libpso::packet::ship::*; | use libpso::packet::ship::*; | ||||||
| use crate::common::serverstate::ClientId; | use crate::common::serverstate::ClientId; | ||||||
| use crate::ship::ship::{ShipError, Clients}; | use crate::ship::ship::{ShipError, Clients, ShipEvent}; | ||||||
| use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError}; | use crate::ship::location::{ClientLocation, LobbyId, ClientLocationError}; | ||||||
| use crate::ship::packet::builder::{player_info}; | use crate::ship::packet::builder::{player_info}; | ||||||
| use crate::ship::items::state::ItemState; | use crate::ship::items::state::ItemState; | ||||||
| @ -11,7 +11,8 @@ pub async fn join_lobby(id: ClientId, | |||||||
|                         lobby: LobbyId, |                         lobby: LobbyId, | ||||||
|                         client_location: &ClientLocation, |                         client_location: &ClientLocation, | ||||||
|                         clients: &Clients, |                         clients: &Clients, | ||||||
|                         item_state: &ItemState) |                         item_state: &ItemState, | ||||||
|  |                         event: ShipEvent) | ||||||
|                         -> Result<JoinLobby, ShipError> { |                         -> Result<JoinLobby, ShipError> { | ||||||
|     let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; |     let lobby_clients = client_location.get_clients_in_lobby(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; | ||||||
| 
 | 
 | ||||||
| @ -41,7 +42,7 @@ pub async fn join_lobby(id: ClientId, | |||||||
|         one: 1, |         one: 1, | ||||||
|         lobby: lobby.id(), |         lobby: lobby.id(), | ||||||
|         block: client_block, |         block: client_block, | ||||||
|         event: 0, |         event: event.into(), | ||||||
|         padding: 0, |         padding: 0, | ||||||
|         playerinfo, |         playerinfo, | ||||||
|     }) |     }) | ||||||
| @ -51,7 +52,8 @@ pub async fn add_to_lobby(id: ClientId, | |||||||
|                           lobby: LobbyId, |                           lobby: LobbyId, | ||||||
|                           client_location: &ClientLocation, |                           client_location: &ClientLocation, | ||||||
|                           clients: &Clients, |                           clients: &Clients, | ||||||
|                           item_state: &ItemState) |                           item_state: &ItemState, | ||||||
|  |                           event: ShipEvent) | ||||||
|                           -> Result<AddToLobby, ShipError> { |                           -> Result<AddToLobby, ShipError> { | ||||||
|     let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; |     let area_client = client_location.get_local_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?; | ||||||
|     let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; |     let leader = client_location.get_lobby_leader(lobby).await.map_err(|err| -> ClientLocationError { err.into() })?; | ||||||
| @ -66,7 +68,7 @@ pub async fn add_to_lobby(id: ClientId, | |||||||
|                 one: 1, |                 one: 1, | ||||||
|                 lobby: lobby.id(), |                 lobby: lobby.id(), | ||||||
|                 block: client.block as u16, |                 block: client.block as u16, | ||||||
|                 event: 0, |                 event: event.into(), | ||||||
|                 padding: 0, |                 padding: 0, | ||||||
|                 playerinfo: player_info(0x100, client, &area_client, &inventory).await, |                 playerinfo: player_info(0x100, client, &area_client, &inventory).await, | ||||||
|             }) |             }) | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| use libpso::packet::ship::*; | use libpso::packet::ship::*; | ||||||
| use crate::common::serverstate::ClientId; | use crate::common::serverstate::ClientId; | ||||||
| use crate::ship::ship::{ShipError, ClientState, Clients}; | use crate::ship::ship::{ShipError, ClientState, Clients, ShipEvent}; | ||||||
| use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError}; | use crate::ship::location::{ClientLocation, RoomId, AreaClient, ClientLocationError}; | ||||||
| use crate::ship::room::RoomState; | use crate::ship::room::RoomState; | ||||||
| use crate::ship::items::state::ItemState; | use crate::ship::items::state::ItemState; | ||||||
| @ -13,7 +13,8 @@ pub async fn join_room(id: ClientId, | |||||||
|                        clients: &Clients, |                        clients: &Clients, | ||||||
|                        client_location: &ClientLocation, |                        client_location: &ClientLocation, | ||||||
|                        room_id: RoomId, |                        room_id: RoomId, | ||||||
|                        room: &RoomState) |                        room: &RoomState, | ||||||
|  |                        event: ShipEvent) | ||||||
|                        -> Result<JoinRoom, ShipError> { |                        -> Result<JoinRoom, ShipError> { | ||||||
|     let all_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; |     let all_clients = client_location.get_clients_in_room(room_id).await.map_err(|err| -> ClientLocationError { err.into() })?; | ||||||
|     let players = futures::stream::iter(all_clients.iter()) |     let players = futures::stream::iter(all_clients.iter()) | ||||||
| @ -40,7 +41,7 @@ pub async fn join_room(id: ClientId, | |||||||
|         one: 1, |         one: 1, | ||||||
|         difficulty: room.mode.difficulty().into(), |         difficulty: room.mode.difficulty().into(), | ||||||
|         battle: room.mode.battle(), |         battle: room.mode.battle(), | ||||||
|         event: 0, |         event: event.into(), | ||||||
|         section: room.section_id.into(), |         section: room.section_id.into(), | ||||||
|         challenge: room.mode.challenge(), |         challenge: room.mode.challenge(), | ||||||
|         random_seed: room.random_seed, |         random_seed: room.random_seed, | ||||||
| @ -57,8 +58,7 @@ pub async fn add_to_room(_id: ClientId, | |||||||
|                          area_client: &AreaClient, |                          area_client: &AreaClient, | ||||||
|                          leader: &AreaClient, |                          leader: &AreaClient, | ||||||
|                          item_state: &ItemState, |                          item_state: &ItemState, | ||||||
|                    _room_id: RoomId, |                          event: ShipEvent) | ||||||
| ) |  | ||||||
|                          -> Result<AddToRoom, ShipError> { |                          -> Result<AddToRoom, ShipError> { | ||||||
|     let inventory = item_state.get_character_inventory(&client.character).await?; |     let inventory = item_state.get_character_inventory(&client.character).await?; | ||||||
|     Ok(AddToRoom { |     Ok(AddToRoom { | ||||||
| @ -68,7 +68,7 @@ pub async fn add_to_room(_id: ClientId, | |||||||
|         one: 0, // TODO: ????????
 |         one: 0, // TODO: ????????
 | ||||||
|         lobby: 0xFF, |         lobby: 0xFF, | ||||||
|         block: 0, |         block: 0, | ||||||
|         event: 0, |         event: event.into(), | ||||||
|         padding: 0, |         padding: 0, | ||||||
|         playerinfo: player_info(0x10000, client, area_client, &inventory).await, |         playerinfo: player_info(0x10000, client, area_client, &inventory).await, | ||||||
|     }) |     }) | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| use libpso::packet::ship::*; | use libpso::packet::ship::*; | ||||||
| use crate::common::serverstate::ClientId; | use crate::common::serverstate::ClientId; | ||||||
| use crate::common::leveltable::LEVEL_TABLE; | use crate::common::leveltable::LEVEL_TABLE; | ||||||
| use crate::ship::ship::{SendShipPacket, ShipError, Clients}; | use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; | ||||||
| use crate::ship::room::Rooms; | use crate::ship::room::Rooms; | ||||||
| use crate::ship::character::{FullCharacterBytesBuilder}; | use crate::ship::character::{FullCharacterBytesBuilder}; | ||||||
| use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; | use crate::ship::location::{ClientLocation, LobbyId, RoomLobby, ClientLocationError, RoomId}; | ||||||
| @ -55,11 +55,12 @@ pub async fn send_player_to_lobby(id: ClientId, | |||||||
|                                   _pkt: CharData, |                                   _pkt: CharData, | ||||||
|                                   client_location: &mut ClientLocation, |                                   client_location: &mut ClientLocation, | ||||||
|                                   clients: &Clients, |                                   clients: &Clients, | ||||||
|                                   item_state: &ItemState) |                                   item_state: &ItemState, | ||||||
|  |                                   event: ShipEvent) | ||||||
|                                   -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { |                                   -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { | ||||||
|     let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).await.map_err(|_| ShipError::TooManyClients)?; |     let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).await.map_err(|_| ShipError::TooManyClients)?; | ||||||
|     let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state).await?; |     let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; | ||||||
|     let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state).await?; |     let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; | ||||||
|     let neighbors = client_location.get_client_neighbors(id).await.unwrap(); |     let neighbors = client_location.get_client_neighbors(id).await.unwrap(); | ||||||
|     Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] |     Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] | ||||||
|        .into_iter() |        .into_iter() | ||||||
| @ -74,7 +75,8 @@ pub async fn change_lobby<EG>(id: ClientId, | |||||||
|                               clients: &Clients, |                               clients: &Clients, | ||||||
|                               item_state: &mut ItemState, |                               item_state: &mut ItemState, | ||||||
|                               rooms: &Rooms, |                               rooms: &Rooms, | ||||||
|                               entity_gateway: &mut EG) |                               entity_gateway: &mut EG, | ||||||
|  |                               event: ShipEvent) | ||||||
|                               -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> |                               -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> | ||||||
| where | where | ||||||
|     EG: EntityGateway + Clone + 'static, |     EG: EntityGateway + Clone + 'static, | ||||||
| @ -117,8 +119,8 @@ where | |||||||
|         Box::pin(async move { |         Box::pin(async move { | ||||||
|             item_state.load_character(&mut entity_gateway, &client.character).await |             item_state.load_character(&mut entity_gateway, &client.character).await | ||||||
|         })}).await??; |         })}).await??; | ||||||
|     let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state).await?; |     let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, item_state, event).await?; | ||||||
|     let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state).await?; |     let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, item_state, event).await?; | ||||||
|     let neighbors = client_location.get_client_neighbors(id).await?; |     let neighbors = client_location.get_client_neighbors(id).await?; | ||||||
|     Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] |     Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] | ||||||
|        .into_iter() |        .into_iter() | ||||||
| @ -126,6 +128,7 @@ where | |||||||
|               .map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))) |               .map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))) | ||||||
|        .chain(old_neighbors.into_iter() |        .chain(old_neighbors.into_iter() | ||||||
|               .map(|c| (c.client, SendShipPacket::LeaveLobby(leave_lobby.clone())))) |               .map(|c| (c.client, SendShipPacket::LeaveLobby(leave_lobby.clone())))) | ||||||
|  |        .chain(std::iter::once((id, SendShipPacket::LobbyEvent(LobbyEvent{ event: event.into()})))) | ||||||
|        .collect()) |        .collect()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom}; | |||||||
| use futures::stream::{FuturesOrdered, StreamExt}; | use futures::stream::{FuturesOrdered, StreamExt}; | ||||||
| use libpso::packet::ship::*; | use libpso::packet::ship::*; | ||||||
| use crate::common::serverstate::ClientId; | use crate::common::serverstate::ClientId; | ||||||
| use crate::ship::ship::{SendShipPacket, ShipError, Clients}; | use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; | ||||||
| use crate::ship::room::Rooms; | use crate::ship::room::Rooms; | ||||||
| use crate::ship::location::{ClientLocation, ClientLocationError}; | use crate::ship::location::{ClientLocation, ClientLocationError}; | ||||||
| use crate::ship::packet::builder::quest; | use crate::ship::packet::builder::quest; | ||||||
| @ -94,7 +94,8 @@ pub async fn player_chose_quest(id: ClientId, | |||||||
|                                 questmenuselect: QuestMenuSelect, |                                 questmenuselect: QuestMenuSelect, | ||||||
|                                 clients: &Clients, |                                 clients: &Clients, | ||||||
|                                 client_location: &ClientLocation, |                                 client_location: &ClientLocation, | ||||||
|                                 rooms: &Rooms) |                                 rooms: &Rooms, | ||||||
|  |                                 event: ShipEvent) | ||||||
|                                 -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { |                                 -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { | ||||||
|     let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; |     let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?; | ||||||
| 
 | 
 | ||||||
| @ -115,7 +116,7 @@ pub async fn player_chose_quest(id: ClientId, | |||||||
|                 .clone(); |                 .clone(); | ||||||
| 
 | 
 | ||||||
|             let rare_monster_drops = room.rare_monster_table.clone(); |             let rare_monster_drops = room.rare_monster_table.clone(); | ||||||
|             room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_drops); |             room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_drops, event); | ||||||
|             room.map_areas = quest.map_areas.clone(); |             room.map_areas = quest.map_areas.clone(); | ||||||
| 
 | 
 | ||||||
|             let bin = quest::quest_header(&questmenuselect, &quest.bin_blob, "bin"); |             let bin = quest::quest_header(&questmenuselect, &quest.bin_blob, "bin"); | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ use libpso::packet::ship::*; | |||||||
| use libpso::packet::messages::*; | use libpso::packet::messages::*; | ||||||
| use crate::common::serverstate::ClientId; | use crate::common::serverstate::ClientId; | ||||||
| use crate::common::leveltable::LEVEL_TABLE; | use crate::common::leveltable::LEVEL_TABLE; | ||||||
| use crate::ship::ship::{SendShipPacket, ShipError, Clients}; | use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent}; | ||||||
| use crate::ship::room::Rooms; | use crate::ship::room::Rooms; | ||||||
| use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; | use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError}; | ||||||
| use crate::ship::packet::builder; | use crate::ship::packet::builder; | ||||||
| @ -17,7 +17,8 @@ pub async fn create_room(id: ClientId, | |||||||
|                          client_location: &mut ClientLocation, |                          client_location: &mut ClientLocation, | ||||||
|                          clients: &Clients, |                          clients: &Clients, | ||||||
|                          item_state: &mut ItemState, |                          item_state: &mut ItemState, | ||||||
|                          rooms: &Rooms) |                          rooms: &Rooms, | ||||||
|  |                          event: ShipEvent) | ||||||
|                          -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { |                          -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { | ||||||
|     let level = clients.with(id, |client| Box::pin(async move { |     let level = clients.with(id, |client| Box::pin(async move { | ||||||
|         LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) |         LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp) | ||||||
| @ -44,12 +45,12 @@ pub async fn create_room(id: ClientId, | |||||||
|         let mut item_state = item_state.clone(); |         let mut item_state = item_state.clone(); | ||||||
|         Box::pin(async move { |         Box::pin(async move { | ||||||
|             item_state.add_character_to_room(room_id, &client.character, area_client).await; |             item_state.add_character_to_room(room_id, &client.character, area_client).await; | ||||||
|             let mut room = room::RoomState::from_create_room(&create_room, client.character.section_id)?; |             let mut room = room::RoomState::from_create_room(&create_room, client.character.section_id, event)?; | ||||||
|             room.bursting = true; |             room.bursting = true; | ||||||
|             Ok::<_, ShipError>(room) |             Ok::<_, ShipError>(room) | ||||||
|         })}).await??; |         })}).await??; | ||||||
| 
 | 
 | ||||||
|     let join_room = builder::room::join_room(id, clients, client_location, room_id, &room).await?; |     let join_room = builder::room::join_room(id, clients, client_location, room_id, &room, event).await?; | ||||||
|     rooms.add(room_id, room).await?; |     rooms.add(room_id, room).await?; | ||||||
| 
 | 
 | ||||||
|     let mut result = vec![(id, SendShipPacket::JoinRoom(join_room))]; |     let mut result = vec![(id, SendShipPacket::JoinRoom(join_room))]; | ||||||
| @ -87,7 +88,8 @@ pub async fn join_room(id: ClientId, | |||||||
|                        client_location: &mut ClientLocation, |                        client_location: &mut ClientLocation, | ||||||
|                        clients: &Clients, |                        clients: &Clients, | ||||||
|                        item_state: &mut ItemState, |                        item_state: &mut ItemState, | ||||||
|                        rooms: &Rooms) |                        rooms: &Rooms, | ||||||
|  |                        event: ShipEvent) | ||||||
|                        -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { |                        -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> { | ||||||
|     let room_id = RoomId(pkt.item as usize); |     let room_id = RoomId(pkt.item as usize); | ||||||
|     if !rooms.exists(room_id).await { |     if !rooms.exists(room_id).await { | ||||||
| @ -134,12 +136,12 @@ pub async fn join_room(id: ClientId, | |||||||
|         let clients = clients.clone(); |         let clients = clients.clone(); | ||||||
|         let client_location = client_location.clone(); |         let client_location = client_location.clone(); | ||||||
|         Box::pin(async move { |         Box::pin(async move { | ||||||
|             builder::room::join_room(id, &clients, &client_location, room_id, room).await |             builder::room::join_room(id, &clients, &client_location, room_id, room, event).await | ||||||
|         })}).await??; |         })}).await??; | ||||||
|     let add_to = clients.with(id, |client| { |     let add_to = clients.with(id, |client| { | ||||||
|         let item_state = item_state.clone(); |         let item_state = item_state.clone(); | ||||||
|         Box::pin(async move { |         Box::pin(async move { | ||||||
|             builder::room::add_to_room(id, client, &area_client, &room_leader, &item_state, room_id).await |             builder::room::add_to_room(id, client, &area_client, &room_leader, &item_state, event).await | ||||||
|         })}).await??; |         })}).await??; | ||||||
| 
 | 
 | ||||||
|     rooms.with_mut(room_id, |room| Box::pin(async move { |     rooms.with_mut(room_id, |room| Box::pin(async move { | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ use crate::ship::monster::{load_monster_stats_table, MonsterType, MonsterStats}; | |||||||
| use crate::ship::map::area::MapAreaLookup; | use crate::ship::map::area::MapAreaLookup; | ||||||
| use crate::ship::map::enemy::RareMonsterAppearTable; | use crate::ship::map::enemy::RareMonsterAppearTable; | ||||||
| use crate::ship::quests; | use crate::ship::quests; | ||||||
| use crate::ship::ship::ShipError; | use crate::ship::ship::{ShipError, ShipEvent}; | ||||||
| use crate::ship::location::{MAX_ROOMS, RoomId}; | use crate::ship::location::{MAX_ROOMS, RoomId}; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -343,7 +343,7 @@ impl RoomState { | |||||||
|         self.quest_group = QuestCategoryType::from(group); |         self.quest_group = QuestCategoryType::from(group); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, section_id: SectionID) -> Result<RoomState, RoomCreationError> { |     pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom, section_id: SectionID, event: ShipEvent) -> Result<RoomState, RoomCreationError> { | ||||||
|         if [create_room.battle, create_room.challenge, create_room.single_player].iter().sum::<u8>() > 1 { |         if [create_room.battle, create_room.challenge, create_room.single_player].iter().sum::<u8>() > 1 { | ||||||
|             return Err(RoomCreationError::InvalidMode) |             return Err(RoomCreationError::InvalidMode) | ||||||
|         } |         } | ||||||
| @ -410,7 +410,7 @@ impl RoomState { | |||||||
|             rare_monster_table: Box::new(rare_monster_table.clone()), |             rare_monster_table: Box::new(rare_monster_table.clone()), | ||||||
|             name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), |             name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), | ||||||
|             password: create_room.password, |             password: create_room.password, | ||||||
|             maps: Maps::new(room_mode, &rare_monster_table), // TODO: rare_monster_table here feels janky. is there some way to call the the RoomState.rare_monster_table we already created?
 |             maps: Maps::new(room_mode, &rare_monster_table, event), | ||||||
|             section_id, |             section_id, | ||||||
|             drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)), |             drop_table: Box::new(DropTable::new(room_mode.episode(), room_mode.difficulty(), section_id)), | ||||||
|             bursting: false, |             bursting: false, | ||||||
|  | |||||||
| @ -42,6 +42,57 @@ pub const SHIP_PORT: u16 = 23423; | |||||||
| pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; | pub const QUEST_CATEGORY_MENU_ID: u32 = 0xA2; | ||||||
| pub const QUEST_SELECT_MENU_ID: u32 = 0xA3; | pub const QUEST_SELECT_MENU_ID: u32 = 0xA3; | ||||||
| 
 | 
 | ||||||
|  | #[derive(Clone, Copy)] | ||||||
|  | pub enum ShipEvent { | ||||||
|  |     None, | ||||||
|  |     Christmas, | ||||||
|  |     Valentines, | ||||||
|  |     Easter, | ||||||
|  |     Halloween, | ||||||
|  |     Sonic, | ||||||
|  |     NewYear, | ||||||
|  |     Summer, | ||||||
|  |     White, | ||||||
|  |     Wedding, | ||||||
|  |     Fall, | ||||||
|  |     Spring, | ||||||
|  |     Summer2, | ||||||
|  |     Spring2, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<ShipEvent> for u32 { | ||||||
|  |     fn from(other: ShipEvent) -> u32 { | ||||||
|  |         u16::from(other) as u32 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<ShipEvent> for u16 { | ||||||
|  |     fn from(other: ShipEvent) -> u16 { | ||||||
|  |         u8::from(other) as u16 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<ShipEvent> for u8 { | ||||||
|  |     fn from(other: ShipEvent) -> u8 { | ||||||
|  |         match other { | ||||||
|  |             ShipEvent::None => 0, | ||||||
|  |             ShipEvent::Christmas => 1, | ||||||
|  |             ShipEvent::Valentines => 3, | ||||||
|  |             ShipEvent::Easter => 4, | ||||||
|  |             ShipEvent::Halloween => 5, | ||||||
|  |             ShipEvent::Sonic => 6, | ||||||
|  |             ShipEvent::NewYear => 7, | ||||||
|  |             ShipEvent::Summer => 8, | ||||||
|  |             ShipEvent::White => 9, | ||||||
|  |             ShipEvent::Wedding => 10, | ||||||
|  |             ShipEvent::Fall => 11, | ||||||
|  |             ShipEvent::Spring => 12, | ||||||
|  |             ShipEvent::Summer2 => 13, | ||||||
|  |             ShipEvent::Spring2 => 14, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #[derive(Error, Debug)] | #[derive(Error, Debug)] | ||||||
| pub enum ShipError { | pub enum ShipError { | ||||||
| @ -240,6 +291,7 @@ pub enum SendShipPacket { | |||||||
|     AcknowledgeTrade(AcknowledgeTrade), |     AcknowledgeTrade(AcknowledgeTrade), | ||||||
|     CancelTrade(CancelTrade), |     CancelTrade(CancelTrade), | ||||||
|     TradeSuccessful(TradeSuccessful), |     TradeSuccessful(TradeSuccessful), | ||||||
|  |     LobbyEvent(LobbyEvent), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl SendServerPacket for SendShipPacket { | impl SendServerPacket for SendShipPacket { | ||||||
| @ -282,6 +334,7 @@ impl SendServerPacket for SendShipPacket { | |||||||
|             SendShipPacket::AcknowledgeTrade(pkt) => pkt.as_bytes(), |             SendShipPacket::AcknowledgeTrade(pkt) => pkt.as_bytes(), | ||||||
|             SendShipPacket::CancelTrade(pkt) => pkt.as_bytes(), |             SendShipPacket::CancelTrade(pkt) => pkt.as_bytes(), | ||||||
|             SendShipPacket::TradeSuccessful(pkt) => pkt.as_bytes(), |             SendShipPacket::TradeSuccessful(pkt) => pkt.as_bytes(), | ||||||
|  |             SendShipPacket::LobbyEvent(pkt) => pkt.as_bytes(), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -321,6 +374,7 @@ pub struct ShipServerStateBuilder<EG: EntityGateway + Clone + 'static> { | |||||||
|     ip: Option<Ipv4Addr>, |     ip: Option<Ipv4Addr>, | ||||||
|     port: Option<u16>, |     port: Option<u16>, | ||||||
|     auth_token: Option<AuthToken>, |     auth_token: Option<AuthToken>, | ||||||
|  |     event: Option<ShipEvent>, | ||||||
|     num_blocks: usize, |     num_blocks: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -332,6 +386,7 @@ impl<EG: EntityGateway + Clone + 'static> Default for ShipServerStateBuilder<EG> | |||||||
|             ip: None, |             ip: None, | ||||||
|             port: None, |             port: None, | ||||||
|             auth_token: None, |             auth_token: None, | ||||||
|  |             event: None, | ||||||
|             num_blocks: 2, |             num_blocks: 2, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -368,6 +423,12 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerStateBuilder<EG> { | |||||||
|         self |         self | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     #[must_use] | ||||||
|  |     pub fn event(mut self, event: ShipEvent) -> ShipServerStateBuilder<EG> { | ||||||
|  |         self.event = Some(event); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #[must_use] |     #[must_use] | ||||||
|     pub fn blocks(mut self, num_blocks: usize) -> ShipServerStateBuilder<EG> { |     pub fn blocks(mut self, num_blocks: usize) -> ShipServerStateBuilder<EG> { | ||||||
|         self.num_blocks = num_blocks; |         self.num_blocks = num_blocks; | ||||||
| @ -385,6 +446,7 @@ impl<EG: EntityGateway + Clone + 'static> ShipServerStateBuilder<EG> { | |||||||
|             port: self.port.unwrap_or(SHIP_PORT), |             port: self.port.unwrap_or(SHIP_PORT), | ||||||
|             shops: ItemShops::default(), |             shops: ItemShops::default(), | ||||||
|             blocks: Blocks(blocks), |             blocks: Blocks(blocks), | ||||||
|  |             event: self.event.unwrap_or(ShipEvent::None), | ||||||
| 
 | 
 | ||||||
|             auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), |             auth_token: self.auth_token.unwrap_or_else(|| AuthToken("".into())), | ||||||
|             ship_list: Vec::new(), |             ship_list: Vec::new(), | ||||||
| @ -424,6 +486,7 @@ pub struct ShipServerState<EG: EntityGateway + Clone + 'static> { | |||||||
|     item_state: items::state::ItemState, |     item_state: items::state::ItemState, | ||||||
|     shops: ItemShops, |     shops: ItemShops, | ||||||
|     pub blocks: Blocks, |     pub blocks: Blocks, | ||||||
|  |     event: ShipEvent, | ||||||
| 
 | 
 | ||||||
|     ip: Ipv4Addr, |     ip: Ipv4Addr, | ||||||
|     port: u16, |     port: u16, | ||||||
| @ -611,14 +674,14 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> { | |||||||
|                         let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); |                         let select_block = handler::lobby::block_selected(id, menuselect, &self.clients, &self.item_state).await?.into_iter(); | ||||||
|                         leave_lobby.chain(select_block).collect() |                         leave_lobby.chain(select_block).collect() | ||||||
|                     } |                     } | ||||||
|                     ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await?, |                     ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await?, | ||||||
|                     QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?, |                     QUEST_CATEGORY_MENU_ID => handler::quest::select_quest_category(id, menuselect, &block.client_location, &block.rooms).await?, | ||||||
|                     _ => unreachable!(), |                     _ => unreachable!(), | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             RecvShipPacket::QuestMenuSelect(questmenuselect) => { |             RecvShipPacket::QuestMenuSelect(questmenuselect) => { | ||||||
|                 let block = self.blocks.get_from_client(id, &self.clients).await?; |                 let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
|                 handler::quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms).await? |                 handler::quest::player_chose_quest(id, questmenuselect, &self.clients, &block.client_location, &block.rooms, self.event).await? | ||||||
|             }, |             }, | ||||||
|             RecvShipPacket::MenuDetail(menudetail) => { |             RecvShipPacket::MenuDetail(menudetail) => { | ||||||
|                 let block = self.blocks.get_from_client(id, &self.clients).await?; |                 let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
| @ -636,7 +699,7 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> { | |||||||
|                         menu: room_password_req.menu, |                         menu: room_password_req.menu, | ||||||
|                         item: room_password_req.item, |                         item: room_password_req.item, | ||||||
|                     }; |                     }; | ||||||
|                     handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await? |                     handler::room::join_room(id, menuselect, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await? | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))] |                     vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("Incorrect password".into())))] | ||||||
| @ -644,7 +707,7 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> { | |||||||
|             }, |             }, | ||||||
|             RecvShipPacket::CharData(chardata) => { |             RecvShipPacket::CharData(chardata) => { | ||||||
|                 let block = self.blocks.get_from_client(id, &self.clients).await?; |                 let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
|                 handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state).await? |                 handler::lobby::send_player_to_lobby(id, chardata, &mut block.client_location, &self.clients, &self.item_state, self.event).await? | ||||||
|             }, |             }, | ||||||
|             RecvShipPacket::Message(msg) => { |             RecvShipPacket::Message(msg) => { | ||||||
|                 self.message(id, msg).await? |                 self.message(id, msg).await? | ||||||
| @ -658,7 +721,7 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> { | |||||||
|             }, |             }, | ||||||
|             RecvShipPacket::CreateRoom(create_room) => { |             RecvShipPacket::CreateRoom(create_room) => { | ||||||
|                 let block = self.blocks.get_from_client(id, &self.clients).await?; |                 let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
|                 handler::room::create_room(id, create_room, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms).await? |                 handler::room::create_room(id, create_room, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, self.event).await? | ||||||
|             }, |             }, | ||||||
|             RecvShipPacket::RoomNameRequest(_req) => { |             RecvShipPacket::RoomNameRequest(_req) => { | ||||||
|                 let block = self.blocks.get_from_client(id, &self.clients).await?; |                 let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
| @ -696,7 +759,7 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> { | |||||||
|             }, |             }, | ||||||
|             RecvShipPacket::LobbySelect(pkt) => { |             RecvShipPacket::LobbySelect(pkt) => { | ||||||
|                 let block = self.blocks.get_from_client(id, &self.clients).await?; |                 let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
|                 handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway).await? |                 handler::lobby::change_lobby(id, pkt.lobby, &mut block.client_location, &self.clients, &mut self.item_state, &block.rooms, &mut self.entity_gateway, self.event).await? | ||||||
|             }, |             }, | ||||||
|             RecvShipPacket::RequestQuestList(rql) => { |             RecvShipPacket::RequestQuestList(rql) => { | ||||||
|                 let block = self.blocks.get_from_client(id, &self.clients).await?; |                 let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
| @ -744,7 +807,6 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { |     async fn on_disconnect(&mut self, id: ClientId) -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> { | ||||||
|         //let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?;
 |  | ||||||
|         let block = self.blocks.get_from_client(id, &self.clients).await?; |         let block = self.blocks.get_from_client(id, &self.clients).await?; | ||||||
|         let area_client = block.client_location.get_local_client(id).await?; |         let area_client = block.client_location.get_local_client(id).await?; | ||||||
|         let neighbors = block.client_location.get_client_neighbors(id).await?; |         let neighbors = block.client_location.get_client_neighbors(id).await?; | ||||||
| @ -763,17 +825,6 @@ impl<EG: EntityGateway + Clone> ServerState for ShipServerState<EG> { | |||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         /* |  | ||||||
|         if let Some(shipgate_sender) = self.shipgate_sender.as_ref() { |  | ||||||
|             shipgate_sender.send(ShipMessage::RemoveUser(client.user.id)).await; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         block.client_location.remove_client_from_area(id).await; |  | ||||||
|         self.clients.with(id, |client| Box::pin(async move { |  | ||||||
|             self.item_state.remove_character_from_room(&client.character).await |  | ||||||
|         })).await?; |  | ||||||
|          */ |  | ||||||
| 
 |  | ||||||
|         if let Some(mut client) = self.clients.remove(&id).await { |         if let Some(mut client) = self.clients.remove(&id).await { | ||||||
|             client.user.at_ship = false; |             client.user.at_ship = false; | ||||||
|             self.entity_gateway.save_user(&client.user).await; |             self.entity_gateway.save_user(&client.user).await; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user