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