Compare commits

...

8 Commits

34 changed files with 194 additions and 72 deletions

View File

@ -9,7 +9,7 @@
<version>0</version>
</parent>
<artifactId>SaneEconomyCore</artifactId>
<version>0.17.0-SNAPSHOT</version>
<version>0.17.2-SNAPSHOT</version>
<dependencies>
<dependency>

View File

@ -5,6 +5,7 @@ import org.appledash.saneeconomy.economy.logger.TransactionLogger;
import org.appledash.saneeconomy.vault.VaultHook;
import java.util.Optional;
import java.util.UUID;
/**
* Created by appledash on 9/18/16.
@ -27,4 +28,6 @@ public interface ISaneEconomy {
Optional<TransactionLogger> getTransactionLogger();
VaultHook getVaultHook();
String getLastName(UUID uuid);
}

View File

@ -36,7 +36,7 @@ public class SaneEconomy extends SanePlugin implements ISaneEconomy {
private TransactionLogger transactionLogger;
private GithubVersionChecker versionChecker;
private final Map<String, SaneCommand> COMMANDS = new HashMap<String, SaneCommand>() {
private final Map<String, SaneCommand> commands = new HashMap<String, SaneCommand>() {
{
this.put("balance", new BalanceCommand(SaneEconomy.this));
this.put("ecoadmin", new EconomyAdminCommand(SaneEconomy.this));
@ -184,7 +184,7 @@ public class SaneEconomy extends SanePlugin implements ISaneEconomy {
private void loadCommands() {
this.getLogger().info("Initializing commands...");
this.COMMANDS.forEach((name, command) -> this.getCommand(name).setExecutor(command));
this.commands.forEach((name, command) -> this.getCommand(name).setExecutor(command));
this.getLogger().info("Initialized commands.");
}
@ -241,4 +241,9 @@ public class SaneEconomy extends SanePlugin implements ISaneEconomy {
public VaultHook getVaultHook() {
return this.vaultHook;
}
@Override
public String getLastName(UUID uuid) {
return this.economyManager.getBackend().getLastName("player:" + uuid.toString());
}
}

View File

@ -48,7 +48,7 @@ public class BalanceTopCommand extends SaneCommand {
try {
page = Math.abs(Integer.parseInt(args[0]));
} catch (NumberFormatException e) {
this.saneEconomy.getMessenger().sendMessage(sender, "{1} is not a valid number.");
this.saneEconomy.getMessenger().sendMessage(sender, "{1} is not a valid number.", args[0]);
return;
}
}
@ -65,6 +65,12 @@ public class BalanceTopCommand extends SaneCommand {
AtomicInteger index = new AtomicInteger(offset + 1); /* I know it's stupid, but you can't do some_int++ from within the lambda. */
this.saneEconomy.getMessenger().sendMessage(sender, "Top {1} players on page {2}:", topBalances.size(), page);
topBalances.forEach((player, balance) -> this.saneEconomy.getMessenger().sendMessage(sender, "[{1:02d}] {2} - {3}", index.getAndIncrement(), player == null ? "<unknown>" : player, this.saneEconomy.getEconomyManager().getCurrency().formatAmount(balance)));
topBalances.forEach((player, balance) ->
this.saneEconomy.getMessenger().sendMessage(sender, "[{1:02d}] {2} - {3}",
index.getAndIncrement(),
player == null ? "<unknown>" : player,
this.saneEconomy.getEconomyManager().getCurrency().formatAmount(balance))
);
}
}

View File

@ -68,6 +68,11 @@ public class PayCommand extends SaneCommand {
return;
}
if (!this.saneEconomy.getConfig().getConfigurationSection("economy").getBoolean("pay-offline-players", true) && !toPlayer.isOnline()) {
this.saneEconomy.getMessenger().sendMessage(sender, "You cannot pay an offline player.");
return;
}
String sAmount = args[1];
BigDecimal amount = NumberUtils.parseAndFilter(ecoMan.getCurrency(), sAmount);

View File

