From a41576e767285996eecffeae05f753389cbc98fd Mon Sep 17 00:00:00 2001 From: Shane Handley Date: Thu, 14 May 2020 13:48:19 +1000 Subject: [PATCH] Correctly set the exp target for the next level when spawning a character. Removed the unwrap_or from the update method for stats persistence, and have a dedicated method for updating single rows with a new connection. --- common/src/comp/stats.rs | 13 ++++++----- common/src/sys/stats.rs | 2 +- server/src/events/player.rs | 2 +- server/src/persistence/models.rs | 38 +++++++++++++++++++++++++++++++- server/src/persistence/stats.rs | 23 +++++++++---------- 5 files changed, 57 insertions(+), 21 deletions(-) diff --git a/common/src/comp/stats.rs b/common/src/comp/stats.rs index 1c31af1187..628cb8d80c 100644 --- a/common/src/comp/stats.rs +++ b/common/src/comp/stats.rs @@ -85,17 +85,16 @@ impl fmt::Display for StatChangeError { impl Error for StatChangeError {} impl Exp { + /// Used to determine how much exp is required to reach the next level. When + /// a character levels up, the next level target is increased by this value + const EXP_INCREASE_FACTOR: u32 = 25; + pub fn current(&self) -> u32 { self.current } pub fn maximum(&self) -> u32 { self.maximum } pub fn set_current(&mut self, current: u32) { self.current = current; } - // TODO: Uncomment when needed - // pub fn set_maximum(&mut self, maximum: u32) { - // self.maximum = maximum; - // } - pub fn change_by(&mut self, current: i64) { self.current = ((self.current as i64) + current) as u32; } @@ -103,6 +102,10 @@ impl Exp { pub fn change_maximum_by(&mut self, maximum: i64) { self.maximum = ((self.maximum as i64) + maximum) as u32; } + + pub fn update_maximum(&mut self, level: u32) { + self.maximum = Self::EXP_INCREASE_FACTOR + (level * Self::EXP_INCREASE_FACTOR); + } } impl Level { diff --git a/common/src/sys/stats.rs b/common/src/sys/stats.rs index 61396bc8fb..448b97fec8 100644 --- a/common/src/sys/stats.rs +++ b/common/src/sys/stats.rs @@ -64,8 +64,8 @@ impl<'a> System<'a> for Sys { let stat = stats.get_mut_unchecked(); while stat.exp.current() >= stat.exp.maximum() { stat.exp.change_by(-(stat.exp.maximum() as i64)); - stat.exp.change_maximum_by(25); stat.level.change_by(1); + stat.exp.update_maximum(stat.level.level()); } stat.update_max_hp(); diff --git a/server/src/events/player.rs b/server/src/events/player.rs index 4d42df8aea..8c14b647de 100644 --- a/server/src/events/player.rs +++ b/server/src/events/player.rs @@ -78,7 +78,7 @@ pub fn handle_client_disconnect(server: &mut Server, entity: EcsEntity) -> Event state.read_storage::().get(entity), ) { if let Some(character_id) = player.character_id { - persistence::stats::update(character_id, stats, None, db_dir); + persistence::stats::update_item(character_id, stats, db_dir); } } diff --git a/server/src/persistence/models.rs b/server/src/persistence/models.rs index 241fc0ba0c..74ff72d796 100644 --- a/server/src/persistence/models.rs +++ b/server/src/persistence/models.rs @@ -87,9 +87,13 @@ pub struct Stats { impl From> for comp::Stats { fn from(data: StatsJoinData) -> comp::Stats { + let level = data.stats.level as u32; + let mut base_stats = comp::Stats::new(String::from(data.alias), *data.body); - base_stats.level.set_level(data.stats.level as u32); + base_stats.level.set_level(level); + base_stats.exp.update_maximum(level); + base_stats.exp.set_current(data.stats.exp as u32); base_stats.update_max_hp(); @@ -155,4 +159,36 @@ mod tests { willpower: 4, }) } + + #[test] + fn loads_stats_with_correct_level() { + let data = StatsJoinData { + alias: "test", + body: &comp::Body::from(&Body { + character_id: 0, + race: 0, + body_type: comp::humanoid::BodyType::Female as i16, + hair_style: 0, + beard: 0, + eyebrows: 0, + accessory: 0, + hair_color: 0, + skin: 0, + eye_color: 0, + }), + stats: &Stats { + character_id: 0, + level: 3, + exp: 70, + endurance: 0, + fitness: 2, + willpower: 3, + }, + }; + + let stats = comp::Stats::from(data); + + assert_eq!(stats.level.level(), 3); + assert_eq!(stats.exp.current(), 70); + } } diff --git a/server/src/persistence/stats.rs b/server/src/persistence/stats.rs index ee0355ee1b..57a66bfdab 100644 --- a/server/src/persistence/stats.rs +++ b/server/src/persistence/stats.rs @@ -4,18 +4,11 @@ use super::{establish_connection, models::StatsUpdate, schema}; use crate::comp; use diesel::prelude::*; -pub fn update( - character_id: i32, - stats: &comp::Stats, - conn: Option<&SqliteConnection>, - db_dir: &str, -) { - log::warn!("stats persisting..."); - +fn update(character_id: i32, stats: &comp::Stats, connection: &SqliteConnection) { if let Err(error) = diesel::update(schema::stats::table.filter(schema::stats::character_id.eq(character_id))) .set(&StatsUpdate::from(stats)) - .execute(conn.unwrap_or(&establish_connection(db_dir))) + .execute(connection) { log::warn!( "Failed to update stats for character: {:?}: {:?}", @@ -25,8 +18,12 @@ pub fn update( } } -pub fn batch_update<'a>(updates: impl Iterator, db_dir: &str) { - let connection = &establish_connection(db_dir); - - updates.for_each(|(character_id, stats)| update(character_id, stats, Some(connection), db_dir)); +pub fn update_item(character_id: i32, stats: &comp::Stats, db_dir: &str) { + update(character_id, stats, &establish_connection(db_dir)); +} + +pub fn batch_update<'a>(updates: impl Iterator, db_dir: &str) { + let connection = establish_connection(db_dir); + + updates.for_each(|(character_id, stats)| update(character_id, stats, &connection)); }