From 1e86142a58577757dfec716fd2a4bd872ae8da2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Steinh=C3=BCbl=20=28xHyroM=29?= Date: Thu, 5 Oct 2023 17:31:52 +0200 Subject: [PATCH] feat: handle maximum balance --- .../api/exception/CannotBeGreaterThan.java | 7 +++ .../api/exception/CannotBeNegative.java | 7 +++ .../lighteco/bukkit/commands/GiveCommand.java | 5 +- .../lighteco/bukkit/commands/PayCommand.java | 5 +- .../lighteco/bukkit/commands/SetCommand.java | 5 +- .../lighteco/bukkit/commands/TakeCommand.java | 5 +- .../dev/xhyrom/lighteco/bukkit/util/Util.java | 19 ++++++ .../xhyrom/lighteco/common/config/Config.java | 6 ++ .../config/message/CurrencyMessageConfig.java | 1 + .../command/AbstractCommandManager.java | 59 +++++++++++++++++-- .../lighteco/common/model/user/User.java | 24 ++++++-- .../provider/sql/SqlStorageProvider.java | 2 +- .../money/bukkit/hooks/vault/Vault.java | 10 ++-- 13 files changed, 132 insertions(+), 23 deletions(-) create mode 100644 api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeGreaterThan.java create mode 100644 api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeNegative.java create mode 100644 bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/util/Util.java diff --git a/api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeGreaterThan.java b/api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeGreaterThan.java new file mode 100644 index 0000000..45d6b92 --- /dev/null +++ b/api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeGreaterThan.java @@ -0,0 +1,7 @@ +package dev.xhyrom.lighteco.api.exception; + +public class CannotBeGreaterThan extends IllegalArgumentException { + public CannotBeGreaterThan(String message) { + super(message); + } +} diff --git a/api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeNegative.java b/api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeNegative.java new file mode 100644 index 0000000..4373dd9 --- /dev/null +++ b/api/src/main/java/dev/xhyrom/lighteco/api/exception/CannotBeNegative.java @@ -0,0 +1,7 @@ +package dev.xhyrom.lighteco.api.exception; + +public class CannotBeNegative extends IllegalArgumentException { + public CannotBeNegative(String message) { + super(message); + } +} diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/GiveCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/GiveCommand.java index e138c0d..dbc6ab6 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/GiveCommand.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/GiveCommand.java @@ -7,6 +7,7 @@ import dev.jorel.commandapi.arguments.OfflinePlayerArgument; import dev.jorel.commandapi.executors.CommandArguments; import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; +import dev.xhyrom.lighteco.bukkit.util.Util; import dev.xhyrom.lighteco.common.model.currency.Currency; import lombok.RequiredArgsConstructor; import org.bukkit.OfflinePlayer; @@ -27,8 +28,8 @@ public class GiveCommand implements Command { .withArguments( new OfflinePlayerArgument("target"), currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 1) - : new IntegerArgument("amount", 1) + ? new DoubleArgument("amount", 1, Util.bigDecimalToDouble(this.manager.plugin.getConfig().maximumBalance)) + : new IntegerArgument("amount", 1, this.manager.plugin.getConfig().maximumBalance.intValue()) ) .executes((sender, args) -> { this.handleGive(sender, args, currency); diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/PayCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/PayCommand.java index 4e07a94..4a1f584 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/PayCommand.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/PayCommand.java @@ -7,6 +7,7 @@ import dev.jorel.commandapi.arguments.OfflinePlayerArgument; import dev.jorel.commandapi.executors.CommandArguments; import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; +import dev.xhyrom.lighteco.bukkit.util.Util; import dev.xhyrom.lighteco.common.model.currency.Currency; import lombok.RequiredArgsConstructor; import org.bukkit.OfflinePlayer; @@ -27,8 +28,8 @@ public class PayCommand implements Command { .withArguments( new OfflinePlayerArgument("target"), currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 1) - : new IntegerArgument("amount", 1) + ? new DoubleArgument("amount", 1, Util.bigDecimalToDouble(this.manager.plugin.getConfig().maximumBalance)) + : new IntegerArgument("amount", 1, this.manager.plugin.getConfig().maximumBalance.intValue()) ) .executesPlayer((sender, args) -> { this.handlePay(sender, args, currency); diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/SetCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/SetCommand.java index c45f9ff..ac410f0 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/SetCommand.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/SetCommand.java @@ -7,6 +7,7 @@ import dev.jorel.commandapi.arguments.OfflinePlayerArgument; import dev.jorel.commandapi.executors.CommandArguments; import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; +import dev.xhyrom.lighteco.bukkit.util.Util; import dev.xhyrom.lighteco.common.model.currency.Currency; import lombok.RequiredArgsConstructor; import org.bukkit.OfflinePlayer; @@ -27,8 +28,8 @@ public class SetCommand implements Command { .withArguments( new OfflinePlayerArgument("target"), currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 0) - : new IntegerArgument("amount", 0) + ? new DoubleArgument("amount", 0, Util.bigDecimalToDouble(this.manager.plugin.getConfig().maximumBalance)) + : new IntegerArgument("amount", 0, this.manager.plugin.getConfig().maximumBalance.intValue()) ) .executes((sender, args) -> { this.handleSet(sender, args, currency); diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/TakeCommand.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/TakeCommand.java index 3f25263..015f6f9 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/TakeCommand.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/commands/TakeCommand.java @@ -7,6 +7,7 @@ import dev.jorel.commandapi.arguments.OfflinePlayerArgument; import dev.jorel.commandapi.executors.CommandArguments; import dev.xhyrom.lighteco.bukkit.chat.BukkitCommandSender; import dev.xhyrom.lighteco.bukkit.manager.BukkitCommandManager; +import dev.xhyrom.lighteco.bukkit.util.Util; import dev.xhyrom.lighteco.common.model.currency.Currency; import lombok.RequiredArgsConstructor; import org.bukkit.OfflinePlayer; @@ -27,8 +28,8 @@ public class TakeCommand implements Command { .withArguments( new OfflinePlayerArgument("target"), currency.getProxy().fractionalDigits() > 0 - ? new DoubleArgument("amount", 1) - : new IntegerArgument("amount", 1) + ? new DoubleArgument("amount", 1, Util.bigDecimalToDouble(this.manager.plugin.getConfig().maximumBalance)) + : new IntegerArgument("amount", 1, this.manager.plugin.getConfig().maximumBalance.intValue()) ) .executes((sender, args) -> { this.handleTake(sender, args, currency); diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/util/Util.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/util/Util.java new file mode 100644 index 0000000..d4da7cc --- /dev/null +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/util/Util.java @@ -0,0 +1,19 @@ +package dev.xhyrom.lighteco.bukkit.util; + +import lombok.experimental.UtilityClass; + +import java.math.BigDecimal; + +@UtilityClass +public class Util { + public double bigDecimalToDouble(final BigDecimal value) { + double amount = value.doubleValue(); + + // Don't return bigger balance than user actually has + if (BigDecimal.valueOf(amount).compareTo(value) > 0) { + amount = Math.nextAfter(amount, Double.NEGATIVE_INFINITY); + } + + return amount; + } +} diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/config/Config.java b/common/src/main/java/dev/xhyrom/lighteco/common/config/Config.java index 7f1e85a..983c921 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/config/Config.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/config/Config.java @@ -7,6 +7,8 @@ import eu.okaeri.configs.OkaeriConfig; import eu.okaeri.configs.annotation.Comment; import eu.okaeri.configs.annotation.Header; +import java.math.BigDecimal; + @Header("LightEco configuration file.") @Header("") public class Config extends OkaeriConfig { @@ -21,6 +23,10 @@ public class Config extends OkaeriConfig { @Comment("Save interval to storage in seconds.") public long saveInterval = 5L; + @Comment("Maximum allowed balance.") + @Comment("If you want to change this value, you must also change the data type in the database.") + public BigDecimal maximumBalance = BigDecimal.valueOf(999999999999999.99); + @Comment("Messages") public MessageConfig messages = new MessageConfig(); diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java b/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java index 3bc4c4b..7d6d645 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/config/message/CurrencyMessageConfig.java @@ -18,4 +18,5 @@ public class CurrencyMessageConfig extends OkaeriConfig { public String wait = "Please wait a moment before using this command again."; public String notEnoughMoney = "You don't have enough money!"; public String cannotPaySelf = "You cannot pay yourself!"; + public String cannotBeGreaterThan = "Amount cannot be greater than "; } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/AbstractCommandManager.java b/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/AbstractCommandManager.java index 3fef971..5853b0a 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/AbstractCommandManager.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/manager/command/AbstractCommandManager.java @@ -1,5 +1,6 @@ package dev.xhyrom.lighteco.common.manager.command; +import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan; import dev.xhyrom.lighteco.common.config.message.CurrencyMessageConfig; import dev.xhyrom.lighteco.common.model.chat.CommandSender; import dev.xhyrom.lighteco.common.model.currency.Currency; @@ -101,7 +102,19 @@ public abstract class AbstractCommandManager implements CommandManager { addToMustWait(sender.getUniqueId(), target.getUniqueId()); amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN); - target.setBalance(currency, amount); + try { + target.setBalance(currency, amount); + } catch (CannotBeGreaterThan e) { + removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); + sender.sendMessage( + miniMessage.deserialize( + this.getConfig(currency).cannotBeGreaterThan, + Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } sender.sendMessage( miniMessage.deserialize( @@ -120,7 +133,19 @@ public abstract class AbstractCommandManager implements CommandManager { addToMustWait(sender.getUniqueId(), target.getUniqueId()); amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN); - target.deposit(currency, amount); + try { + target.deposit(currency, amount); + } catch (CannotBeGreaterThan e) { + removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); + sender.sendMessage( + miniMessage.deserialize( + this.getConfig(currency).cannotBeGreaterThan, + Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } sender.sendMessage( miniMessage.deserialize( @@ -140,7 +165,19 @@ public abstract class AbstractCommandManager implements CommandManager { addToMustWait(sender.getUniqueId(), target.getUniqueId()); amount = amount.setScale(currency.getProxy().fractionalDigits(), RoundingMode.DOWN); - target.withdraw(currency, amount); + try { + target.withdraw(currency, amount); + } catch (CannotBeGreaterThan e) { + removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); + sender.sendMessage( + miniMessage.deserialize( + this.getConfig(currency).cannotBeGreaterThan, + Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } sender.sendMessage( miniMessage.deserialize( @@ -186,8 +223,20 @@ public abstract class AbstractCommandManager implements CommandManager { // subtract tax from amount BigDecimal taxedAmount = amount.subtract(tax); - target.deposit(currency, taxedAmount); - user.withdraw(currency, amount); + try { + target.deposit(currency, taxedAmount); + user.withdraw(currency, amount); + } catch (CannotBeGreaterThan e) { + removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); + sender.sendMessage( + miniMessage.deserialize( + this.getConfig(currency).cannotBeGreaterThan, + Placeholder.parsed("max", this.plugin.getConfig().maximumBalance.toPlainString()) + ) + ); + + return; + } String template = tax.compareTo(BigDecimal.ZERO) > 0 ? this.getConfig(currency).payWithTax diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/model/user/User.java b/common/src/main/java/dev/xhyrom/lighteco/common/model/user/User.java index bf0744b..4280c2d 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/model/user/User.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/model/user/User.java @@ -1,5 +1,7 @@ package dev.xhyrom.lighteco.common.model.user; +import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan; +import dev.xhyrom.lighteco.api.exception.CannotBeNegative; import dev.xhyrom.lighteco.common.api.impl.ApiUser; import dev.xhyrom.lighteco.common.cache.RedisBackedMap; import dev.xhyrom.lighteco.common.model.currency.Currency; @@ -46,13 +48,17 @@ public class User { return balances.getOrDefault(currency, currency.getDefaultBalance()); } - public void setBalance(@NonNull Currency currency, @NonNull BigDecimal balance) { + public void setBalance(@NonNull Currency currency, @NonNull BigDecimal balance) throws CannotBeNegative, CannotBeGreaterThan { this.setBalance(currency, balance, false); } - public void setBalance(@NonNull Currency currency, @NonNull BigDecimal balance, boolean force) { + public void setBalance(@NonNull Currency currency, @NonNull BigDecimal balance, boolean force) throws CannotBeNegative, CannotBeGreaterThan { if (balance.compareTo(BigDecimal.ZERO) < 0) { - throw new IllegalArgumentException("Balance cannot be negative"); + throw new CannotBeNegative("Balance cannot be negative"); + } + + if (balance.compareTo(this.plugin.getConfig().maximumBalance) > 0) { + throw new CannotBeGreaterThan("Balance cannot be greater than " + this.plugin.getConfig().maximumBalance); } balance = balance.setScale(currency.fractionalDigits(), RoundingMode.DOWN); @@ -62,19 +68,27 @@ public class User { this.setDirty(true); } - public void deposit(@NonNull Currency currency, @NonNull BigDecimal amount) throws IllegalArgumentException { + public void deposit(@NonNull Currency currency, @NonNull BigDecimal amount) throws CannotBeNegative, CannotBeGreaterThan { if (amount.compareTo(BigDecimal.ZERO) < 0) { throw new IllegalArgumentException("Amount cannot be negative"); } + if (amount.compareTo(this.plugin.getConfig().maximumBalance) > 0) { + throw new CannotBeGreaterThan("Amount cannot be greater than " + this.plugin.getConfig().maximumBalance); + } + this.setBalance(currency, this.getBalance(currency).add(amount)); } - public void withdraw(@NonNull Currency currency, @NonNull BigDecimal amount) throws IllegalArgumentException { + public void withdraw(@NonNull Currency currency, @NonNull BigDecimal amount) throws CannotBeNegative, CannotBeGreaterThan { if (amount.compareTo(BigDecimal.ZERO) < 0) { throw new IllegalArgumentException("Amount cannot be negative"); } + if (amount.compareTo(this.plugin.getConfig().maximumBalance) > 0) { + throw new CannotBeGreaterThan("Amount cannot be greater than " + this.plugin.getConfig().maximumBalance); + } + if (this.getBalance(currency).compareTo(amount) < 0) { // Withdraw all amount = this.getBalance(currency); diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java b/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java index 94bbb89..afc900d 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/sql/SqlStorageProvider.java @@ -31,7 +31,7 @@ public class SqlStorageProvider implements StorageProvider { private static final String CREATE_TABLE = """ CREATE TABLE IF NOT EXISTS '{prefix}_{table}' ( 'uuid' VARCHAR(36) NOT NULL, - 'balance' DECIMAL(10, 2) NOT NULL, + 'balance' DECIMAL(20, 2) NOT NULL, PRIMARY KEY (`uuid`) ); """.trim(); diff --git a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/Vault.java b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/Vault.java index 1c19bd0..454cdf2 100644 --- a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/Vault.java +++ b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/bukkit/hooks/vault/Vault.java @@ -2,6 +2,8 @@ package dev.xhyrom.lighteco.currency.money.bukkit.hooks.vault; import dev.xhyrom.lighteco.api.LightEco; import dev.xhyrom.lighteco.api.LightEcoProvider; +import dev.xhyrom.lighteco.api.exception.CannotBeGreaterThan; +import dev.xhyrom.lighteco.api.exception.CannotBeNegative; import dev.xhyrom.lighteco.api.model.currency.Currency; import dev.xhyrom.lighteco.api.model.user.User; import dev.xhyrom.lighteco.currency.money.common.Plugin; @@ -114,12 +116,12 @@ public class Vault extends AbstractEconomy { try { user.withdraw(currency, BigDecimal.valueOf(amount)); - } catch (IllegalArgumentException e) { + } catch (CannotBeGreaterThan | CannotBeNegative e) { return new EconomyResponse( amount, bigDecimalToDouble(user.getBalance(currency)), EconomyResponse.ResponseType.FAILURE, - "Cannot withdraw negative funds" + e.getMessage() ); } @@ -143,12 +145,12 @@ public class Vault extends AbstractEconomy { try { user.deposit(currency, BigDecimal.valueOf(amount)); - } catch (IllegalArgumentException e) { + } catch (CannotBeGreaterThan | CannotBeNegative e) { return new EconomyResponse( amount, bigDecimalToDouble(user.getBalance(currency)), EconomyResponse.ResponseType.FAILURE, - "Cannot deposit negative funds" + e.getMessage() ); }