@ -8,7 +8,6 @@ import org.bukkit.configuration.ConfigurationSection;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.UUID;
/**
* Created by AppleDash on 6/13/2016.
@ -78,7 +77,7 @@ public class Currency {
*/
public String formatAmount(BigDecimal amount) {
return ChatColor.translateAlternateColorCodes('&',
MessageUtils.indexedFormat(this.balanceFormat, this.format.format(amount), amount.equals(BigDecimal.ONE) ? this.nameSingular : this.namePlural)
MessageUtils.indexedFormat(this.balanceFormat, this.format.format(amount), amount.compareTo(BigDecimal.ONE) == 0 ? this.nameSingular : this.namePlural)
);
}

View File

@ -11,6 +11,7 @@ import org.appledash.saneeconomy.event.SaneEconomyTransactionEvent;
import org.appledash.saneeconomy.utils.MapUtil;
import org.appledash.saneeconomy.utils.NumberUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
@ -28,6 +29,8 @@ public class EconomyManager {
private final Currency currency;
private final EconomyStorageBackend backend;
private final String serverAccountName;
private static final BigDecimal REQUIRED_BALANCE_ACCURACY = new BigDecimal("0.0001");
public EconomyManager(ISaneEconomy saneEconomy, Currency currency, EconomyStorageBackend backend, String serverAccountName) {
this.saneEconomy = saneEconomy;
@ -83,8 +86,25 @@ public class EconomyManager {
* @return True if they have requiredBalance or more, false otherwise
*/
public boolean hasBalance(Economable targetPlayer, BigDecimal requiredBalance) {
return (EconomableConsole.isConsole(targetPlayer)) || (this.getBalance(targetPlayer).compareTo(requiredBalance) >= 0);
return (EconomableConsole.isConsole(targetPlayer)) || (hasBalance(this.getBalance(targetPlayer), requiredBalance));
}
/**
* Compare account balance and required balance to a reasonable degree of accuracy. <br>
* <b>Visible for testing</b>
*
* @param accountBalance account balance
* @param requiredBalance required balance
* @return true if the account has the required balance to some degree of accuracy, false otherwise
*/
public boolean hasBalance(BigDecimal accountBalance, BigDecimal requiredBalance) {
if (accountBalance.compareTo(requiredBalance) >= 0) {
return true;
}
// Must compare to degree of accuracy
// See https://github.com/AppleDash/SaneEconomy/issues/100
BigDecimal difference = requiredBalance.subtract(accountBalance);
return difference.compareTo(REQUIRED_BALANCE_ACCURACY) < 0; // difference < PRECISION
}
/**
@ -192,20 +212,20 @@ public class EconomyManager {
* @return Map of OfflinePlayer to Double
*/
public Map<String, BigDecimal> getTopBalances(int amount, int offset) {
LinkedHashMap<String, BigDecimal> uuidBalances = this.backend.getTopBalances();
LinkedHashMap<String, BigDecimal> playerNamesToBalances = this.backend.getTopBalances();
/* TODO
uuidBalances.forEach((uuid, balance) -> {
OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(uuid);
if (offlinePlayer != null) {
/*uuidBalances.re((uuid, balance) -> {
String playerName = this.backend.getLastName(uuid);
if (playerName != null) {
if ((this.saneEconomy.getVaultHook() == null) || !this.saneEconomy.getVaultHook().hasPermission(offlinePlayer, "saneeconomy.balancetop.hide")) {
playerBalances.put(Bukkit.getServer().getOfflinePlayer(uuid), balance);
}
}
});
*/
});*/
return MapUtil.skipAndTake(uuidBalances, offset, amount);
return MapUtil.skipAndTake(playerNamesToBalances, offset, amount);
}
public EconomyStorageBackend getBackend() {

View File

@ -67,6 +67,14 @@ public interface EconomyStorageBackend {
*/
void waitUntilFlushed();
/**
* Get the last name associated with a unique ID.
*
* @param uuid Unique ID.
* @return Last name, or null if none.
*/
String getLastName(String uuid);
enum EconomableReloadReason {
CROSS_SERVER_SYNC, PLAYER_JOIN
}

View File

@ -44,9 +44,9 @@ public abstract class EconomyStorageBackendCaching implements EconomyStorageBack
public void reloadTopPlayerBalances() {
Map<String, BigDecimal> balances = new HashMap<>();
this.balances.forEach((identifier, balance) -> {
balances.put(this.uuidToName.get(identifier), balance);
});
this.balances.forEach((identifier, balance) ->
balances.put(this.uuidToName.get(identifier), balance)
);
this.topBalances = MapUtil.sortByValue(balances);
}
@ -64,4 +64,9 @@ public abstract class EconomyStorageBackendCaching implements EconomyStorageBack
this.reloadDatabase();
}
@Override
public String getLastName(String uuid) {
return this.uuidToName.get(uuid);
}
}

View File

@ -25,11 +25,11 @@ public class EconomyStorageBackendJSON extends EconomyStorageBackendCaching {
@Override
public void setBalance(Economable economable, BigDecimal newBalance) {
this.balances.put(economable.getUniqueIdentifier(), newBalance);
this.uuidToName.put(economable.getUniqueIdentifier(), economable.getName());
this.saveDatabase();
}
@Override
@SuppressWarnings("unchecked")
public void reloadDatabase() {
if (!this.file.exists()) {
return;
@ -42,9 +42,9 @@ public class EconomyStorageBackendJSON extends EconomyStorageBackendCaching {
this.balances = new ConcurrentHashMap<>();
this.uuidToName = new ConcurrentHashMap<>(dataHolder.uuidToName);
dataHolder.balances.forEach((s, bal) -> {
this.balances.put(s, new BigDecimal(bal));
});
dataHolder.balances.forEach((s, bal) ->
this.balances.put(s, new BigDecimal(bal))
);
this.saveDatabase();
} catch (FileNotFoundException e) {
@ -55,7 +55,7 @@ public class EconomyStorageBackendJSON extends EconomyStorageBackendCaching {
this.balances = new ConcurrentHashMap<>(dataHolder.balances);
this.uuidToName = new ConcurrentHashMap<>(dataHolder.uuidToName);
} catch (FileNotFoundException ex) {
throw new RuntimeException("Failed to load database!", e);
throw new RuntimeException("Failed to load database!", ex);
}
}
}
@ -74,7 +74,7 @@ public class EconomyStorageBackendJSON extends EconomyStorageBackendCaching {
}
}
@SuppressWarnings("FieldMayBeFinal")
@SuppressWarnings({"FieldMayBeFinal", "CanBeFinal"})
private static class DataHolderOld {
@SerializedName("balances")
private Map<String, Double> balances;

View File

@ -105,6 +105,7 @@ public class EconomyStorageBackendMySQL extends EconomyStorageBackendCaching {
while (rs.next()) {
this.balances.put(rs.getString("unique_identifier"), new BigDecimal(rs.getString("balance")));
this.uuidToName.put(rs.getString("unique_identifier"), rs.getString("last_name"));
}
} catch (SQLException e) {
throw new RuntimeException("Failed to reload data from SQL.", e);
@ -115,17 +116,18 @@ public class EconomyStorageBackendMySQL extends EconomyStorageBackendCaching {
public void setBalance(Economable economable, BigDecimal newBalance) {
BigDecimal oldBalance = this.getBalance(economable);
this.balances.put(economable.getUniqueIdentifier(), newBalance);
this.uuidToName.put(economable.getUniqueIdentifier(), economable.getName());
this.dbConn.executeAsyncOperation("set_balance_" + economable.getUniqueIdentifier(), (conn) -> {
try {
this.ensureAccountExists(economable, conn);
conn.prepareStatement("LOCK TABLE " + this.dbConn.getTable(SANEECONOMY_BALANCES) + " WRITE").execute();
this.dbConn.lockTable(conn, SANEECONOMY_BALANCES);
PreparedStatement statement = this.dbConn.prepareStatement(conn, String.format("UPDATE `%s` SET balance = ?, last_name = ? WHERE `unique_identifier` = ?", this.dbConn.getTable(SANEECONOMY_BALANCES)));
statement.setString(1, newBalance.toString());
statement.setString(2, economable.getName());
statement.setString(3, economable.getUniqueIdentifier());
statement.executeUpdate();
conn.prepareStatement("UNLOCK TABLES").execute();
this.dbConn.unlockTables(conn);
} catch (Exception e) {
this.balances.put(economable.getUniqueIdentifier(), oldBalance);
throw new RuntimeException("SQL error has occurred.", e);

View File

@ -16,7 +16,7 @@ public class EconomableConsole implements Economable {
@Override
public String getUniqueIdentifier() {
return "console:" + CONSOLE_UUID.toString();
return "console:" + CONSOLE_UUID;
}
public static boolean isConsole(Economable economable) {

View File

@ -18,6 +18,6 @@ public class EconomableGeneric implements Economable {
@Override
public String getName() {
return this.uniqueIdentifier.substring(16);
return this.uniqueIdentifier.substring(16); // FIXME: Why 16?
}
}

View File

@ -31,7 +31,7 @@ public class JoinQuitListener implements Listener {
public void onPlayerJoin(PlayerJoinEvent evt) {
Player player = evt.getPlayer();
Economable economable = Economable.wrap((OfflinePlayer) player);
BigDecimal startBalance = new BigDecimal(this.plugin.getConfig().getDouble("economy.start-balance", 0.0D));
BigDecimal startBalance = BigDecimal.valueOf(this.plugin.getConfig().getDouble("economy.start-balance", 0.0D));
/* A starting balance is configured AND they haven't been given it yet. */
if ((startBalance.compareTo(BigDecimal.ZERO) > 0) && !this.plugin.getEconomyManager().accountExists(economable)) {

View File

@ -26,6 +26,7 @@ public final class PlayerUtils {
return player;
}
//noinspection ReuseOfLocalVariable
player = Bukkit.getServer().getPlayer(playerNameOrUUID);
if (player == null) {

View File

@ -105,13 +105,15 @@ public class SaneEconomyConfiguration {
/**
* Convert one EconomyStorageBackend to another.
* Right now, this just consists of converting all player balances. Data in the old backend is kept.
* Why is this in here?
* @param oldBackend Old backend
* @param newBackend New backend
*/
private void convertBackends(EconomyStorageBackend oldBackend, EconomyStorageBackend newBackend) {
oldBackend.getAllBalances().forEach((uniqueId, balance) -> {
newBackend.setBalance(new EconomableGeneric(uniqueId), balance);
});
oldBackend.getAllBalances().forEach((uniqueId, balance) ->
newBackend.setBalance(new EconomableGeneric(uniqueId), balance)
);
newBackend.waitUntilFlushed();
}

View File

@ -31,7 +31,6 @@ public final class WebUtils {
return out.toString();
} catch (IOException e) {
SaneEconomy.logger().warning("Failed to get contents of URL " + url);
throw new RuntimeException("Failed to get URL contents!", e);
}
}

View File

@ -15,8 +15,10 @@ import java.util.logging.Logger;
*/
public class MySQLConnection {
private static final Logger LOGGER = Logger.getLogger("MySQLConnection");
public static final int FIVE_SECONDS = 5000;
private final DatabaseCredentials dbCredentials;
private final SaneDatabase saneDatabase;
private boolean canLockTables = true;
public MySQLConnection(DatabaseCredentials dbCredentials) {
this.dbCredentials = dbCredentials;
@ -48,6 +50,31 @@ public class MySQLConnection {
}
}
public void lockTable(Connection conn, String tableName) throws SQLException {
if (!this.canLockTables) {
return;
}
try {
conn.prepareStatement("LOCK TABLE " + this.getTable(tableName) + " WRITE").execute();
this.canLockTables = true;
} catch (SQLException e) {
if (this.canLockTables) {
LOGGER.warning("Your MySQL user does not have privileges to LOCK TABLES - this may cause issues if you are running this plugin with the same database on multiple servers.");
}
this.canLockTables = false;
}
}
public void unlockTables(Connection conn) throws SQLException {
if (!this.canLockTables) {
return;
}
conn.prepareStatement("UNLOCK TABLES").execute();
}
public void executeAsyncOperation(String tag, Consumer<Connection> callback) {
this.saneDatabase.runDatabaseOperationAsync(tag, () -> this.doExecuteAsyncOperation(1, callback));
}
@ -79,7 +106,7 @@ public class MySQLConnection {
public void waitUntilFlushed() {
long startTime = System.currentTimeMillis();
while (!this.saneDatabase.areAllTransactionsDone()) {
if ((System.currentTimeMillis() - startTime) > 5000) {
if ((System.currentTimeMillis() - startTime) > FIVE_SECONDS) {
LOGGER.warning("Took too long to flush all transactions - something has probably hung :(");
break;
}

View File

@ -25,6 +25,7 @@ economy:
notify-admin-give: false # Whether to notify players when /ecoadmin give is used on them.
notify-admin-take: false # Whether to notify players when /ecoadmin take is used on them.
notify-admin-set: false # Whether to notify players when /ecoadmin set is used on them.
pay-offline-players: true # Whether to allow paying offline players or not.
multi-server-sync: false # Experimental balance syncing without player rejoins, across BungeeCord networks.
update-check: true # Whether to check for updates to the plugin and notify admins about them.

View File

@ -7,6 +7,9 @@
# The order of placeholders can be changed. Anything after the :, like the '02d' in {1:02d} is a Java String.format specifier. If you don't know what that is, I recommend leaving it as-is.
# IMPORTANT: If your translation has a colon ( : ) character inside of it, you must enclose the entire part after "translation: " in single quotes ( ' ).
# If this file doesn't work for some reason, check your console for errors with "SnakeYAML" included in them.
####################################################################################################
########## READ ABOVE IF YOU INTEND TO EDIT THIS FILE, BEFORE ASKING FOR HELP! #####################
####################################################################################################
messages:
- message: "You don't have permission to check the balance of {1}."
- message: "That player is not online."

View File

@ -15,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(new BigDecimal(1.0D)), "1.00 test dollar");
Assert.assertEquals(currency.formatAmount(new BigDecimal(1337.0D)), "1337.00 test dollars");
Assert.assertEquals(currency.formatAmount(new BigDecimal("1.0")), "1.00 test dollar");
Assert.assertEquals(currency.formatAmount(new BigDecimal("1337.0")), "1337.00 test dollars");
}
}

View File

@ -19,9 +19,9 @@ public class EconomableTest {
@Test
public void testWrapFaction() {
UUID uuid = UUID.randomUUID();
Economable economable = Economable.wrap(String.format("faction-%s", uuid.toString()));
Economable economable = Economable.wrap(String.format("faction-%s", uuid));
Assert.assertEquals(economable.getClass(), EconomableFaction.class);
Assert.assertEquals(economable.getUniqueIdentifier(), String.format("faction:%s", uuid.toString()));
Assert.assertEquals(economable.getUniqueIdentifier(), String.format("faction:%s", uuid));
}
@Test

View File

@ -18,6 +18,7 @@ import org.junit.Test;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
/**
@ -45,7 +46,7 @@ public class EconomyManagerTest {
SaneEcoAssert.assertEquals(BigDecimal.ZERO, this.economyManager.getBalance(playerOne));
SaneEcoAssert.assertEquals(BigDecimal.ZERO, this.economyManager.getBalance(playerTwo));
this.economyManager.setBalance(playerOne, new BigDecimal(100.0));
this.economyManager.setBalance(playerOne, new BigDecimal("100.0"));
// Now one should have an account, but two should not
Assert.assertTrue(this.economyManager.accountExists(playerOne));
@ -56,7 +57,7 @@ public class EconomyManagerTest {
SaneEcoAssert.assertEquals(BigDecimal.ZERO, this.economyManager.getBalance(playerTwo));
// One should be able to transfer to two
Assert.assertSame(this.economyManager.transact(new Transaction(this.economyManager.getCurrency(), playerOne, playerTwo, new BigDecimal(50.0), TransactionReason.PLAYER_PAY)).getStatus(), TransactionResult.Status.SUCCESS);
Assert.assertSame(this.economyManager.transact(new Transaction(this.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
SaneEcoAssert.assertEquals("Player one should have 50 dollars", new BigDecimal("50.00"), this.economyManager.getBalance(playerOne));
@ -117,4 +118,25 @@ public class EconomyManagerTest {
return true;
}
@Test
public void testHasRequiredBalance() {
for (int n = 0; n < 20; n++) { // in the absence of Junit 5's @RepeatedTest
BigDecimal bigDecimal = randomBigDecimal();
// We MUST modify the BigDecimal in some way otherwise the test will always succeed
// See https://github.com/AppleDash/SaneEconomy/issues/100
for (int m = 0; m < 20; m++) {
bigDecimal = bigDecimal.add(randomBigDecimal()).subtract(randomBigDecimal());
}
//
Assert.assertTrue("Account must have required balance despite loss of precision (repeat " + n + ")",
economyManager.hasBalance(bigDecimal, new BigDecimal(bigDecimal.doubleValue())));
}
}
private static BigDecimal randomBigDecimal() {
return new BigDecimal(ThreadLocalRandom.current().nextDouble());
}
}

View File

@ -6,6 +6,7 @@ import org.appledash.saneeconomy.economy.logger.TransactionLogger;
import org.appledash.saneeconomy.vault.VaultHook;
import java.util.Optional;
import java.util.UUID;
/**
* Created by appledash on 9/18/16.
@ -26,4 +27,9 @@ public class MockSaneEconomy implements ISaneEconomy {
public VaultHook getVaultHook() {
return null;
}
@Override
public String getLastName(UUID uuid) {
return uuid.toString();
}
}

View File

@ -34,6 +34,7 @@ import java.util.logging.Logger;
* Created by appledash on 7/15/17.
* Blackjack is best pony.
*/
@SuppressWarnings("all")
public class MockServer implements Server {
public static MockServer instance;
@ -501,12 +502,12 @@ public class MockServer implements Server {
}
@Override
public CachedServerIcon loadServerIcon(File file) throws Exception {
public CachedServerIcon loadServerIcon(File file) {
return null;
}
@Override
public CachedServerIcon loadServerIcon(BufferedImage bufferedImage) throws Exception {
public CachedServerIcon loadServerIcon(BufferedImage bufferedImage) {
return null;
}

View File

@ -16,7 +16,7 @@
<dependency>
<groupId>org.appledash</groupId>
<artifactId>SaneEconomyCore</artifactId>
<version>0.17.0-SNAPSHOT</version>
<version>0.17.2-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -12,6 +12,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@ -83,11 +84,11 @@ public class EntityDamageListener implements Listener {
if (offlinePlayer.isOnline()) {
Player player = Bukkit.getServer().getPlayer(offlinePlayer.getUniqueId());
this.plugin.getMessenger().sendMessage(player, "You have been awarded {1} for doing {2:.2f}% of the damage required to kill that {3}!", this.plugin.getSaneEconomy().getEconomyManager().getCurrency().formatAmount(thisAmount), thisPercent, entity.getName());
this.plugin.getMessenger().sendMessage(player, "You have been awarded {1} for doing {2:.2f}% of the damage required to kill that {3}!", this.plugin.getSaneEconomy().getEconomyManager().getCurrency().formatAmount(BigDecimal.valueOf(thisAmount)), thisPercent, entity.getName());
}
this.plugin.getSaneEconomy().getEconomyManager().transact(new Transaction(
this.plugin.getSaneEconomy().getEconomyManager().getCurrency(), Economable.PLUGIN, Economable.wrap(offlinePlayer), thisAmount, TransactionReason.PLUGIN_GIVE
this.plugin.getSaneEconomy().getEconomyManager().getCurrency(), Economable.PLUGIN, Economable.wrap(offlinePlayer), BigDecimal.valueOf(thisAmount), TransactionReason.PLUGIN_GIVE
));
}

View File

@ -17,7 +17,7 @@
<dependency>
<groupId>org.appledash</groupId>
<artifactId>SaneEconomyCore</artifactId>
<version>0.17.0-SNAPSHOT</version>
<version>0.17.2-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -1,5 +1,6 @@
package org.appledash.saneeconomy.onlinetime;
import java.math.BigDecimal;
import java.util.Map;
/**
@ -8,14 +9,14 @@ import java.util.Map;
*/
public class Payout {
private final int secondsInterval;
private final double amount;
private final BigDecimal amount;
private final String message;
private String permission;
private final long reportInterval;
public Payout(int secondsInterval, double amount, String message, long reportInterval) {
this.secondsInterval = secondsInterval;
this.amount = amount;
this.amount = BigDecimal.valueOf(amount);
this.message = message;
this.reportInterval = reportInterval;
}
@ -24,7 +25,7 @@ public class Payout {
return this.secondsInterval;
}
public double getAmount() {
public BigDecimal getAmount() {
return this.amount;
}

View File

@ -10,6 +10,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import java.math.BigDecimal;
import java.util.*;
/**
@ -18,7 +19,7 @@ import java.util.*;
*/
public class SaneEconomyOnlineTime extends SanePlugin implements Listener {
private final Map<UUID, Long> onlineSeconds = new HashMap<>();
private final Map<UUID, Double> reportingAmounts = new HashMap<>();
private final Map<UUID, BigDecimal> reportingAmounts = new HashMap<>();
private final List<Payout> payouts = new ArrayList<>();
private SaneEconomy saneEconomy;
@ -47,7 +48,7 @@ public class SaneEconomyOnlineTime extends SanePlugin implements Listener {
if ((onlineSeconds % payout.getSecondsInterval()) == 0) {
if (this.reportingAmounts.containsKey(player.getUniqueId())) {
this.reportingAmounts.put(player.getUniqueId(), this.reportingAmounts.get(player.getUniqueId()) + payout.getAmount());
this.reportingAmounts.put(player.getUniqueId(), this.reportingAmounts.get(player.getUniqueId()).add(payout.getAmount()));
} else {
this.reportingAmounts.put(player.getUniqueId(), payout.getAmount());
}
@ -56,8 +57,8 @@ public class SaneEconomyOnlineTime extends SanePlugin implements Listener {
}
if ((onlineSeconds % payout.getReportInterval()) == 0) {
this.getMessenger().sendMessage(player, payout.getMessage(), this.saneEconomy.getEconomyManager().getCurrency().formatAmount(this.reportingAmounts.getOrDefault(player.getUniqueId(), 0.0D)), payout.getReportInterval());
this.reportingAmounts.put(player.getUniqueId(), 0.0D);
this.getMessenger().sendMessage(player, payout.getMessage(), this.saneEconomy.getEconomyManager().getCurrency().formatAmount(this.reportingAmounts.getOrDefault(player.getUniqueId(), BigDecimal.ZERO)), payout.getReportInterval());
this.reportingAmounts.put(player.getUniqueId(), BigDecimal.ZERO);
}
}

View File

@ -16,7 +16,7 @@
<dependency>
<groupId>org.appledash</groupId>
<artifactId>SaneEconomyCore</artifactId>
<version>0.17.0-SNAPSHOT</version>
<version>0.17.2-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -16,6 +16,7 @@ import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import java.math.BigDecimal;
import java.util.Optional;
import java.util.logging.Logger;
@ -114,7 +115,7 @@ public class InteractListener implements Listener {
private void doSell(SignShop shop, Player player) { // TODO: Selling enchanted items
EconomyManager ecoMan = this.plugin.getSaneEconomy().getEconomyManager();
int quantity = player.isSneaking() ? 1 : shop.getQuantity();
double price = shop.getSellPrice(quantity);
BigDecimal price = shop.getSellPrice(quantity);
if (!player.getInventory().containsAtLeast(new ItemStack(shop.getItemStack()), quantity)) {
this.plugin.getMessenger().sendMessage(player, "You do not have {1} {2}!", quantity, shop.getItemStack().getType().name());

View File

@ -7,6 +7,8 @@ import org.appledash.saneeconomy.economy.transaction.TransactionReason;
import org.appledash.saneeconomysignshop.util.ItemInfo;
import org.bukkit.entity.Player;
import java.math.BigDecimal;
/**
* Created by appledash on 1/1/17.
* Blackjack is still best pony.
@ -18,9 +20,9 @@ public class ShopTransaction {
private final Player player;
private final ItemInfo item;
private final int quantity;
private final double price;
private final BigDecimal price;
public ShopTransaction(Currency currency, TransactionDirection direction, Player player, ItemInfo item, int quantity, double price) {
public ShopTransaction(Currency currency, TransactionDirection direction, Player player, ItemInfo item, int quantity, BigDecimal price) {
this.currency = currency;
this.direction = direction;
this.player = player;
@ -45,7 +47,7 @@ public class ShopTransaction {
return this.quantity;
}
public double getPrice() {
public BigDecimal getPrice() {
return this.price;
}

View File

@ -9,6 +9,7 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.UUID;
/**
@ -20,8 +21,8 @@ public class SignShop implements Serializable {
private final SerializableLocation location;
private final ItemInfo item;
private final int quantity;
private final double buyPrice;
private final double sellPrice;
private final BigDecimal buyPrice;
private final BigDecimal sellPrice;
public SignShop(UUID ownerUuid, Location location, ItemStack item, int quantity, double buyPrice, double sellPrice) {
if ((ownerUuid == null) || (location == null) || (item == null)) {
@ -36,8 +37,8 @@ public class SignShop implements Serializable {
this.location = new SerializableLocation(location);
this.item = new ItemInfo(item);
this.quantity = quantity;
this.buyPrice = buyPrice;
this.sellPrice = sellPrice;
this.buyPrice = BigDecimal.valueOf(buyPrice);
this.sellPrice = BigDecimal.valueOf(sellPrice);
}
/**
@ -68,7 +69,7 @@ public class SignShop implements Serializable {
* Get the price that the player can buy this item from the server for
* @return Buy price for this.getQuantity() items
*/
public double getBuyPrice() {
public BigDecimal getBuyPrice() {
return this.buyPrice;
}
@ -76,7 +77,7 @@ public class SignShop implements Serializable {
* Get the price that the player can sell this item to the server for
* @return Buy price for this.getQuantity() items
*/
public double getSellPrice() {
public BigDecimal getSellPrice() {
return this.sellPrice;
}
@ -86,8 +87,8 @@ public class SignShop implements Serializable {
* @param quantity Quantity of items to price
* @return Price to buy that number of items at this shop
*/
public double getBuyPrice(int quantity) {
return this.buyPrice * ((float)quantity / (float)this.quantity); // TODO: Is this okay?
public BigDecimal getBuyPrice(int quantity) {
return this.buyPrice.multiply(BigDecimal.valueOf((double) quantity / this.quantity)); // TODO: Is this okay?
}
/**
@ -96,8 +97,8 @@ public class SignShop implements Serializable {
* @param quantity Quantity of items to price
* @return Price to sell that number of items at this shop
*/
public double getSellPrice(int quantity) {
return this.sellPrice * ((float)quantity / (float)this.quantity); // TODO: Is this okay?
public BigDecimal getSellPrice(int quantity) {
return this.sellPrice.multiply(BigDecimal.valueOf((double) quantity / this.quantity)); // TODO: Is this okay?
}
/**
@ -105,7 +106,7 @@ public class SignShop implements Serializable {
* @return True if they can, false if they can't
*/
public boolean canBuy() {
return this.buyPrice >= 0;
return this.buyPrice.compareTo(BigDecimal.ZERO) >= 0;
}
/**
@ -113,7 +114,7 @@ public class SignShop implements Serializable {
* @return True if they can, false if they can't
*/
public boolean canSell() {
return this.sellPrice >= 0;
return this.sellPrice.compareTo(BigDecimal.ZERO) >= 0;
}
/**