fixes bug (float precision) by using f64

This commit is contained in:
2019-10-18 21:39:23 +02:00
parent 61c9a4e6d4
commit b0441f3402
4 changed files with 38 additions and 33 deletions

View File

@@ -50,13 +50,13 @@ pub fn sell_item_transaction(
conn: &DbConnection, conn: &DbConnection,
id: i32, id: i32,
loot_id: i32, loot_id: i32,
price_mod: Option<f32>, price_mod: Option<f64>,
) -> QueryResult<(Item, Wealth)> { ) -> QueryResult<(Item, Wealth)> {
conn.transaction(|| { conn.transaction(|| {
let deleted = LootManager(conn, id) let deleted = LootManager(conn, id)
.remove(loot_id)?; .remove(loot_id)?;
let mut sell_value = let mut sell_value =
deleted.base_price as f32 / 2.0; deleted.base_price as f64 / 2.0;
if let Some(modifier) = price_mod { if let Some(modifier) = price_mod {
sell_value *= modifier; sell_value *= modifier;
} }
@@ -75,15 +75,15 @@ pub fn buy_item_from_inventory(
conn: &DbConnection, conn: &DbConnection,
id: i32, id: i32,
item_id: i32, item_id: i32,
price_mod: Option<f32>, price_mod: Option<f64>,
) -> QueryResult<(Item, Wealth)> { ) -> QueryResult<(Item, Wealth)> {
conn.transaction(|| { conn.transaction(|| {
// Find item in inventory // Find item in inventory
let item = Inventory(conn).find(item_id)?; let item = Inventory(conn).find(item_id)?;
let new_item = LootManager(conn, id).add_from(&item)?; let new_item = LootManager(conn, id).add_from(&item)?;
let sell_price = match price_mod { let sell_price = match price_mod {
Some(modifier) => item.base_price as f32 * modifier, Some(modifier) => item.base_price as f64 * modifier,
None => item.base_price as f32, None => item.base_price as f64,
}; };
AsPlayer(conn, id) AsPlayer(conn, id)
.update_wealth(-sell_price) .update_wealth(-sell_price)

View File

@@ -33,7 +33,7 @@ impl<'q> Players<'q> {
players::table.find(id).first(self.0) players::table.find(id).first(self.0)
} }
pub fn add(&self, name: &str, wealth: f32) -> QueryResult<Player> { pub fn add(&self, name: &str, wealth: f64) -> QueryResult<Player> {
diesel::insert_into(players::table) diesel::insert_into(players::table)
.values(&NewPlayer::create(name, wealth)) .values(&NewPlayer::create(name, wealth))
.execute(self.0)?; .execute(self.0)?;
@@ -44,30 +44,19 @@ impl<'q> Players<'q> {
pub struct AsPlayer<'q>(pub &'q DbConnection, pub i32); pub struct AsPlayer<'q>(pub &'q DbConnection, pub i32);
impl<'q> AsPlayer<'q> { impl<'q> AsPlayer<'q> {
pub fn update_wealth(&self, value_in_gp: f32) -> QueryResult<Wealth> { pub fn update_wealth(&self, value_in_gp: f64) -> QueryResult<Wealth> {
use crate::schema::players::dsl::*; use crate::schema::players::dsl::*;
let current_wealth = players let current_wealth = players
.find(self.1) .find(self.1)
.select((cp, sp, gp, pp)) .select((cp, sp, gp, pp))
.first::<Wealth>(self.0)?; .first::<Wealth>(self.0)?;
dbg!(&current_wealth); let updated_wealth = Wealth::from_gp(current_wealth.to_gp() + value_in_gp);
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,
};
diesel::update(players) diesel::update(players)
.filter(id.eq(self.1)) .filter(id.eq(self.1))
.set(&updated_wealth) .set(&updated_wealth)
.execute(self.0)?; .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<()> { 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 : /// The conversion is slightly different than standard rules :
/// ``` 1pp = 100gp = 1000sp = 10000 cp ``` /// ``` 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 rest = (gold.fract() * 100.0).round() as i32;
let gold = gold.trunc() as i32; let gold = gold.trunc() as i32;
let pp = gold / 100; let pp = gold / 100;
@@ -118,7 +107,7 @@ impl Wealth {
/// let wealth = Wealth::from_gp(403.21); /// let wealth = Wealth::from_gp(403.21);
/// assert_eq!(wealth.as_tuple(), (1, 2, 3, 4)); /// 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); let (cp, sp, gp, pp) = unpack_gold_value(gp);
Self { cp, sp, gp, pp } Self { cp, sp, gp, pp }
} }
@@ -130,10 +119,10 @@ impl Wealth {
/// let wealth = Wealth{ pp: 4, gp: 5, sp: 8, cp: 4}; /// let wealth = Wealth{ pp: 4, gp: 5, sp: 8, cp: 4};
/// assert_eq!(wealth.to_gp(), 405.84); /// 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 i = self.pp * 100 + self.gp;
let f = (self.sp * 10 + self.cp) as f32 / 100.0; let f = (self.sp * 10 + self.cp) as f64 / 100.0;
i as f32 + f i as f64 + f
} }
/// Pack the counts inside a tuple, from lower to higher coin value. /// Pack the counts inside a tuple, from lower to higher coin value.
pub fn as_tuple(&self) -> (i32, i32, i32, i32) { 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; use std::ops::Add;
impl Add for Wealth { impl Add for Wealth {
@@ -168,7 +173,7 @@ pub(crate) struct NewPlayer<'a> {
} }
impl<'a> 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(); let (cp, sp, gp, pp) = Wealth::from_gp(wealth_in_gp).as_tuple();
Self { Self {
name, name,

View File

@@ -86,9 +86,9 @@ pub enum ApiActions {
// Player actions // Player actions
FetchPlayer(i32), FetchPlayer(i32),
FetchLoot(i32), FetchLoot(i32),
UpdateWealth(i32, f32), UpdateWealth(i32, f64),
BuyItems(i32, Vec<(i32, Option<f32>)>), BuyItems(i32, Vec<(i32, Option<f64>)>),
SellItems(i32, Vec<(i32, Option<f32>)>), SellItems(i32, Vec<(i32, Option<f64>)>),
ClaimItem(i32, i32), ClaimItem(i32, i32),
UnclaimItem(i32, i32), UnclaimItem(i32, i32),
// Group actions // Group actions
@@ -96,7 +96,7 @@ pub enum ApiActions {
} }
pub enum AdminActions { pub enum AdminActions {
AddPlayer(String, f32), AddPlayer(String, f64),
//AddInventoryItem(pub String, pub i32), //AddInventoryItem(pub String, pub i32),
ResolveClaims, ResolveClaims,
//SetClaimsTimeout(pub i32), //SetClaimsTimeout(pub i32),

View File

@@ -10,7 +10,7 @@ use crate::api;
type AppPool = web::Data<db::Pool>; type AppPool = web::Data<db::Pool>;
type PlayerId = web::Path<i32>; type PlayerId = web::Path<i32>;
type ItemId = web::Json<i32>; type ItemId = web::Json<i32>;
type ItemListWithMods = web::Json<Vec<(i32, Option<f32>)>>; type ItemListWithMods = web::Json<Vec<(i32, Option<f64>)>>;
/// Wraps call to the database query and convert its result as a async HttpResponse /// Wraps call to the database query and convert its result as a async HttpResponse
pub fn db_call( pub fn db_call(
@@ -65,7 +65,7 @@ fn configure_app(config: &mut web::ServiceConfig) {
web::resource("/wealth") web::resource("/wealth")
//.route(web::get().to_async(...)) //.route(web::get().to_async(...))
.route(web::put().to_async( .route(web::put().to_async(
|pool, (player, data): (PlayerId, web::Json<f32>)| { |pool, (player, data): (PlayerId, web::Json<f64>)| {
db_call( db_call(
pool, pool,
Q::UpdateWealth(*player, *data), Q::UpdateWealth(*player, *data),