character playtime #116
| @ -413,4 +413,6 @@ pub struct CharacterEntity { | ||||
|     pub option_flags: u32, | ||||
|     pub keyboard_config: CharacterKeyboardConfig, | ||||
|     pub gamepad_config: CharacterGamepadConfig, | ||||
| 
 | ||||
|     pub playtime: u32, | ||||
| } | ||||
|  | ||||
| @ -147,6 +147,10 @@ pub trait EntityGateway: Send + Sync { | ||||
|     async fn create_trade(&mut self, _char_id1: &CharacterEntityId, _char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> { | ||||
|         unimplemented!(); | ||||
|     } | ||||
| 
 | ||||
|     async fn set_character_playtime(&mut self, _char_id: &CharacterEntityId, _playtime: u32) -> Result<(), GatewayError> { | ||||
|         unimplemented!(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -346,6 +346,7 @@ impl EntityGateway for InMemoryGateway { | ||||
|             option_flags: character.option_flags, | ||||
|             keyboard_config: character.keyboard_config, | ||||
|             gamepad_config: character.gamepad_config, | ||||
|             playtime: 0, | ||||
|         }; | ||||
|         characters.insert(new_character.id, new_character.clone()); | ||||
|         Ok(new_character) | ||||
| @ -503,4 +504,15 @@ impl EntityGateway for InMemoryGateway { | ||||
|         trades.push(new_trade.clone()); | ||||
|         Ok(new_trade) | ||||
|     } | ||||
| 
 | ||||
|     async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { | ||||
|         let mut characters = self.characters.lock().unwrap(); | ||||
|         if let Some(character) = characters.get_mut(char_id) { | ||||
|             character.playtime = playtime; | ||||
|             Ok(()) | ||||
|         } | ||||
|         else { | ||||
|             Err(GatewayError::Error) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,2 @@ | ||||
| alter table player_character | ||||
|   add playtime integer; | ||||
| @ -219,6 +219,8 @@ pub struct PgCharacter { | ||||
|     tech_menu: Vec<u8>, | ||||
|     keyboard_config: Vec<u8>, | ||||
|     gamepad_config: Vec<u8>, | ||||
| 
 | ||||
|     playtime: i32, | ||||
| } | ||||
| 
 | ||||
| impl From<PgCharacter> for CharacterEntity { | ||||
| @ -274,6 +276,7 @@ impl From<PgCharacter> for CharacterEntity { | ||||
|             gamepad_config: CharacterGamepadConfig { | ||||
|                 gamepad_config: vec_to_array(other.gamepad_config) | ||||
|             }, | ||||
|             playtime: other.playtime as u32, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -269,39 +269,40 @@ async fn save_character(conn: &mut sqlx::PgConnection, char: &CharacterEntity) - | ||||
|     let q = r#"update player_character set
 | ||||
|                    user_account=$1, slot=$2, name=$3, exp=$4, class=$5, section_id=$6, costume=$7, skin=$8, face=$9, head=$10, hair=$11, hair_r=$12, | ||||
|                    hair_g=$13, hair_b=$14, prop_x=$15, prop_y=$16, techs=$17, config=$18, infoboard=$19, guildcard=$20, power=$21, mind=$22, def=$23, | ||||
|                    evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29 | ||||
|                    where id=$32;"#;
 | ||||
|                    evade=$24, luck=$25, hp=$26, tp=$27, tech_menu=$28, option_flags=$29, playtime=$30 | ||||
|                    where id=$31;"#;
 | ||||
|     sqlx::query(q) | ||||
|         .bind(char.user_id.0) | ||||
|         .bind(char.slot as i16) | ||||
|         .bind(&char.name) | ||||
|         .bind(char.exp as i32) | ||||
|         .bind(char.char_class.to_string()) | ||||
|         .bind(char.section_id.to_string()) | ||||
|         .bind(char.appearance.costume as i16) | ||||
|         .bind(char.appearance.skin as i16) | ||||
|         .bind(char.appearance.face as i16) | ||||
|         .bind(char.appearance.head as i16) | ||||
|         .bind(char.appearance.hair as i16) | ||||
|         .bind(char.appearance.hair_r as i16) | ||||
|         .bind(char.appearance.hair_g as i16) | ||||
|         .bind(char.appearance.hair_b as i16) | ||||
|         .bind(char.appearance.prop_x) | ||||
|         .bind(char.appearance.prop_y) | ||||
|         .bind(&char.techs.as_bytes().to_vec()) | ||||
|         .bind(&char.config.as_bytes().to_vec()) | ||||
|         .bind(String::from_utf16_lossy(&char.info_board.board).trim_matches(char::from(0))) | ||||
|         .bind(&char.guildcard.description) | ||||
|         .bind(char.materials.power as i16) | ||||
|         .bind(char.materials.mind as i16) | ||||
|         .bind(char.materials.def as i16) | ||||
|         .bind(char.materials.evade as i16) | ||||
|         .bind(char.materials.luck as i16) | ||||
|         .bind(char.materials.hp as i16) | ||||
|         .bind(char.materials.tp as i16) | ||||
|         .bind(char.tech_menu.tech_menu.to_vec()) | ||||
|         .bind(char.option_flags as i32) | ||||
|         .bind(char.id.0 as i32) | ||||
|         .bind(char.user_id.0) // $1
 | ||||
|         .bind(char.slot as i16) // $2
 | ||||
|         .bind(&char.name) // $3
 | ||||
|         .bind(char.exp as i32) // $4
 | ||||
|         .bind(char.char_class.to_string()) // $5
 | ||||
|         .bind(char.section_id.to_string()) // $6
 | ||||
|         .bind(char.appearance.costume as i16) // $7
 | ||||
|         .bind(char.appearance.skin as i16) // $8
 | ||||
|         .bind(char.appearance.face as i16) // $9
 | ||||
|         .bind(char.appearance.head as i16) // $10
 | ||||
|         .bind(char.appearance.hair as i16) // $11
 | ||||
|         .bind(char.appearance.hair_r as i16) // $12
 | ||||
|         .bind(char.appearance.hair_g as i16) // $13
 | ||||
|         .bind(char.appearance.hair_b as i16) // $14
 | ||||
|         .bind(char.appearance.prop_x) // $15
 | ||||
|         .bind(char.appearance.prop_y) // $16
 | ||||
|         .bind(&char.techs.as_bytes().to_vec()) // $17
 | ||||
|         .bind(&char.config.as_bytes().to_vec()) // $18
 | ||||
|         .bind(String::from_utf16_lossy(&char.info_board.board).trim_matches(char::from(0))) // $19
 | ||||
|         .bind(&char.guildcard.description) // $20
 | ||||
|         .bind(char.materials.power as i16) // $21
 | ||||
|         .bind(char.materials.mind as i16) // $22
 | ||||
|         .bind(char.materials.def as i16) // $23
 | ||||
|         .bind(char.materials.evade as i16) // $24
 | ||||
|         .bind(char.materials.luck as i16) // $25
 | ||||
|         .bind(char.materials.hp as i16) // $26
 | ||||
|         .bind(char.materials.tp as i16) // $27
 | ||||
|         .bind(char.tech_menu.tech_menu.to_vec()) // $28
 | ||||
|         .bind(char.option_flags as i32) // $29
 | ||||
|         .bind(char.playtime as i32) // $20
 | ||||
|         .bind(char.id.0 as i32) // $31
 | ||||
|         .execute(conn).await?; | ||||
|     Ok(()) | ||||
| } | ||||
| @ -566,6 +567,16 @@ async fn create_trade(conn: &mut sqlx::PgConnection, char_id1: &CharacterEntityI | ||||
|     Ok(trade.into()) | ||||
| } | ||||
| 
 | ||||
| async fn set_character_playtime(conn: &mut sqlx::PgConnection, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> | ||||
| { | ||||
|     sqlx::query_as::<_, PgTradeEntity>(r#"update player_character set playtime=$2 where id=$1;"#) | ||||
|         .bind(char_id.0) | ||||
|         .bind(playtime) | ||||
|         .fetch_one(conn) | ||||
|         .await?; | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| #[async_trait::async_trait] | ||||
| impl EntityGateway for PostgresGateway { | ||||
|     async fn transaction<'a>(&'a mut self) -> Result<Box<dyn EntityGatewayTransaction + 'a>, GatewayError> | ||||
| @ -705,6 +716,10 @@ impl EntityGateway for PostgresGateway { | ||||
|     async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> { | ||||
|         create_trade(&mut *self.pool.acquire().await?, char_id1, char_id2).await | ||||
|     } | ||||
| 
 | ||||
|     async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { | ||||
|         set_character_playtime(&mut *self.pool.acquire().await?, char_id, playtime).await | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -825,5 +840,9 @@ impl<'c> EntityGateway for PostgresTransaction<'c> { | ||||
|     async fn create_trade(&mut self, char_id1: &CharacterEntityId, char_id2: &CharacterEntityId) -> Result<TradeEntity, GatewayError> { | ||||
|         create_trade(&mut *self.pgtransaction, char_id1, char_id2).await | ||||
|     } | ||||
| 
 | ||||
|     async fn set_character_playtime(&mut self, char_id: &CharacterEntityId, playtime: u32) -> Result<(), GatewayError> { | ||||
|         set_character_playtime(&mut *self.pgtransaction, char_id, playtime).await | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -790,7 +790,7 @@ impl<'a> SelectScreenCharacterBuilder<'a> { | ||||
|             prop_x: character.appearance.prop_x, | ||||
|             prop_y: character.appearance.prop_y, | ||||
|             name: utf8_to_utf16_array!(character.name, 16), | ||||
|             //play_time: character.play_time,
 | ||||
|             play_time: character.playtime, | ||||
|             ..character::SelectScreenCharacter::default() | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -290,10 +290,6 @@ pub struct LoadingQuest { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| pub struct ClientState { | ||||
|     pub user: UserAccountEntity, | ||||
|     pub settings: UserSettingsEntity, | ||||
| @ -312,10 +308,13 @@ pub struct ClientState { | ||||
|     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, | ||||
| @ -332,10 +331,18 @@ impl ClientState { | ||||
|             tool_shop: Vec::new(), | ||||
|             armor_shop: Vec::new(), | ||||
|             tek: None, | ||||
|             character_playtime, | ||||
|             log_on_time: chrono::Utc::now(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub struct ItemShops { | ||||
|     pub weapon_shop: HashMap<(room::Difficulty, SectionID), WeaponShop<rand_chacha::ChaCha20Rng>>, | ||||
|     pub tool_shop: ToolShop<rand_chacha::ChaCha20Rng>, | ||||
| @ -631,6 +638,11 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> { | ||||
| 
 | ||||
|     async fn handle(&mut self, id: ClientId, pkt: &RecvShipPacket) | ||||
|               -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, anyhow::Error> { | ||||
|         if let Some(client) = self.clients.get_mut(&id) { | ||||
|             client.update_playtime(); | ||||
|             self.entity_gateway.set_character_playtime(&client.character.id, client.character.playtime).await?; | ||||
|         } | ||||
| 
 | ||||
|         Ok(match pkt { | ||||
|             RecvShipPacket::Login(login) => { | ||||
|                 Box::new(handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_state, &self.shipgate_sender, &self.name, self.blocks.0.len()) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user