add client.rs
This commit is contained in:
		
							parent
							
								
									4dc814d244
								
							
						
					
					
						commit
						6f0fa05e3b
					
				
							
								
								
									
										172
									
								
								src/ship/client.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								src/ship/client.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,172 @@ | ||||
| use std::collections::HashMap; | ||||
| use async_std::sync::{Arc, RwLock, RwLockReadGuard}; | ||||
| 
 | ||||
| use futures::future::BoxFuture; | ||||
| 
 | ||||
| use libpso::packet::ship::*; | ||||
| use libpso::packet::login::Session; | ||||
| 
 | ||||
| use crate::common::serverstate::ClientId; | ||||
| use crate::entity::account::{UserAccountEntity, UserSettingsEntity}; | ||||
| use crate::entity::character::CharacterEntity; | ||||
| use crate::entity::item; | ||||
| 
 | ||||
| use crate::ship::ship::ShipError; | ||||
| use crate::ship::items; | ||||
| use crate::ship::map::MapArea; | ||||
| use crate::ship::shops::{WeaponShopItem, ToolShopItem, ArmorShopItem}; | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone, Default)] | ||||
| pub struct Clients(Arc<RwLock<HashMap<ClientId, RwLock<ClientState>>>>); | ||||
| 
 | ||||
| impl Clients { | ||||
|     pub async fn add(&mut self, client_id: ClientId, client_state: ClientState) { | ||||
|         self.0 | ||||
|             .write() | ||||
|             .await | ||||
|             .insert(client_id, RwLock::new(client_state)); | ||||
|     } | ||||
| 
 | ||||
|     pub async fn remove(&mut self, client_id: &ClientId) -> Option<ClientState> { | ||||
|         Some(self.0 | ||||
|             .write() | ||||
|             .await | ||||
|             .remove(client_id)? | ||||
|             .into_inner()) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn with<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result<T, ShipError> | ||||
|     where | ||||
|         T: Send, | ||||
|         F: for<'b> FnOnce(&'b ClientState) -> BoxFuture<'b, T> + Send + 'a, | ||||
|     { | ||||
|         let clients = self.0 | ||||
|             .read() | ||||
|             .await; | ||||
|         let client = clients | ||||
|             .get(&client_id) | ||||
|             .ok_or_else(|| ShipError::ClientNotFound(client_id))? | ||||
|             .read() | ||||
|             .await; | ||||
| 
 | ||||
|         Ok(func(&client).await) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn with_many<'a, T, F, const N: usize>(&'a self, client_ids: [ClientId; N], func: F) -> Result<T, ShipError> | ||||
|     where | ||||
|         T: Send, | ||||
|         F: for<'b> FnOnce([RwLockReadGuard<'b, ClientState>; N]) -> BoxFuture<'b, T> + Send + 'a, | ||||
|     { | ||||
|         let clients = self.0 | ||||
|             .read() | ||||
|             .await; | ||||
|         
 | ||||
|         let mut client_states: [std::mem::MaybeUninit<RwLockReadGuard<ClientState>>; N] = unsafe { | ||||
|             std::mem::MaybeUninit::uninit().assume_init() | ||||
|         }; | ||||
| 
 | ||||
|         for (cindex, client_id) in client_ids.iter().enumerate() { | ||||
|             let c = clients | ||||
|                 .get(client_id) | ||||
|                 .ok_or_else(|| ShipError::ClientNotFound(*client_id))? | ||||
|                 .read() | ||||
|                 .await; | ||||
|             client_states[cindex].write(c); | ||||
|         } | ||||
|         
 | ||||
|         let client_states = unsafe { | ||||
|             // TODO: this should just be a normal transmute but due to compiler limitations it
 | ||||
|             // does not yet work with const generics
 | ||||
|             // https://github.com/rust-lang/rust/issues/61956
 | ||||
|             std::mem::transmute_copy::<_, [RwLockReadGuard<ClientState>; N]>(&client_states) | ||||
|         }; | ||||
| 
 | ||||
|         Ok(func(client_states).await) | ||||
|     } | ||||
| 
 | ||||
|     pub async fn with_mut<'a, T, F>(&'a self, client_id: ClientId, func: F) -> Result<T, ShipError> | ||||
|     where | ||||
|         T: Send, | ||||
|         F: for<'b> FnOnce(&'b mut ClientState) -> BoxFuture<'b, T> + Send + 'a, | ||||
|     { | ||||
|         let clients = self.0 | ||||
|             .read() | ||||
|             .await; | ||||
|         let mut client = clients | ||||
|             .get(&client_id) | ||||
|             .ok_or_else(|| ShipError::ClientNotFound(client_id))? | ||||
|             .write() | ||||
|             .await; | ||||
| 
 | ||||
|         Ok(func(&mut client).await) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| pub struct ItemDropLocation { | ||||
|     pub map_area: MapArea, | ||||
|     pub x: f32, | ||||
|     pub z: f32, | ||||
|     pub item_id: items::ClientItemId, | ||||
| } | ||||
| 
 | ||||
| pub struct LoadingQuest { | ||||
|     pub header_bin: Option<QuestHeader>, | ||||
|     pub header_dat: Option<QuestHeader>, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub struct ClientState { | ||||
|     pub user: UserAccountEntity, | ||||
|     pub settings: UserSettingsEntity, | ||||
|     pub character: CharacterEntity, | ||||
|     _session: Session, | ||||
|     //guildcard: GuildCard,
 | ||||
|     pub block: usize, | ||||
|     pub item_drop_location: Option<ItemDropLocation>, | ||||
|     pub done_loading_quest: bool, | ||||
|     pub area: Option<MapArea>, | ||||
|     pub x: f32, | ||||
|     pub y: f32, | ||||
|     pub z: f32, | ||||
|     pub weapon_shop: Vec<WeaponShopItem>, | ||||
|     pub tool_shop: Vec<ToolShopItem>, | ||||
|     pub armor_shop: Vec<ArmorShopItem>, | ||||
|     pub tek: Option<(items::ClientItemId, item::weapon::TekSpecialModifier, item::weapon::TekPercentModifier, i32)>, | ||||
|     pub character_playtime: chrono::Duration, | ||||
|     pub log_on_time: chrono::DateTime<chrono::Utc>, | ||||
| } | ||||
| 
 | ||||
| impl ClientState { | ||||
|     pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, session: Session) -> ClientState { | ||||
|         let character_playtime = chrono::Duration::seconds(character.playtime as i64); | ||||
|         ClientState { | ||||
|             user, | ||||
|             settings, | ||||
|             character, | ||||
|             _session: session, | ||||
|             block: 0, | ||||
|             item_drop_location: None, | ||||
|             done_loading_quest: false, | ||||
|             area: None, | ||||
|             x: 0.0, | ||||
|             y: 0.0, | ||||
|             z: 0.0, | ||||
|             weapon_shop: Vec::new(), | ||||
|             tool_shop: Vec::new(), | ||||
|             armor_shop: Vec::new(), | ||||
|             tek: None, | ||||
|             character_playtime, | ||||
|             log_on_time: chrono::Utc::now(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn update_playtime(&mut self) { | ||||
|         let additional_playtime = chrono::Utc::now() - self.log_on_time; | ||||
|         self.character.playtime = (self.character_playtime + additional_playtime).num_seconds() as u32; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user