diff --git a/README.md b/README.md index 7029583..04969e7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ - **Multi-currency** - LightEco supports creating your own currencies and using them in your server - **Local and global currencies** - LightEco offers support for both local and global currencies, enabling you to create server-specific or proxy-wide currencies. - **Storage** - LightEco offers support for multiple storage types. -- **Open-source** - LightEco is open-source, and is available on [GitHub](https://github.com/xHyroM/lightecp) +- **Open-source** - LightEco is open-source, and is available on [GitHub](https://github.com/xHyroM/lighteco) ## Development @@ -23,4 +23,4 @@ Monorepo structure: ## License -LightEco is licensed under the [Apache-2.0 License](./LICENSE). \ No newline at end of file +LightEco is licensed under the [Apache-2.0 License](./LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..885d902 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,36 @@ +# Security Policy + +## Supported Versions + +LightEco is currently in alpha version, which means it's still not done. As such, it may contain bugs or other issues. We are working hard to improve the plugin and fix any problems that are found, but we encourage users to report any issues they encounter to us so that we can address them as quickly as possible. + +| Version | Supported | +| ------- | ------------------ | +| 0.x.x | :white_check_mark: | + +## Reporting a Vulnerability + +If you find a security vulnerability, please report it to us as soon as possible. We take security very seriously and we appreciate your help in keeping our plugin safe. + +**How to report a vulnerability** + +You can report a vulnerability to us by: + +* **Discord:** Contact me on Discord at [`xhyrom`](https://s.xhyrom.dev/discord-user). +* **Email:** Send an email to `github@xhyrom.dev`. + +**What to expect when reporting a vulnerability** + +We will investigate your report as soon as possible. We will typically provide you with an update within 24 hours. + +If the vulnerability is accepted, we will work to fix it as quickly as possible. We will notify you when the fix is released. + +If the vulnerability is declined, we will provide you with a reason for the decision. + +**What to include in your report** + +When reporting a vulnerability, please include the following information: + +* **A detailed description of the vulnerability.** This should include how the vulnerability can be exploited and what impact it could have. +* **Steps to reproduce the vulnerability.** This will help us to quickly investigate the issue. +* **Any additional information that you think may be helpful.** This could include screenshots, code samples, or other relevant data. diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 5c0dfcb..23c986e 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -3,6 +3,12 @@ plugins { } dependencies { + api("net.kyori:adventure-api:4.12.0") { + exclude(module = "adventure-bom") + exclude(module = "checker-qual") + exclude(module = "annotations") + } + compileOnly("org.projectlombok:lombok:1.18.28") annotationProcessor("org.projectlombok:lombok:1.18.28") 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/api/src/main/java/dev/xhyrom/lighteco/api/model/currency/Currency.java b/api/src/main/java/dev/xhyrom/lighteco/api/model/currency/Currency.java index 8f06741..308f086 100644 --- a/api/src/main/java/dev/xhyrom/lighteco/api/model/currency/Currency.java +++ b/api/src/main/java/dev/xhyrom/lighteco/api/model/currency/Currency.java @@ -13,6 +13,19 @@ public interface Currency { */ String getIdentifier(); + /** + * Returns the identifier aliases of the currency. + *

+ * Useful if you want multiple commands for the same currency. + * For example, you can have a command `/hyrocoins` but also `/hc`. + *

+ * + * @return the aliases + */ + default String[] getIdentifierAliases() { + return new String[0]; + }; + /** * Returns the type of the currency, either {@link Type#LOCAL} or {@link Type#GLOBAL} * diff --git a/api/src/main/java/dev/xhyrom/lighteco/api/model/user/User.java b/api/src/main/java/dev/xhyrom/lighteco/api/model/user/User.java index 715dada..5bf88fe 100644 --- a/api/src/main/java/dev/xhyrom/lighteco/api/model/user/User.java +++ b/api/src/main/java/dev/xhyrom/lighteco/api/model/user/User.java @@ -1,6 +1,7 @@ package dev.xhyrom.lighteco.api.model.user; import dev.xhyrom.lighteco.api.model.currency.Currency; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -59,4 +60,12 @@ public interface User { * @throws IllegalArgumentException if the amount is negative */ void withdraw(@NonNull Currency currency, @NonNull BigDecimal amount) throws IllegalArgumentException; + + /** + * Send a message to this user. + * Message will be silently dropped if the user is offline. + * + * @param message the message + */ + void sendMessage(Component message); } diff --git a/build.gradle.kts b/build.gradle.kts index 4335316..d196431 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,9 +13,11 @@ val commitHash = determineCommitHash(project) allprojects { group = "dev.xhyrom" version = "$majorVersion.$minorVersion.$patchVersion" + description = "Incredibly fast, lightweight, and modular plugin that excels across multiple platforms." ext { set("version", "$majorVersion.$minorVersion.$patchVersion+$commitHash") + set("description", description) } } @@ -54,5 +56,5 @@ fun determineCommitHash(project: Project): String { standardOutput = commitHashInfo } - return commitHashInfo.toString() + return commitHashInfo.toString().strip() } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts b/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts index a799e87..3a09e7d 100644 --- a/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts +++ b/buildSrc/src/main/kotlin/lighteco.base-logic.gradle.kts @@ -23,4 +23,63 @@ tasks { compileJava { options.encoding = Charsets.UTF_8.name() } +} + +publishing { + // Publishing to repo.jopga.me + publications.create("mavenJava") { + repositories.maven { + url = uri("https://repo.jopga.me/releases") + + credentials(PasswordCredentials::class) + authentication { + create("basic") + } + } + + groupId = rootProject.group as String + artifactId = project.name + version = rootProject.version as String + + pom { + name.set("LightEco") + url.set("https://github.com/xHyroM/lighteco") + description.set(project.description) + organization { + name.set("xHyroM") + url.set("https://xhyrom.dev") + } + developers { + developer { + id.set("xHyroM") + name.set("xHyroM") + email.set("lol@xhyrom.dev") + timezone.set("Europe/Bratislava") + url.set("https://xhyrom.dev") + } + } + scm { + connection.set("scm:git:https://github.com/xHyroM/lighteco.git") + developerConnection.set("scm:git:git@github.com:xHyroM/lighteco.git") + url.set("https://github.com/xHyroM/lighteco") + } + licenses { + license { + name.set("Apache License 2.0") + url.set("https://github.com/xHyroM/lighteco/blob/main/LICENSE") + distribution.set("repo") + } + } + ciManagement { + system.set("GitHub Actions") + url.set("https://github.com/xHyroM/lighteco/actions") + } + } + + artifact(tasks.named("jar")) { + classifier = "" + } + + artifact(tasks.named("sourcesJar")) + } } \ No newline at end of file diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index cbefc31..7fe7247 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -13,7 +13,7 @@ repositories { dependencies { implementation(project(":lighteco-common")) - implementation("dev.jorel:commandapi-bukkit-shade:9.1.0") + implementation("dev.jorel:commandapi-bukkit-shade:9.2.0") implementation("net.kyori:adventure-platform-bukkit:4.2.0") compileOnly("org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT") diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoBootstrap.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoBootstrap.java index caddaec..52929c2 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoBootstrap.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoBootstrap.java @@ -9,6 +9,8 @@ import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger; import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerAdapter; import lombok.Getter; import org.bukkit.OfflinePlayer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -29,6 +31,7 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr private final PluginLogger logger; @Getter private final SchedulerAdapter scheduler; + private BukkitAudiences audience; public BukkitLightEcoBootstrap(JavaPlugin loader) { this.loader = loader; @@ -48,6 +51,8 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr public void onEnable() { CommandAPI.onEnable(); this.plugin.enable(); + + this.audience = BukkitAudiences.create(loader); } @Override @@ -83,4 +88,9 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr public InputStream getResourceStream(String filename) { return this.loader.getResource(filename); } + + @Override + public Audience getPlayerAudience(UUID uniqueId) { + return audience.player(uniqueId); + } } diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoLoader.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoLoader.java index da91c69..a8f76e9 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoLoader.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/BukkitLightEcoLoader.java @@ -1,7 +1,5 @@ package dev.xhyrom.lighteco.bukkit; -import dev.jorel.commandapi.CommandAPI; -import dev.jorel.commandapi.CommandAPIBukkitConfig; import org.bukkit.plugin.java.JavaPlugin; // Used inside plugin.yml @@ -16,20 +14,15 @@ public class BukkitLightEcoLoader extends JavaPlugin { @Override public void onLoad() { this.bootstrap.onLoad(); - CommandAPI.onLoad(new CommandAPIBukkitConfig(this) - .verboseOutput(this.bootstrap.getPlugin().getConfig().debug) - ); } @Override public void onEnable() { - CommandAPI.onEnable(); this.bootstrap.onEnable(); } @Override public void onDisable() { - CommandAPI.onDisable(); this.bootstrap.onDisable(); } } diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/PlaceholderAPIExpansion.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/PlaceholderAPIExpansion.java index a4162ad..b0bbb01 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/PlaceholderAPIExpansion.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/hooks/PlaceholderAPIExpansion.java @@ -6,31 +6,30 @@ import dev.xhyrom.lighteco.common.model.user.User; import lombok.RequiredArgsConstructor; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; @RequiredArgsConstructor public class PlaceholderAPIExpansion extends PlaceholderExpansion { private final BukkitLightEcoPlugin plugin; @Override - public @NotNull String getIdentifier() { + public @NonNull String getIdentifier() { return "lighteco"; } @Override - public @NotNull String getAuthor() { + public @NonNull String getAuthor() { return this.plugin.getBootstrap().getLoader().getDescription().getAuthors().toString(); } @Override - public @NotNull String getVersion() { + public @NonNull String getVersion() { return this.plugin.getBootstrap().getLoader().getDescription().getVersion(); } @Override - public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) { + public @Nullable String onRequest(OfflinePlayer player, @NonNull String params) { String[] args = params.split("_"); if (args.length < 2) return null; diff --git a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitCommandManager.java b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitCommandManager.java index 9b78ab5..53d1260 100644 --- a/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitCommandManager.java +++ b/bukkit/src/main/java/dev/xhyrom/lighteco/bukkit/manager/BukkitCommandManager.java @@ -20,28 +20,11 @@ public class BukkitCommandManager extends AbstractCommandManager { @Override public void registerCurrencyCommand(@NonNull Currency currency) { - String permissionBase = "lighteco.currency." + currency.getIdentifier() + ".command."; + registerCommands(currency.getIdentifier(), currency); - // Balance - for (CommandAPICommand cmd : new BalanceCommand( - this, - currency.getIdentifier(), - currency, - permissionBase - ).multipleBuild()) { - cmd.register(); + for (String alias : currency.getIdentifierAliases()) { + registerCommands(alias, currency); } - - CommandAPICommand cmd = new CommandAPICommand(currency.getIdentifier()) - .withSubcommand(new SetCommand(this, currency, permissionBase).build()) - .withSubcommand(new GiveCommand(this, currency, permissionBase).build()) - .withSubcommand(new TakeCommand(this, currency, permissionBase).build()) - .withSubcommands(new BalanceCommand(this, "balance", currency, permissionBase).multipleBuild()); - - if (currency.isPayable()) - cmd = cmd.withSubcommand(new PayCommand(this, currency, permissionBase).build()); - - cmd.register(); } @Override @@ -69,6 +52,30 @@ public class BukkitCommandManager extends AbstractCommandManager { ).multipleBuild()) { cmd.register(); } + } + private void registerCommands(@NonNull String name, @NonNull Currency currency) { + String permissionBase = "lighteco.currency." + currency.getIdentifier() + ".command."; + + // Balance + for (CommandAPICommand cmd : new BalanceCommand( + this, + name, + currency, + permissionBase + ).multipleBuild()) { + cmd.register(); + } + + CommandAPICommand cmd = new CommandAPICommand(name) + .withSubcommand(new SetCommand(this, currency, permissionBase).build()) + .withSubcommand(new GiveCommand(this, currency, permissionBase).build()) + .withSubcommand(new TakeCommand(this, currency, permissionBase).build()) + .withSubcommands(new BalanceCommand(this, "balance", currency, permissionBase).multipleBuild()); + + if (currency.isPayable()) + cmd = cmd.withSubcommand(new PayCommand(this, currency, permissionBase).build()); + + cmd.register(); } } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 91998ab..049f144 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -4,6 +4,7 @@ plugins { dependencies { api(project(":lighteco-api")) + api("org.checkerframework:checker-qual:3.8.0") api("net.kyori:adventure-api:4.12.0") { exclude(module = "adventure-bom") exclude(module = "checker-qual") @@ -23,6 +24,5 @@ dependencies { compileOnly("org.projectlombok:lombok:1.18.28") annotationProcessor("org.projectlombok:lombok:1.18.28") - compileOnly("org.checkerframework:checker-qual:3.8.0") compileOnly("org.jetbrains:annotations:20.1.0") } \ No newline at end of file diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUser.java b/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUser.java index afc0f5c..a3d01d4 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUser.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUser.java @@ -2,6 +2,7 @@ package dev.xhyrom.lighteco.common.api.impl; import dev.xhyrom.lighteco.api.model.currency.Currency; import dev.xhyrom.lighteco.api.model.user.User; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -60,4 +61,9 @@ public class ApiUser implements User { this.handler.withdraw(internal, amount); } + + @Override + public void sendMessage(Component message) { + this.handler.sendMessage(message); + } } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUserManager.java b/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUserManager.java index 89098d2..c65d882 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUserManager.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/api/impl/ApiUserManager.java @@ -5,7 +5,6 @@ import dev.xhyrom.lighteco.api.model.user.User; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.jetbrains.annotations.NotNull; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -37,7 +36,7 @@ public class ApiUserManager extends ApiAbstractManager saveUsers(@NotNull @NonNull User... users) { + public @NonNull CompletableFuture saveUsers(@NonNull User... users) { return this.plugin.getStorage().saveUsers(users); } 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..00380ce 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 @@ -14,8 +14,11 @@ public class CurrencyMessageConfig extends OkaeriConfig { public String pay = " | Paid to "; public String payWithTax = " | Paid to ( after tax)"; + public String payReceived = " | Received from "; + public String payReceivedWithTax = " | Received from ( after tax)"; 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..dec658f 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,13 +223,28 @@ 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 : this.getConfig(currency).pay; + String templateReceived = tax.compareTo(BigDecimal.ZERO) > 0 + ? this.getConfig(currency).payReceivedWithTax + : this.getConfig(currency).payReceived; sender.sendMessage( miniMessage.deserialize( @@ -206,6 +258,18 @@ public abstract class AbstractCommandManager implements CommandManager { ) ); + target.sendMessage( + miniMessage.deserialize( + templateReceived, + Placeholder.parsed("currency", currency.getIdentifier()), + Placeholder.parsed("sender", user.getUsername()), + Placeholder.parsed("amount", amount.toPlainString()), + Placeholder.parsed("taxed_amount", taxedAmount.toPlainString()), + Placeholder.parsed("sender_balance", user.getBalance(currency).toPlainString()), + Placeholder.parsed("receiver_balance", target.getBalance(currency).toPlainString()) + ) + ); + removeFromMustWait(target.getUniqueId(), sender.getUniqueId()); } } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/model/currency/Currency.java b/common/src/main/java/dev/xhyrom/lighteco/common/model/currency/Currency.java index 8946d49..cb978a4 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/model/currency/Currency.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/model/currency/Currency.java @@ -16,6 +16,10 @@ public class Currency { return proxy.getIdentifier(); } + public String[] getIdentifierAliases() { + return proxy.getIdentifierAliases(); + } + public dev.xhyrom.lighteco.api.model.currency.Currency.Type getType() { return proxy.getType(); } 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..83069dc 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,11 +1,14 @@ 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; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.NonNull; import java.math.BigDecimal; @@ -46,13 +49,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 +69,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); @@ -82,4 +97,8 @@ public class User { this.setBalance(currency, this.getBalance(currency).subtract(amount)); } + + public void sendMessage(@NonNull Component message) { + this.plugin.getBootstrap().getPlayerAudience(this.getUniqueId()).sendMessage(message); + } } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java index edebb01..e0545a0 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/plugin/bootstrap/LightEcoBootstrap.java @@ -2,6 +2,7 @@ package dev.xhyrom.lighteco.common.plugin.bootstrap; import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger; import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerAdapter; +import net.kyori.adventure.audience.Audience; import java.io.InputStream; import java.nio.file.Path; @@ -20,4 +21,5 @@ public interface LightEcoBootstrap { List getOnlinePlayers(); InputStream getResourceStream(String filename); + Audience getPlayerAudience(UUID uniqueId); } diff --git a/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/memory/MemoryStorageProvider.java b/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/memory/MemoryStorageProvider.java index bdea3e5..0658bf1 100644 --- a/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/memory/MemoryStorageProvider.java +++ b/common/src/main/java/dev/xhyrom/lighteco/common/storage/provider/memory/MemoryStorageProvider.java @@ -5,7 +5,6 @@ import dev.xhyrom.lighteco.api.storage.StorageProvider; import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.UUID; @@ -43,7 +42,7 @@ public class MemoryStorageProvider implements StorageProvider { } @Override - public void saveUsers(@NotNull @NonNull User... users) { + public void saveUsers(@NonNull User... users) { for (User user : users) { this.userDatabase.put(user.getUniqueId(), user); } 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..1240330 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 @@ -8,7 +8,6 @@ import dev.xhyrom.lighteco.common.storage.StorageType; import dev.xhyrom.lighteco.common.storage.provider.sql.connection.ConnectionFactory; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.jetbrains.annotations.NotNull; import java.math.BigDecimal; import java.sql.Connection; @@ -31,7 +30,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(); @@ -163,7 +162,7 @@ public class SqlStorageProvider implements StorageProvider { } @Override - public void saveUsers(@NotNull @NonNull User... users) throws Exception { + public void saveUsers(@NonNull User... users) throws Exception { // use transaction try (Connection c = this.connectionFactory.getConnection()) { try { diff --git a/currency-money/README.md b/currency-money/README.md index e788a02..0ea6d3b 100644 --- a/currency-money/README.md +++ b/currency-money/README.md @@ -15,8 +15,8 @@ - **Vault support** - Money supports Vault, allowing you to use other economy plugins with Money. - **Configurable** - Money is configurable, allowing you to change the currency's name, symbol, and more. - **Lightweight** - Money is lightweight, and is designed to be as efficient as possible. -- **Open-source** - Money is open-source, and is available on [GitHub](https://github.com/xHyroM/tree/main/currency-money) +- **Open-source** - Money is open-source, and is available on [GitHub](https://github.com/xHyroM/lighteco/tree/main/currency-money) ## License -Money is licensed under the [Apache-2.0 License](./LICENSE). \ No newline at end of file +Money is licensed under the [Apache-2.0 License](./LICENSE). diff --git a/currency-money/build.gradle.kts b/currency-money/build.gradle.kts index e63ef0b..7c721b7 100644 --- a/currency-money/build.gradle.kts +++ b/currency-money/build.gradle.kts @@ -2,6 +2,8 @@ plugins { id("lighteco.addon-logic") } +description = "Addon that adds main currency to LightEco that uses Vault to hook into other economy plugins." + repositories { maven("https://repo.papermc.io/repository/maven-public/") maven("https://jitpack.io") 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..03888e4 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; @@ -50,7 +52,7 @@ public class Vault extends AbstractEconomy { NumberFormat format = NumberFormat.getInstance(); format.setCurrency(java.util.Currency.getInstance(this.plugin.getConfig().currencyCode)); - return format.format(BigDecimal.valueOf(amount)); + return format.format(amount); } @Override @@ -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() ); } diff --git a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/common/currency/MoneyCurrency.java b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/common/currency/MoneyCurrency.java index 5dbcef8..1858cf1 100644 --- a/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/common/currency/MoneyCurrency.java +++ b/currency-money/src/main/java/dev/xhyrom/lighteco/currency/money/common/currency/MoneyCurrency.java @@ -17,6 +17,11 @@ public class MoneyCurrency implements Currency { return "money"; } + @Override + public String[] getIdentifierAliases() { + return new String[]{"eco"}; + } + @Override public Type getType() { return Type.LOCAL; diff --git a/currency-money/src/main/resources/plugin.yml b/currency-money/src/main/resources/plugin.yml index b5bdfbb..d1c95bb 100644 --- a/currency-money/src/main/resources/plugin.yml +++ b/currency-money/src/main/resources/plugin.yml @@ -4,6 +4,7 @@ version: ${version} main: dev.xhyrom.lighteco.currency.money.bukkit.BukkitMCLoader author: ${author} api-version: 1.20 +load: STARTUP softdepend: - Vault diff --git a/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java b/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java index 469ab9f..ab281f0 100644 --- a/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java +++ b/sponge-8/src/main/java/dev/xhyrom/lighteco/sponge/SpongeLightEcoBootstrap.java @@ -5,6 +5,7 @@ import dev.xhyrom.lighteco.common.plugin.bootstrap.LightEcoBootstrap; import dev.xhyrom.lighteco.common.plugin.bootstrap.LoaderBootstrap; import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger; import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerAdapter; +import net.kyori.adventure.audience.Audience; import org.apache.logging.log4j.Logger; import org.spongepowered.plugin.builtin.jvm.Plugin; @@ -73,4 +74,9 @@ public class SpongeLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr public InputStream getResourceStream(String filename) { return null; } + + @Override + public Audience getPlayerAudience(UUID uniqueId) { + return null; + } }