Experimental conversion to BigDecimal

This commit is contained in:
AppleDash 2019-11-04 04:43:33 -05:00
parent f22618ebda
commit db8970ebbd
20 changed files with 152 additions and 114 deletions

View File

@ -7,6 +7,7 @@ import org.appledash.sanelib.command.exception.type.usage.TooManyArgumentsExcept
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@ -55,7 +56,7 @@ public class BalanceTopCommand extends SaneCommand {
int offset = (page - 1) * nPerPage;
Map<String, Double> topBalances = this.saneEconomy.getEconomyManager().getTopBalances(nPerPage, offset);
Map<String, BigDecimal> topBalances = this.saneEconomy.getEconomyManager().getTopBalances(nPerPage, offset);
if (topBalances.isEmpty()) {
this.saneEconomy.getMessenger().sendMessage(sender, "There aren't enough players to display that page.");

View File

@ -17,6 +17,8 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.math.BigDecimal;
/**
* Created by AppleDash on 6/13/2016.
* Blackjack is still best pony.
@ -73,10 +75,10 @@ public class EconomyAdminCommand extends SaneCommand {
EconomyManager ecoMan = saneEconomy.getEconomyManager();
Economable economable = Economable.wrap(targetPlayer);
double amount = NumberUtils.parseAndFilter(ecoMan.getCurrency(), sAmount);
BigDecimal amount = NumberUtils.parseAndFilter(ecoMan.getCurrency(), sAmount);
if (!(subCommand.equalsIgnoreCase("set") && amount == 0) && amount <= 0) { // If they're setting it to 0 it's fine, otherwise reject numbers under 1.
this.saneEconomy.getMessenger().sendMessage(sender, "{1} is not a positive number.", ((amount == -1) ? sAmount : String.valueOf(amount)));
if (!(subCommand.equalsIgnoreCase("set") && amount.equals(BigDecimal.ZERO)) && amount.compareTo(BigDecimal.ZERO) <= 0) { // If they're setting it to 0 it's fine, otherwise reject numbers under 1.
this.saneEconomy.getMessenger().sendMessage(sender, "{1} is not a positive number.", ((amount.equals(BigDecimal.ONE.negate())) ? sAmount : String.valueOf(amount)));
return;
}
@ -84,7 +86,7 @@ public class EconomyAdminCommand extends SaneCommand {
Transaction transaction = new Transaction(ecoMan.getCurrency(), Economable.wrap(sender), Economable.wrap(targetPlayer), amount, TransactionReason.ADMIN_GIVE);
TransactionResult result = ecoMan.transact(transaction);
double newAmount = result.getToBalance();
BigDecimal newAmount = result.getToBalance();
this.saneEconomy.getMessenger().sendMessage(sender, "Added {1} to {2}. Their balance is now {3}.",
ecoMan.getCurrency().formatAmount(amount),
@ -107,7 +109,7 @@ public class EconomyAdminCommand extends SaneCommand {
Transaction transaction = new Transaction(ecoMan.getCurrency(), Economable.wrap(targetPlayer), Economable.wrap(sender), amount, TransactionReason.ADMIN_TAKE);
TransactionResult result = ecoMan.transact(transaction);
double newAmount = result.getFromBalance();
BigDecimal newAmount = result.getFromBalance();
this.saneEconomy.getMessenger().sendMessage(sender, "Took {1} from {2}. Their balance is now {3}.",
ecoMan.getCurrency().formatAmount(amount),
@ -127,13 +129,13 @@ public class EconomyAdminCommand extends SaneCommand {
}
if (subCommand.equalsIgnoreCase("set")) {
double oldBal = ecoMan.getBalance(economable);
BigDecimal oldBal = ecoMan.getBalance(economable);
ecoMan.setBalance(economable, amount);
this.saneEconomy.getMessenger().sendMessage(sender, "Balance for {1} set to {2}.", sTargetPlayer, ecoMan.getCurrency().formatAmount(amount));
saneEconomy.getTransactionLogger().ifPresent((logger) -> {
// FIXME: This is a silly hack to get it to log.
if (oldBal > 0.0) {
if (oldBal.compareTo(BigDecimal.ZERO) > 0) {
logger.logTransaction(new Transaction(
ecoMan.getCurrency(), economable, Economable.CONSOLE, oldBal, TransactionReason.ADMIN_TAKE
));

View File

@ -15,6 +15,8 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.math.BigDecimal;
/**
* Created by AppleDash on 6/14/2016.
* Blackjack is still best pony.
@ -67,10 +69,10 @@ public class PayCommand extends SaneCommand {
}
String sAmount = args[1];
double amount = NumberUtils.parseAndFilter(ecoMan.getCurrency(), sAmount);
BigDecimal amount = NumberUtils.parseAndFilter(ecoMan.getCurrency(), sAmount);
if (amount <= 0) {
this.saneEconomy.getMessenger().sendMessage(sender, "{1} is not a positive number.", ((amount == -1) ? sAmount : String.valueOf(amount)));
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
this.saneEconomy.getMessenger().sendMessage(sender, "{1} is not a positive number.", ((amount.equals(BigDecimal.ONE.negate())) ? sAmount : String.valueOf(amount)));
return;
}

View File

@ -5,6 +5,7 @@ import org.appledash.sanelib.messages.MessageUtils;
import org.bukkit.ChatColor;
import org.bukkit.configuration.ConfigurationSection;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
@ -29,6 +30,8 @@ public class Currency {
this.namePlural = namePlural;
this.format = format;
this.balanceFormat = balanceFormat;
this.format.setParseBigDecimal(true);
}
public static Currency fromConfig(ConfigurationSection config) {
@ -72,9 +75,9 @@ public class Currency {
* @param amount Money amount.
* @return Formatted amount string.
*/
public String formatAmount(double amount) {
public String formatAmount(BigDecimal amount) {
String formatted;
if (amount == 1) {
if (amount.equals(BigDecimal.ONE)) {
formatted = MessageUtils.indexedFormat(balanceFormat, format.format(amount), nameSingular);
} else {
formatted = MessageUtils.indexedFormat(balanceFormat, format.format(amount), namePlural);

View File

@ -13,6 +13,7 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import java.awt.*;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
@ -69,9 +70,9 @@ public class EconomyManager {
* @param targetPlayer Player to get balance of
* @return Player's balance
*/
public double getBalance(Economable targetPlayer) {
public BigDecimal getBalance(Economable targetPlayer) {
if (targetPlayer == Economable.CONSOLE) {
return Double.MAX_VALUE;
return new BigDecimal(Double.MAX_VALUE);
}
return backend.getBalance(targetPlayer);
@ -84,8 +85,8 @@ public class EconomyManager {
* @param requiredBalance How much money we're checking for
* @return True if they have requiredBalance or more, false otherwise
*/
public boolean hasBalance(Economable targetPlayer, double requiredBalance) {
return (targetPlayer == Economable.CONSOLE) || (getBalance(targetPlayer) >= requiredBalance);
public boolean hasBalance(Economable targetPlayer, BigDecimal requiredBalance) {
return (targetPlayer == Economable.CONSOLE) || (getBalance(targetPlayer).compareTo(requiredBalance) >= 0);
}
@ -96,8 +97,8 @@ public class EconomyManager {
* @param amount Amount to add
* @throws IllegalArgumentException If amount is negative
*/
private void addBalance(Economable targetPlayer, double amount) {
setBalance(targetPlayer, backend.getBalance(targetPlayer) + amount);
private void addBalance(Economable targetPlayer, BigDecimal amount) {
setBalance(targetPlayer, backend.getBalance(targetPlayer).add(amount));
}
/**
@ -109,9 +110,9 @@ public class EconomyManager {
* @param amount Amount to subtract
* @throws IllegalArgumentException If amount is negative
*/
private void subtractBalance(Economable targetPlayer, double amount) {
private void subtractBalance(Economable targetPlayer, BigDecimal amount) {
// Ensure we don't go negative.
setBalance(targetPlayer, Math.max(0.0, backend.getBalance(targetPlayer) - amount));
setBalance(targetPlayer, backend.getBalance(targetPlayer).subtract(amount).max(BigDecimal.ZERO));
}
/**
@ -120,7 +121,7 @@ public class EconomyManager {
* @param amount Amount to set balance to
* @throws IllegalArgumentException If amount is negative
*/
public void setBalance(Economable targetPlayer, double amount) {
public void setBalance(Economable targetPlayer, BigDecimal amount) {
amount = NumberUtils.filterAmount(currency, amount);
if (targetPlayer == Economable.CONSOLE) {
@ -138,7 +139,7 @@ public class EconomyManager {
public TransactionResult transact(Transaction transaction) {
Economable sender = transaction.getSender();
Economable receiver = transaction.getReceiver();
double amount = transaction.getAmount(); // This amount is validated and filtered upon creation of Transaction
BigDecimal amount = transaction.getAmount(); // This amount is validated and filtered upon creation of Transaction
if (Bukkit.getServer().getPluginManager() != null) { // Bukkit.getServer().getPluginManager() == null from our JUnit tests.
SaneEconomyTransactionEvent evt = new SaneEconomyTransactionEvent(transaction);
@ -185,8 +186,8 @@ public class EconomyManager {
* @param amount Maximum number of players to show.
* @return Map of OfflinePlayer to Double
*/
public Map<String, Double> getTopBalances(int amount, int offset) {
LinkedHashMap<String, Double> uuidBalances = backend.getTopBalances();
public Map<String, BigDecimal> getTopBalances(int amount, int offset) {
LinkedHashMap<String, BigDecimal> uuidBalances = backend.getTopBalances();
/* TODO
uuidBalances.forEach((uuid, balance) -> {

View File

@ -2,6 +2,7 @@ package org.appledash.saneeconomy.economy.backend;
import org.appledash.saneeconomy.economy.economable.Economable;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
@ -25,20 +26,20 @@ public interface EconomyStorageBackend {
* @param economable Economable
* @return Player's current balance
*/
double getBalance(Economable economable);
BigDecimal getBalance(Economable economable);
/**
* Set the balance of an Economable, overwriting the old balance.
* @param economable Economable
* @param newBalance Player's new balance
*/
void setBalance(Economable economable, double newBalance);
void setBalance(Economable economable, BigDecimal newBalance);
/**
* Get the UUIDs of the players who have the most money, along with how much money they have.
* @return Map of player UUIDs to amounts.
*/
LinkedHashMap<String, Double> getTopBalances();
LinkedHashMap<String, BigDecimal> getTopBalances();
/**
* Reload this backend's database from disk.
@ -60,7 +61,7 @@ public interface EconomyStorageBackend {
* Get the balances of all entities in this database.
* @return Map of unique identifiers to balances.
*/
Map<String, Double> getAllBalances();
Map<String, BigDecimal> getAllBalances();
/**
* Wait until all of the data in memory has been written out to disk.

View File

@ -6,6 +6,7 @@ import org.appledash.saneeconomy.economy.backend.EconomyStorageBackend;
import org.appledash.saneeconomy.economy.economable.Economable;
import org.appledash.saneeconomy.utils.MapUtil;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@ -17,8 +18,8 @@ import java.util.concurrent.ConcurrentHashMap;
* Blackjack is still best pony.
*/
public abstract class EconomyStorageBackendCaching implements EconomyStorageBackend {
protected Map<String, Double> balances = new ConcurrentHashMap<>();
private LinkedHashMap<String, Double> topBalances = new LinkedHashMap<>();
protected Map<String, BigDecimal> balances = new ConcurrentHashMap<>();
private LinkedHashMap<String, BigDecimal> topBalances = new LinkedHashMap<>();
protected Map<String, String> uuidToName = new HashMap<>();
@Override
@ -27,21 +28,21 @@ public abstract class EconomyStorageBackendCaching implements EconomyStorageBack
}
@Override
public double getBalance(Economable economable) {
public BigDecimal getBalance(Economable economable) {
if (!accountExists(economable)) {
return 0.0D;
return BigDecimal.ZERO;
}
return balances.get(economable.getUniqueIdentifier());
}
public LinkedHashMap<String, Double> getTopBalances() {
public LinkedHashMap<String, BigDecimal> getTopBalances() {
return topBalances;
}
@Override
public void reloadTopPlayerBalances() {
Map<String, Double> balances = new HashMap<>();
Map<String, BigDecimal> balances = new HashMap<>();
this.balances.forEach((identifier, balance) -> {
balances.put(this.uuidToName.get(identifier), balance);
@ -51,7 +52,7 @@ public abstract class EconomyStorageBackendCaching implements EconomyStorageBack
}
@Override
public Map<String, Double> getAllBalances() {
public Map<String, BigDecimal> getAllBalances() {
return ImmutableMap.copyOf(balances);
}

View File

@ -5,6 +5,7 @@ import org.appledash.saneeconomy.SaneEconomy;
import org.appledash.saneeconomy.economy.economable.Economable;
import java.io.*;
import java.math.BigDecimal;
import java.util.Map;
import java.util.UUID;
@ -43,7 +44,7 @@ public class EconomyStorageBackendFlatfile extends EconomyStorageBackendCaching
return;
}
balances = (Map<String, Double>) ois.readObject();
//FIXME balances = (Map<String, Double>) ois.readObject();
uuidToName = (Map<String, String>) ois.readObject();
ois.close();
@ -66,7 +67,8 @@ public class EconomyStorageBackendFlatfile extends EconomyStorageBackendCaching
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
ois.readInt(); // We already know it's 2.
this.balances = (Map<String, Double>) ois.readObject();
//FIXME this.balances = (Map<String, Double>) ois.readObject();
if (Boolean.TRUE) throw new ClassNotFoundException();
/* Yes, this is kind of bad, but we want to make sure we're loading AND saving the new version of the DB. */
saveDatabase();
@ -94,8 +96,8 @@ public class EconomyStorageBackendFlatfile extends EconomyStorageBackendCaching
}
@Override
public synchronized void setBalance(Economable economable, double newBalance) {
this.balances.put(economable.getUniqueIdentifier(), newBalance);
public synchronized void setBalance(Economable economable, BigDecimal newBalance) {
//FIXME this.balances.put(economable.getUniqueIdentifier(), newBalance);
this.uuidToName.put(economable.getUniqueIdentifier(), economable.getName());
saveDatabase();
}

View File

@ -7,6 +7,7 @@ import com.google.gson.annotations.SerializedName;
import org.appledash.saneeconomy.economy.economable.Economable;
import java.io.*;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -23,7 +24,7 @@ public class EconomyStorageBackendJSON extends EconomyStorageBackendCaching {
}
@Override
public void setBalance(Economable economable, double newBalance) {
public void setBalance(Economable economable, BigDecimal newBalance) {
balances.put(economable.getUniqueIdentifier(), newBalance);
saveDatabase();
}
@ -45,7 +46,7 @@ public class EconomyStorageBackendJSON extends EconomyStorageBackendCaching {
// if that fails, load the new format
try {
DataHolder dataHolder = gson.fromJson(new FileReader(file), DataHolder.class);
this.balances = new ConcurrentHashMap<>(dataHolder.balances);
//FIXME this.balances = new ConcurrentHashMap<>(dataHolder.balances);
this.uuidToName = new ConcurrentHashMap<>(dataHolder.uuidToName);
} catch (FileNotFoundException e1) {
throw new RuntimeException("Failed to load database!", e1);
@ -60,8 +61,8 @@ public class EconomyStorageBackendJSON extends EconomyStorageBackendCaching {
private synchronized void saveDatabase() {
try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file, false))) {
DataHolder dataHolder = new DataHolder(this.balances, this.uuidToName);
bufferedWriter.write(gson.toJson(dataHolder));
//FIXME DataHolder dataHolder = new DataHolder(this.balances, this.uuidToName);
//FIXMEbufferedWriter.write(gson.toJson(dataHolder));
} catch (IOException e) {
throw new RuntimeException("Failed to save database", e);
}

View File

@ -4,6 +4,7 @@ import org.appledash.saneeconomy.economy.economable.Economable;
import org.appledash.saneeconomy.utils.database.MySQLConnection;
import org.appledash.sanelib.database.DatabaseCredentials;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -57,6 +58,8 @@ public class EconomyStorageBackendMySQL extends EconomyStorageBackendCaching {
schemaVersion = 3;
}
// TODO: Schema upgrade from storing balances as decimals to storing them as Strings
if (schemaVersion != 3) {
throw new RuntimeException("Invalid database schema version!");
}
@ -90,7 +93,7 @@ public class EconomyStorageBackendMySQL extends EconomyStorageBackendCaching {
balances.clear();
while (rs.next()) {
balances.put(rs.getString("unique_identifier"), rs.getDouble("balance"));
balances.put(rs.getString("unique_identifier"), new BigDecimal(rs.getString("balance")));
}
} catch (SQLException e) {
throw new RuntimeException("Failed to reload data from SQL.", e);
@ -98,8 +101,8 @@ public class EconomyStorageBackendMySQL extends EconomyStorageBackendCaching {
}
@Override
public void setBalance(final Economable economable, final double newBalance) {
final double oldBalance = getBalance(economable);
public void setBalance(final Economable economable, final BigDecimal newBalance) {
final BigDecimal oldBalance = getBalance(economable);
balances.put(economable.getUniqueIdentifier(), newBalance);
dbConn.executeAsyncOperation("set_balance_" + economable.getUniqueIdentifier(), (conn) -> {
@ -107,7 +110,7 @@ public class EconomyStorageBackendMySQL extends EconomyStorageBackendCaching {
ensureAccountExists(economable, conn);
conn.prepareStatement("LOCK TABLE " + dbConn.getTable("saneeconomy_balances") + " WRITE").execute();
PreparedStatement statement = dbConn.prepareStatement(conn, String.format("UPDATE `%s` SET balance = ?, last_name = ? WHERE `unique_identifier` = ?", dbConn.getTable("saneeconomy_balances")));
statement.setDouble(1, newBalance);
statement.setString(1, newBalance.toString());
statement.setString(2, economable.getName());
statement.setString(3, economable.getUniqueIdentifier());
statement.executeUpdate();
@ -160,7 +163,7 @@ public class EconomyStorageBackendMySQL extends EconomyStorageBackendCaching {
ResultSet rs = ps.executeQuery();
if (rs.next()) {
this.balances.put(uniqueIdentifier, rs.getDouble("balance"));
this.balances.put(uniqueIdentifier, new BigDecimal(rs.getString("balance")));
}
} catch (SQLException e) {
throw new RuntimeException("SQL error has occured", e);

View File

@ -5,6 +5,7 @@ import org.appledash.saneeconomy.economy.transaction.TransactionReason;
import org.appledash.saneeconomy.utils.database.MySQLConnection;
import org.appledash.sanelib.database.DatabaseCredentials;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@ -20,13 +21,13 @@ public class TransactionLoggerMySQL implements TransactionLogger {
this.dbConn = new MySQLConnection(credentials);
}
private void logGeneric(String from, String to, double change, TransactionReason reason) {
private void logGeneric(String from, String to, BigDecimal change, TransactionReason reason) {
this.dbConn.executeAsyncOperation("log_transaction", (conn) -> {
try {
PreparedStatement ps = conn.prepareStatement(String.format("INSERT INTO `%s` (`source`, `destination`, `amount`, `reason`) VALUES (?, ?, ?, ?)", dbConn.getTable("transaction_logs")));
ps.setString(1, from);
ps.setString(2, to);
ps.setDouble(3, change);
ps.setString(3, change.toString());
ps.setString(4, reason.toString());
ps.executeUpdate();
} catch (SQLException e) {

View File

@ -5,6 +5,8 @@ import org.appledash.saneeconomy.economy.economable.Economable;
import org.appledash.saneeconomy.economy.transaction.TransactionReason.AffectedParties;
import org.appledash.saneeconomy.utils.NumberUtils;
import java.math.BigDecimal;
/**
* Created by appledash on 9/21/16.
* Blackjack is best pony.
@ -12,11 +14,11 @@ import org.appledash.saneeconomy.utils.NumberUtils;
public class Transaction {
private final Economable sender;
private final Economable receiver;
private final double amount;
private final BigDecimal amount;
private final TransactionReason reason;
public Transaction(Currency currency, Economable sender, Economable receiver, double amount, TransactionReason reason) {
if (amount <= 0.0) {
public Transaction(Currency currency, Economable sender, Economable receiver, BigDecimal amount, TransactionReason reason) {
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Cannot transact a zero or negative amount!");
}
@ -35,7 +37,7 @@ public class Transaction {
return receiver;
}
public double getAmount() {
public BigDecimal getAmount() {
return amount;
}

View File

@ -1,16 +1,18 @@
package org.appledash.saneeconomy.economy.transaction;
import java.math.BigDecimal;
/**
* Created by appledash on 9/21/16.
* Blackjack is best pony.
*/
public class TransactionResult {
private final Transaction transaction;
private final double fromBalance;
private final double toBalance;
private final BigDecimal fromBalance;
private final BigDecimal toBalance;
private Status status;
public TransactionResult(Transaction transaction, double fromBalance, double toBalance) {
public TransactionResult(Transaction transaction, BigDecimal fromBalance, BigDecimal toBalance) {
this.transaction = transaction;
this.fromBalance = fromBalance;
this.toBalance = toBalance;
@ -18,7 +20,7 @@ public class TransactionResult {
}
public TransactionResult(Transaction transaction, Status status) {
this(transaction, -1, -1);
this(transaction, BigDecimal.ONE.negate(), BigDecimal.ONE.negate());
this.status = status;
}
@ -26,11 +28,11 @@ public class TransactionResult {
return transaction;
}
public double getFromBalance() {
public BigDecimal getFromBalance() {
return fromBalance;
}
public double getToBalance() {
public BigDecimal getToBalance() {
return toBalance;
}

View File

@ -14,6 +14,8 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import java.math.BigDecimal;
/**
* Created by AppleDash on 6/13/2016.
* Blackjack is still best pony.
@ -29,10 +31,10 @@ public class JoinQuitListener implements Listener {
public void onPlayerJoin(PlayerJoinEvent evt) {
Player player = evt.getPlayer();
Economable economable = Economable.wrap((OfflinePlayer) player);
double startBalance = plugin.getConfig().getDouble("economy.start-balance", 0.0D);
BigDecimal startBalance = new BigDecimal(plugin.getConfig().getDouble("economy.start-balance", 0.0D));
/* A starting balance is configured AND they haven't been given it yet. */
if ((startBalance > 0) && !plugin.getEconomyManager().accountExists(economable)) {
if ((startBalance.compareTo(BigDecimal.ZERO) > 0) && !plugin.getEconomyManager().accountExists(economable)) {
plugin.getEconomyManager().transact(new Transaction(
plugin.getEconomyManager().getCurrency(), Economable.CONSOLE, economable, startBalance, TransactionReason.STARTING_BALANCE
));

View File

@ -3,6 +3,8 @@ package org.appledash.saneeconomy.utils;
import com.google.common.base.Strings;
import org.appledash.saneeconomy.economy.Currency;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
@ -11,9 +13,9 @@ import java.text.ParseException;
* Blackjack is still best pony.
*/
public class NumberUtils {
private static final double INVALID_DOUBLE = -1;
private static final BigDecimal INVALID_DOUBLE = BigDecimal.ONE.negate();
public static double parsePositiveDouble(String sDouble) {
public static BigDecimal parsePositiveDouble(String sDouble) {
if (Strings.isNullOrEmpty(sDouble)) {
return INVALID_DOUBLE;
}
@ -24,34 +26,42 @@ public class NumberUtils {
return INVALID_DOUBLE;
}
double doub;
BigDecimal doub;
try {
doub = NumberFormat.getInstance().parse(sDouble).doubleValue();
doub = (BigDecimal) constructDecimalFormat().parseObject(sDouble);
} catch (ParseException | NumberFormatException e) {
return INVALID_DOUBLE;
}
if (doub < 0) {
if (doub.compareTo(BigDecimal.ZERO) < 0) {
return INVALID_DOUBLE;
}
if (Double.isInfinite(doub) || Double.isNaN(doub)) {
/*if (Double.isInfinite(doub) || Double.isNaN(doub)) {
return INVALID_DOUBLE;
}
}*/
return doub;
}
public static double filterAmount(Currency currency, double amount) {
public static BigDecimal filterAmount(Currency currency, BigDecimal amount) {
try {
return NumberFormat.getInstance().parse(currency.getFormat().format(Math.abs(amount))).doubleValue();
return (BigDecimal) constructDecimalFormat().parse(currency.getFormat().format(amount.abs()));
} catch (ParseException e) {
throw new NumberFormatException();
}
}
public static double parseAndFilter(Currency currency, String sDouble) {
public static BigDecimal parseAndFilter(Currency currency, String sDouble) {
return filterAmount(currency, parsePositiveDouble(sDouble));
}
private static DecimalFormat constructDecimalFormat() {
DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance();
decimalFormat.setParseBigDecimal(true);
return decimalFormat;
}
}

View File

@ -11,6 +11,7 @@ import org.appledash.saneeconomy.economy.transaction.TransactionResult;
import org.appledash.saneeconomy.utils.PlayerUtils;
import org.bukkit.OfflinePlayer;
import java.math.BigDecimal;
import java.util.List;
/**
@ -40,7 +41,7 @@ public class EconomySaneEconomy implements Economy {
@Override
public String format(double v) {
return SaneEconomy.getInstance().getEconomyManager().getCurrency().formatAmount(v);
return SaneEconomy.getInstance().getEconomyManager().getCurrency().formatAmount(new BigDecimal(v));
}
@Override
@ -75,12 +76,12 @@ public class EconomySaneEconomy implements Economy {
@Override
public double getBalance(String target) {
return SaneEconomy.getInstance().getEconomyManager().getBalance(makeEconomable(target));
return SaneEconomy.getInstance().getEconomyManager().getBalance(makeEconomable(target)).doubleValue();
}
@Override
public double getBalance(OfflinePlayer offlinePlayer) {
return SaneEconomy.getInstance().getEconomyManager().getBalance(Economable.wrap(offlinePlayer));
return SaneEconomy.getInstance().getEconomyManager().getBalance(Economable.wrap(offlinePlayer)).doubleValue();
}
@Override
@ -95,12 +96,12 @@ public class EconomySaneEconomy implements Economy {
@Override
public boolean has(String target, double amount) {
return SaneEconomy.getInstance().getEconomyManager().hasBalance(makeEconomable(target), amount);
return SaneEconomy.getInstance().getEconomyManager().hasBalance(makeEconomable(target), new BigDecimal(amount));
}
@Override
public boolean has(OfflinePlayer offlinePlayer, double amount) {
return SaneEconomy.getInstance().getEconomyManager().hasBalance(Economable.wrap(offlinePlayer), amount);
return SaneEconomy.getInstance().getEconomyManager().hasBalance(Economable.wrap(offlinePlayer), new BigDecimal(amount));
}
@Override
@ -120,7 +121,7 @@ public class EconomySaneEconomy implements Economy {
}
return transact(new Transaction(
SaneEconomy.getInstance().getEconomyManager().getCurrency(), makeEconomable(target), Economable.PLUGIN, amount, TransactionReason.PLUGIN_TAKE
SaneEconomy.getInstance().getEconomyManager().getCurrency(), makeEconomable(target), Economable.PLUGIN, new BigDecimal(amount), TransactionReason.PLUGIN_TAKE
));
}
@ -135,7 +136,7 @@ public class EconomySaneEconomy implements Economy {
}
return transact(new Transaction(
SaneEconomy.getInstance().getEconomyManager().getCurrency(), Economable.wrap(offlinePlayer), Economable.PLUGIN, amount, TransactionReason.PLUGIN_TAKE
SaneEconomy.getInstance().getEconomyManager().getCurrency(), Economable.wrap(offlinePlayer), Economable.PLUGIN, new BigDecimal(amount), TransactionReason.PLUGIN_TAKE
));
}
@ -156,7 +157,7 @@ public class EconomySaneEconomy implements Economy {
}
return transact(new Transaction(
SaneEconomy.getInstance().getEconomyManager().getCurrency(), Economable.PLUGIN, makeEconomable(target), amount, TransactionReason.PLUGIN_GIVE
SaneEconomy.getInstance().getEconomyManager().getCurrency(), Economable.PLUGIN, makeEconomable(target), new BigDecimal(amount), TransactionReason.PLUGIN_GIVE
));
}
@ -167,7 +168,7 @@ public class EconomySaneEconomy implements Economy {
}
return transact(new Transaction(
SaneEconomy.getInstance().getEconomyManager().getCurrency(), Economable.PLUGIN, Economable.wrap(offlinePlayer), v, TransactionReason.PLUGIN_GIVE
SaneEconomy.getInstance().getEconomyManager().getCurrency(), Economable.PLUGIN, Economable.wrap(offlinePlayer), new BigDecimal(v), TransactionReason.PLUGIN_GIVE
));
}
@ -281,7 +282,7 @@ public class EconomySaneEconomy implements Economy {
TransactionResult result = SaneEconomy.getInstance().getEconomyManager().transact(transaction);
if (result.getStatus() == TransactionResult.Status.SUCCESS) {
return new EconomyResponse(transaction.getAmount(), result.getToBalance(), EconomyResponse.ResponseType.SUCCESS, null);
return new EconomyResponse(transaction.getAmount().doubleValue(), result.getToBalance().doubleValue(), EconomyResponse.ResponseType.SUCCESS, null);
}
return new EconomyResponse(0, 0, EconomyResponse.ResponseType.FAILURE, result.getStatus().toString());

View File

@ -4,6 +4,7 @@ import org.appledash.saneeconomy.economy.Currency;
import org.junit.Assert;
import org.junit.Test;
import java.math.BigDecimal;
import java.text.DecimalFormat;
/**
@ -14,7 +15,7 @@ public class CurrencyTest {
@Test
public void testCurrencyFormat() {
Currency currency = new Currency("test dollar", "test dollars", new DecimalFormat("0.00"));
Assert.assertEquals(currency.formatAmount(1.0D), "1.00 test dollar");
Assert.assertEquals(currency.formatAmount(1337.0D), "1337.00 test dollars");
Assert.assertEquals(currency.formatAmount(new BigDecimal(1.0D)), "1.00 test dollar");
Assert.assertEquals(currency.formatAmount(new BigDecimal(1337.0D)), "1337.00 test dollars");
}
}

View File

@ -14,6 +14,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
@ -40,44 +41,42 @@ public class EconomyManagerTest {
// Accounts should not exist
Assert.assertFalse(economyManager.accountExists(playerOne));
Assert.assertFalse(economyManager.accountExists(playerTwo));
Assert.assertEquals(0.0D, economyManager.getBalance(playerOne), 0.0);
Assert.assertEquals(0.0D, economyManager.getBalance(playerTwo), 0.0);
Assert.assertEquals(BigDecimal.ZERO, economyManager.getBalance(playerOne));
Assert.assertEquals(BigDecimal.ZERO, economyManager.getBalance(playerTwo));
economyManager.setBalance(playerOne, 100.0D);
economyManager.setBalance(playerOne, new BigDecimal(100.0));
// Now one should have an account, but two should not
Assert.assertTrue(economyManager.accountExists(playerOne));
Assert.assertFalse(economyManager.accountExists(playerTwo));
// One should have balance, two should not
Assert.assertEquals(100.0, economyManager.getBalance(playerOne), 0.0);
Assert.assertEquals(0.0, economyManager.getBalance(playerTwo), 0.0);
Assert.assertEquals(new BigDecimal("100.00"), economyManager.getBalance(playerOne));
Assert.assertEquals(BigDecimal.ZERO, economyManager.getBalance(playerTwo));
// One should be able to transfer to two
Assert.assertTrue(economyManager.transact(new Transaction(economyManager.getCurrency(), playerOne, playerTwo, 50.0, TransactionReason.PLAYER_PAY)).getStatus() == TransactionResult.Status.SUCCESS);
Assert.assertSame(economyManager.transact(new Transaction(economyManager.getCurrency(), playerOne, playerTwo, new BigDecimal(50.0), TransactionReason.PLAYER_PAY)).getStatus(), TransactionResult.Status.SUCCESS);
// One should now have only 50 left, two should have 50 now
Assert.assertEquals("Player one should have 50 dollars", 50.0, economyManager.getBalance(playerOne), 0.0);
Assert.assertEquals("Player two should have 50 dollars", 50.0, economyManager.getBalance(playerTwo), 0.0);
Assert.assertEquals("Player one should have 50 dollars", new BigDecimal("50.00"), economyManager.getBalance(playerOne));
Assert.assertEquals("Player two should have 50 dollars", new BigDecimal("50.00"), economyManager.getBalance(playerTwo));
// Ensure that balance addition and subtraction works...
Assert.assertEquals(25.0, economyManager.transact(
new Transaction(economyManager.getCurrency(), playerOne, Economable.CONSOLE, 25.0, TransactionReason.TEST_TAKE)
).getFromBalance(), 0.0);
Assert.assertEquals(new BigDecimal("25.00"), economyManager.transact(
new Transaction(economyManager.getCurrency(), playerOne, Economable.CONSOLE, new BigDecimal("25.00"), TransactionReason.TEST_TAKE)
).getFromBalance());
Assert.assertEquals(50.0, economyManager.transact(
new Transaction(economyManager.getCurrency(), Economable.CONSOLE, playerOne, 25.0, TransactionReason.TEST_GIVE)
).getToBalance(), 0.0);
Assert.assertEquals(new BigDecimal("50.00"), economyManager.transact(
new Transaction(economyManager.getCurrency(), Economable.CONSOLE, playerOne, new BigDecimal("25.00"), TransactionReason.TEST_GIVE)
).getToBalance());
Assert.assertEquals(TransactionResult.Status.ERR_NOT_ENOUGH_FUNDS, economyManager.transact(
new Transaction(economyManager.getCurrency(), playerTwo, Economable.CONSOLE, Double.MAX_VALUE, TransactionReason.TEST_TAKE)
new Transaction(economyManager.getCurrency(), playerTwo, Economable.CONSOLE, new BigDecimal(Double.MAX_VALUE), TransactionReason.TEST_TAKE)
).getStatus());
// Ensure that hasBalance works
Assert.assertTrue(economyManager.hasBalance(playerOne, 50.0));
Assert.assertFalse(economyManager.hasBalance(playerOne, 51.0));
Assert.assertTrue(economyManager.hasBalance(playerOne, new BigDecimal("50.00")));
Assert.assertFalse(economyManager.hasBalance(playerOne, new BigDecimal("51.00")));
}
@Test
@ -90,13 +89,13 @@ public class EconomyManagerTest {
Economable economable = Economable.wrap(new MockOfflinePlayer("Dude" + i));
names.add("Dude" + i);
economables.add(economable);
this.economyManager.setBalance(economable, random.nextInt(1000));
this.economyManager.setBalance(economable, new BigDecimal(random.nextInt(1000)));
}
this.economyManager.getBackend().reloadTopPlayerBalances();
List<Double> javaSortedBalances = economables.stream().map(this.economyManager::getBalance).sorted((left, right) -> -left.compareTo(right)).collect(Collectors.toList());
List<Double> ecoManTopBalances = ImmutableList.copyOf(this.economyManager.getTopBalances(10, 0).values());
List<BigDecimal> javaSortedBalances = economables.stream().map(this.economyManager::getBalance).sorted((left, right) -> -left.compareTo(right)).collect(Collectors.toList());
List<BigDecimal> ecoManTopBalances = ImmutableList.copyOf(this.economyManager.getTopBalances(10, 0).values());
Assert.assertTrue("List is not correctly sorted!", areListsEqual(javaSortedBalances, ecoManTopBalances));
Assert.assertEquals("Wrong number of top balances!", 5, this.economyManager.getTopBalances(5, 0).size());

View File

@ -5,6 +5,7 @@ import org.appledash.saneeconomy.utils.NumberUtils;
import org.junit.Assert;
import org.junit.Test;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Locale;
@ -16,21 +17,21 @@ public class NumberUtilsTest {
@Test
public void testParsePositive() {
// Valid input
Assert.assertEquals(69.0, NumberUtils.parsePositiveDouble("69.0"), 0.0);
Assert.assertEquals(new BigDecimal("69.0"), NumberUtils.parsePositiveDouble("69.0"));
// Valid but not positive
Assert.assertEquals(-1.0, NumberUtils.parsePositiveDouble("-10.0"), 0.0);
Assert.assertEquals(BigDecimal.ONE.negate(), NumberUtils.parsePositiveDouble("-10.0"));
// Invalid
Assert.assertEquals(-1.0, NumberUtils.parsePositiveDouble("nan"), 0.0);
Assert.assertEquals(-1.0, NumberUtils.parsePositiveDouble("ponies"), 0.0);
Assert.assertEquals(BigDecimal.ONE.negate(), NumberUtils.parsePositiveDouble("nan"));
Assert.assertEquals(BigDecimal.ONE.negate(), NumberUtils.parsePositiveDouble("ponies"));
// Infinite
Assert.assertEquals(-1.0, NumberUtils.parsePositiveDouble("1E1000000000"), 0.0);
// TODO: Not needed with BigDecimal? Assert.assertEquals(BigDecimal.ONE.negate(), NumberUtils.parsePositiveDouble("1E1000000000"));
}
@Test
public void testFilter() {
Currency currency = new Currency(null, null, new DecimalFormat("0.00"));
Assert.assertEquals(NumberUtils.filterAmount(currency, 1337.420D), 1337.42, 0.0);
Assert.assertEquals(new BigDecimal("1337.42"), NumberUtils.filterAmount(currency, new BigDecimal("1337.420")));
}
@Test

View File

@ -3,13 +3,15 @@ package org.appledash.saneeconomy.test.mock;
import org.appledash.saneeconomy.economy.backend.type.EconomyStorageBackendCaching;
import org.appledash.saneeconomy.economy.economable.Economable;
import java.math.BigDecimal;
/**
* Created by AppleDash on 7/29/2016.
* Blackjack is still best pony.
*/
public class MockEconomyStorageBackend extends EconomyStorageBackendCaching {
@Override
public void setBalance(Economable player, double newBalance) {
public void setBalance(Economable player, BigDecimal newBalance) {
balances.put(player.getUniqueIdentifier(), newBalance);
this.uuidToName.put(player.getUniqueIdentifier(), player.getName());
}