From b0441f3402fefe581e4332c6ca1ae49475b2f108 Mon Sep 17 00:00:00 2001 From: Artus Date: Fri, 18 Oct 2019 21:39:23 +0200 Subject: [PATCH] fixes bug (float precision) by using f64 --- lootalot_db/src/lib.rs | 10 +++---- lootalot_db/src/models/player.rs | 49 ++++++++++++++++++-------------- src/api.rs | 8 +++--- src/server.rs | 4 +-- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/lootalot_db/src/lib.rs b/lootalot_db/src/lib.rs index bb55bef..6fa7bda 100644 --- a/lootalot_db/src/lib.rs +++ b/lootalot_db/src/lib.rs @@ -50,13 +50,13 @@ pub fn sell_item_transaction( conn: &DbConnection, id: i32, loot_id: i32, - price_mod: Option, + price_mod: Option, ) -> QueryResult<(Item, Wealth)> { conn.transaction(|| { let deleted = LootManager(conn, id) .remove(loot_id)?; let mut sell_value = - deleted.base_price as f32 / 2.0; + deleted.base_price as f64 / 2.0; if let Some(modifier) = price_mod { sell_value *= modifier; } @@ -75,15 +75,15 @@ pub fn buy_item_from_inventory( conn: &DbConnection, id: i32, item_id: i32, - price_mod: Option, + price_mod: Option, ) -> QueryResult<(Item, Wealth)> { conn.transaction(|| { // Find item in inventory let item = Inventory(conn).find(item_id)?; let new_item = LootManager(conn, id).add_from(&item)?; let sell_price = match price_mod { - Some(modifier) => item.base_price as f32 * modifier, - None => item.base_price as f32, + Some(modifier) => item.base_price as f64 * modifier, + None => item.base_price as f64, }; AsPlayer(conn, id) .update_wealth(-sell_price) diff --git a/lootalot_db/src/models/player.rs b/lootalot_db/src/models/player.rs index bb7fbe5..38f06ad 100644 --- a/lootalot_db/src/models/player.rs +++ b/lootalot_db/src/models/player.rs @@ -33,7 +33,7 @@ impl<'q> Players<'q> { players::table.find(id).first(self.0) } - pub fn add(&self, name: &str, wealth: f32) -> QueryResult { + pub fn add(&self, name: &str, wealth: f64) -> QueryResult { diesel::insert_into(players::table) .values(&NewPlayer::create(name, wealth)) .execute(self.0)?; @@ -44,30 +44,19 @@ impl<'q> Players<'q> { pub struct AsPlayer<'q>(pub &'q DbConnection, pub i32); impl<'q> AsPlayer<'q> { - pub fn update_wealth(&self, value_in_gp: f32) -> QueryResult { + pub fn update_wealth(&self, value_in_gp: f64) -> QueryResult { use crate::schema::players::dsl::*; let current_wealth = players .find(self.1) .select((cp, sp, gp, pp)) .first::(self.0)?; - dbg!(¤t_wealth); - dbg!(current_wealth.to_gp()); - dbg!(value_in_gp); - let updated_wealth = Wealth::from_gp(dbg!((current_wealth.to_gp() * 100.0 + value_in_gp * 100.0) / 100.0)); - dbg!(&updated_wealth); - // Difference in coins that is sent back - let difference = Wealth { - cp: updated_wealth.cp - current_wealth.cp, - sp: updated_wealth.sp - current_wealth.sp, - gp: updated_wealth.gp - current_wealth.gp, - pp: updated_wealth.pp - current_wealth.pp, - }; - + let updated_wealth = Wealth::from_gp(current_wealth.to_gp() + value_in_gp); diesel::update(players) .filter(id.eq(self.1)) .set(&updated_wealth) .execute(self.0)?; - Ok(difference) + // Difference in coins that is sent back + Ok(updated_wealth - current_wealth) } pub fn update_debt(&self, value_in_gp: i32) -> QueryResult<()> { @@ -86,7 +75,7 @@ impl<'q> AsPlayer<'q> { /// The conversion is slightly different than standard rules : /// ``` 1pp = 100gp = 1000sp = 10000 cp ``` /// -fn unpack_gold_value(gold: f32) -> (i32, i32, i32, i32) { +fn unpack_gold_value(gold: f64) -> (i32, i32, i32, i32) { let rest = (gold.fract() * 100.0).round() as i32; let gold = gold.trunc() as i32; let pp = gold / 100; @@ -118,7 +107,7 @@ impl Wealth { /// let wealth = Wealth::from_gp(403.21); /// assert_eq!(wealth.as_tuple(), (1, 2, 3, 4)); /// ``` - pub fn from_gp(gp: f32) -> Self { + pub fn from_gp(gp: f64) -> Self { let (cp, sp, gp, pp) = unpack_gold_value(gp); Self { cp, sp, gp, pp } } @@ -130,10 +119,10 @@ impl Wealth { /// let wealth = Wealth{ pp: 4, gp: 5, sp: 8, cp: 4}; /// assert_eq!(wealth.to_gp(), 405.84); /// ``` - pub fn to_gp(&self) -> f32 { + pub fn to_gp(&self) -> f64 { let i = self.pp * 100 + self.gp; - let f = (self.sp * 10 + self.cp) as f32 / 100.0; - i as f32 + f + let f = (self.sp * 10 + self.cp) as f64 / 100.0; + i as f64 + f } /// Pack the counts inside a tuple, from lower to higher coin value. pub fn as_tuple(&self) -> (i32, i32, i32, i32) { @@ -141,6 +130,22 @@ impl Wealth { } } +use std::ops::Sub; + +impl Sub for Wealth { + type Output = Self; + /// What needs to be added to 'other' so that + /// the result equals 'self' + fn sub(self, other: Self) -> Self { + Wealth { + cp: self.cp - other.cp, + sp: self.sp - other.sp, + gp: self.gp - other.gp, + pp: self.pp - other.pp, + } + } +} + use std::ops::Add; impl Add for Wealth { @@ -168,7 +173,7 @@ pub(crate) struct NewPlayer<'a> { } impl<'a> NewPlayer<'a> { - pub(crate) fn create(name: &'a str, wealth_in_gp: f32) -> Self { + pub(crate) fn create(name: &'a str, wealth_in_gp: f64) -> Self { let (cp, sp, gp, pp) = Wealth::from_gp(wealth_in_gp).as_tuple(); Self { name, diff --git a/src/api.rs b/src/api.rs index 19515e3..981c394 100644 --- a/src/api.rs +++ b/src/api.rs @@ -86,9 +86,9 @@ pub enum ApiActions { // Player actions FetchPlayer(i32), FetchLoot(i32), - UpdateWealth(i32, f32), - BuyItems(i32, Vec<(i32, Option)>), - SellItems(i32, Vec<(i32, Option)>), + UpdateWealth(i32, f64), + BuyItems(i32, Vec<(i32, Option)>), + SellItems(i32, Vec<(i32, Option)>), ClaimItem(i32, i32), UnclaimItem(i32, i32), // Group actions @@ -96,7 +96,7 @@ pub enum ApiActions { } pub enum AdminActions { - AddPlayer(String, f32), + AddPlayer(String, f64), //AddInventoryItem(pub String, pub i32), ResolveClaims, //SetClaimsTimeout(pub i32), diff --git a/src/server.rs b/src/server.rs index 870087f..b08074e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -10,7 +10,7 @@ use crate::api; type AppPool = web::Data; type PlayerId = web::Path; type ItemId = web::Json; -type ItemListWithMods = web::Json)>>; +type ItemListWithMods = web::Json)>>; /// Wraps call to the database query and convert its result as a async HttpResponse pub fn db_call( @@ -65,7 +65,7 @@ fn configure_app(config: &mut web::ServiceConfig) { web::resource("/wealth") //.route(web::get().to_async(...)) .route(web::put().to_async( - |pool, (player, data): (PlayerId, web::Json)| { + |pool, (player, data): (PlayerId, web::Json)| { db_call( pool, Q::UpdateWealth(*player, *data),