Browse Source

track character playtime

pull/116/head
jake 2 years ago
parent
commit
4788f707ed
  1. 2
      src/entity/character.rs
  2. 4
      src/entity/gateway/entitygateway.rs
  3. 12
      src/entity/gateway/inmemory.rs
  4. 2
      src/entity/gateway/postgres/migrations/V0006__playtime.sql
  5. 3
      src/entity/gateway/postgres/models.rs
  6. 83
      src/entity/gateway/postgres/postgres.rs
  7. 2
      src/login/character.rs
  8. 20
      src/ship/ship.rs

2
src/entity/character.rs

@ -413,4 +413,6 @@ pub struct CharacterEntity {
pub option_flags: u32,
pub keyboard_config: CharacterKeyboardConfig,
pub gamepad_config: CharacterGamepadConfig,
pub playtime: u32,
}

4
src/entity/gateway/entitygateway.rs

@ -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!();
}
}

12
src/entity/gateway/inmemory.rs

@ -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)
}
}
}

2
src/entity/gateway/postgres/migrations/V0006__playtime.sql

@ -0,0 +1,2 @@
alter table player_character
add playtime integer;

3
src/entity/gateway/postgres/models.rs

@ -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,
}
}
}

83
src/entity/gateway/postgres/postgres.rs

@ -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
}
}

2
src/login/character.rs

@ -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()
}
}

20
src/ship/ship.rs

@ -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…
Cancel
Save