From 91e417228716f86b0351fd1256effca7902c1c55 Mon Sep 17 00:00:00 2001 From: david Date: Mon, 14 Jul 2025 19:52:21 +0200 Subject: [PATCH 01/32] Added `CurrencyHolder` interface Introduced `CurrencyHolder` to centralize currency management logic. Applied the interface to `EconomyController`, `BankController`, and related classes to unify and enhance functionality. Deprecated older currency formatting methods in favor of `Currency` methods. --- .../wrapper/service/model/WrappedAccount.java | 9 +- .../service/api/economy/Account.java | 8 ++ .../api/economy/EconomyController.java | 18 +-- .../api/economy/bank/BankController.java | 18 +-- .../api/economy/currency/CurrencyHolder.java | 118 ++++++++++++++++++ 5 files changed, 138 insertions(+), 33 deletions(-) create mode 100644 src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java index 929fae79..42e15641 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java @@ -13,11 +13,13 @@ @NullMarked public class WrappedAccount implements Account { + private final EconomyController controller; private final @Nullable World world; private final Economy economy; private final OfflinePlayer holder; - public WrappedAccount(@Nullable World world, Economy economy, OfflinePlayer holder) { + public WrappedAccount(EconomyController controller, @Nullable World world, Economy economy, OfflinePlayer holder) { + this.controller = controller; this.world = world; this.economy = economy; this.holder = holder; @@ -25,6 +27,11 @@ public WrappedAccount(@Nullable World world, Economy economy, OfflinePlayer hold @Override public BigDecimal deposit(Number amount) { + public CurrencyHolder getController() { + return controller; + } + + @Override var response = economy.depositPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); return new BigDecimal(response.balance); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index 427d8e9b..17935951 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -1,5 +1,6 @@ package net.thenextlvl.service.api.economy; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.World; import org.jspecify.annotations.NullMarked; @@ -12,6 +13,13 @@ */ @NullMarked public interface Account extends Comparable { + /** + * Retrieves the associated {@code CurrencyHolder} for the account. + * + * @return the {@code CurrencyHolder} capable of managing currencies for the account + */ + CurrencyHolder getController(); + /** * Deposits the specified amount into the account balance. * diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index 51891942..e6f97ac5 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -1,6 +1,7 @@ package net.thenextlvl.service.api.economy; import net.thenextlvl.service.api.Controller; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jetbrains.annotations.Unmodifiable; @@ -16,22 +17,7 @@ * The AccountController interface provides methods to create, retrieve and delete accounts. */ @NullMarked -public interface EconomyController extends Controller { - /** - * Formats the specified amount as a string. - * - * @param amount the number amount to be formatted - * @return the formatted amount as a string - */ - String format(Number amount); - - /** - * Retrieves the number of fractional digits used for formatting currency amounts. - * - * @return the number of fractional digits used for formatting currency amounts - */ - int fractionalDigits(); - +public interface EconomyController extends Controller, CurrencyHolder { /** * Retrieves the plural form of the currency name based on the provided locale. * diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index 9d67aef7..d640c250 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -1,6 +1,7 @@ package net.thenextlvl.service.api.economy.bank; import net.thenextlvl.service.api.Controller; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jetbrains.annotations.Unmodifiable; @@ -12,22 +13,7 @@ import java.util.concurrent.CompletableFuture; @NullMarked -public interface BankController extends Controller { - /** - * Formats the specified amount as a string. - * - * @param amount the number amount to be formatted - * @return the formatted amount as a string - */ - String format(Number amount); - - /** - * Retrieves the number of fractional digits used for formatting currency amounts. - * - * @return the number of fractional digits used for formatting currency amounts - */ - int fractionalDigits(); - +public interface BankController extends Controller, CurrencyHolder { /** * Creates a bank for the specified player with the given name. *

diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java new file mode 100644 index 00000000..b265241d --- /dev/null +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -0,0 +1,118 @@ +package net.thenextlvl.service.api.economy.currency; + +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.jetbrains.annotations.Unmodifiable; + +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; + +/** + * Represents an entity capable of handling currencies in an economy system. + * This interface provides methods for formatting, retrieving, creating, + * and deleting currencies, as well as determining support for multiple currencies. + */ +public interface CurrencyHolder { + /** + * Formats the specified amount as a string. + * + * @param amount the number amount to be formatted + * @return the formatted amount as a string + * @deprecated use {@link Currency#format(Number, Locale)} + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default String format(Number amount) { + return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().format(amount, Locale.US)); + } + + /** + * Retrieves the number of fractional digits used for formatting currency amounts. + * + * @return the number of fractional digits used for formatting currency amounts + * @deprecated use {@link Currency#getFractionalDigits()} + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default int fractionalDigits() { + return getDefaultCurrency().getFractionalDigits(); + } + + /** + * Retrieves all currencies managed by the currency holder. + * + * @return an unmodifiable set of currencies + * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + */ + default @Unmodifiable Set getCurrencies() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Retrieves a currency by its name. + * + * @param name the name of the currency to retrieve + * @return an {@code Optional} containing the currency, or empty + * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + */ + default Optional getCurrency(String name) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Checks if a currency with the specified name exists. + * + * @param name the name of the currency to check for existence + * @return {@code true} if the currency exists, otherwise {@code false} + * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + */ + default boolean hasCurrency(String name) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Creates a new currency by configuring a {@link Currency.Builder}. + *

+ * If a currency with the same name already exists, this method returns empty. + * + * @param name the name of the new currency + * @param builder a consumer to configure the {@link Currency.Builder} for currency creation + * @return an optional containing the created {@link Currency}, or empty + * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + */ + default Optional createCurrency(String name, Consumer builder) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Deletes a currency with the specified name. + * + * @param name the name of the currency to delete + * @return {@code true} if the currency was successfully deleted, otherwise {@code false} + * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + */ + default boolean deleteCurrency(String name) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Retrieves the default currency for this economy controller. + * + * @return the default currency + */ + Currency getDefaultCurrency(); + + /** + * Determines whether the economy controller supports multiple currencies. + * + * @return {@code true} if multi-currency is supported, otherwise {@code false} + * @implSpec If multiple currencies are supported, all respective methods have to be implemented. + * @see #createCurrency(String, Consumer) + * @see #deleteCurrency(String) + * @see #getCurrencies() + * @see #getCurrency(String) + * @see #hasCurrency(String) + */ + default boolean hasMultiCurrencySupport() { + return false; + } +} From d978e3f055fe879a43cf63731f18a6ef5b0c9cbe Mon Sep 17 00:00:00 2001 From: david Date: Mon, 14 Jul 2025 19:54:10 +0200 Subject: [PATCH 02/32] Added `Currency` interface and improved currency handling Introduced `Currency` interface to define currency properties and formatting. Deprecated older `EconomyController` methods in favor of `Currency` methods for better consistency and multi-currency support. --- .../api/economy/EconomyController.java | 23 ++- .../api/economy/currency/Currency.java | 187 ++++++++++++++++++ 2 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index e6f97ac5..1b288a36 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -1,6 +1,8 @@ package net.thenextlvl.service.api.economy; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.thenextlvl.service.api.Controller; +import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -14,7 +16,8 @@ import java.util.concurrent.CompletableFuture; /** - * The AccountController interface provides methods to create, retrieve and delete accounts. + * EconomyController is an interface that provides methods for managing and interacting + * with economic systems, such as currency formatting, account retrieval, and multi-currency support. */ @NullMarked public interface EconomyController extends Controller, CurrencyHolder { @@ -23,23 +26,35 @@ public interface EconomyController extends Controller, CurrencyHolder { * * @param locale the locale for which to retrieve the plural currency name * @return the plural form of the currency name as a string + * @deprecated use {@link Currency#getDisplayNamePlural(Locale)} */ - String getCurrencyNamePlural(Locale locale); + @Deprecated(forRemoval = true, since = "2.4.0") + default String getCurrencyNamePlural(Locale locale) { + return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getDisplayNamePlural(locale)); + } /** * Retrieves the name of the currency associated with the specified locale. * * @param locale the locale for which to retrieve the currency name * @return the name of the currency as a string + * @deprecated use {@link Currency#getDisplayNameSingular(Locale)} */ - String getCurrencyNameSingular(Locale locale); + @Deprecated(forRemoval = true, since = "2.4.0") + default String getCurrencyNameSingular(Locale locale) { + return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getDisplayNameSingular(locale)); + } /** * Retrieves the currency symbol associated with the economy controller. * * @return the currency symbol as a string + * @deprecated use {@link Currency#getSymbol()} */ - String getCurrencySymbol(); + @Deprecated(forRemoval = true, since = "2.4.0") + default String getCurrencySymbol() { + return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getSymbol()); + } /** * Loads all accounts asynchronously. diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java new file mode 100644 index 00000000..370cbe2b --- /dev/null +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -0,0 +1,187 @@ +package net.thenextlvl.service.api.economy.currency; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.identity.Identity; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +import java.util.Locale; +import java.util.Optional; +import java.util.OptionalInt; + +@NullMarked +public interface Currency { + /** + * Retrieves the name of the currency. + * + * @return the name of the currency as a string + */ + String getName(); + + /** + * Retrieves the singular display name component of the currency based on the audience's locale. + *

+ * If the audience does not specify a locale, {@link Locale#US} is used. + * + * @param audience the audience whose locale is used to determine the singular display name + * @return the singular display name as a {@code Component} for the audience's locale + */ + @ApiStatus.NonExtendable + default Component getDisplayNameSingular(Audience audience) { + return getDisplayNameSingular(audience.getOrDefault(Identity.LOCALE, Locale.US)); + } + + /** + * Retrieves the singular display name component of the currency for the specified locale. + * + * @param locale the locale for which the singular display name should be retrieved + * @return the singular display name as a {@code Component} for the specified locale + */ + Component getDisplayNameSingular(Locale locale); + + + /** + * Retrieves the plural display name component of the currency based on the audience's locale. + *

+ * If the audience does not specify a locale, {@link Locale#US} is used. + * + * @param audience the audience whose locale is used to determine the plural display name + * @return the plural display name as a {@code Component} for the audience's locale + */ + @ApiStatus.NonExtendable + default Component getDisplayNamePlural(Audience audience) { + return getDisplayNamePlural(audience.getOrDefault(Identity.LOCALE, Locale.US)); + } + + /** + * Retrieves the plural display name component of the currency for the specified locale. + * + * @param locale the locale for which the plural display name should be retrieved + * @return the plural display name as a {@code Component} for the specified locale + */ + Component getDisplayNamePlural(Locale locale); + + /** + * Retrieves the currency symbol. + * + * @return the currency symbol as a component + */ + Component getSymbol(); + + /** + * Formats the specified amount as a component. + * + * @param amount the amount to be formatted + * @param audience the audience to format the amount for + * @return the formatted amount as a component + * @see #format(Number, Locale) + */ + @ApiStatus.NonExtendable + default Component format(Number amount, Audience audience) { + return format(amount, audience.getOrDefault(Identity.LOCALE, Locale.US)); + } + + /** + * Formats the specified amount as a component. + * + * @param amount the amount to be formatted + * @param locale the locale to format the amount in + * @return the formatted amount as a component + * @see #format(Number, Audience) + */ + Component format(Number amount, Locale locale); + + /** + * Retrieves the number of fractional digits used for formatting currency amounts. + * + * @return the number of fractional digits used for formatting currency amounts + */ + int getFractionalDigits(); + + /** + * A builder interface for constructing instances of {@link Currency}. + * The {@code Builder} allows for the configuration of currency properties such as + * singular and plural display names, currency symbol, and fractional digits. + */ + interface Builder { + /** + * Sets the singular display name of the currency for a specific locale. + * + * @param name the singular display name component of the currency + * @param locale the locale for which the singular display name is being set + * @return the builder instance for chaining + */ + Builder displayNameSingular(Component name, Locale locale); + + /** + * Retrieves the singular display name component of the currency for the specified locale. + * + * @param locale the locale for which the singular display name should be retrieved + * @return an {@code Optional} containing the singular display name as a {@code Component}, or empty + */ + Optional displayNameSingular(Locale locale); + + /** + * Sets the plural display name of the currency for a specific locale. + * + * @param name the plural display name component of the currency + * @param locale the locale for which the plural display name is being set + * @return the builder instance for chaining + */ + Builder displayNamePlural(Component name, Locale locale); + + /** + * Retrieves the plural display name component of the currency for the specified locale. + * + * @param locale the locale for which the plural display name should be retrieved + * @return an {@code Optional} containing the plural display name as a {@code Component}, or empty + */ + Optional displayNamePlural(Locale locale); + + /** + * Sets the currency symbol as a {@code Component}. + * + * @param symbol the symbol component to represent the currency + * @return the builder instance for chaining + */ + Builder symbol(Component symbol); + + /** + * Retrieves the currency symbol set on the {@code Builder}. + * + * @return an {@code Optional} containing the symbol as a {@code Component}, or empty + */ + Optional symbol(); + + /** + * Sets the number of fractional digits to be used for the currency. + *

+ * Fractional digits are generally used to specify the precision of the currency values, + * for example, 2 fractional digits for most currencies such as USD (representing cents). + * + * @param fractionalDigits the number of fractional digits to set (must be a non-negative integer) + * @return the builder instance for chaining + * @throws IllegalArgumentException if {@code fractionalDigits} is negative + */ + Builder fractionalDigits(int fractionalDigits) throws IllegalArgumentException; + + /** + * Retrieves the number of fractional digits set for the currency. + *

+ * Fractional digits represent the precision of the currency, + * such as 2 for most currencies like USD (representing cents). + * + * @return an {@code OptionalInt} containing the number of fractional digits, or empty + */ + OptionalInt fractionalDigits(); + + /** + * Builds and returns a {@link Currency} instance based on the properties set on the {@code Builder}. + * + * @return the constructed {@link Currency} instance + */ + @ApiStatus.OverrideOnly + Currency build(); + } +} From 205a7b7b663465cf83bc1412e97c78380c2ba4a2 Mon Sep 17 00:00:00 2001 From: david Date: Mon, 14 Jul 2025 19:56:14 +0200 Subject: [PATCH 03/32] Refactored to use `Currency` for balance operations Replaced direct balance manipulation methods with `Currency`-based equivalents for consistency and multi-currency support. Deprecated older methods and introduced `WrappedCurrency` for compatibility with Vault's economy API. Updated placeholders and wrapper classes accordingly. --- .../economy/ServiceBankPlaceholderStore.java | 21 ++++-- .../ServiceEconomyPlaceholderStore.java | 23 +++++-- .../wrapper/VaultEconomyServiceWrapper.java | 37 ++++++---- .../wrapper/service/BankServiceWrapper.java | 16 ++--- .../service/EconomyServiceWrapper.java | 34 +++------ .../wrapper/service/WrappedCurrency.java | 47 +++++++++++++ .../wrapper/service/model/WrappedAccount.java | 17 +++-- .../wrapper/service/model/WrappedBank.java | 21 +++--- .../service/api/economy/Account.java | 69 +++++++++++++++++-- 9 files changed, 203 insertions(+), 82 deletions(-) create mode 100644 plugin/src/main/java/net/thenextlvl/service/wrapper/service/WrappedCurrency.java diff --git a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java index 15a48017..c14e8957 100644 --- a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java +++ b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java @@ -1,5 +1,6 @@ package net.thenextlvl.service.placeholder.economy; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.thenextlvl.service.ServicePlugin; import net.thenextlvl.service.api.economy.bank.Bank; import net.thenextlvl.service.api.economy.bank.BankController; @@ -7,6 +8,7 @@ import org.jspecify.annotations.NullMarked; import java.math.BigDecimal; +import java.util.Locale; import java.util.stream.Collectors; @NullMarked @@ -24,12 +26,17 @@ protected void registerResolvers() { // %serviceio_bank_balance% registerResolver("bank_balance", (provider, player, matcher) -> { - return provider.getBank(player).map(Bank::getBalance).orElse(BigDecimal.ZERO).toPlainString(); + return provider.getBank(player) + .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO).toPlainString(); }); // %serviceio_bank_balance_formatted% registerResolver("bank_balance_formatted", (provider, player, matcher) -> { - return provider.format(provider.getBank(player).map(Bank::getBalance).orElse(BigDecimal.ZERO)); + var format = provider.getDefaultCurrency().format(provider.getBank(player) + .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO), Locale.US); + return PlainTextComponentSerializer.plainText().serialize(format); }); // %serviceio_bank_% @@ -43,14 +50,20 @@ protected void registerResolvers() { registerResolver("bank_%s_balance", (provider, player, matcher) -> { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; - return provider.getBank(player, world).map(Bank::getBalance).orElse(BigDecimal.ZERO).toPlainString(); + return provider.getBank(player, world) + .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO) + .toPlainString(); }); // %serviceio_bank__balance_formatted% registerResolver("bank_%s_balance_formatted", (provider, player, matcher) -> { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; - return provider.format(provider.getBank(player, world).map(Bank::getBalance).orElse(BigDecimal.ZERO)); + var format = provider.getDefaultCurrency().format(provider.getBank(player, world) + .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO), Locale.US); + return PlainTextComponentSerializer.plainText().serialize(format); }); // %serviceio_banks% diff --git a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java index adae3c46..50912ce5 100644 --- a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java +++ b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java @@ -1,12 +1,13 @@ package net.thenextlvl.service.placeholder.economy; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.thenextlvl.service.ServicePlugin; -import net.thenextlvl.service.api.economy.Account; import net.thenextlvl.service.api.economy.EconomyController; import net.thenextlvl.service.placeholder.api.PlaceholderStore; import org.jspecify.annotations.NullMarked; import java.math.BigDecimal; +import java.util.Locale; @NullMarked public class ServiceEconomyPlaceholderStore extends PlaceholderStore { @@ -18,26 +19,38 @@ public ServiceEconomyPlaceholderStore(ServicePlugin plugin) { protected void registerResolvers() { // %serviceio_balance% registerResolver("balance", (provider, player, matcher) -> { - return provider.getAccount(player).map(Account::getBalance).orElse(BigDecimal.ZERO).toPlainString(); + return provider.getAccount(player) + .map(account -> account.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO) + .toPlainString(); }); // %serviceio_balance_% registerResolver("balance_%s", (provider, player, matcher) -> { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; - return provider.getAccount(player, world).map(Account::getBalance).orElse(BigDecimal.ZERO).toPlainString(); + return provider.getAccount(player, world) + .map(account -> account.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO) + .toPlainString(); }); // %serviceio_balance_formatted% registerResolver("balance_formatted", (provider, player, matcher) -> { - return provider.format(provider.getAccount(player).map(Account::getBalance).orElse(BigDecimal.ZERO)); + var format = provider.getDefaultCurrency().format(provider.getAccount(player) + .map(account -> account.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO), Locale.US); + return PlainTextComponentSerializer.plainText().serialize(format); }); // %serviceio_balance_formatted_% registerResolver("balance_formatted_%s", (provider, player, matcher) -> { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; - return provider.format(provider.getAccount(player, world).map(Account::getBalance).orElse(BigDecimal.ZERO)); + var format = provider.getDefaultCurrency().format(provider.getAccount(player, world) + .map(account -> account.getBalance(provider.getDefaultCurrency())) + .orElse(BigDecimal.ZERO), Locale.US); + return PlainTextComponentSerializer.plainText().serialize(format); }); } } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java index b8813dfe..a81bf0df 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java @@ -1,5 +1,6 @@ package net.thenextlvl.service.wrapper; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.EconomyResponse; import net.thenextlvl.service.api.economy.Account; @@ -52,22 +53,25 @@ public boolean hasBankSupport() { @Override public int fractionalDigits() { - return economyController.fractionalDigits(); + return economyController.getDefaultCurrency().getFractionalDigits(); } @Override public String format(double amount) { - return economyController.format(amount); + var format = economyController.getDefaultCurrency().format(amount, Locale.US); + return PlainTextComponentSerializer.plainText().serialize(format); } @Override public String currencyNamePlural() { - return economyController.getCurrencyNamePlural(Locale.US); + var name = economyController.getDefaultCurrency().getDisplayNamePlural(Locale.US); + return PlainTextComponentSerializer.plainText().serialize(name); } @Override public String currencyNameSingular() { - return economyController.getCurrencyNameSingular(Locale.US); + var name = economyController.getDefaultCurrency().getDisplayNameSingular(Locale.US); + return PlainTextComponentSerializer.plainText().serialize(name); } @Override @@ -110,7 +114,7 @@ public double getBalance(@Nullable String playerName, @Nullable String worldName @Override public double getBalance(@Nullable OfflinePlayer player, @Nullable String worldName) { return getAccount(player, worldName) - .map(Account::getBalance) + .map(account -> account.getBalance(economyController.getDefaultCurrency())) .map(Number::doubleValue) .orElse(0.0); } @@ -154,8 +158,8 @@ public EconomyResponse withdrawPlayer(@Nullable String playerName, @Nullable Str @Override public EconomyResponse withdrawPlayer(@Nullable OfflinePlayer player, @Nullable String worldName, double amount) { return getAccount(player, worldName).map(account -> { - var balance = account.getBalance(); - var withdraw = account.withdraw(amount); + var balance = account.getBalance(economyController.getDefaultCurrency()); + var withdraw = account.withdraw(amount, economyController.getDefaultCurrency()); var responseType = amount != 0 && balance.equals(withdraw) ? FAILURE : SUCCESS; return new EconomyResponse(amount, withdraw.doubleValue(), responseType, null); }).orElseGet(() -> new EconomyResponse(amount, 0, FAILURE, null)); @@ -180,8 +184,8 @@ public EconomyResponse depositPlayer(@Nullable String name, @Nullable String wor @Override public EconomyResponse depositPlayer(@Nullable OfflinePlayer player, @Nullable String worldName, double amount) { return getAccount(player, worldName).map(account -> { - var balance = account.getBalance(); - var deposit = account.deposit(amount); + var balance = account.getBalance(economyController.getDefaultCurrency()); + var deposit = account.deposit(amount, economyController.getDefaultCurrency()); var responseType = amount != 0 && balance.equals(deposit) ? FAILURE : SUCCESS; return new EconomyResponse(amount, deposit.doubleValue(), responseType, null); }).orElseGet(() -> new EconomyResponse(amount, 0, FAILURE, null)); @@ -211,7 +215,8 @@ public EconomyResponse deleteBank(String name) { public EconomyResponse bankBalance(String name) { try { var bank = bankController().tryGetBank(name).join(); - return new EconomyResponse(0, bank.getBalance().doubleValue(), SUCCESS, null); + var balance = bank.getBalance(economyController.getDefaultCurrency()); + return new EconomyResponse(0, balance.doubleValue(), SUCCESS, null); } catch (Exception e) { return new EconomyResponse(0, 0, FAILURE, e.getMessage()); } @@ -221,7 +226,7 @@ public EconomyResponse bankBalance(String name) { public EconomyResponse bankHas(String name, double amount) { try { var bank = bankController().tryGetBank(name).join(); - var balance = bank.getBalance().doubleValue(); + var balance = bank.getBalance(economyController.getDefaultCurrency()).doubleValue(); var response = balance >= amount ? SUCCESS : FAILURE; return new EconomyResponse(amount, balance, response, null); } catch (Exception e) { @@ -233,7 +238,7 @@ public EconomyResponse bankHas(String name, double amount) { public EconomyResponse bankWithdraw(String name, double amount) { try { var bank = bankController().tryGetBank(name).join(); - var balance = bank.withdraw(amount).doubleValue(); + var balance = bank.withdraw(amount, economyController.getDefaultCurrency()).doubleValue(); var response = balance >= amount ? SUCCESS : FAILURE; return new EconomyResponse(amount, balance, response, null); } catch (Exception e) { @@ -245,7 +250,7 @@ public EconomyResponse bankWithdraw(String name, double amount) { public EconomyResponse bankDeposit(String name, double amount) { try { var bank = bankController().tryGetBank(name).join(); - var balance = bank.deposit(amount).doubleValue(); + var balance = bank.deposit(amount, economyController.getDefaultCurrency()).doubleValue(); var response = balance >= amount ? SUCCESS : FAILURE; return new EconomyResponse(amount, balance, response, null); } catch (Exception e) { @@ -264,7 +269,8 @@ public EconomyResponse isBankOwner(String name, @Nullable OfflinePlayer player) try { var bank = bankController().tryGetBank(name).join(); var response = player != null && bank.getOwner().equals(player.getUniqueId()) ? SUCCESS : FAILURE; - return new EconomyResponse(0, bank.getBalance().doubleValue(), response, null); + var balance = bank.getBalance(economyController.getDefaultCurrency()); + return new EconomyResponse(0, balance.doubleValue(), response, null); } catch (Exception e) { return new EconomyResponse(0, 0, FAILURE, e.getMessage()); } @@ -281,7 +287,8 @@ public EconomyResponse isBankMember(String name, @Nullable OfflinePlayer player) try { var bank = bankController().tryGetBank(name).join(); var response = player != null && bank.isMember(player.getUniqueId()) ? SUCCESS : FAILURE; - return new EconomyResponse(0, bank.getBalance().doubleValue(), response, null); + var balance = bank.getBalance(economyController.getDefaultCurrency()); + return new EconomyResponse(0, balance.doubleValue(), response, null); } catch (Exception e) { return new EconomyResponse(0, 0, FAILURE, e.getMessage()); } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java index 2a43c46e..be934a62 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java @@ -4,7 +4,6 @@ import net.milkbowl.vault.economy.EconomyResponse; import net.thenextlvl.service.api.economy.bank.Bank; import net.thenextlvl.service.api.economy.bank.BankController; -import net.thenextlvl.service.wrapper.Wrapper; import net.thenextlvl.service.wrapper.service.model.WrappedBank; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -22,20 +21,17 @@ public class BankServiceWrapper implements BankController, Wrapper { private final Economy economy; private final Plugin provider; + private final Currency currency; public BankServiceWrapper(Economy economy, Plugin provider) { + this.currency = new WrappedCurrency(economy); this.economy = economy; this.provider = provider; } @Override - public String format(Number amount) { - return economy.format(amount.doubleValue()); - } - - @Override - public int fractionalDigits() { - return economy.fractionalDigits(); + public Currency getDefaultCurrency() { + return currency; } @Override @@ -103,7 +99,7 @@ public CompletableFuture deleteBank(UUID uuid, World world) { @Override public @Unmodifiable Set getBanks() { return economy.getBanks().stream() - .map(bank -> new WrappedBank(bank, null, economy, provider)) + .map(bank -> new WrappedBank(bank, null, economy, plugin)) .collect(Collectors.toUnmodifiableSet()); } @@ -114,7 +110,7 @@ public CompletableFuture deleteBank(UUID uuid, World world) { @Override public Optional getBank(String name) { - return Optional.of(new WrappedBank(name, null, economy, provider)); + return Optional.of(new WrappedBank(this, name, null, economy, provider)); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index 20d3c8e0..ddc90cf5 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -2,6 +2,7 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.Account; +import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.EconomyController; import net.thenextlvl.service.wrapper.Wrapper; import net.thenextlvl.service.wrapper.service.model.WrappedAccount; @@ -12,7 +13,6 @@ import org.jspecify.annotations.NullMarked; import java.util.Arrays; -import java.util.Locale; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -21,34 +21,16 @@ @NullMarked public class EconomyServiceWrapper implements EconomyController, Wrapper { + private final Currency currency; private final Economy economy; private final Plugin provider; public EconomyServiceWrapper(Economy economy, Plugin provider) { + this.currency = new WrappedCurrency(economy); this.economy = economy; this.provider = provider; } - @Override - public String format(Number amount) { - return economy.format(amount.doubleValue()); - } - - @Override - public String getCurrencyNamePlural(Locale locale) { - return economy.currencyNamePlural(); - } - - @Override - public String getCurrencyNameSingular(Locale locale) { - return economy.currencyNameSingular(); - } - - @Override - public String getCurrencySymbol() { - return ""; - } - @Override public CompletableFuture<@Unmodifiable Set> loadAccounts() { return CompletableFuture.completedFuture(getAccounts()); @@ -58,20 +40,20 @@ public String getCurrencySymbol() { public @Unmodifiable Set getAccounts() { return Arrays.stream(provider.getServer().getOfflinePlayers()) .filter(economy::hasAccount) - .map(player -> new WrappedAccount(null, economy, player)) + .map(player -> new WrappedAccount(this, null, economy, player)) .collect(Collectors.toUnmodifiableSet()); } @Override public Optional getAccount(OfflinePlayer player) { if (!economy.hasAccount(player)) return Optional.empty(); - return Optional.of(new WrappedAccount(null, economy, player)); + return Optional.of(new WrappedAccount(this, null, economy, player)); } @Override public Optional getAccount(OfflinePlayer player, World world) { if (!economy.hasAccount(player, world.getName())) return Optional.empty(); - return Optional.of(new WrappedAccount(world, economy, player)); + return Optional.of(new WrappedAccount(this, world, economy, player)); } @Override @@ -137,8 +119,8 @@ public CompletableFuture deleteAccount(UUID uuid, World world) { } @Override - public int fractionalDigits() { - return economy.fractionalDigits(); + public Currency getDefaultCurrency() { + return currency; } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/WrappedCurrency.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/WrappedCurrency.java new file mode 100644 index 00000000..fd016cc4 --- /dev/null +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/WrappedCurrency.java @@ -0,0 +1,47 @@ +package net.thenextlvl.service.wrapper.service; + +import net.kyori.adventure.text.Component; +import net.milkbowl.vault.economy.Economy; +import net.thenextlvl.service.api.economy.currency.Currency; +import org.jspecify.annotations.NullMarked; + +import java.util.Locale; + +@NullMarked +public class WrappedCurrency implements Currency { + private final Economy economy; + + public WrappedCurrency(Economy economy) { + this.economy = economy; + } + + @Override + public String getName() { + return economy.getName(); + } + + @Override + public Component getDisplayNameSingular(Locale locale) { + return Component.text(economy.currencyNameSingular()); + } + + @Override + public Component getDisplayNamePlural(Locale locale) { + return Component.text(economy.currencyNamePlural()); + } + + @Override + public Component getSymbol() { + return Component.empty(); + } + + @Override + public Component format(Number amount, Locale locale) { + return Component.text(economy.format(amount.doubleValue())); + } + + @Override + public int getFractionalDigits() { + return economy.fractionalDigits(); + } +} diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java index 42e15641..6eb830bb 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java @@ -2,6 +2,9 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.Account; +import net.thenextlvl.service.api.economy.currency.Currency; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; +import net.thenextlvl.service.api.economy.EconomyController; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jspecify.annotations.NullMarked; @@ -26,24 +29,24 @@ public WrappedAccount(EconomyController controller, @Nullable World world, Econo } @Override - public BigDecimal deposit(Number amount) { public CurrencyHolder getController() { return controller; } @Override + public BigDecimal deposit(Number amount, Currency currency) { var response = economy.depositPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); return new BigDecimal(response.balance); } @Override - public BigDecimal getBalance() { + public BigDecimal getBalance(Currency currency) { var balance = economy.getBalance(holder, world != null ? world.getName() : null); return new BigDecimal(balance); } @Override - public BigDecimal withdraw(Number amount) { + public BigDecimal withdraw(Number amount, Currency currency) { var response = economy.withdrawPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); return new BigDecimal(response.balance); } @@ -59,9 +62,9 @@ public UUID getOwner() { } @Override - public void setBalance(Number balance) { - var difference = balance.doubleValue() - getBalance().doubleValue(); - if (difference > 0) deposit(difference); - else if (difference < 0) withdraw(-difference); + public void setBalance(Number balance, Currency currency) { + var difference = balance.doubleValue() - getBalance(currency).doubleValue(); + if (difference > 0) deposit(difference, currency); + else if (difference < 0) withdraw(-difference, currency); } } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java index e9badfb0..639cf5bc 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java @@ -1,6 +1,7 @@ package net.thenextlvl.service.wrapper.service.model; import net.milkbowl.vault.economy.Economy; +import net.thenextlvl.service.ServicePlugin; import net.thenextlvl.service.api.economy.bank.Bank; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -31,17 +32,17 @@ public WrappedBank(String name, @Nullable World world, Economy economy, Plugin p } @Override - public BigDecimal deposit(Number amount) { + public BigDecimal deposit(Number amount, Currency currency) { return new BigDecimal(economy.bankDeposit(name, amount.doubleValue()).balance); } @Override - public BigDecimal getBalance() { + public BigDecimal getBalance(Currency currency) { return new BigDecimal(economy.bankBalance(name).balance); } @Override - public BigDecimal withdraw(Number amount) { + public BigDecimal withdraw(Number amount, Currency currency) { return new BigDecimal(economy.bankWithdraw(name, amount.doubleValue()).balance); } @@ -60,18 +61,18 @@ public UUID getOwner() { } @Override - public void setBalance(Number balance) { - var difference = balance.doubleValue() - getBalance().doubleValue(); - if (difference > 0) deposit(difference); - else if (difference < 0) withdraw(-difference); + public void setBalance(Number balance, Currency currency) { + var difference = balance.doubleValue() - getBalance(currency).doubleValue(); + if (difference > 0) deposit(difference, currency); + else if (difference < 0) withdraw(-difference, currency); } @Override public @Unmodifiable Set getMembers() { return Arrays.stream(provider.getServer().getOfflinePlayers()) - .filter(player -> economy.isBankMember(name, player).transactionSuccess()) - .map(OfflinePlayer::getUniqueId) - .collect(Collectors.toUnmodifiableSet()); + .filter(player -> economy.isBankMember(name, player).transactionSuccess()) + .map(OfflinePlayer::getUniqueId) + .collect(Collectors.toUnmodifiableSet()); } @Override diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index 17935951..d7844f90 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -1,5 +1,6 @@ package net.thenextlvl.service.api.economy; +import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.World; import org.jspecify.annotations.NullMarked; @@ -25,23 +26,55 @@ public interface Account extends Comparable { * * @param amount the amount to be deposited * @return the new balance after the deposit + * @deprecated use {@link #deposit(Number, Currency)} */ - BigDecimal deposit(Number amount); + @Deprecated(forRemoval = true, since = "2.4.0") + default BigDecimal deposit(Number amount) { + return deposit(amount, getController().getDefaultCurrency()); + } + + /** + * Deposits the specified amount of the given currency into the account balance. + * + * @param amount the amount to be deposited + * @param currency the currency that is being deposited + * @return the new balance after the deposit + */ + BigDecimal deposit(Number amount, Currency currency); /** * Retrieves the balance of the account. * * @return the balance of the account + * @deprecated use {@link #getBalance(Currency)} */ - BigDecimal getBalance(); + @Deprecated(forRemoval = true, since = "2.4.0") + default BigDecimal getBalance() { + return getBalance(getController().getDefaultCurrency()); + } + + BigDecimal getBalance(Currency currency); /** * Withdraws the specified amount from the account balance. * * @param amount the amount to be withdrawn * @return the new balance after the withdrawal + * @deprecated use {@link #withdraw(Number, Currency)} + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default BigDecimal withdraw(Number amount) { + return withdraw(amount, getController().getDefaultCurrency()); + } + + /** + * Withdraws the specified amount of the given currency from the account balance. + * + * @param amount the amount to be withdrawn + * @param currency the currency in which the withdrawal is to be made + * @return the new balance after the withdrawal */ - BigDecimal withdraw(Number amount); + BigDecimal withdraw(Number amount, Currency currency); /** * Returns an optional containing the world associated with this account. @@ -63,16 +96,42 @@ public interface Account extends Comparable { * @param account the account to be compared * @return a negative integer, zero, or a positive integer if this account is * less than, equal to, or greater than the specified account + * @deprecated use {@link #compareTo(Account, Currency)} */ @Override + @Deprecated(forRemoval = true, since = "2.4.0") default int compareTo(Account account) { - return getBalance().compareTo(account.getBalance()); + return compareTo(account, getController().getDefaultCurrency()); + } + + /** + * Compares this account with another account based on their balances in the specified currency. + * + * @param account the account to be compared + * @param currency the currency in which the balances should be compared + * @return a negative integer, zero, or a positive integer if this account's balance + * is less than, equal to, or greater than the specified account's balance + */ + default int compareTo(Account account, Currency currency) { + return getBalance(currency).compareTo(account.getBalance(currency)); } /** * Sets the balance of the account to the specified value. * * @param balance the new balance of the account + * @deprecated use {@link #setBalance(Number, Currency)} + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default void setBalance(Number balance) { + setBalance(balance, getController().getDefaultCurrency()); + } + + /** + * Sets the balance of the account to the specified value in the given currency. + * + * @param balance the new balance to be set + * @param currency the currency of the balance */ - void setBalance(Number balance); + void setBalance(Number balance, Currency currency); } From 619d4eb76c62d2e569d02133de06274987145241 Mon Sep 17 00:00:00 2001 From: david Date: Mon, 14 Jul 2025 20:08:16 +0200 Subject: [PATCH 04/32] Added TODOs for improving `ServiceConvertCommand` Outlined areas for improvement, including API cleanup, error handling, data loss warnings, and progress tracking. --- .../net/thenextlvl/service/command/ServiceConvertCommand.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java b/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java index 44c9dcbd..a6825396 100644 --- a/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java +++ b/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java @@ -66,6 +66,8 @@ public CompletableFuture convert(OfflinePlayer player, BankController sour bank.getWorld().map(world -> target.createBank(bank.getOwner(), bank.getName(), world)) .orElseGet(() -> target.createBank(bank.getOwner(), bank.getName())) .thenAccept(targetBank -> { + // todo: convert all currencies + // todo: convert balance with currencies targetBank.setBalance(bank.getBalance()); bank.getMembers().forEach(targetBank::addMember); }))); From 65b6d1b694fbbd610bfa5218517010c2ed70262a Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 19:49:08 +0200 Subject: [PATCH 05/32] Bumped version to 3.0.0-pre1 Updated deprecation annotations to mark methods for removal in version 3.0.0. Added `@since 3.0.0` annotations to newly introduced methods in `CurrencyHolder`. --- .../net/thenextlvl/service/api/economy/Account.java | 10 +++++----- .../service/api/economy/EconomyController.java | 6 +++--- .../service/api/economy/currency/CurrencyHolder.java | 11 +++++++++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index d7844f90..f9517a0c 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -28,7 +28,7 @@ public interface Account extends Comparable { * @return the new balance after the deposit * @deprecated use {@link #deposit(Number, Currency)} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default BigDecimal deposit(Number amount) { return deposit(amount, getController().getDefaultCurrency()); } @@ -48,7 +48,7 @@ default BigDecimal deposit(Number amount) { * @return the balance of the account * @deprecated use {@link #getBalance(Currency)} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default BigDecimal getBalance() { return getBalance(getController().getDefaultCurrency()); } @@ -62,7 +62,7 @@ default BigDecimal getBalance() { * @return the new balance after the withdrawal * @deprecated use {@link #withdraw(Number, Currency)} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default BigDecimal withdraw(Number amount) { return withdraw(amount, getController().getDefaultCurrency()); } @@ -99,7 +99,7 @@ default BigDecimal withdraw(Number amount) { * @deprecated use {@link #compareTo(Account, Currency)} */ @Override - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default int compareTo(Account account) { return compareTo(account, getController().getDefaultCurrency()); } @@ -122,7 +122,7 @@ default int compareTo(Account account, Currency currency) { * @param balance the new balance of the account * @deprecated use {@link #setBalance(Number, Currency)} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default void setBalance(Number balance) { setBalance(balance, getController().getDefaultCurrency()); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index 1b288a36..dab3eda1 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -28,7 +28,7 @@ public interface EconomyController extends Controller, CurrencyHolder { * @return the plural form of the currency name as a string * @deprecated use {@link Currency#getDisplayNamePlural(Locale)} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default String getCurrencyNamePlural(Locale locale) { return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getDisplayNamePlural(locale)); } @@ -40,7 +40,7 @@ default String getCurrencyNamePlural(Locale locale) { * @return the name of the currency as a string * @deprecated use {@link Currency#getDisplayNameSingular(Locale)} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default String getCurrencyNameSingular(Locale locale) { return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getDisplayNameSingular(locale)); } @@ -51,7 +51,7 @@ default String getCurrencyNameSingular(Locale locale) { * @return the currency symbol as a string * @deprecated use {@link Currency#getSymbol()} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default String getCurrencySymbol() { return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getSymbol()); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index b265241d..70d6ebba 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -21,7 +21,7 @@ public interface CurrencyHolder { * @return the formatted amount as a string * @deprecated use {@link Currency#format(Number, Locale)} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default String format(Number amount) { return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().format(amount, Locale.US)); } @@ -32,7 +32,7 @@ default String format(Number amount) { * @return the number of fractional digits used for formatting currency amounts * @deprecated use {@link Currency#getFractionalDigits()} */ - @Deprecated(forRemoval = true, since = "2.4.0") + @Deprecated(forRemoval = true, since = "3.0.0") default int fractionalDigits() { return getDefaultCurrency().getFractionalDigits(); } @@ -42,6 +42,7 @@ default int fractionalDigits() { * * @return an unmodifiable set of currencies * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + * @since 3.0.0 */ default @Unmodifiable Set getCurrencies() { throw new UnsupportedOperationException("Not implemented yet"); @@ -53,6 +54,7 @@ default int fractionalDigits() { * @param name the name of the currency to retrieve * @return an {@code Optional} containing the currency, or empty * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + * @since 3.0.0 */ default Optional getCurrency(String name) { throw new UnsupportedOperationException("Not implemented yet"); @@ -64,6 +66,7 @@ default Optional getCurrency(String name) { * @param name the name of the currency to check for existence * @return {@code true} if the currency exists, otherwise {@code false} * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + * @since 3.0.0 */ default boolean hasCurrency(String name) { throw new UnsupportedOperationException("Not implemented yet"); @@ -78,6 +81,7 @@ default boolean hasCurrency(String name) { * @param builder a consumer to configure the {@link Currency.Builder} for currency creation * @return an optional containing the created {@link Currency}, or empty * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + * @since 3.0.0 */ default Optional createCurrency(String name, Consumer builder) { throw new UnsupportedOperationException("Not implemented yet"); @@ -89,6 +93,7 @@ default Optional createCurrency(String name, Consumer Date: Tue, 15 Jul 2025 19:52:15 +0200 Subject: [PATCH 06/32] Added `@Contract` annotations for API methods Enhanced method contracts with `@Contract` annotations to improve nullability and immutability handling while clarifying method behaviors. --- .../net/thenextlvl/service/api/economy/Account.java | 2 ++ .../service/api/economy/EconomyController.java | 13 ++++++++++--- .../thenextlvl/service/api/economy/bank/Bank.java | 2 ++ .../service/api/economy/bank/BankController.java | 7 ++++++- .../service/api/economy/currency/Currency.java | 11 +++++++++++ .../api/economy/currency/CurrencyHolder.java | 4 ++++ 6 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index f9517a0c..cd4d2e52 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -3,6 +3,7 @@ import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.World; +import org.jetbrains.annotations.Contract; import org.jspecify.annotations.NullMarked; import java.math.BigDecimal; @@ -20,6 +21,7 @@ public interface Account extends Comparable { * @return the {@code CurrencyHolder} capable of managing currencies for the account */ CurrencyHolder getController(); + @Contract(pure = true) /** * Deposits the specified amount into the account balance. diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index dab3eda1..b5458ecd 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -6,6 +6,7 @@ import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; @@ -167,6 +168,7 @@ default CompletableFuture> tryGetAccount(UUID uuid, World worl * @return a CompletableFuture that will complete with the created account * @throws IllegalStateException if a similar account already exists */ + @Contract("_ -> new") default CompletableFuture createAccount(OfflinePlayer player) { return createAccount(player.getUniqueId()); } @@ -178,7 +180,8 @@ default CompletableFuture createAccount(OfflinePlayer player) { * @param world the world in which the player's account will be created * @return a CompletableFuture that will complete with the created account */ - default CompletableFuture createAccount(OfflinePlayer player, World world) { + @Contract("_, _ -> new") + default CompletableFuture createAccount(OfflinePlayer player, @Nullable World world) { return createAccount(player.getUniqueId(), world); } @@ -188,7 +191,10 @@ default CompletableFuture createAccount(OfflinePlayer player, World wor * @param uuid the uuid of the account to be created * @return a CompletableFuture that will complete with the created account */ - CompletableFuture createAccount(UUID uuid); + @Contract("_ -> new") + default CompletableFuture createAccount(UUID uuid) { + return createAccount(uuid, null); + } /** * Creates an account with the given uuid and world. @@ -197,7 +203,8 @@ default CompletableFuture createAccount(OfflinePlayer player, World wor * @param world the world in which the account will be created * @return a CompletableFuture that will complete with the created account */ - CompletableFuture createAccount(UUID uuid, World world); + @Contract("_, _ -> new") + CompletableFuture createAccount(UUID uuid, @Nullable World world); /** * Loads the account for the specified player asynchronously. diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java index 023d72e4..e2ade398 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java @@ -2,6 +2,7 @@ import net.thenextlvl.service.api.economy.Account; import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; @@ -28,6 +29,7 @@ public interface Bank extends Account { * * @return the name of the bank. */ + @Contract(pure = true) String getName(); /** diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index d640c250..591eb4c0 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -4,6 +4,7 @@ import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; @@ -23,6 +24,7 @@ public interface BankController extends Controller, CurrencyHolder { * @param name the name of the bank (must be unique) * @return a CompletableFuture that completes with the created bank */ + @Contract("_, _ -> new") default CompletableFuture createBank(OfflinePlayer player, String name) { return createBank(player.getUniqueId(), name); } @@ -37,7 +39,8 @@ default CompletableFuture createBank(OfflinePlayer player, String name) { * @param world the world in which the bank is located * @return a CompletableFuture that completes with the created bank */ - default CompletableFuture createBank(OfflinePlayer player, String name, World world) { + @Contract("_, _, _ -> new") + default CompletableFuture createBank(OfflinePlayer player, String name, @Nullable World world) { return createBank(player.getUniqueId(), name, world); } @@ -51,6 +54,7 @@ default CompletableFuture createBank(OfflinePlayer player, String name, Wo * @return a CompletableFuture that completes with the created bank */ CompletableFuture createBank(UUID uuid, String name); + @Contract("_, _ -> new") /** * Creates a new bank with the provided UUID, name, and world. @@ -63,6 +67,7 @@ default CompletableFuture createBank(OfflinePlayer player, String name, Wo * @return a CompletableFuture that completes with the created bank */ CompletableFuture createBank(UUID uuid, String name, World world); + @Contract("_, _, _ -> new") /** * Loads a bank asynchronously with the specified player. diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index 370cbe2b..5afbef48 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -4,6 +4,7 @@ import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; import org.jspecify.annotations.NullMarked; import java.util.Locale; @@ -17,6 +18,7 @@ public interface Currency { * * @return the name of the currency as a string */ + @Contract(pure = true) String getName(); /** @@ -112,6 +114,7 @@ interface Builder { * @param locale the locale for which the singular display name is being set * @return the builder instance for chaining */ + @Contract(value = "_, _ -> this", pure = true) Builder displayNameSingular(Component name, Locale locale); /** @@ -120,6 +123,7 @@ interface Builder { * @param locale the locale for which the singular display name should be retrieved * @return an {@code Optional} containing the singular display name as a {@code Component}, or empty */ + @Contract(value = "_ -> new") Optional displayNameSingular(Locale locale); /** @@ -129,6 +133,7 @@ interface Builder { * @param locale the locale for which the plural display name is being set * @return the builder instance for chaining */ + @Contract(value = "_, _ -> this", pure = true) Builder displayNamePlural(Component name, Locale locale); /** @@ -137,6 +142,7 @@ interface Builder { * @param locale the locale for which the plural display name should be retrieved * @return an {@code Optional} containing the plural display name as a {@code Component}, or empty */ + @Contract(value = "_ -> new") Optional displayNamePlural(Locale locale); /** @@ -145,6 +151,7 @@ interface Builder { * @param symbol the symbol component to represent the currency * @return the builder instance for chaining */ + @Contract(value = "_ -> this", pure = true) Builder symbol(Component symbol); /** @@ -152,6 +159,7 @@ interface Builder { * * @return an {@code Optional} containing the symbol as a {@code Component}, or empty */ + @Contract(value = "-> new") Optional symbol(); /** @@ -164,6 +172,7 @@ interface Builder { * @return the builder instance for chaining * @throws IllegalArgumentException if {@code fractionalDigits} is negative */ + @Contract(value = "_ -> this") Builder fractionalDigits(int fractionalDigits) throws IllegalArgumentException; /** @@ -174,6 +183,7 @@ interface Builder { * * @return an {@code OptionalInt} containing the number of fractional digits, or empty */ + @Contract(value = "-> new") OptionalInt fractionalDigits(); /** @@ -181,6 +191,7 @@ interface Builder { * * @return the constructed {@link Currency} instance */ + @Contract("-> new") @ApiStatus.OverrideOnly Currency build(); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index 70d6ebba..5972d7e2 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -1,6 +1,7 @@ package net.thenextlvl.service.api.economy.currency; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import java.util.Locale; @@ -83,6 +84,7 @@ default boolean hasCurrency(String name) { * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} * @since 3.0.0 */ + @Contract("_, _ -> new") default Optional createCurrency(String name, Consumer builder) { throw new UnsupportedOperationException("Not implemented yet"); } @@ -105,6 +107,7 @@ default boolean deleteCurrency(String name) { * @return the default currency * @since 3.0.0 */ + @Contract(pure = true) Currency getDefaultCurrency(); /** @@ -119,6 +122,7 @@ default boolean deleteCurrency(String name) { * @see #hasCurrency(String) * @since 3.0.0 */ + @Contract(pure = true) default boolean hasMultiCurrencySupport() { return false; } From 8b54dccb568f8ea04bc1f44dfd2d64cd2a157d45 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:00:49 +0200 Subject: [PATCH 07/32] Added support for nullable `World` parameters Refactored `EconomyController` and `BankController` methods to include `@Nullable` `World` parameters. Adjusted method signatures and default behaviors to accommodate this change. --- .../wrapper/service/BankServiceWrapper.java | 55 +++-------- .../service/EconomyServiceWrapper.java | 77 ++++++--------- .../api/economy/EconomyController.java | 89 +++++++++++------- .../api/economy/bank/BankController.java | 94 ++++++++++--------- 4 files changed, 144 insertions(+), 171 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java index be934a62..f7298460 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java @@ -10,6 +10,7 @@ import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.Set; @@ -35,48 +36,28 @@ public Currency getDefaultCurrency() { } @Override - public CompletableFuture createBank(OfflinePlayer player, String name) { + public CompletableFuture createBank(OfflinePlayer player, String name, @Nullable World world) { return CompletableFuture.completedFuture(economy.createBank(name, player)) .thenApply(bank -> getBank(name).orElseThrow()); } @Override - public CompletableFuture createBank(OfflinePlayer player, String name, World world) { - return createBank(player, name); - } - - @Override - public CompletableFuture createBank(UUID uuid, String name) { - return createBank(provider.getServer().getOfflinePlayer(uuid), name); - } - - @Override - public CompletableFuture createBank(UUID uuid, String name, World world) { + public CompletableFuture createBank(UUID uuid, String name, @Nullable World world) { return createBank(provider.getServer().getOfflinePlayer(uuid), name, world); } @Override - public CompletableFuture loadBank(String name) { - return CompletableFuture.completedFuture(getBank(name).orElse(null)); + public CompletableFuture> loadBank(String name) { + return CompletableFuture.completedFuture(getBank(name)); } @Override - public CompletableFuture loadBank(UUID uuid) { - return CompletableFuture.completedFuture(getBank(uuid).orElse(null)); + public CompletableFuture> loadBank(UUID uuid, @Nullable World world) { + return CompletableFuture.completedFuture(getBank(uuid, world)); } @Override - public CompletableFuture loadBank(UUID uuid, World world) { - return CompletableFuture.completedFuture(getBank(uuid, world).orElse(null)); - } - - @Override - public CompletableFuture<@Unmodifiable Set> loadBanks() { - return CompletableFuture.completedFuture(getBanks()); - } - - @Override - public CompletableFuture<@Unmodifiable Set> loadBanks(World world) { + public CompletableFuture<@Unmodifiable Set> loadBanks(@Nullable World world) { return CompletableFuture.completedFuture(getBanks(world)); } @@ -87,40 +68,30 @@ public CompletableFuture deleteBank(String name) { } @Override - public CompletableFuture deleteBank(UUID uuid) { - return deleteBank(getBank(uuid).orElseThrow().getName()); - } - - @Override - public CompletableFuture deleteBank(UUID uuid, World world) { + public CompletableFuture deleteBank(UUID uuid, @Nullable World world) { return deleteBank(getBank(uuid, world).orElseThrow().getName()); } @Override public @Unmodifiable Set getBanks() { return economy.getBanks().stream() - .map(bank -> new WrappedBank(bank, null, economy, plugin)) + .map(bank -> new WrappedBank(this, bank, null, economy, plugin)) .collect(Collectors.toUnmodifiableSet()); } - @Override - public @Unmodifiable Set getBanks(World world) { - return getBanks(); - } - @Override public Optional getBank(String name) { return Optional.of(new WrappedBank(this, name, null, economy, provider)); } @Override - public Optional getBank(UUID uuid) { + public Optional getBank(UUID uuid, @Nullable World world) { return Optional.empty(); } @Override - public Optional getBank(UUID uuid, World world) { - return Optional.empty(); + public boolean hasMultiWorldSupport() { + return false; } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index ddc90cf5..5f4cb38b 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -2,17 +2,17 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.Account; -import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.EconomyController; -import net.thenextlvl.service.wrapper.Wrapper; import net.thenextlvl.service.wrapper.service.model.WrappedAccount; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Arrays; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -32,90 +32,67 @@ public EconomyServiceWrapper(Economy economy, Plugin provider) { } @Override - public CompletableFuture<@Unmodifiable Set> loadAccounts() { - return CompletableFuture.completedFuture(getAccounts()); + public CompletableFuture<@Unmodifiable Set> loadAccounts(@Nullable World world) { + return CompletableFuture.completedFuture(getAccounts(world)); } @Override - public @Unmodifiable Set getAccounts() { + public @Unmodifiable Set getAccounts(@Nullable World world) { return Arrays.stream(provider.getServer().getOfflinePlayers()) - .filter(economy::hasAccount) - .map(player -> new WrappedAccount(this, null, economy, player)) + .filter(player -> economy.hasAccount(player, world != null ? world.getName() : null)) + .map(player -> new WrappedAccount(this, world, economy, player)) .collect(Collectors.toUnmodifiableSet()); } @Override - public Optional getAccount(OfflinePlayer player) { - if (!economy.hasAccount(player)) return Optional.empty(); - return Optional.of(new WrappedAccount(this, null, economy, player)); - } - - @Override - public Optional getAccount(OfflinePlayer player, World world) { - if (!economy.hasAccount(player, world.getName())) return Optional.empty(); + public Optional getAccount(OfflinePlayer player, @Nullable World world) { + if (!economy.hasAccount(player, world != null ? world.getName() : null)) return Optional.empty(); return Optional.of(new WrappedAccount(this, world, economy, player)); } @Override - public Optional getAccount(UUID uuid) { - return getAccount(provider.getServer().getOfflinePlayer(uuid)); - } - - @Override - public Optional getAccount(UUID uuid, World world) { + public Optional getAccount(UUID uuid, @Nullable World world) { return getAccount(provider.getServer().getOfflinePlayer(uuid), world); } @Override - public CompletableFuture createAccount(OfflinePlayer player) { - return CompletableFuture.completedFuture(economy.createPlayerAccount(player)) - .thenApply(account -> getAccount(player).orElseThrow()); + public CompletableFuture createAccount(OfflinePlayer player, @Nullable World world) { + var created = economy.createPlayerAccount(player, world != null ? world.getName() : null); + if (created) loadAccount(player, world).thenApply(account -> account.orElseThrow(() -> + new IllegalStateException("Could not find player account after creation"))); + return CompletableFuture.failedFuture(new IllegalStateException( + "Similar account already exists" + )); } @Override - public CompletableFuture createAccount(OfflinePlayer player, World world) { - return CompletableFuture.completedFuture(economy.createPlayerAccount(player, world.getName())) - .thenApply(account -> getAccount(player, world).orElseThrow()); + public CompletableFuture createAccount(UUID uuid, @Nullable World world) { + return createAccount(plugin.getServer().getOfflinePlayer(uuid), world); } @Override - public CompletableFuture createAccount(UUID uuid) { - return createAccount(provider.getServer().getOfflinePlayer(uuid)); - } - - @Override - public CompletableFuture createAccount(UUID uuid, World world) { - return createAccount(provider.getServer().getOfflinePlayer(uuid), world); - } - - @Override - public CompletableFuture> loadAccount(OfflinePlayer player) { - return CompletableFuture.completedFuture(getAccount(player)); - } - - @Override - public CompletableFuture> loadAccount(OfflinePlayer player, World world) { + public CompletableFuture> loadAccount(OfflinePlayer player, @Nullable World world) { return CompletableFuture.completedFuture(getAccount(player, world)); } @Override - public CompletableFuture> loadAccount(UUID uuid) { - return loadAccount(provider.getServer().getOfflinePlayer(uuid)); + public CompletableFuture> loadAccount(UUID uuid, @Nullable World world) { + return loadAccount(provider.getServer().getOfflinePlayer(uuid), world); } @Override - public CompletableFuture> loadAccount(UUID uuid, World world) { - return loadAccount(provider.getServer().getOfflinePlayer(uuid), world); + public CompletableFuture deleteAccount(UUID uuid, @Nullable World world) { + return CompletableFuture.completedFuture(false); } @Override - public CompletableFuture deleteAccount(UUID uuid) { + public CompletableFuture deleteAccounts(List accounts, @Nullable World world) { return CompletableFuture.completedFuture(false); } @Override - public CompletableFuture deleteAccount(UUID uuid, World world) { - return CompletableFuture.completedFuture(false); + public boolean hasMultiWorldSupport() { + return false; } @Override diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index b5458ecd..f1e742ea 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -9,7 +9,9 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; +import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.Set; @@ -58,20 +60,41 @@ default String getCurrencySymbol() { } /** - * Loads all accounts asynchronously. + * Loads all accounts. * - * @return a {@link CompletableFuture} that, when completed, will provide a {@link Set} of {@link Account} objects representing - * all the accounts available. + * @return a {@link CompletableFuture} that completes with an unmodifiable {@link Set} of {@link Account} objects + * representing all available accounts */ - CompletableFuture<@Unmodifiable Set> loadAccounts(); + default CompletableFuture<@Unmodifiable Set> loadAccounts() { + return loadAccounts(null); + } + + /** + * Loads all accounts associated with the specified world. + * + * @param world the world for which the accounts are to be loaded + * @return a {@link CompletableFuture} that completes with an unmodifiable {@link Set} of {@link Account} objects + * representing all available accounts + */ + CompletableFuture<@Unmodifiable Set> loadAccounts(@Nullable World world); + + /** + * Retrieves all the accounts that are currently loaded. + * + * @return an unmodifiable set of accounts + */ + default @Unmodifiable Set getAccounts() { + return getAccounts(null); + } /** - * Retrieves all the accounts currently available. + * Retrieves all the accounts associated with the specified world that are currently loaded. * - * @return a set of accounts + * @param world the world for which the accounts are to be retrieved + * @return an unmodifiable set of accounts for the given world */ @Unmodifiable - Set getAccounts(); + Set getAccounts(@Nullable World world); /** * Retrieve the account for the specified player. @@ -80,7 +103,7 @@ default String getCurrencySymbol() { * @return an optional containing the account, or empty */ default Optional getAccount(OfflinePlayer player) { - return getAccount(player.getUniqueId()); + return getAccount(player, null); } /** @@ -90,7 +113,7 @@ default Optional getAccount(OfflinePlayer player) { * @param world the world in which the account is located * @return an optional containing the account, or empty */ - default Optional getAccount(OfflinePlayer player, World world) { + default Optional getAccount(OfflinePlayer player, @Nullable World world) { return getAccount(player.getUniqueId(), world); } @@ -100,7 +123,9 @@ default Optional getAccount(OfflinePlayer player, World world) { * @param uuid the uuid of the account to be retrieved * @return an optional containing the account, or empty */ - Optional getAccount(UUID uuid); + default Optional getAccount(UUID uuid) { + return getAccount(uuid, null); + } /** * Retrieve the account for the specified uuid and world. @@ -109,7 +134,7 @@ default Optional getAccount(OfflinePlayer player, World world) { * @param world the world in which the account is located * @return an optional containing the account, or empty */ - Optional getAccount(UUID uuid, World world); + Optional getAccount(UUID uuid, @Nullable World world); /** * Retrieve the account for the specified player or try to load it. @@ -118,9 +143,7 @@ default Optional getAccount(OfflinePlayer player, World world) { * @return a CompletableFuture that will complete with the retrieved account */ default CompletableFuture> tryGetAccount(OfflinePlayer player) { - return getAccount(player) - .map(account -> CompletableFuture.completedFuture(Optional.of(account))) - .orElseGet(() -> loadAccount(player)); + return tryGetAccount(player, null); } /** @@ -130,10 +153,8 @@ default CompletableFuture> tryGetAccount(OfflinePlayer player) * @param world the world in which the account is located * @return a CompletableFuture that will complete with the retrieved account */ - default CompletableFuture> tryGetAccount(OfflinePlayer player, World world) { - return getAccount(player, world) - .map(account -> CompletableFuture.completedFuture(Optional.of(account))) - .orElseGet(() -> loadAccount(player, world)); + default CompletableFuture> tryGetAccount(OfflinePlayer player, @Nullable World world) { + return tryGetAccount(player.getUniqueId(), world); } /** @@ -143,9 +164,7 @@ default CompletableFuture> tryGetAccount(OfflinePlayer player, * @return a CompletableFuture that will complete with the retrieved account */ default CompletableFuture> tryGetAccount(UUID uuid) { - return getAccount(uuid) - .map(account -> CompletableFuture.completedFuture(Optional.of(account))) - .orElseGet(() -> loadAccount(uuid)); + return tryGetAccount(uuid, null); } /** @@ -155,7 +174,7 @@ default CompletableFuture> tryGetAccount(UUID uuid) { * @param world the world in which the account is located * @return a CompletableFuture that will complete with the retrieved account */ - default CompletableFuture> tryGetAccount(UUID uuid, World world) { + default CompletableFuture> tryGetAccount(UUID uuid, @Nullable World world) { return getAccount(uuid, world) .map(account -> CompletableFuture.completedFuture(Optional.of(account))) .orElseGet(() -> loadAccount(uuid, world)); @@ -170,7 +189,7 @@ default CompletableFuture> tryGetAccount(UUID uuid, World worl */ @Contract("_ -> new") default CompletableFuture createAccount(OfflinePlayer player) { - return createAccount(player.getUniqueId()); + return createAccount(player, null); } /** @@ -213,7 +232,7 @@ default CompletableFuture createAccount(UUID uuid) { * @return a CompletableFuture that will complete with the retrieved account */ default CompletableFuture> loadAccount(OfflinePlayer player) { - return loadAccount(player.getUniqueId()); + return loadAccount(player, null); } /** @@ -223,7 +242,7 @@ default CompletableFuture> loadAccount(OfflinePlayer player) { * @param world the world in which the account is located * @return a CompletableFuture that will complete with the retrieved account */ - default CompletableFuture> loadAccount(OfflinePlayer player, World world) { + default CompletableFuture> loadAccount(OfflinePlayer player, @Nullable World world) { return loadAccount(player.getUniqueId(), world); } @@ -233,7 +252,9 @@ default CompletableFuture> loadAccount(OfflinePlayer player, W * @param uuid the uuid of the account to be retrieved * @return a CompletableFuture that will complete with the retrieved account */ - CompletableFuture> loadAccount(UUID uuid); + default CompletableFuture> loadAccount(UUID uuid) { + return loadAccount(uuid, null); + } /** * Loads the account for the specified uuid and world asynchronously. @@ -242,7 +263,7 @@ default CompletableFuture> loadAccount(OfflinePlayer player, W * @param world the world in which the account is located * @return a CompletableFuture that will complete with the retrieved account */ - CompletableFuture> loadAccount(UUID uuid, World world); + CompletableFuture> loadAccount(UUID uuid, @Nullable World world); /** * Deletes the specified account. @@ -251,9 +272,7 @@ default CompletableFuture> loadAccount(OfflinePlayer player, W * @return a CompletableFuture that will complete when the account is deleted */ default CompletableFuture deleteAccount(Account account) { - return account.getWorld() - .map(world -> deleteAccount(account.getOwner(), world)) - .orElseGet(() -> deleteAccount(account.getOwner())); + return deleteAccount(account.getOwner(), account.getWorld().orElse(null)); } /** @@ -263,7 +282,7 @@ default CompletableFuture deleteAccount(Account account) { * @return a CompletableFuture that will complete when the account is deleted */ default CompletableFuture deleteAccount(OfflinePlayer player) { - return deleteAccount(player.getUniqueId()); + return deleteAccount(player, null); } /** @@ -273,7 +292,7 @@ default CompletableFuture deleteAccount(OfflinePlayer player) { * @param world the world in which the player's account exists * @return a CompletableFuture that will complete when the account is deleted */ - default CompletableFuture deleteAccount(OfflinePlayer player, World world) { + default CompletableFuture deleteAccount(OfflinePlayer player, @Nullable World world) { return deleteAccount(player.getUniqueId(), world); } @@ -283,7 +302,9 @@ default CompletableFuture deleteAccount(OfflinePlayer player, World wor * @param uuid the uuid of the account to be deleted * @return a CompletableFuture that will complete when the account is deleted */ - CompletableFuture deleteAccount(UUID uuid); + default CompletableFuture deleteAccount(UUID uuid) { + return deleteAccount(uuid, null); + } /** * Deletes the account with the specified uuid in the specified world. @@ -292,5 +313,5 @@ default CompletableFuture deleteAccount(OfflinePlayer player, World wor * @param world the world in which the account exists * @return a CompletableFuture that will complete when the account is deleted */ - CompletableFuture deleteAccount(UUID uuid, World world); + CompletableFuture deleteAccount(UUID uuid, @Nullable World world); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index 591eb4c0..fb5bbd50 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.Set; @@ -26,7 +27,7 @@ public interface BankController extends Controller, CurrencyHolder { */ @Contract("_, _ -> new") default CompletableFuture createBank(OfflinePlayer player, String name) { - return createBank(player.getUniqueId(), name); + return createBank(player, name, null); } /** @@ -53,8 +54,10 @@ default CompletableFuture createBank(OfflinePlayer player, String name, @N * @param name the name of the bank (must be unique) * @return a CompletableFuture that completes with the created bank */ - CompletableFuture createBank(UUID uuid, String name); @Contract("_, _ -> new") + default CompletableFuture createBank(UUID uuid, String name) { + return createBank(uuid, name, null); + } /** * Creates a new bank with the provided UUID, name, and world. @@ -66,8 +69,8 @@ default CompletableFuture createBank(OfflinePlayer player, String name, @N * @param world the world in which the bank exists * @return a CompletableFuture that completes with the created bank */ - CompletableFuture createBank(UUID uuid, String name, World world); @Contract("_, _, _ -> new") + CompletableFuture createBank(UUID uuid, String name, @Nullable World world); /** * Loads a bank asynchronously with the specified player. @@ -75,8 +78,8 @@ default CompletableFuture createBank(OfflinePlayer player, String name, @N * @param player the player for whom the bank should be loaded * @return a CompletableFuture that completes with the loaded bank */ - default CompletableFuture loadBank(OfflinePlayer player) { - return loadBank(player.getUniqueId()); + default CompletableFuture> loadBank(OfflinePlayer player) { + return loadBank(player, null); } /** @@ -86,7 +89,7 @@ default CompletableFuture loadBank(OfflinePlayer player) { * @param world the world in which the bank is located * @return a CompletableFuture that completes with the loaded bank */ - default CompletableFuture loadBank(OfflinePlayer player, World world) { + default CompletableFuture> loadBank(OfflinePlayer player, @Nullable World world) { return loadBank(player.getUniqueId(), world); } @@ -96,7 +99,7 @@ default CompletableFuture loadBank(OfflinePlayer player, World world) { * @param name the name of the bank to be loaded * @return a CompletableFuture that completes with the loaded bank */ - CompletableFuture loadBank(String name); + CompletableFuture> loadBank(String name); /** * Loads a bank asynchronously with the specified UUID. @@ -104,7 +107,9 @@ default CompletableFuture loadBank(OfflinePlayer player, World world) { * @param uuid the UUID of the bank * @return a CompletableFuture that completes with the loaded bank */ - CompletableFuture loadBank(UUID uuid); + default CompletableFuture> loadBank(UUID uuid) { + return loadBank(uuid, null); + } /** * Loads a bank asynchronously with the specified UUID and world. @@ -113,14 +118,16 @@ default CompletableFuture loadBank(OfflinePlayer player, World world) { * @param world the world in which the bank is located * @return a CompletableFuture that completes with the loaded bank */ - CompletableFuture loadBank(UUID uuid, World world); + CompletableFuture> loadBank(UUID uuid, @Nullable World world); /** * Retrieves a Set of all banks. * * @return a CompletableFuture that completes with a Set of all banks */ - CompletableFuture<@Unmodifiable Set> loadBanks(); + default CompletableFuture<@Unmodifiable Set> loadBanks() { + return loadBanks(null); + } /** * Retrieves a set of all banks in the specified world. @@ -128,7 +135,7 @@ default CompletableFuture loadBank(OfflinePlayer player, World world) { * @param world the world from which to retrieve the banks * @return a CompletableFuture that completes with a Set of banks in the specified world */ - CompletableFuture<@Unmodifiable Set> loadBanks(World world); + CompletableFuture<@Unmodifiable Set> loadBanks(@Nullable World world); /** * Tries to retrieve the {@link Bank} with the specified name. @@ -137,10 +144,10 @@ default CompletableFuture loadBank(OfflinePlayer player, World world) { * @return a {@code CompletableFuture} that completes with an {@code Optional} containing the bank * associated with the name, or an empty Optional if not found */ - default CompletableFuture tryGetBank(String name) { - return getBank(name) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadBank(name)); + default CompletableFuture> tryGetBank(String name) { + var bank = getBank(name); + if (bank.isEmpty()) return loadBank(name); + return CompletableFuture.completedFuture(bank); } /** @@ -150,10 +157,8 @@ default CompletableFuture tryGetBank(String name) { * @return a CompletableFuture that completes with an Optional containing the Bank associated with * the player, or an empty Optional if not found */ - default CompletableFuture tryGetBank(OfflinePlayer player) { - return getBank(player) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadBank(player)); + default CompletableFuture> tryGetBank(OfflinePlayer player) { + return tryGetBank(player, null); } /** @@ -164,10 +169,8 @@ default CompletableFuture tryGetBank(OfflinePlayer player) { * @return a CompletableFuture that completes with an Optional containing the Bank associated with * the player and world, or an empty Optional if not found */ - default CompletableFuture tryGetBank(OfflinePlayer player, World world) { - return getBank(player, world) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadBank(player, world)); + default CompletableFuture> tryGetBank(OfflinePlayer player, @Nullable World world) { + return tryGetBank(player.getUniqueId(), world); } /** @@ -177,10 +180,8 @@ default CompletableFuture tryGetBank(OfflinePlayer player, World world) { * @return a CompletableFuture that completes with an Optional containing the Bank associated with the UUID, * or an empty Optional if not found */ - default CompletableFuture tryGetBank(UUID uuid) { - return getBank(uuid) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadBank(uuid)); + default CompletableFuture> tryGetBank(UUID uuid) { + return tryGetBank(uuid, null); } /** @@ -191,10 +192,10 @@ default CompletableFuture tryGetBank(UUID uuid) { * @return a CompletableFuture that completes with an Optional containing the Bank associated with * the UUID and world, or an empty Optional if not found */ - default CompletableFuture tryGetBank(UUID uuid, World world) { - return getBank(uuid, world) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadBank(uuid, world)); + default CompletableFuture> tryGetBank(UUID uuid, @Nullable World world) { + var bank = getBank(uuid, world); + if (bank.isEmpty()) return loadBank(uuid, world); + return CompletableFuture.completedFuture(bank); } /** @@ -204,9 +205,7 @@ default CompletableFuture tryGetBank(UUID uuid, World world) { * @return a CompletableFuture that completes with a boolean value indicating whether the deletion was successful */ default CompletableFuture deleteBank(Bank bank) { - return bank.getWorld() - .map(world -> deleteBank(bank.getOwner(), world)) - .orElseGet(() -> deleteBank(bank.getOwner())); + return deleteBank(bank.getOwner(), bank.getWorld().orElse(null)); } /** @@ -216,7 +215,7 @@ default CompletableFuture deleteBank(Bank bank) { * @return a CompletableFuture that completes with a boolean value indicating whether the deletion was successful */ default CompletableFuture deleteBank(OfflinePlayer player) { - return deleteBank(player.getUniqueId()); + return deleteBank(player, null); } /** @@ -226,7 +225,7 @@ default CompletableFuture deleteBank(OfflinePlayer player) { * @param world the world where the bank is located * @return a CompletableFuture that completes with a boolean value indicating whether the deletion was successful */ - default CompletableFuture deleteBank(OfflinePlayer player, World world) { + default CompletableFuture deleteBank(OfflinePlayer player, @Nullable World world) { return deleteBank(player.getUniqueId(), world); } @@ -244,7 +243,9 @@ default CompletableFuture deleteBank(OfflinePlayer player, World world) * @param uuid The UUID of the bank to be deleted. * @return A CompletableFuture that completes with a boolean value indicating whether the deletion was successful. */ - CompletableFuture deleteBank(UUID uuid); + default CompletableFuture deleteBank(UUID uuid) { + return deleteBank(uuid, null); + } /** * Deletes a bank with the specified UUID in the given world. @@ -253,15 +254,16 @@ default CompletableFuture deleteBank(OfflinePlayer player, World world) * @param world the world where the bank is located * @return a CompletableFuture that completes with a boolean value indicating whether the deletion was successful */ - CompletableFuture deleteBank(UUID uuid, World world); + CompletableFuture deleteBank(UUID uuid, @Nullable World world); /** * Retrieves a set of all banks. * * @return a set of all banks */ - @Unmodifiable - Set getBanks(); + default @Unmodifiable Set getBanks() { + return getBanks(null); + } /** * Retrieves a set of all banks in the {@link World}. @@ -270,7 +272,7 @@ default CompletableFuture deleteBank(OfflinePlayer player, World world) * @return a {@code Set} containing all the banks in the world */ @Unmodifiable - Set getBanks(World world); + Set getBanks(@Nullable World world); /** * Retrieves the {@link Bank} associated with the specified name. @@ -287,7 +289,7 @@ default CompletableFuture deleteBank(OfflinePlayer player, World world) * @return an {@code Optional} containing the bank associated with the player, or empty if not found */ default Optional getBank(OfflinePlayer player) { - return getBank(player.getUniqueId()); + return getBank(player, null); } /** @@ -297,7 +299,7 @@ default Optional getBank(OfflinePlayer player) { * @param world the world the bank belongs to * @return an {@code Optional} containing the bank associated with the player and world, or empty if not found */ - default Optional getBank(OfflinePlayer player, World world) { + default Optional getBank(OfflinePlayer player, @Nullable World world) { return getBank(player.getUniqueId(), world); } @@ -307,7 +309,9 @@ default Optional getBank(OfflinePlayer player, World world) { * @param uuid the UUID of the bank's owner * @return an Optional containing the Bank associated with the UUID, or empty if not found */ - Optional getBank(UUID uuid); + default Optional getBank(UUID uuid) { + return getBank(uuid, null); + } /** * Retrieves the {@link Bank} associated with the specified UUID and world. @@ -316,5 +320,5 @@ default Optional getBank(OfflinePlayer player, World world) { * @param world the world the bank belongs to * @return an Optional containing the Bank associated with the UUID and world, or empty if not found */ - Optional getBank(UUID uuid, World world); + Optional getBank(UUID uuid, @Nullable World world); } From 72f62c04376a92b90340addc3e9f93265b8c3bed Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:03:00 +0200 Subject: [PATCH 08/32] Added `hasMultiWorldSupport` to controllers Introduced `hasMultiWorldSupport` method in `EconomyController` and `BankController`. This determines multi-world handling capabilities and clarifies parameter behavior for non-supported cases. --- .../service/api/economy/EconomyController.java | 10 ++++++++++ .../service/api/economy/bank/BankController.java | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index f1e742ea..4d32f09e 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -314,4 +314,14 @@ default CompletableFuture deleteAccount(UUID uuid) { * @return a CompletableFuture that will complete when the account is deleted */ CompletableFuture deleteAccount(UUID uuid, @Nullable World world); + + /** + * Determines whether the controller supports handling of multiple worlds. + * + * @return {@code true} if multi-world economy is supported, otherwise {@code false} + * @implSpec If multiple worlds are not supported, + * implementations must ignore world-specific parameters and only handle cases where the world parameter is null. + */ + @Contract(pure = true) + boolean hasMultiWorldSupport(); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index fb5bbd50..39b54f36 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -321,4 +321,14 @@ default Optional getBank(UUID uuid) { * @return an Optional containing the Bank associated with the UUID and world, or empty if not found */ Optional getBank(UUID uuid, @Nullable World world); + + /** + * Determines whether the controller supports handling of multiple worlds. + * + * @return {@code true} if multi-world banking is supported, otherwise {@code false} + * @implSpec If multiple worlds are not supported, + * implementations must ignore world-specific parameters and only handle cases where the world parameter is null. + */ + @Contract(pure = true) + boolean hasMultiWorldSupport(); } From 8a0585fb3c49ec6039f5ae3f10db8d7c2735d884 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:05:10 +0200 Subject: [PATCH 09/32] Updated Javadocs for method clarity Enhanced documentation across `EconomyController` and `CurrencyHolder`. Clarified behaviors, improved annotations, and ensured consistent descriptions for return values and exceptions. --- .../api/economy/EconomyController.java | 27 ++++++++++++------- .../api/economy/currency/CurrencyHolder.java | 5 ++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index 4d32f09e..90191028 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -182,10 +182,11 @@ default CompletableFuture> tryGetAccount(UUID uuid, @Nullable /** * Creates an account for the specified player. + *

+ * Completes with an {@link IllegalStateException} if a similar account already exists * * @param player the player for whom the account will be created * @return a CompletableFuture that will complete with the created account - * @throws IllegalStateException if a similar account already exists */ @Contract("_ -> new") default CompletableFuture createAccount(OfflinePlayer player) { @@ -194,6 +195,8 @@ default CompletableFuture createAccount(OfflinePlayer player) { /** * Creates an account for the specified player in the specified world. + *

+ * Completes with an {@link IllegalStateException} if a similar account already exists * * @param player the player for whom the account will be created * @param world the world in which the player's account will be created @@ -206,6 +209,8 @@ default CompletableFuture createAccount(OfflinePlayer player, @Nullable /** * Creates an account with the given uuid. + *

+ * Completes with an {@link IllegalStateException} if a similar account already exists * * @param uuid the uuid of the account to be created * @return a CompletableFuture that will complete with the created account @@ -217,6 +222,8 @@ default CompletableFuture createAccount(UUID uuid) { /** * Creates an account with the given uuid and world. + *

+ * Completes with an {@link IllegalStateException} if a similar account already exists * * @param uuid the uuid of the account to be created * @param world the world in which the account will be created @@ -269,49 +276,49 @@ default CompletableFuture> loadAccount(UUID uuid) { * Deletes the specified account. * * @param account the account to be deleted - * @return a CompletableFuture that will complete when the account is deleted + * @return a {@code CompletableFuture} completing with a boolean indicating whether the account was deleted */ default CompletableFuture deleteAccount(Account account) { return deleteAccount(account.getOwner(), account.getWorld().orElse(null)); } /** - * Deletes the account of the specified player. + * Deletes the account of the given player. * * @param player the player whose account will be deleted - * @return a CompletableFuture that will complete when the account is deleted + * @return a {@code CompletableFuture} completing with a boolean indicating whether the account was deleted */ default CompletableFuture deleteAccount(OfflinePlayer player) { return deleteAccount(player, null); } /** - * Deletes the account of the specified player in the specified world. + * Deletes the account of the given player in the specified world. * * @param player the player whose account will be deleted * @param world the world in which the player's account exists - * @return a CompletableFuture that will complete when the account is deleted + * @return a {@code CompletableFuture} completing with a boolean indicating whether the account was deleted */ default CompletableFuture deleteAccount(OfflinePlayer player, @Nullable World world) { return deleteAccount(player.getUniqueId(), world); } /** - * Deletes the account with the specified uuid. + * Deletes the account of the given owner's UUID. * * @param uuid the uuid of the account to be deleted - * @return a CompletableFuture that will complete when the account is deleted + * @return a {@code CompletableFuture} completing with a boolean indicating whether the account was deleted */ default CompletableFuture deleteAccount(UUID uuid) { return deleteAccount(uuid, null); } /** - * Deletes the account with the specified uuid in the specified world. + * Deletes the account of the given owner's uuid in the specified world. * * @param uuid the uuid of the account to be deleted * @param world the world in which the account exists - * @return a CompletableFuture that will complete when the account is deleted + * @return a {@code CompletableFuture} completing with a boolean indicating whether the account was deleted */ CompletableFuture deleteAccount(UUID uuid, @Nullable World world); diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index 5972d7e2..1b378a26 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -39,7 +39,8 @@ default int fractionalDigits() { } /** - * Retrieves all currencies managed by the currency holder. + * Retrieves all currencies managed by the currency holder, + * including the {@link #getDefaultCurrency() default currency}. * * @return an unmodifiable set of currencies * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} @@ -111,7 +112,7 @@ default boolean deleteCurrency(String name) { Currency getDefaultCurrency(); /** - * Determines whether the economy controller supports multiple currencies. + * Determines whether the holder supports multiple currencies. * * @return {@code true} if multi-currency is supported, otherwise {@code false} * @implSpec If multiple currencies are supported, all respective methods have to be implemented. From 5f5a486a1932789f8973f1071fc0a0ca7650304c Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:05:22 +0200 Subject: [PATCH 10/32] Removed `@ApiStatus.NonExtendable` from `Currency` methods --- .../net/thenextlvl/service/api/economy/currency/Currency.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index 5afbef48..436317de 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -29,7 +29,6 @@ public interface Currency { * @param audience the audience whose locale is used to determine the singular display name * @return the singular display name as a {@code Component} for the audience's locale */ - @ApiStatus.NonExtendable default Component getDisplayNameSingular(Audience audience) { return getDisplayNameSingular(audience.getOrDefault(Identity.LOCALE, Locale.US)); } @@ -51,7 +50,6 @@ default Component getDisplayNameSingular(Audience audience) { * @param audience the audience whose locale is used to determine the plural display name * @return the plural display name as a {@code Component} for the audience's locale */ - @ApiStatus.NonExtendable default Component getDisplayNamePlural(Audience audience) { return getDisplayNamePlural(audience.getOrDefault(Identity.LOCALE, Locale.US)); } @@ -79,7 +77,6 @@ default Component getDisplayNamePlural(Audience audience) { * @return the formatted amount as a component * @see #format(Number, Locale) */ - @ApiStatus.NonExtendable default Component format(Number amount, Audience audience) { return format(amount, audience.getOrDefault(Identity.LOCALE, Locale.US)); } From 17a9b4513e015e9984883fabb8f87c3d84d6d282 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:06:01 +0200 Subject: [PATCH 11/32] Renamed `getController` to `getHolder` Updated methods to use `getHolder` for consistency with the `CurrencyHolder` interface. --- .../wrapper/service/model/WrappedAccount.java | 2 +- .../service/wrapper/service/model/WrappedBank.java | 6 ++++++ .../net/thenextlvl/service/api/economy/Account.java | 12 ++++++------ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java index 6eb830bb..ce5e6c47 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java @@ -29,7 +29,7 @@ public WrappedAccount(EconomyController controller, @Nullable World world, Econo } @Override - public CurrencyHolder getController() { + public CurrencyHolder getHolder() { return controller; } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java index 639cf5bc..905a7073 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java @@ -3,6 +3,7 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.ServicePlugin; import net.thenextlvl.service.api.economy.bank.Bank; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; @@ -31,6 +32,11 @@ public WrappedBank(String name, @Nullable World world, Economy economy, Plugin p this.provider = provider; } + @Override + public CurrencyHolder getHolder() { + return controller; + } + @Override public BigDecimal deposit(Number amount, Currency currency) { return new BigDecimal(economy.bankDeposit(name, amount.doubleValue()).balance); diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index cd4d2e52..850c08fd 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -20,8 +20,8 @@ public interface Account extends Comparable { * * @return the {@code CurrencyHolder} capable of managing currencies for the account */ - CurrencyHolder getController(); @Contract(pure = true) + CurrencyHolder getHolder(); /** * Deposits the specified amount into the account balance. @@ -32,7 +32,7 @@ public interface Account extends Comparable { */ @Deprecated(forRemoval = true, since = "3.0.0") default BigDecimal deposit(Number amount) { - return deposit(amount, getController().getDefaultCurrency()); + return deposit(amount, getHolder().getDefaultCurrency()); } /** @@ -52,7 +52,7 @@ default BigDecimal deposit(Number amount) { */ @Deprecated(forRemoval = true, since = "3.0.0") default BigDecimal getBalance() { - return getBalance(getController().getDefaultCurrency()); + return getBalance(getHolder().getDefaultCurrency()); } BigDecimal getBalance(Currency currency); @@ -66,7 +66,7 @@ default BigDecimal getBalance() { */ @Deprecated(forRemoval = true, since = "3.0.0") default BigDecimal withdraw(Number amount) { - return withdraw(amount, getController().getDefaultCurrency()); + return withdraw(amount, getHolder().getDefaultCurrency()); } /** @@ -103,7 +103,7 @@ default BigDecimal withdraw(Number amount) { @Override @Deprecated(forRemoval = true, since = "3.0.0") default int compareTo(Account account) { - return compareTo(account, getController().getDefaultCurrency()); + return compareTo(account, getHolder().getDefaultCurrency()); } /** @@ -126,7 +126,7 @@ default int compareTo(Account account, Currency currency) { */ @Deprecated(forRemoval = true, since = "3.0.0") default void setBalance(Number balance) { - setBalance(balance, getController().getDefaultCurrency()); + setBalance(balance, getHolder().getDefaultCurrency()); } /** From fa532d4c4d2e1806b39de9eed6c12953bef6c523 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:06:50 +0200 Subject: [PATCH 12/32] Removed redundant `deleteAccounts` method Eliminated unused `deleteAccounts` method and corresponding import to streamline the `EconomyServiceWrapper` class. --- .../service/wrapper/service/EconomyServiceWrapper.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index 5f4cb38b..3868e540 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -12,7 +12,6 @@ import org.jspecify.annotations.Nullable; import java.util.Arrays; -import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -85,11 +84,6 @@ public CompletableFuture deleteAccount(UUID uuid, @Nullable World world return CompletableFuture.completedFuture(false); } - @Override - public CompletableFuture deleteAccounts(List accounts, @Nullable World world) { - return CompletableFuture.completedFuture(false); - } - @Override public boolean hasMultiWorldSupport() { return false; From e8f79a59465a32bc27ce2a6a351aed66a8a25576 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:07:07 +0200 Subject: [PATCH 13/32] Commented out incomplete conversion logic Replaced unfinished bank and account conversion workflows with `CompletableFuture.completedFuture(null)`. Added TODOs and FIXMEs to address unresolved implementation details. --- .../command/ServiceConvertCommand.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java b/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java index a6825396..7cd0c7d2 100644 --- a/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java +++ b/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java @@ -62,15 +62,17 @@ private LiteralArgumentBuilder conver private static final class BankConverter extends PlayerConverter { @Override public CompletableFuture convert(OfflinePlayer player, BankController source, BankController target) { - return source.loadBanks().thenAccept(banks -> banks.forEach(bank -> - bank.getWorld().map(world -> target.createBank(bank.getOwner(), bank.getName(), world)) - .orElseGet(() -> target.createBank(bank.getOwner(), bank.getName())) - .thenAccept(targetBank -> { - // todo: convert all currencies - // todo: convert balance with currencies - targetBank.setBalance(bank.getBalance()); - bank.getMembers().forEach(targetBank::addMember); - }))); + return CompletableFuture.completedFuture(null); + // todo: convert all currencies + // todo: convert balance with currencies + // fixme: + // return source.loadBanks().thenAccept(banks -> banks.forEach(bank -> + // bank.getWorld().map(world -> target.createBank(bank.getOwner(), bank.getName(), world)) + // .orElseGet(() -> target.createBank(bank.getOwner(), bank.getName())) + // .thenAccept(targetBank -> { + // targetBank.setBalance(bank.getBalance()); + // bank.getMembers().forEach(targetBank::addMember); + // }))); } } @@ -121,14 +123,16 @@ public CompletableFuture convert(EconomyController source, EconomyControll } public CompletableFuture convert(Account account, EconomyController source, EconomyController target) { - return account.getWorld().map(world -> target.tryGetAccount(account.getOwner(), world) - .thenCompose(account1 -> account1.map(CompletableFuture::completedFuture) - .orElseGet(() -> target.createAccount(account.getOwner(), world))) - .thenAccept(account1 -> account1.setBalance(account.getBalance()))) - .orElseGet(() -> target.tryGetAccount(account.getOwner()) - .thenCompose(account1 -> account1.map(CompletableFuture::completedFuture) - .orElseGet(() -> target.createAccount(account.getOwner()))) - .thenAccept(account1 -> account1.setBalance(account.getBalance()))); + return CompletableFuture.completedFuture(null); + // fixme + // return account.getWorld().map(world -> target.tryGetAccount(account.getOwner(), world) + // .thenCompose(account1 -> account1.map(CompletableFuture::completedFuture) + // .orElseGet(() -> target.createAccount(account.getOwner(), world))) + // .thenAccept(account1 -> account1.setBalance(account.getBalance()))) + // .orElseGet(() -> target.tryGetAccount(account.getOwner()) + // .thenCompose(account1 -> account1.map(CompletableFuture::completedFuture) + // .orElseGet(() -> target.createAccount(account.getOwner()))) + // .thenAccept(account1 -> account1.setBalance(account.getBalance()))); } } From 050af7c266fa99b56dd68fb6616906c38eb59426 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 20:41:02 +0200 Subject: [PATCH 14/32] Added `@since` annotations across API interfaces Documented the version in which interfaces, methods, and classes were introduced. --- .../net/thenextlvl/service/api/Controller.java | 6 ++++++ .../service/api/capability/Capability.java | 2 ++ .../api/capability/CapabilityException.java | 2 ++ .../service/api/capability/CapabilityProvider.java | 1 + .../service/api/character/Character.java | 1 + .../service/api/character/CharacterCapability.java | 2 ++ .../service/api/character/CharacterController.java | 2 ++ .../api/character/event/CharacterDamageEvent.java | 2 ++ .../api/character/event/CharacterEvent.java | 2 ++ .../event/EntityDamageCharacterEvent.java | 2 ++ .../event/PlayerInteractCharacterEvent.java | 2 ++ .../service/api/chat/ChatController.java | 2 ++ .../thenextlvl/service/api/chat/ChatProfile.java | 11 +++++++++++ .../thenextlvl/service/api/economy/Account.java | 14 ++++++++++++++ .../service/api/economy/EconomyController.java | 6 +++++- .../thenextlvl/service/api/economy/bank/Bank.java | 2 ++ .../service/api/economy/bank/BankController.java | 6 ++++++ .../service/api/economy/currency/Currency.java | 5 +++++ .../api/economy/currency/CurrencyHolder.java | 11 ++++------- .../net/thenextlvl/service/api/group/Group.java | 2 ++ .../service/api/group/GroupController.java | 2 ++ .../thenextlvl/service/api/group/GroupHolder.java | 2 ++ .../thenextlvl/service/api/hologram/Hologram.java | 2 ++ .../service/api/hologram/HologramCapability.java | 2 ++ .../service/api/hologram/HologramController.java | 2 ++ .../service/api/hologram/HologramDisplay.java | 1 + .../service/api/hologram/HologramLine.java | 1 + .../thenextlvl/service/api/hologram/LineType.java | 2 ++ .../net/thenextlvl/service/api/model/Display.java | 2 ++ .../net/thenextlvl/service/api/model/InfoNode.java | 2 ++ .../thenextlvl/service/api/model/Persistable.java | 2 ++ .../thenextlvl/service/api/model/Positioned.java | 2 ++ .../net/thenextlvl/service/api/model/Viewable.java | 2 ++ .../api/permission/PermissionController.java | 1 + .../service/api/permission/PermissionHolder.java | 2 ++ 35 files changed, 102 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/Controller.java b/src/main/java/net/thenextlvl/service/api/Controller.java index ab45388b..5d0b7c12 100644 --- a/src/main/java/net/thenextlvl/service/api/Controller.java +++ b/src/main/java/net/thenextlvl/service/api/Controller.java @@ -4,6 +4,12 @@ import org.jetbrains.annotations.Contract; import org.jspecify.annotations.NullMarked; +/** + * The `Controller` interface provides methods to retrieve basic information + * about the controller, such as the associated plugin and name. + * + * @since 2.2.1 + */ @NullMarked public interface Controller { /** diff --git a/src/main/java/net/thenextlvl/service/api/capability/Capability.java b/src/main/java/net/thenextlvl/service/api/capability/Capability.java index 5e707c46..56d943bd 100644 --- a/src/main/java/net/thenextlvl/service/api/capability/Capability.java +++ b/src/main/java/net/thenextlvl/service/api/capability/Capability.java @@ -13,6 +13,8 @@ *

* Implementations of this interface can be used in conjunction with capability * providers or related systems to organize and query available functionalities. + * + * @since 2.2.0 */ public interface Capability extends Keyed { } diff --git a/src/main/java/net/thenextlvl/service/api/capability/CapabilityException.java b/src/main/java/net/thenextlvl/service/api/capability/CapabilityException.java index 3a5b3752..67d9f874 100644 --- a/src/main/java/net/thenextlvl/service/api/capability/CapabilityException.java +++ b/src/main/java/net/thenextlvl/service/api/capability/CapabilityException.java @@ -7,6 +7,8 @@ * An exception that indicates a problem related to a specific {@link Capability}. * This exception is typically thrown when there is an issue or unsupported operation * associated with a particular capability in the system. + * + * @since 2.2.0 */ @NullMarked public class CapabilityException extends RuntimeException { diff --git a/src/main/java/net/thenextlvl/service/api/capability/CapabilityProvider.java b/src/main/java/net/thenextlvl/service/api/capability/CapabilityProvider.java index 06765ea1..9ab633ef 100644 --- a/src/main/java/net/thenextlvl/service/api/capability/CapabilityProvider.java +++ b/src/main/java/net/thenextlvl/service/api/capability/CapabilityProvider.java @@ -13,6 +13,7 @@ * capabilities and provides mechanisms to check whether the provider supports individual or multiple capabilities. * * @param the type of {@link Capability} supported by this provider + * @since 2.2.0 */ @NullMarked public interface CapabilityProvider { diff --git a/src/main/java/net/thenextlvl/service/api/character/Character.java b/src/main/java/net/thenextlvl/service/api/character/Character.java index ecfda8ce..34131865 100644 --- a/src/main/java/net/thenextlvl/service/api/character/Character.java +++ b/src/main/java/net/thenextlvl/service/api/character/Character.java @@ -18,6 +18,7 @@ * functionalities such as spawning, despawning, teleportation, and state management. * * @param the type of the entity associated with this character + * @since 2.2.0 */ @NullMarked public interface Character extends Persistable, Viewable { diff --git a/src/main/java/net/thenextlvl/service/api/character/CharacterCapability.java b/src/main/java/net/thenextlvl/service/api/character/CharacterCapability.java index d2c8e2a7..07de6e48 100644 --- a/src/main/java/net/thenextlvl/service/api/character/CharacterCapability.java +++ b/src/main/java/net/thenextlvl/service/api/character/CharacterCapability.java @@ -18,6 +18,8 @@ *

* Each capability is associated with a unique {@link Key} that acts as an * identifier for the capability. + * + * @since 2.2.0 */ @NullMarked public enum CharacterCapability implements Capability { diff --git a/src/main/java/net/thenextlvl/service/api/character/CharacterController.java b/src/main/java/net/thenextlvl/service/api/character/CharacterController.java index 3e5dacb7..5872b0fd 100644 --- a/src/main/java/net/thenextlvl/service/api/character/CharacterController.java +++ b/src/main/java/net/thenextlvl/service/api/character/CharacterController.java @@ -21,6 +21,8 @@ * and interacting with non-player characters (NPCs). * It includes functionality for creating, spawning, retrieving, and checking * entities as NPCs, along with capability management. + * + * @since 2.2.0 */ @NullMarked public interface CharacterController extends CapabilityProvider, Controller { diff --git a/src/main/java/net/thenextlvl/service/api/character/event/CharacterDamageEvent.java b/src/main/java/net/thenextlvl/service/api/character/event/CharacterDamageEvent.java index f62bff4e..04185002 100644 --- a/src/main/java/net/thenextlvl/service/api/character/event/CharacterDamageEvent.java +++ b/src/main/java/net/thenextlvl/service/api/character/event/CharacterDamageEvent.java @@ -14,6 +14,8 @@ * the damage, and controlling whether the event should be cancelled. *

* This event will only be fired for providers that support the {@link CharacterCapability#HEALTH} capability. + * + * @since 2.2.0 */ @NullMarked public class CharacterDamageEvent extends CharacterEvent implements Cancellable { diff --git a/src/main/java/net/thenextlvl/service/api/character/event/CharacterEvent.java b/src/main/java/net/thenextlvl/service/api/character/event/CharacterEvent.java index 4a77e428..3726cf68 100644 --- a/src/main/java/net/thenextlvl/service/api/character/event/CharacterEvent.java +++ b/src/main/java/net/thenextlvl/service/api/character/event/CharacterEvent.java @@ -16,6 +16,8 @@ *

* Subclasses can make use of these common properties while implementing specific * character-related event functionalities. + * + * @since 2.2.0 */ @NullMarked public abstract class CharacterEvent extends Event { diff --git a/src/main/java/net/thenextlvl/service/api/character/event/EntityDamageCharacterEvent.java b/src/main/java/net/thenextlvl/service/api/character/event/EntityDamageCharacterEvent.java index 923e7791..06621179 100644 --- a/src/main/java/net/thenextlvl/service/api/character/event/EntityDamageCharacterEvent.java +++ b/src/main/java/net/thenextlvl/service/api/character/event/EntityDamageCharacterEvent.java @@ -15,6 +15,8 @@ * It can be used to inspect and modify the damage attributed to an entity's attack and to check the critical status. *

* This event will only be fired for providers that support the {@link CharacterCapability#HEALTH} capability. + * + * @since 2.2.0 */ @NullMarked public class EntityDamageCharacterEvent extends CharacterDamageEvent { diff --git a/src/main/java/net/thenextlvl/service/api/character/event/PlayerInteractCharacterEvent.java b/src/main/java/net/thenextlvl/service/api/character/event/PlayerInteractCharacterEvent.java index 04c41241..caa3b326 100644 --- a/src/main/java/net/thenextlvl/service/api/character/event/PlayerInteractCharacterEvent.java +++ b/src/main/java/net/thenextlvl/service/api/character/event/PlayerInteractCharacterEvent.java @@ -19,6 +19,8 @@ * the interaction from proceeding by setting the event's cancelled state. *

* This event will only be fired for providers that support the {@link CharacterCapability#INTERACTIONS} capability. + * + * @since 2.2.0 */ @NullMarked public class PlayerInteractCharacterEvent extends CharacterEvent implements Cancellable { diff --git a/src/main/java/net/thenextlvl/service/api/chat/ChatController.java b/src/main/java/net/thenextlvl/service/api/chat/ChatController.java index b0bb27ac..ccf23f45 100644 --- a/src/main/java/net/thenextlvl/service/api/chat/ChatController.java +++ b/src/main/java/net/thenextlvl/service/api/chat/ChatController.java @@ -11,6 +11,8 @@ /** * The ChatController interface provides methods to retrieve a chat profile of a player. + * + * @since 1.0.0 */ @NullMarked public interface ChatController extends Controller { diff --git a/src/main/java/net/thenextlvl/service/api/chat/ChatProfile.java b/src/main/java/net/thenextlvl/service/api/chat/ChatProfile.java index 8b36f2a4..bc2905b2 100644 --- a/src/main/java/net/thenextlvl/service/api/chat/ChatProfile.java +++ b/src/main/java/net/thenextlvl/service/api/chat/ChatProfile.java @@ -8,6 +8,17 @@ import java.util.Optional; import java.util.Set; +/** + * Represents a chat profile that provides information about a user involved in a chat system. + *

+ * A ChatProfile contains metadata such as the display name, assigned groups, and primary group. + * It also allows querying or setting various information nodes related to the profile. + *

+ * This interface extends the {@code InfoNode} and {@code Display} interfaces, + * inheriting functionalities related to generic information handling and display attributes. + * + * @since 1.0.0 + */ @NullMarked public interface ChatProfile extends InfoNode, Display { /** diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index 850c08fd..be1aabcc 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -12,6 +12,8 @@ /** * Account is an interface representing a financial account. + * + * @since 1.0.0 */ @NullMarked public interface Account extends Comparable { @@ -19,6 +21,7 @@ public interface Account extends Comparable { * Retrieves the associated {@code CurrencyHolder} for the account. * * @return the {@code CurrencyHolder} capable of managing currencies for the account + * @since 3.0.0 */ @Contract(pure = true) CurrencyHolder getHolder(); @@ -41,6 +44,7 @@ default BigDecimal deposit(Number amount) { * @param amount the amount to be deposited * @param currency the currency that is being deposited * @return the new balance after the deposit + * @since 3.0.0 */ BigDecimal deposit(Number amount, Currency currency); @@ -55,6 +59,13 @@ default BigDecimal getBalance() { return getBalance(getHolder().getDefaultCurrency()); } + /** + * Retrieves the balance of the account for the specified currency. + * + * @param currency the currency for which the balance is to be retrieved + * @return the balance of the account for the specified currency + * @since 3.0.0 + */ BigDecimal getBalance(Currency currency); /** @@ -75,6 +86,7 @@ default BigDecimal withdraw(Number amount) { * @param amount the amount to be withdrawn * @param currency the currency in which the withdrawal is to be made * @return the new balance after the withdrawal + * @since 3.0.0 */ BigDecimal withdraw(Number amount, Currency currency); @@ -113,6 +125,7 @@ default int compareTo(Account account) { * @param currency the currency in which the balances should be compared * @return a negative integer, zero, or a positive integer if this account's balance * is less than, equal to, or greater than the specified account's balance + * @since 3.0.0 */ default int compareTo(Account account, Currency currency) { return getBalance(currency).compareTo(account.getBalance(currency)); @@ -134,6 +147,7 @@ default void setBalance(Number balance) { * * @param balance the new balance to be set * @param currency the currency of the balance + * @since 3.0.0 */ void setBalance(Number balance, Currency currency); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index 90191028..0e4c39cd 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -11,7 +11,6 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.Set; @@ -21,6 +20,8 @@ /** * EconomyController is an interface that provides methods for managing and interacting * with economic systems, such as currency formatting, account retrieval, and multi-currency support. + * + * @since 1.0.0 */ @NullMarked public interface EconomyController extends Controller, CurrencyHolder { @@ -64,6 +65,7 @@ default String getCurrencySymbol() { * * @return a {@link CompletableFuture} that completes with an unmodifiable {@link Set} of {@link Account} objects * representing all available accounts + * @since 2.2.0 */ default CompletableFuture<@Unmodifiable Set> loadAccounts() { return loadAccounts(null); @@ -82,6 +84,7 @@ default String getCurrencySymbol() { * Retrieves all the accounts that are currently loaded. * * @return an unmodifiable set of accounts + * @since 2.2.0 */ default @Unmodifiable Set getAccounts() { return getAccounts(null); @@ -328,6 +331,7 @@ default CompletableFuture deleteAccount(UUID uuid) { * @return {@code true} if multi-world economy is supported, otherwise {@code false} * @implSpec If multiple worlds are not supported, * implementations must ignore world-specific parameters and only handle cases where the world parameter is null. + * @since 3.0.0 */ @Contract(pure = true) boolean hasMultiWorldSupport(); diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java index e2ade398..df343d75 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java @@ -13,6 +13,8 @@ * The Bank interface represents a financial entity that can be owned and hold members. * It extends the Account interface, providing additional functionality specific * to banking, such as depositing or withdrawing money. + * + * @since 1.0.0 */ @NullMarked public interface Bank extends Account { diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index 39b54f36..f42729ca 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -14,6 +14,11 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; +/** + * Represents a controller for managing banks tied to players and worlds. + * + * @since 1.0.0 + */ @NullMarked public interface BankController extends Controller, CurrencyHolder { /** @@ -328,6 +333,7 @@ default Optional getBank(UUID uuid) { * @return {@code true} if multi-world banking is supported, otherwise {@code false} * @implSpec If multiple worlds are not supported, * implementations must ignore world-specific parameters and only handle cases where the world parameter is null. + * @since 3.0.0 */ @Contract(pure = true) boolean hasMultiWorldSupport(); diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index 436317de..6498add0 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -11,6 +11,11 @@ import java.util.Optional; import java.util.OptionalInt; +/** + * Represents a currency with support for localization, formatting, and symbolic representation. + * + * @since 3.0.0 + */ @NullMarked public interface Currency { /** diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index 1b378a26..0e1eb707 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -13,6 +13,8 @@ * Represents an entity capable of handling currencies in an economy system. * This interface provides methods for formatting, retrieving, creating, * and deleting currencies, as well as determining support for multiple currencies. + * + * @since 3.0.0 */ public interface CurrencyHolder { /** @@ -20,6 +22,7 @@ public interface CurrencyHolder { * * @param amount the number amount to be formatted * @return the formatted amount as a string + * @since 1.0.0 * @deprecated use {@link Currency#format(Number, Locale)} */ @Deprecated(forRemoval = true, since = "3.0.0") @@ -31,6 +34,7 @@ default String format(Number amount) { * Retrieves the number of fractional digits used for formatting currency amounts. * * @return the number of fractional digits used for formatting currency amounts + * @since 1.0.0 * @deprecated use {@link Currency#getFractionalDigits()} */ @Deprecated(forRemoval = true, since = "3.0.0") @@ -44,7 +48,6 @@ default int fractionalDigits() { * * @return an unmodifiable set of currencies * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} - * @since 3.0.0 */ default @Unmodifiable Set getCurrencies() { throw new UnsupportedOperationException("Not implemented yet"); @@ -56,7 +59,6 @@ default int fractionalDigits() { * @param name the name of the currency to retrieve * @return an {@code Optional} containing the currency, or empty * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} - * @since 3.0.0 */ default Optional getCurrency(String name) { throw new UnsupportedOperationException("Not implemented yet"); @@ -68,7 +70,6 @@ default Optional getCurrency(String name) { * @param name the name of the currency to check for existence * @return {@code true} if the currency exists, otherwise {@code false} * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} - * @since 3.0.0 */ default boolean hasCurrency(String name) { throw new UnsupportedOperationException("Not implemented yet"); @@ -83,7 +84,6 @@ default boolean hasCurrency(String name) { * @param builder a consumer to configure the {@link Currency.Builder} for currency creation * @return an optional containing the created {@link Currency}, or empty * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} - * @since 3.0.0 */ @Contract("_, _ -> new") default Optional createCurrency(String name, Consumer builder) { @@ -96,7 +96,6 @@ default Optional createCurrency(String name, Consumer> { diff --git a/src/main/java/net/thenextlvl/service/api/hologram/HologramCapability.java b/src/main/java/net/thenextlvl/service/api/hologram/HologramCapability.java index 35465563..b7bef3ab 100644 --- a/src/main/java/net/thenextlvl/service/api/hologram/HologramCapability.java +++ b/src/main/java/net/thenextlvl/service/api/hologram/HologramCapability.java @@ -16,6 +16,8 @@ *

* Each capability is associated with a unique {@link Key} that acts as an * identifier for the capability. + * + * @since 2.2.0 */ @NullMarked public enum HologramCapability implements Capability { diff --git a/src/main/java/net/thenextlvl/service/api/hologram/HologramController.java b/src/main/java/net/thenextlvl/service/api/hologram/HologramController.java index a2b7685f..932b985f 100644 --- a/src/main/java/net/thenextlvl/service/api/hologram/HologramController.java +++ b/src/main/java/net/thenextlvl/service/api/hologram/HologramController.java @@ -25,6 +25,8 @@ *

* The controller ensures that capabilities of the hologram provider are respected and throws * exceptions if unsupported capabilities are used. + * + * @since 2.2.0 */ @NullMarked public interface HologramController extends CapabilityProvider, Controller { diff --git a/src/main/java/net/thenextlvl/service/api/hologram/HologramDisplay.java b/src/main/java/net/thenextlvl/service/api/hologram/HologramDisplay.java index 83dc606a..89e1dd07 100644 --- a/src/main/java/net/thenextlvl/service/api/hologram/HologramDisplay.java +++ b/src/main/java/net/thenextlvl/service/api/hologram/HologramDisplay.java @@ -17,6 +17,7 @@ * * @see Display * @see TextDisplay + * @since 2.2.0 */ public interface HologramDisplay { /** diff --git a/src/main/java/net/thenextlvl/service/api/hologram/HologramLine.java b/src/main/java/net/thenextlvl/service/api/hologram/HologramLine.java index 39a81a04..e3075f3f 100644 --- a/src/main/java/net/thenextlvl/service/api/hologram/HologramLine.java +++ b/src/main/java/net/thenextlvl/service/api/hologram/HologramLine.java @@ -11,6 +11,7 @@ * Represents a line within a hologram which can have varying content types and positional attributes. * * @param the type of content associated with the hologram line + * @since 2.2.0 */ @NullMarked public interface HologramLine extends Positioned { diff --git a/src/main/java/net/thenextlvl/service/api/hologram/LineType.java b/src/main/java/net/thenextlvl/service/api/hologram/LineType.java index 5ed3ca86..a7ba415a 100644 --- a/src/main/java/net/thenextlvl/service/api/hologram/LineType.java +++ b/src/main/java/net/thenextlvl/service/api/hologram/LineType.java @@ -3,6 +3,8 @@ /** * Enumeration representing the different types of lines that can be part of a hologram. * Each line type corresponds to a specific kind of visual content that a hologram can display. + * + * @since 2.2.0 */ public enum LineType { /** diff --git a/src/main/java/net/thenextlvl/service/api/model/Display.java b/src/main/java/net/thenextlvl/service/api/model/Display.java index dcd9c0e0..7e73d8ac 100644 --- a/src/main/java/net/thenextlvl/service/api/model/Display.java +++ b/src/main/java/net/thenextlvl/service/api/model/Display.java @@ -9,6 +9,8 @@ /** * The Display interface provides methods to manage display names, prefixes, and suffixes associated with an object. + * + * @since 1.0.0 */ @NullMarked public interface Display { diff --git a/src/main/java/net/thenextlvl/service/api/model/InfoNode.java b/src/main/java/net/thenextlvl/service/api/model/InfoNode.java index 9ab25423..a620e63f 100644 --- a/src/main/java/net/thenextlvl/service/api/model/InfoNode.java +++ b/src/main/java/net/thenextlvl/service/api/model/InfoNode.java @@ -10,6 +10,8 @@ * The InfoNode interface provides methods to retrieve, remove, and set information node values associated with keys. * An information node is a key-value pair where both key and value are stored as string but can be retrieved as any object. * The value is retrieved as an Optional, allowing for a null-safe operation. + * + * @since 1.0.0 */ @NullMarked public interface InfoNode { diff --git a/src/main/java/net/thenextlvl/service/api/model/Persistable.java b/src/main/java/net/thenextlvl/service/api/model/Persistable.java index 0de10db3..00ba6263 100644 --- a/src/main/java/net/thenextlvl/service/api/model/Persistable.java +++ b/src/main/java/net/thenextlvl/service/api/model/Persistable.java @@ -6,6 +6,8 @@ * Represents an object that can be persisted in a storage medium. * A Persistable object provides functionalities to check its persistent state, * retrieve its name, enable or disable persistence, and persist its current state. + * + * @since 2.2.0 */ @NullMarked public interface Persistable { diff --git a/src/main/java/net/thenextlvl/service/api/model/Positioned.java b/src/main/java/net/thenextlvl/service/api/model/Positioned.java index a5228f2f..019a4e82 100644 --- a/src/main/java/net/thenextlvl/service/api/model/Positioned.java +++ b/src/main/java/net/thenextlvl/service/api/model/Positioned.java @@ -8,6 +8,8 @@ /** * The Positioned interface represents an object with a specific position and orientation within a world. * It provides methods to retrieve coordinates, rotation, and associated world and server information. + * + * @since 2.2.0 */ public interface Positioned { /** diff --git a/src/main/java/net/thenextlvl/service/api/model/Viewable.java b/src/main/java/net/thenextlvl/service/api/model/Viewable.java index afdf6cfb..728e7ca5 100644 --- a/src/main/java/net/thenextlvl/service/api/model/Viewable.java +++ b/src/main/java/net/thenextlvl/service/api/model/Viewable.java @@ -10,6 +10,8 @@ /** * The Viewable interface represents an object that can be viewed or tracked by players within a specific range. * It provides methods to manage visibility, track players, and modify how the object is displayed. + * + * @since 2.2.0 */ @NullMarked public interface Viewable extends Positioned { diff --git a/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java b/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java index 112ab5f2..ecc1dafb 100644 --- a/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java +++ b/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java @@ -13,6 +13,7 @@ * The PermissionController interface represents a controller for managing permissions for players. * * @see PermissionHolder + * @since 1.0.0 */ @NullMarked public interface PermissionController extends Controller { diff --git a/src/main/java/net/thenextlvl/service/api/permission/PermissionHolder.java b/src/main/java/net/thenextlvl/service/api/permission/PermissionHolder.java index 0a9d76c0..381ea59a 100644 --- a/src/main/java/net/thenextlvl/service/api/permission/PermissionHolder.java +++ b/src/main/java/net/thenextlvl/service/api/permission/PermissionHolder.java @@ -11,6 +11,8 @@ * The {@code PermissionHolder} interface represents an entity that holds permissions. * It extends the {@link InfoNode} interface. * It provides methods to check, add, and remove permissions for the holder. + * + * @since 1.0.0 */ @NullMarked public interface PermissionHolder extends InfoNode { From b30e45a3961cee5fe45a11f54864b27f47865384 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 15 Jul 2025 21:54:30 +0200 Subject: [PATCH 15/32] Added nullable `World` support to controllers Refactored controllers and related methods to support `@Nullable World` parameters. Adjusted method signatures and default behaviors, introducing helper methods for context handling. This simplifies multi-world and default-world operations. --- .../chat/GroupManagerChatController.java | 49 ++------- .../chat/LuckPermsChatController.java | 28 ++--- .../group/GroupManagerGroupController.java | 82 ++++---------- .../group/LuckPermsGroupController.java | 100 ++++-------------- .../GroupManagerPermissionController.java | 22 ++-- .../LuckPermsPermissionController.java | 28 ++--- .../SuperPermsPermissionController.java | 23 +--- .../model/chat/LuckPermsChatProfile.java | 2 +- .../service/model/group/LuckPermsGroup.java | 6 +- .../wrapper/service/ChatServiceWrapper.java | 29 +---- .../service/PermissionServiceWrapper.java | 29 +---- .../service/api/chat/ChatController.java | 37 ++++--- .../service/api/group/GroupController.java | 88 ++++++++------- .../api/permission/PermissionController.java | 37 ++++--- 14 files changed, 183 insertions(+), 377 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/controller/chat/GroupManagerChatController.java b/plugin/src/main/java/net/thenextlvl/service/controller/chat/GroupManagerChatController.java index daf1c2b5..95df2b14 100644 --- a/plugin/src/main/java/net/thenextlvl/service/controller/chat/GroupManagerChatController.java +++ b/plugin/src/main/java/net/thenextlvl/service/controller/chat/GroupManagerChatController.java @@ -4,8 +4,8 @@ import net.thenextlvl.service.api.chat.ChatProfile; import net.thenextlvl.service.model.chat.GroupManagerChatProfile; import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder; import org.anjocaido.groupmanager.dataholder.WorldDataHolder; -import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; @@ -21,55 +21,20 @@ public class GroupManagerChatController implements ChatController { private final GroupManager groupManager = JavaPlugin.getPlugin(GroupManager.class); @Override - public CompletableFuture loadProfile(OfflinePlayer player) { - return getProfile(player) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> CompletableFuture.completedFuture(null)); - } - - @Override - public CompletableFuture loadProfile(OfflinePlayer player, World world) { - return getProfile(player, world) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> CompletableFuture.completedFuture(null)); - } - - @Override - public CompletableFuture loadProfile(UUID uuid) { - return getProfile(uuid) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> CompletableFuture.completedFuture(null)); - } - - @Override - public CompletableFuture loadProfile(UUID uuid, World world) { + public CompletableFuture loadProfile(UUID uuid, @Nullable World world) { return getProfile(uuid, world) .map(CompletableFuture::completedFuture) .orElseGet(() -> CompletableFuture.completedFuture(null)); } @Override - public Optional getProfile(OfflinePlayer player) { - var holder = groupManager.getWorldsHolder().getDefaultWorld(); - return getProfile(holder, player.getUniqueId(), player.getName()); + public Optional getProfile(UUID uuid, @Nullable World world) { + return getProfile(getHolder(world), uuid, null); } - @Override - public Optional getProfile(OfflinePlayer player, World world) { - var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); - return getProfile(holder, player.getUniqueId(), player.getName()); - } - - @Override - public Optional getProfile(UUID uuid) { - var holder = groupManager.getWorldsHolder().getDefaultWorld(); - return getProfile(holder, uuid, null); - } - - @Override - public Optional getProfile(UUID uuid, World world) { - var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); - return getProfile(holder, uuid, null); + private @Nullable OverloadedWorldHolder getHolder(@Nullable World world) { + if (world == null) return groupManager.getWorldsHolder().getDefaultWorld(); + return groupManager.getWorldsHolder().getWorldData(world.getName()); } private Optional getProfile(@Nullable WorldDataHolder holder, UUID uuid, @Nullable String name) { diff --git a/plugin/src/main/java/net/thenextlvl/service/controller/chat/LuckPermsChatController.java b/plugin/src/main/java/net/thenextlvl/service/controller/chat/LuckPermsChatController.java index a0534efe..82d8fdfc 100644 --- a/plugin/src/main/java/net/thenextlvl/service/controller/chat/LuckPermsChatController.java +++ b/plugin/src/main/java/net/thenextlvl/service/controller/chat/LuckPermsChatController.java @@ -10,6 +10,7 @@ import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -25,33 +26,24 @@ public LuckPermsChatController(Plugin plugin) { } @Override - public CompletableFuture loadProfile(UUID uuid) { - return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> - new LuckPermsChatProfile(user, QueryOptions.defaultContextualOptions())); - } - - @Override - public CompletableFuture loadProfile(UUID uuid, World world) { + public CompletableFuture loadProfile(UUID uuid, @Nullable World world) { return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> { - var options = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsChatProfile(user, options); + return new LuckPermsChatProfile(user, getOptions(world)); }); } @Override - public Optional getProfile(UUID uuid) { - return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> - new LuckPermsChatProfile(user, QueryOptions.defaultContextualOptions())); - } - - @Override - public Optional getProfile(UUID uuid, World world) { + public Optional getProfile(UUID uuid, @Nullable World world) { return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> { - var options = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsChatProfile(user, options); + return new LuckPermsChatProfile(user, getOptions(world)); }); } + private QueryOptions getOptions(@Nullable World world) { + if (world == null) return QueryOptions.defaultContextualOptions(); + return QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); + } + @Override public Plugin getPlugin() { return plugin; diff --git a/plugin/src/main/java/net/thenextlvl/service/controller/group/GroupManagerGroupController.java b/plugin/src/main/java/net/thenextlvl/service/controller/group/GroupManagerGroupController.java index 2284e57e..b5bf4322 100644 --- a/plugin/src/main/java/net/thenextlvl/service/controller/group/GroupManagerGroupController.java +++ b/plugin/src/main/java/net/thenextlvl/service/controller/group/GroupManagerGroupController.java @@ -6,8 +6,8 @@ import net.thenextlvl.service.model.group.GroupManagerGroup; import net.thenextlvl.service.model.permission.GroupManagerPermissionHolder; import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder; import org.anjocaido.groupmanager.dataholder.WorldDataHolder; -import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; @@ -32,59 +32,30 @@ public CompletableFuture createGroup(String name) { } @Override - public CompletableFuture createGroup(String name, World world) { + public CompletableFuture createGroup(String name, @Nullable World world) { + if (world == null) return createGroup(name); var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); if (holder == null) return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(new GroupManagerGroup(holder.createGroup(name))); } @Override - public CompletableFuture loadGroup(String name) { - return CompletableFuture.completedFuture(getGroup(name).orElse(null)); - } - - @Override - public CompletableFuture loadGroup(String name, World world) { + public CompletableFuture loadGroup(String name, @Nullable World world) { return CompletableFuture.completedFuture(getGroup(name, world).orElse(null)); } @Override - public CompletableFuture loadGroupHolder(OfflinePlayer player) { - return CompletableFuture.completedFuture(getGroupHolder(player).orElse(null)); - } - - @Override - public CompletableFuture loadGroupHolder(OfflinePlayer player, World world) { - return CompletableFuture.completedFuture(getGroupHolder(player, world).orElse(null)); - } - - @Override - public CompletableFuture loadGroupHolder(UUID uuid) { - return CompletableFuture.completedFuture(getGroupHolder(uuid).orElse(null)); - } - - @Override - public CompletableFuture loadGroupHolder(UUID uuid, World world) { + public CompletableFuture loadGroupHolder(UUID uuid, @Nullable World world) { return CompletableFuture.completedFuture(getGroupHolder(uuid, world).orElse(null)); } @Override - public CompletableFuture> loadGroups() { - return CompletableFuture.completedFuture(getGroups()); - } - - @Override - public CompletableFuture> loadGroups(World world) { + public CompletableFuture> loadGroups(@Nullable World world) { return CompletableFuture.completedFuture(getGroups(world)); } @Override - public CompletableFuture deleteGroup(Group group) { - return deleteGroup(group.getName()); - } - - @Override - public CompletableFuture deleteGroup(Group group, World world) { + public CompletableFuture deleteGroup(Group group, @Nullable World world) { return deleteGroup(group.getName(), world); } @@ -94,7 +65,8 @@ public CompletableFuture deleteGroup(String name) { } @Override - public CompletableFuture deleteGroup(String name, World world) { + public CompletableFuture deleteGroup(String name, @Nullable World world) { + if (world == null) return deleteGroup(name); var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); if (holder != null) CompletableFuture.completedFuture(holder.removeGroup(name)); return CompletableFuture.completedFuture(null); @@ -107,7 +79,8 @@ public Optional getGroup(String name) { } @Override - public Optional getGroup(String name, World world) { + public Optional getGroup(String name, @Nullable World world) { + if (world == null) return getGroup(name); var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); return Optional.ofNullable(holder) .map(holder1 -> holder1.getGroup(name)) @@ -115,27 +88,8 @@ public Optional getGroup(String name, World world) { } @Override - public Optional getGroupHolder(OfflinePlayer player) { - var holder = groupManager.getWorldsHolder().getDefaultWorld(); - return getHolder(holder, player.getUniqueId(), player.getName()); - } - - @Override - public Optional getGroupHolder(OfflinePlayer player, World world) { - var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); - return getHolder(holder, player.getUniqueId(), player.getName()); - } - - @Override - public Optional getGroupHolder(UUID uuid) { - var holder = groupManager.getWorldsHolder().getDefaultWorld(); - return getHolder(holder, uuid, null); - } - - @Override - public Optional getGroupHolder(UUID uuid, World world) { - var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); - return getHolder(holder, uuid, null); + public Optional getGroupHolder(UUID uuid, @Nullable World world) { + return getHolder(getHolder(world), uuid, null); } @Override @@ -146,14 +100,20 @@ public Set getGroups() { } @Override - public Set getGroups(World world) { - var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); + public Set getGroups(@Nullable World world) { + if (world == null) return getGroups(); + var holder = getHolder(world); if (holder == null) return Set.of(); return holder.getGroups().values().stream() .map(GroupManagerGroup::new) .collect(Collectors.toUnmodifiableSet()); } + private @Nullable OverloadedWorldHolder getHolder(@Nullable World world) { + if (world == null) return groupManager.getWorldsHolder().getDefaultWorld(); + return groupManager.getWorldsHolder().getWorldData(world.getName()); + } + private Optional getHolder(@Nullable WorldDataHolder holder, UUID uuid, @Nullable String name) { if (holder == null) return Optional.empty(); var user = name != null ? holder.getUser(uuid.toString(), name) : holder.getUser(uuid.toString()); diff --git a/plugin/src/main/java/net/thenextlvl/service/controller/group/LuckPermsGroupController.java b/plugin/src/main/java/net/thenextlvl/service/controller/group/LuckPermsGroupController.java index c499c44d..e30711ac 100644 --- a/plugin/src/main/java/net/thenextlvl/service/controller/group/LuckPermsGroupController.java +++ b/plugin/src/main/java/net/thenextlvl/service/controller/group/LuckPermsGroupController.java @@ -12,6 +12,7 @@ import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.Set; @@ -29,124 +30,69 @@ public LuckPermsGroupController(Plugin plugin) { } @Override - public CompletableFuture createGroup(String name) { - return luckPerms.getGroupManager().createAndLoadGroup(name) - .thenApply(group -> new LuckPermsGroup(group, group.getQueryOptions(), null)); - } - - @Override - public CompletableFuture createGroup(String name, World world) { + public CompletableFuture createGroup(String name, @Nullable World world) { return luckPerms.getGroupManager().createAndLoadGroup(name).thenApply(group -> { - var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsGroup(group, context, null); + return new LuckPermsGroup(group, getOptions(world), null); }); } @Override - public CompletableFuture loadGroup(String name) { - return luckPerms.getGroupManager().loadGroup(name).thenCompose(optional -> - optional.map(group -> new LuckPermsGroup(group, group.getQueryOptions(), null)) - .map(CompletableFuture::completedFuture) - .orElse(CompletableFuture.completedFuture(null))); - } - - @Override - public CompletableFuture loadGroup(String name, World world) { - return luckPerms.getGroupManager().loadGroup(name).thenCompose(optional -> optional.map(group -> { - var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsGroup(group, context, world); - }) + public CompletableFuture loadGroup(String name, @Nullable World world) { + return luckPerms.getGroupManager().loadGroup(name).thenCompose(optional -> optional.map(group -> + new LuckPermsGroup(group, getOptions(world), world)) .map(CompletableFuture::completedFuture) .orElse(CompletableFuture.completedFuture(null))); } @Override - public CompletableFuture loadGroupHolder(UUID uuid) { - return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> - new LuckPermsPermissionHolder(user, QueryOptions.defaultContextualOptions())); - } - - @Override - public CompletableFuture loadGroupHolder(UUID uuid, World world) { + public CompletableFuture loadGroupHolder(UUID uuid, @Nullable World world) { return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> { - var options = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsPermissionHolder(user, options); + return new LuckPermsPermissionHolder(user, getOptions(world)); }); } @Override - public CompletableFuture> loadGroups() { - return luckPerms.getGroupManager().loadAllGroups().thenApply(unused -> getGroups()); - } - - @Override - public CompletableFuture> loadGroups(World world) { + public CompletableFuture> loadGroups(@Nullable World world) { return luckPerms.getGroupManager().loadAllGroups().thenApply(unused -> getGroups(world)); } @Override - public CompletableFuture deleteGroup(Group group) { - return !(group instanceof LuckPermsGroup luckPermsGroup) ? deleteGroup(group.getName()) - : luckPerms.getGroupManager().deleteGroup(luckPermsGroup.group()).thenApply(none -> true); + public CompletableFuture deleteGroup(Group group, @Nullable World world) { + if (!(group instanceof LuckPermsGroup luckPermsGroup)) return CompletableFuture.completedFuture(false); + return luckPerms.getGroupManager().deleteGroup(luckPermsGroup.group()).thenApply(none -> true); } @Override - public CompletableFuture deleteGroup(Group group, World world) { - return deleteGroup(group); - } - - @Override - public CompletableFuture deleteGroup(String name) { + public CompletableFuture deleteGroup(String name, @Nullable World world) { return luckPerms.getGroupManager().loadGroup(name).thenApply(optional -> optional.map(luckPerms.getGroupManager()::deleteGroup).isPresent()); } @Override - public CompletableFuture deleteGroup(String name, World world) { - return deleteGroup(name); - } - - @Override - public Optional getGroup(String name) { - return Optional.ofNullable(luckPerms.getGroupManager().getGroup(name)).map(group -> - new LuckPermsGroup(group, group.getQueryOptions(), null)); - } - - @Override - public Optional getGroup(String name, World world) { + public Optional getGroup(String name, @Nullable World world) { return Optional.ofNullable(luckPerms.getGroupManager().getGroup(name)).map(group -> { - var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsGroup(group, context, null); + return new LuckPermsGroup(group, getOptions(world), null); }); } @Override - public Optional getGroupHolder(UUID uuid) { - return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> - new LuckPermsPermissionHolder(user, QueryOptions.defaultContextualOptions())); - } - - @Override - public Optional getGroupHolder(UUID uuid, World world) { + public Optional getGroupHolder(UUID uuid, @Nullable World world) { return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> { - var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsPermissionHolder(user, context); + return new LuckPermsPermissionHolder(user, getOptions(world)); }); } @Override - public Set getGroups() { + public Set getGroups(@Nullable World world) { + var options = getOptions(world); return luckPerms.getGroupManager().getLoadedGroups().stream() - .map(group -> new LuckPermsGroup(group, group.getQueryOptions(), null)) + .map(group -> new LuckPermsGroup(group, options, world)) .collect(Collectors.toUnmodifiableSet()); } - @Override - public Set getGroups(World world) { - var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return luckPerms.getGroupManager().getLoadedGroups().stream() - .map(group -> new LuckPermsGroup(group, context, world)) - .collect(Collectors.toUnmodifiableSet()); + private QueryOptions getOptions(@Nullable World world) { + if (world == null) return luckPerms.getContextManager().getStaticQueryOptions(); + return QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/controller/permission/GroupManagerPermissionController.java b/plugin/src/main/java/net/thenextlvl/service/controller/permission/GroupManagerPermissionController.java index 86645240..80cf0aa5 100644 --- a/plugin/src/main/java/net/thenextlvl/service/controller/permission/GroupManagerPermissionController.java +++ b/plugin/src/main/java/net/thenextlvl/service/controller/permission/GroupManagerPermissionController.java @@ -4,6 +4,7 @@ import net.thenextlvl.service.api.permission.PermissionHolder; import net.thenextlvl.service.model.permission.GroupManagerPermissionHolder; import org.anjocaido.groupmanager.GroupManager; +import org.anjocaido.groupmanager.dataholder.OverloadedWorldHolder; import org.anjocaido.groupmanager.dataholder.WorldDataHolder; import org.bukkit.World; import org.bukkit.plugin.Plugin; @@ -20,25 +21,18 @@ public class GroupManagerPermissionController implements PermissionController { private final GroupManager groupManager = JavaPlugin.getPlugin(GroupManager.class); @Override - public CompletableFuture loadPermissionHolder(UUID uuid) { - var holder = groupManager.getWorldsHolder().getDefaultWorld(); - return CompletableFuture.completedFuture(getHolder(holder, uuid).orElse(null)); + public CompletableFuture loadPermissionHolder(UUID uuid, @Nullable World world) { + return CompletableFuture.completedFuture(getHolder(getHolder(world), uuid).orElse(null)); } @Override - public CompletableFuture loadPermissionHolder(UUID uuid, World world) { - var holder = groupManager.getWorldsHolder().getWorldData(world.getName()); - return CompletableFuture.completedFuture(getHolder(holder, uuid).orElse(null)); + public Optional getPermissionHolder(UUID uuid, @Nullable World world) { + return getHolder(getHolder(world), uuid); } - @Override - public Optional getPermissionHolder(UUID uuid) { - return Optional.empty(); - } - - @Override - public Optional getPermissionHolder(UUID uuid, World world) { - return Optional.empty(); + private @Nullable OverloadedWorldHolder getHolder(@Nullable World world) { + if (world == null) return groupManager.getWorldsHolder().getDefaultWorld(); + return groupManager.getWorldsHolder().getWorldData(world.getName()); } private Optional getHolder(@Nullable WorldDataHolder holder, UUID uuid) { diff --git a/plugin/src/main/java/net/thenextlvl/service/controller/permission/LuckPermsPermissionController.java b/plugin/src/main/java/net/thenextlvl/service/controller/permission/LuckPermsPermissionController.java index f1992d30..530bc469 100644 --- a/plugin/src/main/java/net/thenextlvl/service/controller/permission/LuckPermsPermissionController.java +++ b/plugin/src/main/java/net/thenextlvl/service/controller/permission/LuckPermsPermissionController.java @@ -10,6 +10,7 @@ import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -25,33 +26,24 @@ public LuckPermsPermissionController(Plugin plugin) { } @Override - public CompletableFuture loadPermissionHolder(UUID uuid) { - return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> - new LuckPermsPermissionHolder(user, QueryOptions.defaultContextualOptions())); - } - - @Override - public CompletableFuture loadPermissionHolder(UUID uuid, World world) { + public CompletableFuture loadPermissionHolder(UUID uuid, @Nullable World world) { return luckPerms.getUserManager().loadUser(uuid).thenApply(user -> { - var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsPermissionHolder(user, context); + return new LuckPermsPermissionHolder(user, getOptions(world)); }); } @Override - public Optional getPermissionHolder(UUID uuid) { - return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)) - .map(user -> new LuckPermsPermissionHolder(user, QueryOptions.defaultContextualOptions())); - } - - @Override - public Optional getPermissionHolder(UUID uuid, World world) { + public Optional getPermissionHolder(UUID uuid, @Nullable World world) { return Optional.ofNullable(luckPerms.getUserManager().getUser(uuid)).map(user -> { - var context = QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); - return new LuckPermsPermissionHolder(user, context); + return new LuckPermsPermissionHolder(user, getOptions(world)); }); } + private QueryOptions getOptions(@Nullable World world) { + if (world == null) return QueryOptions.defaultContextualOptions(); + return QueryOptions.contextual(ImmutableContextSet.of("world", world.getName())); + } + @Override public Plugin getPlugin() { return plugin; diff --git a/plugin/src/main/java/net/thenextlvl/service/controller/permission/SuperPermsPermissionController.java b/plugin/src/main/java/net/thenextlvl/service/controller/permission/SuperPermsPermissionController.java index 01f14f5a..b5d2a26c 100644 --- a/plugin/src/main/java/net/thenextlvl/service/controller/permission/SuperPermsPermissionController.java +++ b/plugin/src/main/java/net/thenextlvl/service/controller/permission/SuperPermsPermissionController.java @@ -24,35 +24,20 @@ public SuperPermsPermissionController(ServicePlugin plugin) { } @Override - public CompletableFuture loadPermissionHolder(OfflinePlayer player) { + public CompletableFuture loadPermissionHolder(OfflinePlayer player, @Nullable World world) { return CompletableFuture.completedFuture(getPermissionHolder(player.getPlayer()).orElse(null)); } @Override - public CompletableFuture loadPermissionHolder(OfflinePlayer player, World world) { - return loadPermissionHolder(player); + public CompletableFuture loadPermissionHolder(UUID uuid, @Nullable World world) { + return CompletableFuture.completedFuture(getPermissionHolder(uuid, world).orElse(null)); } @Override - public CompletableFuture loadPermissionHolder(UUID uuid) { - return CompletableFuture.completedFuture(getPermissionHolder(uuid).orElse(null)); - } - - @Override - public CompletableFuture loadPermissionHolder(UUID uuid, World world) { - return loadPermissionHolder(uuid); - } - - @Override - public Optional getPermissionHolder(UUID uuid) { + public Optional getPermissionHolder(UUID uuid, @Nullable World world) { return getPermissionHolder(plugin.getServer().getPlayer(uuid)); } - @Override - public Optional getPermissionHolder(UUID uuid, World world) { - return getPermissionHolder(uuid); - } - private Optional getPermissionHolder(@Nullable Player player) { return Optional.ofNullable(player).map(SuperPermsPermissionHolder::new); } diff --git a/plugin/src/main/java/net/thenextlvl/service/model/chat/LuckPermsChatProfile.java b/plugin/src/main/java/net/thenextlvl/service/model/chat/LuckPermsChatProfile.java index 096d4692..f50219a4 100644 --- a/plugin/src/main/java/net/thenextlvl/service/model/chat/LuckPermsChatProfile.java +++ b/plugin/src/main/java/net/thenextlvl/service/model/chat/LuckPermsChatProfile.java @@ -82,7 +82,7 @@ public boolean setDisplayName(@Nullable String displayName) { } private boolean unsetDisplayName() { - user().data().clear(options().context(), node -> node instanceof DisplayNameNode); + user().data().clear(options().context(), DisplayNameNode.class::isInstance); LuckPermsProvider.get().getUserManager().saveUser(user()); return true; } diff --git a/plugin/src/main/java/net/thenextlvl/service/model/group/LuckPermsGroup.java b/plugin/src/main/java/net/thenextlvl/service/model/group/LuckPermsGroup.java index 926d22a3..cbdc9528 100644 --- a/plugin/src/main/java/net/thenextlvl/service/model/group/LuckPermsGroup.java +++ b/plugin/src/main/java/net/thenextlvl/service/model/group/LuckPermsGroup.java @@ -79,7 +79,7 @@ public Optional getWorld() { @Override public boolean setDisplayName(@Nullable String displayName) { if (displayName == null) { - group.data().clear(node -> node instanceof DisplayNameNode); + group.data().clear(DisplayNameNode.class::isInstance); return true; } var result = group().data().add(DisplayNameNode.builder(displayName).context(options().context()).build()); @@ -97,7 +97,7 @@ public boolean setWeight(int weight) { @Override public boolean setPrefix(@Nullable String prefix, int priority) { if (prefix == null) { - group.data().clear(node -> node instanceof PrefixNode); + group.data().clear(PrefixNode.class::isInstance); return true; } var result = group().data().add(PrefixNode.builder(prefix, priority).context(options().context()).build()); @@ -108,7 +108,7 @@ public boolean setPrefix(@Nullable String prefix, int priority) { @Override public boolean setSuffix(@Nullable String suffix, int priority) { if (suffix == null) { - group.data().clear(node -> node instanceof SuffixNode); + group.data().clear(SuffixNode.class::isInstance); return true; } var result = group().data().add(SuffixNode.builder(suffix, priority).context(options().context()).build()); diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/ChatServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/ChatServiceWrapper.java index c6d2c196..49eafbbc 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/ChatServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/ChatServiceWrapper.java @@ -9,6 +9,7 @@ import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -25,42 +26,22 @@ public ChatServiceWrapper(Chat chat, Plugin provider) { } @Override - public CompletableFuture loadProfile(OfflinePlayer player) { - return CompletableFuture.completedFuture(new WrappedChatProfile(null, chat, player)); - } - - @Override - public CompletableFuture loadProfile(OfflinePlayer player, World world) { + public CompletableFuture loadProfile(OfflinePlayer player, @Nullable World world) { return CompletableFuture.completedFuture(new WrappedChatProfile(world, chat, player)); } @Override - public CompletableFuture loadProfile(UUID uuid) { - return loadProfile(provider.getServer().getOfflinePlayer(uuid)); - } - - @Override - public CompletableFuture loadProfile(UUID uuid, World world) { + public CompletableFuture loadProfile(UUID uuid, @Nullable World world) { return loadProfile(provider.getServer().getOfflinePlayer(uuid), world); } @Override - public Optional getProfile(OfflinePlayer player) { - return Optional.of(new WrappedChatProfile(null, chat, player)); - } - - @Override - public Optional getProfile(OfflinePlayer player, World world) { + public Optional getProfile(OfflinePlayer player, @Nullable World world) { return Optional.of(new WrappedChatProfile(world, chat, player)); } @Override - public Optional getProfile(UUID uuid) { - return getProfile(provider.getServer().getOfflinePlayer(uuid)); - } - - @Override - public Optional getProfile(UUID uuid, World world) { + public Optional getProfile(UUID uuid, @Nullable World world) { return getProfile(provider.getServer().getOfflinePlayer(uuid), world); } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/PermissionServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/PermissionServiceWrapper.java index 54963075..73ce1c1a 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/PermissionServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/PermissionServiceWrapper.java @@ -9,6 +9,7 @@ import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -25,42 +26,22 @@ public PermissionServiceWrapper(Permission permission, Plugin provider) { } @Override - public CompletableFuture loadPermissionHolder(OfflinePlayer player) { - return CompletableFuture.completedFuture(new WrappedPermissionHolder(null, player, permission)); - } - - @Override - public CompletableFuture loadPermissionHolder(OfflinePlayer player, World world) { + public CompletableFuture loadPermissionHolder(OfflinePlayer player, @Nullable World world) { return CompletableFuture.completedFuture(new WrappedPermissionHolder(world, player, permission)); } @Override - public CompletableFuture loadPermissionHolder(UUID uuid) { - return loadPermissionHolder(provider.getServer().getOfflinePlayer(uuid)); - } - - @Override - public CompletableFuture loadPermissionHolder(UUID uuid, World world) { + public CompletableFuture loadPermissionHolder(UUID uuid, @Nullable World world) { return loadPermissionHolder(provider.getServer().getOfflinePlayer(uuid), world); } @Override - public Optional getPermissionHolder(OfflinePlayer player) { - return Optional.of(new WrappedPermissionHolder(null, player, permission)); - } - - @Override - public Optional getPermissionHolder(OfflinePlayer player, World world) { + public Optional getPermissionHolder(OfflinePlayer player, @Nullable World world) { return Optional.of(new WrappedPermissionHolder(world, player, permission)); } @Override - public Optional getPermissionHolder(UUID uuid) { - return getPermissionHolder(provider.getServer().getOfflinePlayer(uuid)); - } - - @Override - public Optional getPermissionHolder(UUID uuid, World world) { + public Optional getPermissionHolder(UUID uuid, @Nullable World world) { return getPermissionHolder(provider.getServer().getOfflinePlayer(uuid), world); } diff --git a/src/main/java/net/thenextlvl/service/api/chat/ChatController.java b/src/main/java/net/thenextlvl/service/api/chat/ChatController.java index ccf23f45..4e70856c 100644 --- a/src/main/java/net/thenextlvl/service/api/chat/ChatController.java +++ b/src/main/java/net/thenextlvl/service/api/chat/ChatController.java @@ -4,6 +4,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -23,7 +24,7 @@ public interface ChatController extends Controller { * @return a CompletableFuture that will complete with the chat profile */ default CompletableFuture loadProfile(OfflinePlayer player) { - return loadProfile(player.getUniqueId()); + return loadProfile(player, null); } /** @@ -33,7 +34,7 @@ default CompletableFuture loadProfile(OfflinePlayer player) { * @param world The world for which the chat profile is requested. * @return A CompletableFuture that will complete with the chat profile. */ - default CompletableFuture loadProfile(OfflinePlayer player, World world) { + default CompletableFuture loadProfile(OfflinePlayer player, @Nullable World world) { return loadProfile(player.getUniqueId(), world); } @@ -43,7 +44,9 @@ default CompletableFuture loadProfile(OfflinePlayer player, World w * @param uuid The UUID of the player whose ChatProfile is to be retrieved. * @return A CompletableFuture that will complete with the chat profile. */ - CompletableFuture loadProfile(UUID uuid); + default CompletableFuture loadProfile(UUID uuid) { + return loadProfile(uuid, null); + } /** * Loads the chat profile for the given UUID in the specified world. @@ -52,7 +55,7 @@ default CompletableFuture loadProfile(OfflinePlayer player, World w * @param world The world for which the ChatProfile is requested. * @return A CompletableFuture that will complete with the chat profile. */ - CompletableFuture loadProfile(UUID uuid, World world); + CompletableFuture loadProfile(UUID uuid, @Nullable World world); /** * Retrieves the chat profile for the given OfflinePlayer or try to load it. @@ -61,9 +64,7 @@ default CompletableFuture loadProfile(OfflinePlayer player, World w * @return a CompletableFuture that will complete with the chat profile */ default CompletableFuture tryGetProfile(OfflinePlayer player) { - return getProfile(player) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadProfile(player)); + return tryGetProfile(player, null); } /** @@ -73,10 +74,8 @@ default CompletableFuture tryGetProfile(OfflinePlayer player) { * @param world The world for which the chat profile is requested. * @return A CompletableFuture that will complete with the chat profile. */ - default CompletableFuture tryGetProfile(OfflinePlayer player, World world) { - return getProfile(player, world) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadProfile(player, world)); + default CompletableFuture tryGetProfile(OfflinePlayer player, @Nullable World world) { + return tryGetProfile(player.getUniqueId(), world); } /** @@ -86,9 +85,7 @@ default CompletableFuture tryGetProfile(OfflinePlayer player, World * @return A CompletableFuture that will complete with the chat profile. */ default CompletableFuture tryGetProfile(UUID uuid) { - return getProfile(uuid) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadProfile(uuid)); + return tryGetProfile(uuid, null); } /** @@ -98,7 +95,7 @@ default CompletableFuture tryGetProfile(UUID uuid) { * @param world The world for which the ChatProfile is requested. * @return A CompletableFuture that will complete with the chat profile. */ - default CompletableFuture tryGetProfile(UUID uuid, World world) { + default CompletableFuture tryGetProfile(UUID uuid, @Nullable World world) { return getProfile(uuid, world) .map(CompletableFuture::completedFuture) .orElseGet(() -> loadProfile(uuid, world)); @@ -111,7 +108,7 @@ default CompletableFuture tryGetProfile(UUID uuid, World world) { * @return an optional containing the chat profile, or empty. */ default Optional getProfile(OfflinePlayer player) { - return getProfile(player.getUniqueId()); + return getProfile(player, null); } /** @@ -121,7 +118,7 @@ default Optional getProfile(OfflinePlayer player) { * @param world The world for which the chat profile is requested. * @return an optional containing the chat profile, or empty. */ - default Optional getProfile(OfflinePlayer player, World world) { + default Optional getProfile(OfflinePlayer player, @Nullable World world) { return getProfile(player.getUniqueId(), world); } @@ -131,7 +128,9 @@ default Optional getProfile(OfflinePlayer player, World world) { * @param uuid The UUID of the player whose ChatProfile is to be retrieved. * @return an optional containing the chat profile, or empty. */ - Optional getProfile(UUID uuid); + default Optional getProfile(UUID uuid) { + return getProfile(uuid, null); + } /** * Retrieves the chat profile for the given UUID in the specified world. @@ -140,5 +139,5 @@ default Optional getProfile(OfflinePlayer player, World world) { * @param world The world for which the ChatProfile is requested. * @return an optional containing the chat profile, or empty. */ - Optional getProfile(UUID uuid, World world); + Optional getProfile(UUID uuid, @Nullable World world); } diff --git a/src/main/java/net/thenextlvl/service/api/group/GroupController.java b/src/main/java/net/thenextlvl/service/api/group/GroupController.java index bc7c2d0a..2542e16f 100644 --- a/src/main/java/net/thenextlvl/service/api/group/GroupController.java +++ b/src/main/java/net/thenextlvl/service/api/group/GroupController.java @@ -5,6 +5,7 @@ import org.bukkit.World; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.Set; @@ -26,7 +27,9 @@ public interface GroupController extends Controller { * @param name the name of the group to create * @return a CompletableFuture that will complete with the created Group object */ - CompletableFuture createGroup(String name); + default CompletableFuture createGroup(String name) { + return createGroup(name, null); + } /** * Creates a new group with the given name. @@ -35,7 +38,7 @@ public interface GroupController extends Controller { * @param world the world the group should be created for * @return a CompletableFuture that will complete with the created Group object */ - CompletableFuture createGroup(String name, World world); + CompletableFuture createGroup(String name, @Nullable World world); /** * Retrieves the group with the given name asynchronously. @@ -43,7 +46,9 @@ public interface GroupController extends Controller { * @param name the name of the group to retrieve * @return a CompletableFuture that will complete with the retrieved Group object */ - CompletableFuture loadGroup(String name); + default CompletableFuture loadGroup(String name) { + return loadGroup(name, null); + } /** * Loads a group asynchronously by its name and world. @@ -52,7 +57,7 @@ public interface GroupController extends Controller { * @param world the world the group should be loaded from * @return a CompletableFuture that will complete with the loaded Group object */ - CompletableFuture loadGroup(String name, World world); + CompletableFuture loadGroup(String name, @Nullable World world); /** * Loads the GroupHolder asynchronously associated with the specified player. @@ -61,7 +66,7 @@ public interface GroupController extends Controller { * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ default CompletableFuture loadGroupHolder(OfflinePlayer player) { - return loadGroupHolder(player.getUniqueId()); + return loadGroupHolder(player, null); } /** @@ -71,7 +76,7 @@ default CompletableFuture loadGroupHolder(OfflinePlayer player) { * @param world the world from which to load the GroupHolder * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ - default CompletableFuture loadGroupHolder(OfflinePlayer player, World world) { + default CompletableFuture loadGroupHolder(OfflinePlayer player, @Nullable World world) { return loadGroupHolder(player.getUniqueId(), world); } @@ -81,7 +86,9 @@ default CompletableFuture loadGroupHolder(OfflinePlayer player, Wor * @param uuid the UUID of the player for whom to load the GroupHolder * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ - CompletableFuture loadGroupHolder(UUID uuid); + default CompletableFuture loadGroupHolder(UUID uuid) { + return loadGroupHolder(uuid, null); + } /** * Loads the GroupHolder asynchronously associated with the specified player's UUID and world. @@ -90,39 +97,31 @@ default CompletableFuture loadGroupHolder(OfflinePlayer player, Wor * @param world the world from which to load the GroupHolder * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ - CompletableFuture loadGroupHolder(UUID uuid, World world); + CompletableFuture loadGroupHolder(UUID uuid, @Nullable World world); default CompletableFuture tryGetGroup(String name) { - return getGroup(name) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadGroup(name)); + return tryGetGroup(name, null); } - default CompletableFuture tryGetGroup(String name, World world) { + default CompletableFuture tryGetGroup(String name, @Nullable World world) { return getGroup(name, world) .map(CompletableFuture::completedFuture) .orElseGet(() -> loadGroup(name, world)); } default CompletableFuture tryGetGroupHolder(OfflinePlayer player) { - return getGroupHolder(player) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadGroupHolder(player)); + return tryGetGroupHolder(player, null); } - default CompletableFuture tryGetGroupHolder(OfflinePlayer player, World world) { - return getGroupHolder(player, world) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadGroupHolder(player, world)); + default CompletableFuture tryGetGroupHolder(OfflinePlayer player, @Nullable World world) { + return tryGetGroupHolder(player.getUniqueId(), world); } default CompletableFuture tryGetGroupHolder(UUID uuid) { - return getGroupHolder(uuid) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadGroupHolder(uuid)); + return tryGetGroupHolder(uuid, null); } - default CompletableFuture tryGetGroupHolder(UUID uuid, World world) { + default CompletableFuture tryGetGroupHolder(UUID uuid, @Nullable World world) { return getGroupHolder(uuid, world) .map(CompletableFuture::completedFuture) .orElseGet(() -> loadGroupHolder(uuid, world)); @@ -133,7 +132,9 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * * @return a CompletableFuture that will complete with a set of groups */ - CompletableFuture<@Unmodifiable Set> loadGroups(); + default CompletableFuture<@Unmodifiable Set> loadGroups() { + return loadGroups(null); + } /** * Retrieves a set of groups asynchronously for the given world. @@ -141,7 +142,7 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @param world the world for which to retrieve the groups * @return a CompletableFuture that will complete with a set of groups */ - CompletableFuture<@Unmodifiable Set> loadGroups(World world); + CompletableFuture<@Unmodifiable Set> loadGroups(@Nullable World world); /** * Deletes the given group. @@ -149,7 +150,9 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @param group the group to delete * @return a CompletableFuture that will complete when the group has been deleted */ - CompletableFuture deleteGroup(Group group); + default CompletableFuture deleteGroup(Group group) { + return deleteGroup(group, null); + } /** * Deletes the given group. @@ -158,7 +161,9 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @param world the world the group should be deleted from * @return a CompletableFuture that will complete when the group has been deleted */ - CompletableFuture deleteGroup(Group group, World world); + default CompletableFuture deleteGroup(Group group, @Nullable World world) { + return deleteGroup(group.getName(), world); + } /** * Deletes the group with the given name. @@ -166,7 +171,9 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @param name the name of the group to delete * @return a CompletableFuture that will complete when the group has been deleted */ - CompletableFuture deleteGroup(String name); + default CompletableFuture deleteGroup(String name) { + return deleteGroup(name, null); + } /** * Deletes the group with the given name. @@ -175,7 +182,7 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @param world the world the group should be deleted from * @return a CompletableFuture that will complete when the group has been deleted */ - CompletableFuture deleteGroup(String name, World world); + CompletableFuture deleteGroup(String name, @Nullable World world); /** * Retrieves the group with the given name. @@ -183,7 +190,9 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @param name the name of the group to retrieve * @return a CompletableFuture that will complete with the retrieved Group object */ - Optional getGroup(String name); + default Optional getGroup(String name) { + return getGroup(name, null); + } /** * Retrieves the group with the given name. @@ -192,7 +201,7 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @param world the world the group should be received from * @return a CompletableFuture that will complete with the retrieved Group object */ - Optional getGroup(String name, World world); + Optional getGroup(String name, @Nullable World world); /** * Retrieves the GroupHolder associated with the given player. @@ -201,7 +210,7 @@ default CompletableFuture tryGetGroupHolder(UUID uuid, World world) * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ default Optional getGroupHolder(OfflinePlayer player) { - return getGroupHolder(player.getUniqueId()); + return getGroupHolder(player, null); } /** @@ -211,7 +220,7 @@ default Optional getGroupHolder(OfflinePlayer player) { * @param world the world the group holder should be received from * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ - default Optional getGroupHolder(OfflinePlayer player, World world) { + default Optional getGroupHolder(OfflinePlayer player, @Nullable World world) { return getGroupHolder(player.getUniqueId(), world); } @@ -221,7 +230,9 @@ default Optional getGroupHolder(OfflinePlayer player, World world) * @param uuid the UUID of the player for which to retrieve the GroupHolder * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ - Optional getGroupHolder(UUID uuid); + default Optional getGroupHolder(UUID uuid) { + return getGroupHolder(uuid, null); + } /** * Retrieves the GroupHolder associated with the given UUID. @@ -230,15 +241,16 @@ default Optional getGroupHolder(OfflinePlayer player, World world) * @param world the world the group holder should be received from * @return a CompletableFuture that will complete with the retrieved GroupHolder object */ - Optional getGroupHolder(UUID uuid, World world); + Optional getGroupHolder(UUID uuid, @Nullable World world); /** * Retrieves all groups. * * @return A CompletableFuture that will complete with a collection of all the groups. */ - @Unmodifiable - Set getGroups(); + default @Unmodifiable Set getGroups() { + return getGroups(null); + } /** * Retrieves all groups. @@ -247,5 +259,5 @@ default Optional getGroupHolder(OfflinePlayer player, World world) * @return A CompletableFuture that will complete with a collection of all the groups. */ @Unmodifiable - Set getGroups(World world); + Set getGroups(@Nullable World world); } diff --git a/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java b/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java index ecc1dafb..be51e669 100644 --- a/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java +++ b/src/main/java/net/thenextlvl/service/api/permission/PermissionController.java @@ -4,6 +4,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -25,7 +26,7 @@ public interface PermissionController extends Controller { * @see PermissionHolder */ default CompletableFuture loadPermissionHolder(OfflinePlayer player) { - return loadPermissionHolder(player.getUniqueId()); + return loadPermissionHolder(player, null); } /** @@ -37,7 +38,7 @@ default CompletableFuture loadPermissionHolder(OfflinePlayer p * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - default CompletableFuture loadPermissionHolder(OfflinePlayer player, World world) { + default CompletableFuture loadPermissionHolder(OfflinePlayer player, @Nullable World world) { return loadPermissionHolder(player.getUniqueId(), world); } @@ -48,7 +49,9 @@ default CompletableFuture loadPermissionHolder(OfflinePlayer p * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - CompletableFuture loadPermissionHolder(UUID uuid); + default CompletableFuture loadPermissionHolder(UUID uuid) { + return loadPermissionHolder(uuid, null); + } /** * Loads the {@code PermissionHolder} for the specified {@code UUID} and {@code World} asynchronously. @@ -58,7 +61,7 @@ default CompletableFuture loadPermissionHolder(OfflinePlayer p * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - CompletableFuture loadPermissionHolder(UUID uuid, World world); + CompletableFuture loadPermissionHolder(UUID uuid, @Nullable World world); /** * Retrieves the {@code PermissionHolder} for the specified {@code OfflinePlayer} or try to load it. @@ -68,9 +71,7 @@ default CompletableFuture loadPermissionHolder(OfflinePlayer p * @see PermissionHolder */ default CompletableFuture tryGetPermissionHolder(OfflinePlayer player) { - return getPermissionHolder(player) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadPermissionHolder(player)); + return tryGetPermissionHolder(player, null); } /** @@ -82,10 +83,8 @@ default CompletableFuture tryGetPermissionHolder(OfflinePlayer * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - default CompletableFuture tryGetPermissionHolder(OfflinePlayer player, World world) { - return getPermissionHolder(player, world) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadPermissionHolder(player, world)); + default CompletableFuture tryGetPermissionHolder(OfflinePlayer player, @Nullable World world) { + return tryGetPermissionHolder(player.getUniqueId(), world); } /** @@ -96,9 +95,7 @@ default CompletableFuture tryGetPermissionHolder(OfflinePlayer * @see PermissionHolder */ default CompletableFuture tryGetPermissionHolder(UUID uuid) { - return getPermissionHolder(uuid) - .map(CompletableFuture::completedFuture) - .orElseGet(() -> loadPermissionHolder(uuid)); + return tryGetPermissionHolder(uuid, null); } /** @@ -109,7 +106,7 @@ default CompletableFuture tryGetPermissionHolder(UUID uuid) { * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - default CompletableFuture tryGetPermissionHolder(UUID uuid, World world) { + default CompletableFuture tryGetPermissionHolder(UUID uuid, @Nullable World world) { return getPermissionHolder(uuid, world) .map(CompletableFuture::completedFuture) .orElseGet(() -> loadPermissionHolder(uuid, world)); @@ -123,7 +120,7 @@ default CompletableFuture tryGetPermissionHolder(UUID uuid, Wo * @see PermissionHolder */ default Optional getPermissionHolder(OfflinePlayer player) { - return getPermissionHolder(player.getUniqueId()); + return getPermissionHolder(player, null); } /** @@ -135,7 +132,7 @@ default Optional getPermissionHolder(OfflinePlayer player) { * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - default Optional getPermissionHolder(OfflinePlayer player, World world) { + default Optional getPermissionHolder(OfflinePlayer player, @Nullable World world) { return getPermissionHolder(player.getUniqueId(), world); } @@ -146,7 +143,9 @@ default Optional getPermissionHolder(OfflinePlayer player, Wor * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - Optional getPermissionHolder(UUID uuid); + default Optional getPermissionHolder(UUID uuid) { + return getPermissionHolder(uuid, null); + } /** * Retrieves the {@code PermissionHolder} for the specified {@code UUID} and {@code World}. @@ -156,5 +155,5 @@ default Optional getPermissionHolder(OfflinePlayer player, Wor * @return a {@code CompletableFuture} that will complete with the permission holder * @see PermissionHolder */ - Optional getPermissionHolder(UUID uuid, World world); + Optional getPermissionHolder(UUID uuid, @Nullable World world); } From 065e9482dbbf72920cbf0154c875990542b92c9b Mon Sep 17 00:00:00 2001 From: david Date: Wed, 16 Jul 2025 17:48:49 +0200 Subject: [PATCH 16/32] Added methods for singular and plural locale mappings Introduced `displayNamesSingular()` and `displayNamesPlural()` methods in `Currency.Builder`. These provide unmodifiable mappings of singular and plural display names for various locales, improving extensibility and localization support. --- .../api/economy/currency/Currency.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index 6498add0..a247e93d 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -5,9 +5,11 @@ import net.kyori.adventure.text.Component; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; import java.util.Locale; +import java.util.Map; import java.util.Optional; import java.util.OptionalInt; @@ -46,7 +48,6 @@ default Component getDisplayNameSingular(Audience audience) { */ Component getDisplayNameSingular(Locale locale); - /** * Retrieves the plural display name component of the currency based on the audience's locale. *

@@ -109,6 +110,15 @@ default Component format(Number amount, Audience audience) { * singular and plural display names, currency symbol, and fractional digits. */ interface Builder { + /** + * Retrieves a map containing the singular display names of the currency for various locales. + * + * @return an unmodifiable map of {@code Locale} and {@code Component} objects + * representing the singular display names of the currency. + */ + @Unmodifiable + Map displayNamesSingular(); + /** * Sets the singular display name of the currency for a specific locale. * @@ -128,6 +138,15 @@ interface Builder { @Contract(value = "_ -> new") Optional displayNameSingular(Locale locale); + /** + * Retrieves a map containing the plural display names of the currency for various locales. + * + * @return an unmodifiable map of {@code Locale} and {@code Component} objects + * representing the plural display names of the currency. + */ + @Unmodifiable + Map displayNamesPlural(); + /** * Sets the plural display name of the currency for a specific locale. * From dc1fe9e624015485fc493d876c848093daebb9a2 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 16:17:47 +0200 Subject: [PATCH 17/32] Refactored currency and account APIs for flexibility Updated `Currency` interface methods to return `Optional` values, improving null safety. Added builders and editing functionalities. Enhanced `Account` methods for simpler balance operations, with `BigDecimal` returns for precision. Bumped version to 3.0.0-pre2. --- .../wrapper/service/model/WrappedBank.java | 11 +-- .../service/api/economy/Account.java | 11 ++- .../api/economy/EconomyController.java | 4 +- .../api/economy/currency/Currency.java | 72 ++++++++++++++----- .../api/economy/currency/CurrencyHolder.java | 18 +++-- 5 files changed, 84 insertions(+), 32 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java index 905a7073..c95a9bc7 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java @@ -3,6 +3,7 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.ServicePlugin; import net.thenextlvl.service.api.economy.bank.Bank; +import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -67,10 +68,12 @@ public UUID getOwner() { } @Override - public void setBalance(Number balance, Currency currency) { - var difference = balance.doubleValue() - getBalance(currency).doubleValue(); - if (difference > 0) deposit(difference, currency); - else if (difference < 0) withdraw(-difference, currency); + public BigDecimal setBalance(Number balance, Currency currency) { + var current = getBalance(currency); + var difference = balance.doubleValue() - current.doubleValue(); + if (difference > 0) return deposit(difference, currency); + else if (difference < 0) return withdraw(-difference, currency); + return current; } @Override diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index be1aabcc..5beca3a1 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -46,7 +46,9 @@ default BigDecimal deposit(Number amount) { * @return the new balance after the deposit * @since 3.0.0 */ - BigDecimal deposit(Number amount, Currency currency); + default BigDecimal deposit(Number amount, Currency currency) { + return setBalance(getBalance(currency).add(BigDecimal.valueOf(amount.doubleValue())), currency); + } /** * Retrieves the balance of the account. @@ -88,7 +90,9 @@ default BigDecimal withdraw(Number amount) { * @return the new balance after the withdrawal * @since 3.0.0 */ - BigDecimal withdraw(Number amount, Currency currency); + default BigDecimal withdraw(Number amount, Currency currency) { + return setBalance(getBalance(currency).subtract(BigDecimal.valueOf(amount.doubleValue())), currency); + } /** * Returns an optional containing the world associated with this account. @@ -147,7 +151,8 @@ default void setBalance(Number balance) { * * @param balance the new balance to be set * @param currency the currency of the balance + * @return the new balance after the operation * @since 3.0.0 */ - void setBalance(Number balance, Currency currency); + BigDecimal setBalance(Number balance, Currency currency); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index 0e4c39cd..b93e688a 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -34,7 +34,7 @@ public interface EconomyController extends Controller, CurrencyHolder { */ @Deprecated(forRemoval = true, since = "3.0.0") default String getCurrencyNamePlural(Locale locale) { - return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getDisplayNamePlural(locale)); + return getDefaultCurrency().getDisplayNamePlural(locale).map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } /** @@ -46,7 +46,7 @@ default String getCurrencyNamePlural(Locale locale) { */ @Deprecated(forRemoval = true, since = "3.0.0") default String getCurrencyNameSingular(Locale locale) { - return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getDisplayNameSingular(locale)); + return getDefaultCurrency().getDisplayNameSingular(locale).map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } /** diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index a247e93d..5de1245d 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -7,11 +7,13 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.OptionalInt; +import java.util.function.Consumer; /** * Represents a currency with support for localization, formatting, and symbolic representation. @@ -34,9 +36,9 @@ public interface Currency { * If the audience does not specify a locale, {@link Locale#US} is used. * * @param audience the audience whose locale is used to determine the singular display name - * @return the singular display name as a {@code Component} for the audience's locale + * @return an {@code Optional} containing the singular display name as a {@code Component} for the audience's locale, or empty */ - default Component getDisplayNameSingular(Audience audience) { + default Optional getDisplayNameSingular(Audience audience) { return getDisplayNameSingular(audience.getOrDefault(Identity.LOCALE, Locale.US)); } @@ -44,9 +46,9 @@ default Component getDisplayNameSingular(Audience audience) { * Retrieves the singular display name component of the currency for the specified locale. * * @param locale the locale for which the singular display name should be retrieved - * @return the singular display name as a {@code Component} for the specified locale + * @return an {@code Optional} containing the singular display name as a {@code Component} for the specified locale, or empty */ - Component getDisplayNameSingular(Locale locale); + Optional getDisplayNameSingular(Locale locale); /** * Retrieves the plural display name component of the currency based on the audience's locale. @@ -54,9 +56,9 @@ default Component getDisplayNameSingular(Audience audience) { * If the audience does not specify a locale, {@link Locale#US} is used. * * @param audience the audience whose locale is used to determine the plural display name - * @return the plural display name as a {@code Component} for the audience's locale + * @return an {@code Optional} containing the plural display name as a {@code Component} for the audience's locale, or empty */ - default Component getDisplayNamePlural(Audience audience) { + default Optional getDisplayNamePlural(Audience audience) { return getDisplayNamePlural(audience.getOrDefault(Identity.LOCALE, Locale.US)); } @@ -64,9 +66,9 @@ default Component getDisplayNamePlural(Audience audience) { * Retrieves the plural display name component of the currency for the specified locale. * * @param locale the locale for which the plural display name should be retrieved - * @return the plural display name as a {@code Component} for the specified locale + * @return an {@code Optional} containing the plural display name as a {@code Component} for the specified locale, or empty */ - Component getDisplayNamePlural(Locale locale); + Optional getDisplayNamePlural(Locale locale); /** * Retrieves the currency symbol. @@ -104,12 +106,44 @@ default Component format(Number amount, Audience audience) { */ int getFractionalDigits(); + /** + * Modifies the current configuration of the currency using the provided builder. + * The builder allows customization of various currency properties. + * + * @param consumer a {@code Consumer} that accepts a {@code Builder} instance to define customizations for the currency + */ + void editCurrency(Consumer consumer); + + /** + * Converts the current {@code Currency} instance into a {@code Builder} for modification or reconstruction. + * + * @return a {@code Builder} instance initialized with the properties of the current {@code Currency} + */ + @ApiStatus.OverrideOnly + Builder toBuilder(); + /** * A builder interface for constructing instances of {@link Currency}. * The {@code Builder} allows for the configuration of currency properties such as * singular and plural display names, currency symbol, and fractional digits. */ interface Builder { + /** + * Sets the name of the currency. + * + * @param name the name to be set + * @return the builder instance for method chaining + */ + @Contract(value = "_ -> this") + Builder name(String name); + + /** + * Retrieves the name currently set on the builder. + * + * @return the name as a string, or {@code null} if not set + */ + String name(); + /** * Retrieves a map containing the singular display names of the currency for various locales. * @@ -122,12 +156,12 @@ interface Builder { /** * Sets the singular display name of the currency for a specific locale. * + * @param locale the locale for which the singular display name is being set, or {@code null} to remove * @param name the singular display name component of the currency - * @param locale the locale for which the singular display name is being set * @return the builder instance for chaining */ - @Contract(value = "_, _ -> this", pure = true) - Builder displayNameSingular(Component name, Locale locale); + @Contract(value = "_, _ -> this") + Builder displayNameSingular(Locale locale, @Nullable Component name); /** * Retrieves the singular display name component of the currency for the specified locale. @@ -150,12 +184,12 @@ interface Builder { /** * Sets the plural display name of the currency for a specific locale. * + * @param locale the locale for which the plural display name is being set, or {@code null} to remove * @param name the plural display name component of the currency - * @param locale the locale for which the plural display name is being set * @return the builder instance for chaining */ - @Contract(value = "_, _ -> this", pure = true) - Builder displayNamePlural(Component name, Locale locale); + @Contract(value = "_, _ -> this") + Builder displayNamePlural(Locale locale, @Nullable Component name); /** * Retrieves the plural display name component of the currency for the specified locale. @@ -169,11 +203,11 @@ interface Builder { /** * Sets the currency symbol as a {@code Component}. * - * @param symbol the symbol component to represent the currency + * @param symbol the symbol component to represent the currency, or {@code null} to remove * @return the builder instance for chaining */ - @Contract(value = "_ -> this", pure = true) - Builder symbol(Component symbol); + @Contract(value = "_ -> this") + Builder symbol(@Nullable Component symbol); /** * Retrieves the currency symbol set on the {@code Builder}. @@ -189,12 +223,12 @@ interface Builder { * Fractional digits are generally used to specify the precision of the currency values, * for example, 2 fractional digits for most currencies such as USD (representing cents). * - * @param fractionalDigits the number of fractional digits to set (must be a non-negative integer) + * @param fractionalDigits the number of fractional digits to set (must be a non-negative integer), or {@code null} to remove * @return the builder instance for chaining * @throws IllegalArgumentException if {@code fractionalDigits} is negative */ @Contract(value = "_ -> this") - Builder fractionalDigits(int fractionalDigits) throws IllegalArgumentException; + Builder fractionalDigits(@Nullable Integer fractionalDigits) throws IllegalArgumentException; /** * Retrieves the number of fractional digits set for the currency. diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index 0e1eb707..b79c4c2c 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -77,16 +77,26 @@ default boolean hasCurrency(String name) { /** * Creates a new currency by configuring a {@link Currency.Builder}. - *

- * If a currency with the same name already exists, this method returns empty. * * @param name the name of the new currency * @param builder a consumer to configure the {@link Currency.Builder} for currency creation - * @return an optional containing the created {@link Currency}, or empty + * @return the newly created {@link Currency} * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + * @throws IllegalArgumentException if a currency with the same name already exists */ @Contract("_, _ -> new") - default Optional createCurrency(String name, Consumer builder) { + default Currency createCurrency(String name, Consumer builder) throws IllegalArgumentException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Adds a new currency to the currency holder. + * + * @param currency the {@code Currency} object to add + * @return {@code true} if the currency was successfully added, otherwise {@code false} + * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + */ + default boolean addCurrency(Currency currency) { throw new UnsupportedOperationException("Not implemented yet"); } From 01585a701d58bb3e7281e8d0621019708ff17a88 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 16:37:25 +0200 Subject: [PATCH 18/32] [ci skip] Improved Javadoc parameter descriptions --- .../java/net/thenextlvl/service/api/character/Character.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/character/Character.java b/src/main/java/net/thenextlvl/service/api/character/Character.java index 34131865..d7696c0e 100644 --- a/src/main/java/net/thenextlvl/service/api/character/Character.java +++ b/src/main/java/net/thenextlvl/service/api/character/Character.java @@ -155,14 +155,14 @@ public interface Character extends Persistable, Viewable { *

* This method requires the provider to support the {@link CharacterCapability#HEALTH} capability. * - * @param invulnerable {@code true} if the character should be invulnerable, {@code false} otherwise + * @param invulnerable {@code true} if the character should be invulnerable, otherwise {@code false} */ void setInvulnerable(boolean invulnerable); /** * Sets the visibility state of the character's tablist entry. * - * @param hidden {@code true} to hide the tablist entry, {@code false} to make it visible + * @param hidden {@code true} to hide the tablist entry, to make it visible {@code false} */ void setTablistEntryHidden(boolean hidden); } From 3982838c902985a354845d0f4ce2b66390f640b7 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 16:41:41 +0200 Subject: [PATCH 19/32] Enhanced currency and account APIs for precision and flexibility Updated `Currency` methods to return `Optional`, improving null safety. Redesigned `setBalance` in `WrappedAccount` to return `BigDecimal` for better precision. Adjusted `WrappedCurrency` to include editing logic and improve locale-based display name handling for currencies. Bumped version to 3.0.0-pre3. --- .../wrapper/VaultEconomyServiceWrapper.java | 8 +++--- .../wrapper/service/BankServiceWrapper.java | 1 + .../service/EconomyServiceWrapper.java | 1 + .../wrapper/service/model/WrappedAccount.java | 7 +++--- .../service/{ => model}/WrappedCurrency.java | 17 +++++++++---- .../api/economy/currency/Currency.java | 25 +++---------------- .../api/economy/currency/CurrencyHolder.java | 12 ++++++--- 7 files changed, 34 insertions(+), 37 deletions(-) rename plugin/src/main/java/net/thenextlvl/service/wrapper/service/{ => model}/WrappedCurrency.java (61%) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java index a81bf0df..38f2230c 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java @@ -64,14 +64,14 @@ public String format(double amount) { @Override public String currencyNamePlural() { - var name = economyController.getDefaultCurrency().getDisplayNamePlural(Locale.US); - return PlainTextComponentSerializer.plainText().serialize(name); + return economyController.getDefaultCurrency().getDisplayNamePlural(Locale.US) + .map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } @Override public String currencyNameSingular() { - var name = economyController.getDefaultCurrency().getDisplayNameSingular(Locale.US); - return PlainTextComponentSerializer.plainText().serialize(name); + return economyController.getDefaultCurrency().getDisplayNameSingular(Locale.US) + .map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java index f7298460..129d5658 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java @@ -5,6 +5,7 @@ import net.thenextlvl.service.api.economy.bank.Bank; import net.thenextlvl.service.api.economy.bank.BankController; import net.thenextlvl.service.wrapper.service.model.WrappedBank; +import net.thenextlvl.service.wrapper.service.model.WrappedCurrency; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index 3868e540..0a6b6951 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -4,6 +4,7 @@ import net.thenextlvl.service.api.economy.Account; import net.thenextlvl.service.api.economy.EconomyController; import net.thenextlvl.service.wrapper.service.model.WrappedAccount; +import net.thenextlvl.service.wrapper.service.model.WrappedCurrency; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java index ce5e6c47..14f2f90d 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java @@ -62,9 +62,10 @@ public UUID getOwner() { } @Override - public void setBalance(Number balance, Currency currency) { + public BigDecimal setBalance(Number balance, Currency currency) { var difference = balance.doubleValue() - getBalance(currency).doubleValue(); - if (difference > 0) deposit(difference, currency); - else if (difference < 0) withdraw(-difference, currency); + if (difference > 0) return deposit(difference, currency); + else if (difference < 0) return withdraw(-difference, currency); + return BigDecimal.ZERO; } } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/WrappedCurrency.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java similarity index 61% rename from plugin/src/main/java/net/thenextlvl/service/wrapper/service/WrappedCurrency.java rename to plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java index fd016cc4..edff0752 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/WrappedCurrency.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java @@ -1,4 +1,4 @@ -package net.thenextlvl.service.wrapper.service; +package net.thenextlvl.service.wrapper.service.model; import net.kyori.adventure.text.Component; import net.milkbowl.vault.economy.Economy; @@ -6,6 +6,8 @@ import org.jspecify.annotations.NullMarked; import java.util.Locale; +import java.util.Optional; +import java.util.function.Consumer; @NullMarked public class WrappedCurrency implements Currency { @@ -21,13 +23,13 @@ public String getName() { } @Override - public Component getDisplayNameSingular(Locale locale) { - return Component.text(economy.currencyNameSingular()); + public Optional getDisplayNameSingular(Locale locale) { + return Optional.ofNullable(economy.currencyNameSingular()).map(Component::text); } @Override - public Component getDisplayNamePlural(Locale locale) { - return Component.text(economy.currencyNamePlural()); + public Optional getDisplayNamePlural(Locale locale) { + return Optional.ofNullable(economy.currencyNamePlural()).map(Component::text); } @Override @@ -44,4 +46,9 @@ public Component format(Number amount, Locale locale) { public int getFractionalDigits() { return economy.fractionalDigits(); } + + @Override + public boolean editCurrency(Consumer consumer) { + return false; + } } diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index 5de1245d..b14ff30d 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -3,7 +3,6 @@ import net.kyori.adventure.audience.Audience; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; @@ -111,16 +110,9 @@ default Component format(Number amount, Audience audience) { * The builder allows customization of various currency properties. * * @param consumer a {@code Consumer} that accepts a {@code Builder} instance to define customizations for the currency + * @return {@code true} if the edit succeeded, otherwise {@code false} */ - void editCurrency(Consumer consumer); - - /** - * Converts the current {@code Currency} instance into a {@code Builder} for modification or reconstruction. - * - * @return a {@code Builder} instance initialized with the properties of the current {@code Currency} - */ - @ApiStatus.OverrideOnly - Builder toBuilder(); + boolean editCurrency(Consumer consumer); /** * A builder interface for constructing instances of {@link Currency}. @@ -136,14 +128,14 @@ interface Builder { */ @Contract(value = "_ -> this") Builder name(String name); - + /** * Retrieves the name currently set on the builder. * * @return the name as a string, or {@code null} if not set */ String name(); - + /** * Retrieves a map containing the singular display names of the currency for various locales. * @@ -240,14 +232,5 @@ interface Builder { */ @Contract(value = "-> new") OptionalInt fractionalDigits(); - - /** - * Builds and returns a {@link Currency} instance based on the properties set on the {@code Builder}. - * - * @return the constructed {@link Currency} instance - */ - @Contract("-> new") - @ApiStatus.OverrideOnly - Currency build(); } } diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index b79c4c2c..1aa10fba 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -90,13 +90,17 @@ default Currency createCurrency(String name, Consumer builder) } /** - * Adds a new currency to the currency holder. + * Creates a new currency using the specified builder. + *

+ * This method enables modifying existing currencies by utilizing a + * pre-configured builder to create a new currency. * - * @param currency the {@code Currency} object to add - * @return {@code true} if the currency was successfully added, otherwise {@code false} + * @param builder the {@link Currency.Builder} containing the configuration for the currency creation + * @return the newly created {@link Currency} * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + * @throws IllegalArgumentException if a currency with the same name already exists */ - default boolean addCurrency(Currency currency) { + default Currency createCurrency(Currency.Builder builder) { throw new UnsupportedOperationException("Not implemented yet"); } From 9dee09ed2abdb32f770ed0f053dc3c05a373c0e1 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 16:56:41 +0200 Subject: [PATCH 20/32] Added exception to `editCurrency` method in `Currency` Declared `throws IllegalArgumentException` for `editCurrency` to handle duplicate currency names explicitly. This improves API safety and clarity for consumers. --- .../net/thenextlvl/service/api/economy/currency/Currency.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index b14ff30d..1646158f 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -111,8 +111,9 @@ default Component format(Number amount, Audience audience) { * * @param consumer a {@code Consumer} that accepts a {@code Builder} instance to define customizations for the currency * @return {@code true} if the edit succeeded, otherwise {@code false} + * @throws IllegalArgumentException if a currency with the same name already exists */ - boolean editCurrency(Consumer consumer); + boolean editCurrency(Consumer consumer) throws IllegalArgumentException; /** * A builder interface for constructing instances of {@link Currency}. From 7da4eef567a5454019ae0e66a57cf677e483d955 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 17:27:56 +0200 Subject: [PATCH 21/32] Added `deleteCurrency(Currency)` method to `CurrencyHolder` Introduced a default method to delete currencies using their object reference. Delegates internally to `deleteCurrency(String)` for streamlined logic and API flexibility. --- .../service/api/economy/currency/CurrencyHolder.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index 1aa10fba..94413d85 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -104,6 +104,17 @@ default Currency createCurrency(Currency.Builder builder) { throw new UnsupportedOperationException("Not implemented yet"); } + /** + * Deletes the specified currency. + * + * @param currency the currency to delete + * @return {@code true} if the currency was successfully deleted, otherwise {@code false} + * @throws UnsupportedOperationException if {@link #hasMultiCurrencySupport()} is {@code false} + */ + default boolean deleteCurrency(Currency currency) { + return deleteCurrency(currency.getName()); + } + /** * Deletes a currency with the specified name. * @@ -128,6 +139,7 @@ default boolean deleteCurrency(String name) { * * @return {@code true} if multi-currency is supported, otherwise {@code false} * @implSpec If multiple currencies are supported, all respective methods have to be implemented. + * @see #createCurrency(Currency.Builder) * @see #createCurrency(String, Consumer) * @see #deleteCurrency(String) * @see #getCurrencies() From af3c1329c17d5a5223a30492a32d9e27ca91c286 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 18:05:03 +0200 Subject: [PATCH 22/32] Reintroduced `toBuilder` method in `Currency` Added a `toBuilder` method to the `Currency` interface and implemented it in `WrappedCurrency` using a `NoOpBuilder`. This allows modification or reconstruction of a `Currency` instance. --- .../service/model/WrappedCurrency.java | 71 +++++++++++++++++++ .../api/economy/currency/Currency.java | 7 ++ 2 files changed, 78 insertions(+) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java index edff0752..97331c94 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java @@ -3,10 +3,14 @@ import net.kyori.adventure.text.Component; import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.currency.Currency; +import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Locale; +import java.util.Map; import java.util.Optional; +import java.util.OptionalInt; import java.util.function.Consumer; @NullMarked @@ -51,4 +55,71 @@ public int getFractionalDigits() { public boolean editCurrency(Consumer consumer) { return false; } + + @Override + public Builder toBuilder() { + return new NoOpBuilder(economy); + } + + private record NoOpBuilder(Economy economy) implements Builder { + @Override + public Builder name(String name) { + return this; + } + + @Override + public String name() { + return economy.getName(); + } + + @Override + public @Unmodifiable Map displayNamesSingular() { + return Map.of(); + } + + @Override + public Builder displayNameSingular(Locale locale, @Nullable Component name) { + return this; + } + + @Override + public Optional displayNameSingular(Locale locale) { + return Optional.empty(); + } + + @Override + public @Unmodifiable Map displayNamesPlural() { + return Map.of(); + } + + @Override + public Builder displayNamePlural(Locale locale, @Nullable Component name) { + return this; + } + + @Override + public Optional displayNamePlural(Locale locale) { + return Optional.empty(); + } + + @Override + public Builder symbol(@Nullable Component symbol) { + return this; + } + + @Override + public Optional symbol() { + return Optional.empty(); + } + + @Override + public Builder fractionalDigits(@Nullable Integer fractionalDigits) throws IllegalArgumentException { + return this; + } + + @Override + public OptionalInt fractionalDigits() { + return OptionalInt.of(economy.fractionalDigits()); + } + } } diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index 1646158f..d88e6c28 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -115,6 +115,13 @@ default Component format(Number amount, Audience audience) { */ boolean editCurrency(Consumer consumer) throws IllegalArgumentException; + /** + * Converts the current {@code Currency} instance into a {@code Builder} for modification or reconstruction. + * + * @return a {@code Builder} instance initialized with the properties of the current {@code Currency} + */ + Builder toBuilder(); + /** * A builder interface for constructing instances of {@link Currency}. * The {@code Builder} allows for the configuration of currency properties such as From cf2a2785afed1f4e05ceb83c23d3ce371be4d4a9 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 19:20:14 +0200 Subject: [PATCH 23/32] Decoupled `CurrencyHolder` from controllers and services Refactored `EconomyController`, `BankController`, and related APIs to delegate currency management to `CurrencyHolder`. Removed deprecated methods from `Account` and `CurrencyHolder`. Updated implementations and placeholder resolvers to align with the changes. Bumped version to 3.0.0-pre4. --- .../economy/ServiceBankPlaceholderStore.java | 14 ++-- .../ServiceEconomyPlaceholderStore.java | 12 +-- .../wrapper/service/BankServiceWrapper.java | 17 +++-- .../service/EconomyServiceWrapper.java | 32 +++++--- .../wrapper/service/model/WrappedAccount.java | 11 +-- .../wrapper/service/model/WrappedBank.java | 6 -- .../service/api/economy/Account.java | 73 +------------------ .../api/economy/EconomyController.java | 40 ++-------- .../api/economy/bank/BankController.java | 10 ++- .../api/economy/currency/CurrencyHolder.java | 27 ------- 10 files changed, 62 insertions(+), 180 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java index c14e8957..bf4c887a 100644 --- a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java +++ b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java @@ -19,6 +19,8 @@ public ServiceBankPlaceholderStore(ServicePlugin plugin) { @Override protected void registerResolvers() { + // todo: currency based placeholders + // %serviceio_bank% registerResolver("bank", (provider, player, matcher) -> { return provider.getBank(player).map(Bank::getName).orElse(""); @@ -27,14 +29,14 @@ protected void registerResolvers() { // %serviceio_bank_balance% registerResolver("bank_balance", (provider, player, matcher) -> { return provider.getBank(player) - .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + .map(bank -> bank.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO).toPlainString(); }); // %serviceio_bank_balance_formatted% registerResolver("bank_balance_formatted", (provider, player, matcher) -> { - var format = provider.getDefaultCurrency().format(provider.getBank(player) - .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + var format = provider.getCurrencyHolder().getDefaultCurrency().format(provider.getBank(player) + .map(bank -> bank.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO), Locale.US); return PlainTextComponentSerializer.plainText().serialize(format); }); @@ -51,7 +53,7 @@ protected void registerResolvers() { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; return provider.getBank(player, world) - .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + .map(bank -> bank.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO) .toPlainString(); }); @@ -60,8 +62,8 @@ protected void registerResolvers() { registerResolver("bank_%s_balance_formatted", (provider, player, matcher) -> { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; - var format = provider.getDefaultCurrency().format(provider.getBank(player, world) - .map(bank -> bank.getBalance(provider.getDefaultCurrency())) + var format = provider.getCurrencyHolder().getDefaultCurrency().format(provider.getBank(player, world) + .map(bank -> bank.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO), Locale.US); return PlainTextComponentSerializer.plainText().serialize(format); }); diff --git a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java index 50912ce5..ba6d5213 100644 --- a/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java +++ b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceEconomyPlaceholderStore.java @@ -20,7 +20,7 @@ protected void registerResolvers() { // %serviceio_balance% registerResolver("balance", (provider, player, matcher) -> { return provider.getAccount(player) - .map(account -> account.getBalance(provider.getDefaultCurrency())) + .map(account -> account.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO) .toPlainString(); }); @@ -30,15 +30,15 @@ protected void registerResolvers() { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; return provider.getAccount(player, world) - .map(account -> account.getBalance(provider.getDefaultCurrency())) + .map(account -> account.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO) .toPlainString(); }); // %serviceio_balance_formatted% registerResolver("balance_formatted", (provider, player, matcher) -> { - var format = provider.getDefaultCurrency().format(provider.getAccount(player) - .map(account -> account.getBalance(provider.getDefaultCurrency())) + var format = provider.getCurrencyHolder().getDefaultCurrency().format(provider.getAccount(player) + .map(account -> account.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO), Locale.US); return PlainTextComponentSerializer.plainText().serialize(format); }); @@ -47,8 +47,8 @@ protected void registerResolvers() { registerResolver("balance_formatted_%s", (provider, player, matcher) -> { var world = plugin.getServer().getWorld(matcher.group(1)); if (world == null) return null; - var format = provider.getDefaultCurrency().format(provider.getAccount(player, world) - .map(account -> account.getBalance(provider.getDefaultCurrency())) + var format = provider.getCurrencyHolder().getDefaultCurrency().format(provider.getAccount(player, world) + .map(account -> account.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) .orElse(BigDecimal.ZERO), Locale.US); return PlainTextComponentSerializer.plainText().serialize(format); }); diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java index 129d5658..d47f22c2 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java @@ -4,8 +4,8 @@ import net.milkbowl.vault.economy.EconomyResponse; import net.thenextlvl.service.api.economy.bank.Bank; import net.thenextlvl.service.api.economy.bank.BankController; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import net.thenextlvl.service.wrapper.service.model.WrappedBank; -import net.thenextlvl.service.wrapper.service.model.WrappedCurrency; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; @@ -21,19 +21,20 @@ @NullMarked public class BankServiceWrapper implements BankController, Wrapper { + private final CurrencyHolder holder; private final Economy economy; private final Plugin provider; private final Currency currency; - public BankServiceWrapper(Economy economy, Plugin provider) { - this.currency = new WrappedCurrency(economy); + public BankServiceWrapper(CurrencyHolder holder, Economy economy, Plugin provider) { + this.holder = holder; this.economy = economy; this.provider = provider; } @Override - public Currency getDefaultCurrency() { - return currency; + public CurrencyHolder getCurrencyHolder() { + return holder; } @Override @@ -74,9 +75,9 @@ public CompletableFuture deleteBank(UUID uuid, @Nullable World world) { } @Override - public @Unmodifiable Set getBanks() { - return economy.getBanks().stream() - .map(bank -> new WrappedBank(this, bank, null, economy, plugin)) + public @Unmodifiable Set getBanks(@Nullable World world) { + return world != null ? Set.of() : economy.getBanks().stream() + .map(bank -> new WrappedBank(bank, null, economy, plugin)) .collect(Collectors.toUnmodifiableSet()); } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index 0a6b6951..f7181387 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -3,6 +3,7 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.Account; import net.thenextlvl.service.api.economy.EconomyController; +import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.wrapper.service.model.WrappedAccount; import net.thenextlvl.service.wrapper.service.model.WrappedCurrency; import org.bukkit.OfflinePlayer; @@ -21,16 +22,21 @@ @NullMarked public class EconomyServiceWrapper implements EconomyController, Wrapper { - private final Currency currency; + private final CurrencyHolder holder; private final Economy economy; private final Plugin provider; public EconomyServiceWrapper(Economy economy, Plugin provider) { - this.currency = new WrappedCurrency(economy); + this.holder = new WrappedCurrencyHolder(economy); this.economy = economy; this.provider = provider; } + @Override + public CurrencyHolder getCurrencyHolder() { + return holder; + } + @Override public CompletableFuture<@Unmodifiable Set> loadAccounts(@Nullable World world) { return CompletableFuture.completedFuture(getAccounts(world)); @@ -40,14 +46,14 @@ public EconomyServiceWrapper(Economy economy, Plugin provider) { public @Unmodifiable Set getAccounts(@Nullable World world) { return Arrays.stream(provider.getServer().getOfflinePlayers()) .filter(player -> economy.hasAccount(player, world != null ? world.getName() : null)) - .map(player -> new WrappedAccount(this, world, economy, player)) + .map(player -> new WrappedAccount(world, economy, player)) .collect(Collectors.toUnmodifiableSet()); } @Override public Optional getAccount(OfflinePlayer player, @Nullable World world) { if (!economy.hasAccount(player, world != null ? world.getName() : null)) return Optional.empty(); - return Optional.of(new WrappedAccount(this, world, economy, player)); + return Optional.of(new WrappedAccount(world, economy, player)); } @Override @@ -90,11 +96,6 @@ public boolean hasMultiWorldSupport() { return false; } - @Override - public Currency getDefaultCurrency() { - return currency; - } - @Override public Plugin getPlugin() { return provider; @@ -104,4 +105,17 @@ public Plugin getPlugin() { public String getName() { return economy.getName() + " Wrapper"; } + + private static class WrappedCurrencyHolder implements CurrencyHolder { + private final Currency currency; + + private WrappedCurrencyHolder(Economy economy) { + this.currency = new WrappedCurrency(economy); + } + + @Override + public Currency getDefaultCurrency() { + return currency; + } + } } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java index 14f2f90d..f68deab4 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java @@ -3,8 +3,6 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.Account; import net.thenextlvl.service.api.economy.currency.Currency; -import net.thenextlvl.service.api.economy.currency.CurrencyHolder; -import net.thenextlvl.service.api.economy.EconomyController; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jspecify.annotations.NullMarked; @@ -16,23 +14,16 @@ @NullMarked public class WrappedAccount implements Account { - private final EconomyController controller; private final @Nullable World world; private final Economy economy; private final OfflinePlayer holder; - public WrappedAccount(EconomyController controller, @Nullable World world, Economy economy, OfflinePlayer holder) { - this.controller = controller; + public WrappedAccount(@Nullable World world, Economy economy, OfflinePlayer holder) { this.world = world; this.economy = economy; this.holder = holder; } - @Override - public CurrencyHolder getHolder() { - return controller; - } - @Override public BigDecimal deposit(Number amount, Currency currency) { var response = economy.depositPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java index c95a9bc7..6baf926b 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java @@ -4,7 +4,6 @@ import net.thenextlvl.service.ServicePlugin; import net.thenextlvl.service.api.economy.bank.Bank; import net.thenextlvl.service.api.economy.currency.Currency; -import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.plugin.Plugin; @@ -33,11 +32,6 @@ public WrappedBank(String name, @Nullable World world, Economy economy, Plugin p this.provider = provider; } - @Override - public CurrencyHolder getHolder() { - return controller; - } - @Override public BigDecimal deposit(Number amount, Currency currency) { return new BigDecimal(economy.bankDeposit(name, amount.doubleValue()).balance); diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index 5beca3a1..d77c64c4 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -1,9 +1,7 @@ package net.thenextlvl.service.api.economy; import net.thenextlvl.service.api.economy.currency.Currency; -import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.World; -import org.jetbrains.annotations.Contract; import org.jspecify.annotations.NullMarked; import java.math.BigDecimal; @@ -16,28 +14,7 @@ * @since 1.0.0 */ @NullMarked -public interface Account extends Comparable { - /** - * Retrieves the associated {@code CurrencyHolder} for the account. - * - * @return the {@code CurrencyHolder} capable of managing currencies for the account - * @since 3.0.0 - */ - @Contract(pure = true) - CurrencyHolder getHolder(); - - /** - * Deposits the specified amount into the account balance. - * - * @param amount the amount to be deposited - * @return the new balance after the deposit - * @deprecated use {@link #deposit(Number, Currency)} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default BigDecimal deposit(Number amount) { - return deposit(amount, getHolder().getDefaultCurrency()); - } - +public interface Account { /** * Deposits the specified amount of the given currency into the account balance. * @@ -50,17 +27,6 @@ default BigDecimal deposit(Number amount, Currency currency) { return setBalance(getBalance(currency).add(BigDecimal.valueOf(amount.doubleValue())), currency); } - /** - * Retrieves the balance of the account. - * - * @return the balance of the account - * @deprecated use {@link #getBalance(Currency)} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default BigDecimal getBalance() { - return getBalance(getHolder().getDefaultCurrency()); - } - /** * Retrieves the balance of the account for the specified currency. * @@ -70,18 +36,6 @@ default BigDecimal getBalance() { */ BigDecimal getBalance(Currency currency); - /** - * Withdraws the specified amount from the account balance. - * - * @param amount the amount to be withdrawn - * @return the new balance after the withdrawal - * @deprecated use {@link #withdraw(Number, Currency)} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default BigDecimal withdraw(Number amount) { - return withdraw(amount, getHolder().getDefaultCurrency()); - } - /** * Withdraws the specified amount of the given currency from the account balance. * @@ -108,20 +62,6 @@ default BigDecimal withdraw(Number amount, Currency currency) { */ UUID getOwner(); - /** - * Compares this account to the specified account based on their balance. - * - * @param account the account to be compared - * @return a negative integer, zero, or a positive integer if this account is - * less than, equal to, or greater than the specified account - * @deprecated use {@link #compareTo(Account, Currency)} - */ - @Override - @Deprecated(forRemoval = true, since = "3.0.0") - default int compareTo(Account account) { - return compareTo(account, getHolder().getDefaultCurrency()); - } - /** * Compares this account with another account based on their balances in the specified currency. * @@ -135,17 +75,6 @@ default int compareTo(Account account, Currency currency) { return getBalance(currency).compareTo(account.getBalance(currency)); } - /** - * Sets the balance of the account to the specified value. - * - * @param balance the new balance of the account - * @deprecated use {@link #setBalance(Number, Currency)} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default void setBalance(Number balance) { - setBalance(balance, getHolder().getDefaultCurrency()); - } - /** * Sets the balance of the account to the specified value in the given currency. * diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index b93e688a..4f2230dc 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -1,8 +1,6 @@ package net.thenextlvl.service.api.economy; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.thenextlvl.service.api.Controller; -import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -11,7 +9,6 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -import java.util.Locale; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -24,41 +21,14 @@ * @since 1.0.0 */ @NullMarked -public interface EconomyController extends Controller, CurrencyHolder { +public interface EconomyController extends Controller { /** - * Retrieves the plural form of the currency name based on the provided locale. + * Retrieves the {@code CurrencyHolder} associated with the economy controller. * - * @param locale the locale for which to retrieve the plural currency name - * @return the plural form of the currency name as a string - * @deprecated use {@link Currency#getDisplayNamePlural(Locale)} + * @return the {@code CurrencyHolder} instance that manages the defined currencies for the controller */ - @Deprecated(forRemoval = true, since = "3.0.0") - default String getCurrencyNamePlural(Locale locale) { - return getDefaultCurrency().getDisplayNamePlural(locale).map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); - } - - /** - * Retrieves the name of the currency associated with the specified locale. - * - * @param locale the locale for which to retrieve the currency name - * @return the name of the currency as a string - * @deprecated use {@link Currency#getDisplayNameSingular(Locale)} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default String getCurrencyNameSingular(Locale locale) { - return getDefaultCurrency().getDisplayNameSingular(locale).map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); - } - - /** - * Retrieves the currency symbol associated with the economy controller. - * - * @return the currency symbol as a string - * @deprecated use {@link Currency#getSymbol()} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default String getCurrencySymbol() { - return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().getSymbol()); - } + @Contract(pure = true) + CurrencyHolder getCurrencyHolder(); /** * Loads all accounts. diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index f42729ca..12da6e22 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -20,7 +20,15 @@ * @since 1.0.0 */ @NullMarked -public interface BankController extends Controller, CurrencyHolder { +public interface BankController extends Controller { + /** + * Retrieves the {@code CurrencyHolder} associated with the economy controller. + * + * @return the {@code CurrencyHolder} instance that manages the defined currencies for the controller + */ + @Contract(pure = true) + CurrencyHolder getCurrencyHolder(); + /** * Creates a bank for the specified player with the given name. *

diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index 94413d85..1992dce6 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -1,10 +1,8 @@ package net.thenextlvl.service.api.economy.currency; -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; -import java.util.Locale; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -17,31 +15,6 @@ * @since 3.0.0 */ public interface CurrencyHolder { - /** - * Formats the specified amount as a string. - * - * @param amount the number amount to be formatted - * @return the formatted amount as a string - * @since 1.0.0 - * @deprecated use {@link Currency#format(Number, Locale)} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default String format(Number amount) { - return PlainTextComponentSerializer.plainText().serialize(getDefaultCurrency().format(amount, Locale.US)); - } - - /** - * Retrieves the number of fractional digits used for formatting currency amounts. - * - * @return the number of fractional digits used for formatting currency amounts - * @since 1.0.0 - * @deprecated use {@link Currency#getFractionalDigits()} - */ - @Deprecated(forRemoval = true, since = "3.0.0") - default int fractionalDigits() { - return getDefaultCurrency().getFractionalDigits(); - } - /** * Retrieves all currencies managed by the currency holder, * including the {@link #getDefaultCurrency() default currency}. From ffd4fe6e0d6b1b2eda89450b33db4a626b561ec8 Mon Sep 17 00:00:00 2001 From: david Date: Sat, 19 Jul 2025 20:14:26 +0200 Subject: [PATCH 24/32] Added `hasBank` methods and improved `Currency` linkage Expanded `BankController` with multiple `hasBank` overloads for better account-checking flexibility. Updated `Currency` to include `getHolder`, improving association tracking. Adjusted wrappers to align with these changes. --- .../wrapper/service/BankServiceWrapper.java | 20 ++++++++- .../service/EconomyServiceWrapper.java | 2 +- .../service/model/WrappedCurrency.java | 10 ++++- .../api/economy/bank/BankController.java | 42 ++++++++++++++++++- .../api/economy/currency/Currency.java | 10 ++++- 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java index d47f22c2..fb2382bd 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java @@ -83,12 +83,30 @@ public CompletableFuture deleteBank(UUID uuid, @Nullable World world) { @Override public Optional getBank(String name) { + if (!economy.getBanks().contains(name)) return Optional.empty(); return Optional.of(new WrappedBank(this, name, null, economy, provider)); } + @Override + public Optional getBank(OfflinePlayer player, @Nullable World world) { + return economy.getBanks().stream().filter(bank -> + economy.isBankOwner(bank, player).transactionSuccess() + ).findAny().flatMap(this::getBank); + } + @Override public Optional getBank(UUID uuid, @Nullable World world) { - return Optional.empty(); + return getBank(plugin.getServer().getOfflinePlayer(uuid), world); + } + + @Override + public boolean hasBank(OfflinePlayer player, @Nullable World world) { + return economy.getBanks().stream().anyMatch(bank -> economy.isBankOwner(bank, player).transactionSuccess()); + } + + @Override + public boolean hasBank(UUID uuid, @Nullable World world) { + return hasBank(plugin.getServer().getOfflinePlayer(uuid), world); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index f7181387..aaf9b3c1 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -110,7 +110,7 @@ private static class WrappedCurrencyHolder implements CurrencyHolder { private final Currency currency; private WrappedCurrencyHolder(Economy economy) { - this.currency = new WrappedCurrency(economy); + this.currency = new WrappedCurrency(this, economy); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java index 97331c94..6bb53642 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java @@ -3,6 +3,7 @@ import net.kyori.adventure.text.Component; import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.currency.Currency; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -15,10 +16,17 @@ @NullMarked public class WrappedCurrency implements Currency { + private final CurrencyHolder holder; private final Economy economy; - public WrappedCurrency(Economy economy) { + public WrappedCurrency(CurrencyHolder holder, Economy economy) { this.economy = economy; + this.holder = holder; + } + + @Override + public CurrencyHolder getHolder() { + return holder; } @Override diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index 12da6e22..37194c6e 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -28,7 +28,7 @@ public interface BankController extends Controller { */ @Contract(pure = true) CurrencyHolder getCurrencyHolder(); - + /** * Creates a bank for the specified player with the given name. *

@@ -335,6 +335,46 @@ default Optional getBank(UUID uuid) { */ Optional getBank(UUID uuid, @Nullable World world); + /** + * Checks if the specified player has a bank account. + * + * @param player the player to check for an associated bank account + * @return {@code true} if the player has a bank account, otherwise {@code false} + */ + default boolean hasBank(OfflinePlayer player) { + return hasBank(player, null); + } + + /** + * Checks if the specified player has a bank account in the given world. + * + * @param player the player to check for an associated bank account + * @param world the world in which to check for the bank account + * @return {@code true} if the player has a bank account in the specified world, otherwise {@code false} + */ + default boolean hasBank(OfflinePlayer player, @Nullable World world) { + return hasBank(player.getUniqueId(), world); + } + + /** + * Checks if the specified uuid is associated with a bank account. + * + * @param uuid the uuid of a player to check for an associated bank account + * @return {@code true} if the uuid is associated with a bank account, otherwise {@code false} + */ + default boolean hasBank(UUID uuid) { + return hasBank(uuid, null); + } + + /** + * Checks if the specified uuid is associated with a bank account in the given world. + * + * @param uuid the uuid of a player to check for an associated bank account + * @param world the world in which to check for the bank account + * @return {@code true} if the uuid is associated with a bank account in the specified world, otherwise {@code false} + */ + boolean hasBank(UUID uuid, @Nullable World world); + /** * Determines whether the controller supports handling of multiple worlds. * diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java index d88e6c28..b06c84a7 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -21,6 +21,14 @@ */ @NullMarked public interface Currency { + /** + * Retrieves the {@code CurrencyHolder} associated with this currency. + * + * @return the {@code CurrencyHolder} instance that manages this currency + */ + @Contract(pure = true) + CurrencyHolder getHolder(); + /** * Retrieves the name of the currency. * @@ -121,7 +129,7 @@ default Component format(Number amount, Audience audience) { * @return a {@code Builder} instance initialized with the properties of the current {@code Currency} */ Builder toBuilder(); - + /** * A builder interface for constructing instances of {@link Currency}. * The {@code Builder} allows for the configuration of currency properties such as From 0c94a62652cb80ad0e3b98e92718e6e2bb2d94c9 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 22 Jul 2025 19:20:34 +0200 Subject: [PATCH 25/32] Implemented `createCurrency` in `CurrencyHolder` Replaced `UnsupportedOperationException` with a fully implemented method. Leveraged builder details for initializing currency attributes such as names, fractional digits, and symbols. Simplified creation logic and enhanced API usability. --- .../service/api/economy/currency/CurrencyHolder.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java index 1992dce6..21d6b0ca 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -74,7 +74,12 @@ default Currency createCurrency(String name, Consumer builder) * @throws IllegalArgumentException if a currency with the same name already exists */ default Currency createCurrency(Currency.Builder builder) { - throw new UnsupportedOperationException("Not implemented yet"); + return createCurrency(builder.name(), delegate -> { + builder.displayNamesPlural().forEach(delegate::displayNamePlural); + builder.displayNamesSingular().forEach(delegate::displayNameSingular); + builder.fractionalDigits().ifPresent(delegate::fractionalDigits); + builder.symbol().ifPresent(delegate::symbol); + }); } /** @@ -112,7 +117,6 @@ default boolean deleteCurrency(String name) { * * @return {@code true} if multi-currency is supported, otherwise {@code false} * @implSpec If multiple currencies are supported, all respective methods have to be implemented. - * @see #createCurrency(Currency.Builder) * @see #createCurrency(String, Consumer) * @see #deleteCurrency(String) * @see #getCurrencies() From 37814eef6932ac7f463f4e55626e7c681478ae24 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 22 Jul 2025 20:43:59 +0200 Subject: [PATCH 26/32] Improved Javadoc and parameter handling in banking APIs Enhanced descriptions for method parameters, added `@apiNote` annotations for clarity, and standardized return value formatting with `{@code}`. Updated references to `uuid` instead of `UUID`. Improved consistency in `Account` API behavior with `BigDecimal.ZERO` returns for unsupported operations. --- .../service/api/economy/Account.java | 15 ++++-- .../service/api/economy/bank/Bank.java | 46 ++++++++++--------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index d77c64c4..2944baa8 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -17,6 +17,8 @@ public interface Account { /** * Deposits the specified amount of the given currency into the account balance. + *

+ * Returns {@link BigDecimal#ZERO} if {@link #canHold(Currency)} returns {@code false} * * @param amount the amount to be deposited * @param currency the currency that is being deposited @@ -38,6 +40,8 @@ default BigDecimal deposit(Number amount, Currency currency) { /** * Withdraws the specified amount of the given currency from the account balance. + *

+ * Returns {@link BigDecimal#ZERO} if {@link #canHold(Currency)} returns {@code false} * * @param amount the amount to be withdrawn * @param currency the currency in which the withdrawal is to be made @@ -49,16 +53,16 @@ default BigDecimal withdraw(Number amount, Currency currency) { } /** - * Returns an optional containing the world associated with this account. + * Returns the world associated with this account. * - * @return an {@code Optional} containing the world associated with this account, or empty + * @return an optional containing the world associated with this account, or empty */ Optional getWorld(); /** - * Returns the UUID of the owner of this account. + * Returns the account owner's uuid. * - * @return the UUID of the owner + * @return the account owner's uuid */ UUID getOwner(); @@ -77,10 +81,13 @@ default int compareTo(Account account, Currency currency) { /** * Sets the balance of the account to the specified value in the given currency. + *

+ * Returns {@link BigDecimal#ZERO} if {@link #canHold(Currency)} returns {@code false} * * @param balance the new balance to be set * @param currency the currency of the balance * @return the new balance after the operation + * @see #canHold(Currency) * @since 3.0.0 */ BigDecimal setBalance(Number balance, Currency currency); diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java index df343d75..170e246f 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java @@ -1,6 +1,7 @@ package net.thenextlvl.service.api.economy.bank; import net.thenextlvl.service.api.economy.Account; +import net.thenextlvl.service.api.economy.currency.Currency; import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; @@ -13,7 +14,7 @@ * The Bank interface represents a financial entity that can be owned and hold members. * It extends the Account interface, providing additional functionality specific * to banking, such as depositing or withdrawing money. - * + * * @since 1.0.0 */ @NullMarked @@ -22,6 +23,7 @@ public interface Bank extends Account { * Retrieves a set of UUIDs representing the members of the bank. * * @return an unmodifiable set containing the UUIDs of the members. + * @apiNote does not contain the uuid of the owner */ @Unmodifiable Set getMembers(); @@ -37,8 +39,8 @@ public interface Bank extends Account { /** * Adds a member to the bank. * - * @param player the OfflinePlayer object representing the player to be added as a member - * @return true if the player was successfully added as a member, false otherwise + * @param player the player to be added as a member + * @return {@code true} if the player was successfully added as a member, otherwise {@code false} */ default boolean addMember(OfflinePlayer player) { return addMember(player.getUniqueId()); @@ -47,62 +49,64 @@ default boolean addMember(OfflinePlayer player) { /** * Adds a member to the bank. * - * @param uuid the UUID of the member to be added - * @return true if the member was successfully added, false otherwise + * @param uuid the uuid of the member to be added + * @return {@code true} if the member was successfully added, otherwise {@code false} */ boolean addMember(UUID uuid); /** * Checks if the specified player is a member of the bank. * - * @param player the OfflinePlayer object representing the player to check for membership - * @return true if the player is a member of the bank, false otherwise + * @param player the player to check for membership + * @return {@code true} if the player is a member of the bank, otherwise {@code false} + * @apiNote returns {@code false} on the owner */ default boolean isMember(OfflinePlayer player) { return isMember(player.getUniqueId()); } /** - * Checks if the specified UUID is associated with a member of the bank. + * Checks if the specified uuid is associated with a member of the bank. * - * @param uuid the UUID of the member to check for membership - * @return true if the UUID corresponds to a member of the bank, false otherwise + * @param uuid the uuid of the member to check for membership + * @return {@code true} if the uuid corresponds to a member of the bank, otherwise {@code false} + * @apiNote returns {@code false} on the owner */ boolean isMember(UUID uuid); /** * Removes a member from the bank. * - * @param player the OfflinePlayer object representing the player to be removed as a member - * @return true if the member was successfully removed, false otherwise + * @param player the player to be removed as a member + * @return {@code true} if the member was successfully removed, otherwise {@code false} */ default boolean removeMember(OfflinePlayer player) { return removeMember(player.getUniqueId()); } /** - * Removes a member from the bank using the specified UUID. + * Removes a member from the bank using the specified uuid. * - * @param uuid the UUID of the member to be removed - * @return true if the member was successfully removed, false otherwise + * @param uuid the uuid of the member to be removed + * @return {@code true} if the member was successfully removed, otherwise {@code false} */ boolean removeMember(UUID uuid); /** - * Sets the specified OfflinePlayer as the owner of the bank. + * Sets the specified player as the owner of the bank. * - * @param player the OfflinePlayer object representing the player to be set as the owner - * @return true if the player was successfully set as the owner, false otherwise + * @param player the player to be set as the owner + * @return {@code true} if the player was successfully set as the owner, otherwise {@code false} */ default boolean setOwner(OfflinePlayer player) { return setOwner(player.getUniqueId()); } /** - * Sets the owner of the bank to the specified UUID. + * Sets the owner of the bank to the specified uuid. * - * @param uuid the UUID of the new owner - * @return true if the owner was successfully set, false otherwise + * @param uuid the uuid of the new owner + * @return {@code true} if the owner was successfully set, otherwise {@code false} */ boolean setOwner(UUID uuid); } From 925174857a9ba795ddeda00e56f9e48864530430 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 22 Jul 2025 20:44:31 +0200 Subject: [PATCH 27/32] Added `canDeposit`, `canWithdraw`, and `canHold` methods Enhanced `Bank` and `Account` APIs with balance operation checks. Implemented default behaviors and updated wrappers to align with the new methods for consistent validation logic. --- .../wrapper/service/model/WrappedAccount.java | 5 ++ .../wrapper/service/model/WrappedBank.java | 25 +++++++++ .../service/api/economy/Account.java | 8 +++ .../service/api/economy/bank/Bank.java | 52 +++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java index f68deab4..f6c8d346 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java @@ -59,4 +59,9 @@ public BigDecimal setBalance(Number balance, Currency currency) { else if (difference < 0) return withdraw(-difference, currency); return BigDecimal.ZERO; } + + @Override + public boolean canHold(Currency currency) { + return true; + } } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java index 6baf926b..35018621 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java @@ -70,6 +70,11 @@ public BigDecimal setBalance(Number balance, Currency currency) { return current; } + @Override + public boolean canHold(Currency currency) { + return false; + } + @Override public @Unmodifiable Set getMembers() { return Arrays.stream(provider.getServer().getOfflinePlayers()) @@ -102,4 +107,24 @@ public boolean removeMember(UUID uuid) { public boolean setOwner(UUID uuid) { return false; } + + @Override + public boolean canDeposit(OfflinePlayer player, Number amount, Currency currency) { + return economy.isBankOwner(getName(), player).transactionSuccess(); + } + + @Override + public boolean canDeposit(UUID uuid, Number amount, Currency currency) { + return canDeposit(plugin.getServer().getOfflinePlayer(uuid), amount, currency); + } + + @Override + public boolean canWithdraw(OfflinePlayer player, Number amount, Currency currency) { + return economy.isBankOwner(getName(), player).transactionSuccess(); + } + + @Override + public boolean canWithdraw(UUID uuid, Number amount, Currency currency) { + return canWithdraw(plugin.getServer().getOfflinePlayer(uuid), amount, currency); + } } diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index 2944baa8..141211a3 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -91,4 +91,12 @@ default int compareTo(Account account, Currency currency) { * @since 3.0.0 */ BigDecimal setBalance(Number balance, Currency currency); + + /** + * Checks if the account can hold the specified currency. + * + * @param currency the currency to check support for + * @return {@code true} if the account can hold the specified currency, otherwise {@code false} + */ + boolean canHold(Currency currency); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java index 170e246f..9f7bbc10 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java @@ -109,4 +109,56 @@ default boolean setOwner(OfflinePlayer player) { * @return {@code true} if the owner was successfully set, otherwise {@code false} */ boolean setOwner(UUID uuid); + + /** + * Checks whether the specified player can deposit the specified amount in the given currency. + *

+ * Returns {@code false} if {@link #canHold(Currency)} returns {@code false} + * + * @param player the player attempting to make the deposit + * @param amount the amount being attempted to deposit + * @param currency the currency of the deposit + * @return {@code true} if the player can deposit the specified amount, otherwise {@code false} + */ + default boolean canDeposit(OfflinePlayer player, Number amount, Currency currency) { + return canDeposit(player.getUniqueId(), amount, currency); + } + + /** + * Checks whether the specified uuid can deposit the specified amount in the given currency. + *

+ * Returns {@code false} if {@link #canHold(Currency)} returns {@code false} + * + * @param uuid the uuid of the player attempting to make the deposit + * @param amount the amount being attempted to deposit + * @param currency the currency of the deposit + * @return {@code true} if the player can deposit the specified amount, otherwise {@code false} + */ + boolean canDeposit(UUID uuid, Number amount, Currency currency); + + /** + * Checks whether the specified player can withdraw the specified amount in the given currency. + *

+ * Returns {@code false} if {@link #canHold(Currency)} returns {@code false} + * + * @param player the player attempting to make the withdrawal + * @param amount the amount being attempted to withdraw + * @param currency the currency of the withdrawal + * @return {@code true} if the player can withdraw the specified amount, otherwise {@code false} + */ + default boolean canWithdraw(OfflinePlayer player, Number amount, Currency currency) { + return canWithdraw(player.getUniqueId(), amount, currency); + } + + /** + * Checks whether the specified uuid can withdraw the specified amount in the given currency. + *

+ * Returns {@code false} if {@link #canHold(Currency)} returns {@code false} + * + * @param uuid the UUID of the player attempting to make the withdrawal + * @param amount the amount being attempted to withdraw + * @param currency the currency of the withdrawal + * @return {@code true} if the player can withdraw the specified amount, otherwise {@code false} + */ + boolean canWithdraw(UUID uuid, Number amount, Currency currency); } From 45447fa32fce9d5c4f193d697808845b9db24c34 Mon Sep 17 00:00:00 2001 From: david Date: Tue, 22 Jul 2025 20:47:59 +0200 Subject: [PATCH 28/32] [ci skip] Added `@since 3.0.0` annotations to API methods Documented version information for newly introduced methods in `Bank` and `Account` to improve clarity and maintainability. --- src/main/java/net/thenextlvl/service/api/economy/Account.java | 1 + .../java/net/thenextlvl/service/api/economy/bank/Bank.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index 141211a3..656dde1c 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -97,6 +97,7 @@ default int compareTo(Account account, Currency currency) { * * @param currency the currency to check support for * @return {@code true} if the account can hold the specified currency, otherwise {@code false} + * @since 3.0.0 */ boolean canHold(Currency currency); } diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java index 9f7bbc10..7239c100 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java @@ -119,6 +119,7 @@ default boolean setOwner(OfflinePlayer player) { * @param amount the amount being attempted to deposit * @param currency the currency of the deposit * @return {@code true} if the player can deposit the specified amount, otherwise {@code false} + * @since 3.0.0 */ default boolean canDeposit(OfflinePlayer player, Number amount, Currency currency) { return canDeposit(player.getUniqueId(), amount, currency); @@ -133,6 +134,7 @@ default boolean canDeposit(OfflinePlayer player, Number amount, Currency currenc * @param amount the amount being attempted to deposit * @param currency the currency of the deposit * @return {@code true} if the player can deposit the specified amount, otherwise {@code false} + * @since 3.0.0 */ boolean canDeposit(UUID uuid, Number amount, Currency currency); @@ -145,6 +147,7 @@ default boolean canDeposit(OfflinePlayer player, Number amount, Currency currenc * @param amount the amount being attempted to withdraw * @param currency the currency of the withdrawal * @return {@code true} if the player can withdraw the specified amount, otherwise {@code false} + * @since 3.0.0 */ default boolean canWithdraw(OfflinePlayer player, Number amount, Currency currency) { return canWithdraw(player.getUniqueId(), amount, currency); @@ -159,6 +162,7 @@ default boolean canWithdraw(OfflinePlayer player, Number amount, Currency curren * @param amount the amount being attempted to withdraw * @param currency the currency of the withdrawal * @return {@code true} if the player can withdraw the specified amount, otherwise {@code false} + * @since 3.0.0 */ boolean canWithdraw(UUID uuid, Number amount, Currency currency); } From 6cbab124d47523f0f4baf2d5cc8bb6e9a88a59cf Mon Sep 17 00:00:00 2001 From: david Date: Thu, 23 Oct 2025 21:34:34 +0200 Subject: [PATCH 29/32] Refactored currency and bank access to use CurrencyHolder --- .../service/listener/ServiceListener.java | 2 +- .../wrapper/VaultEconomyServiceWrapper.java | 56 ++++++++----------- .../wrapper/service/BankServiceWrapper.java | 11 ++-- .../service/EconomyServiceWrapper.java | 4 +- .../wrapper/service/model/WrappedBank.java | 5 +- 5 files changed, 37 insertions(+), 41 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/listener/ServiceListener.java b/plugin/src/main/java/net/thenextlvl/service/listener/ServiceListener.java index 35b65572..67df98f7 100644 --- a/plugin/src/main/java/net/thenextlvl/service/listener/ServiceListener.java +++ b/plugin/src/main/java/net/thenextlvl/service/listener/ServiceListener.java @@ -86,7 +86,7 @@ private void loadServiceEconomyWrapper(RegisteredServiceProvider provid provider.getPlugin().getName(), provider.getProvider().getName(), provider.getPriority().name()); if (!provider.getProvider().hasBankSupport()) return; - var banks = new BankServiceWrapper(provider.getProvider(), provider.getPlugin()); + var banks = new BankServiceWrapper(wrapper.getCurrencyHolder(), provider.getProvider(), provider.getPlugin()); getServicesManager().register(BankController.class, banks, provider.getPlugin(), provider.getPriority()); plugin.getComponentLogger().info("Registered bank service wrapper for {} - {} ({})", provider.getPlugin().getName(), provider.getProvider().getName(), provider.getPriority().name()); diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java index 38f2230c..29e806c4 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java @@ -12,6 +12,7 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import java.math.BigDecimal; import java.util.List; import java.util.Locale; import java.util.Optional; @@ -53,24 +54,24 @@ public boolean hasBankSupport() { @Override public int fractionalDigits() { - return economyController.getDefaultCurrency().getFractionalDigits(); + return economyController.getCurrencyHolder().getDefaultCurrency().getFractionalDigits(); } @Override public String format(double amount) { - var format = economyController.getDefaultCurrency().format(amount, Locale.US); + var format = economyController.getCurrencyHolder().getDefaultCurrency().format(amount, Locale.US); return PlainTextComponentSerializer.plainText().serialize(format); } @Override public String currencyNamePlural() { - return economyController.getDefaultCurrency().getDisplayNamePlural(Locale.US) + return economyController.getCurrencyHolder().getDefaultCurrency().getDisplayNamePlural(Locale.US) .map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } @Override public String currencyNameSingular() { - return economyController.getDefaultCurrency().getDisplayNameSingular(Locale.US) + return economyController.getCurrencyHolder().getDefaultCurrency().getDisplayNameSingular(Locale.US) .map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } @@ -114,7 +115,7 @@ public double getBalance(@Nullable String playerName, @Nullable String worldName @Override public double getBalance(@Nullable OfflinePlayer player, @Nullable String worldName) { return getAccount(player, worldName) - .map(account -> account.getBalance(economyController.getDefaultCurrency())) + .map(account -> account.getBalance(economyController.getCurrencyHolder().getDefaultCurrency())) .map(Number::doubleValue) .orElse(0.0); } @@ -158,8 +159,8 @@ public EconomyResponse withdrawPlayer(@Nullable String playerName, @Nullable Str @Override public EconomyResponse withdrawPlayer(@Nullable OfflinePlayer player, @Nullable String worldName, double amount) { return getAccount(player, worldName).map(account -> { - var balance = account.getBalance(economyController.getDefaultCurrency()); - var withdraw = account.withdraw(amount, economyController.getDefaultCurrency()); + var balance = account.getBalance(economyController.getCurrencyHolder().getDefaultCurrency()); + var withdraw = account.withdraw(amount, economyController.getCurrencyHolder().getDefaultCurrency()); var responseType = amount != 0 && balance.equals(withdraw) ? FAILURE : SUCCESS; return new EconomyResponse(amount, withdraw.doubleValue(), responseType, null); }).orElseGet(() -> new EconomyResponse(amount, 0, FAILURE, null)); @@ -184,8 +185,8 @@ public EconomyResponse depositPlayer(@Nullable String name, @Nullable String wor @Override public EconomyResponse depositPlayer(@Nullable OfflinePlayer player, @Nullable String worldName, double amount) { return getAccount(player, worldName).map(account -> { - var balance = account.getBalance(economyController.getDefaultCurrency()); - var deposit = account.deposit(amount, economyController.getDefaultCurrency()); + var balance = account.getBalance(economyController.getCurrencyHolder().getDefaultCurrency()); + var deposit = account.deposit(amount, economyController.getCurrencyHolder().getDefaultCurrency()); var responseType = amount != 0 && balance.equals(deposit) ? FAILURE : SUCCESS; return new EconomyResponse(amount, deposit.doubleValue(), responseType, null); }).orElseGet(() -> new EconomyResponse(amount, 0, FAILURE, null)); @@ -213,37 +214,28 @@ public EconomyResponse deleteBank(String name) { @Override public EconomyResponse bankBalance(String name) { - try { - var bank = bankController().tryGetBank(name).join(); - var balance = bank.getBalance(economyController.getDefaultCurrency()); - return new EconomyResponse(0, balance.doubleValue(), SUCCESS, null); - } catch (Exception e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + return bankController().tryGetBank(name).join() + .map(bank -> bank.getBalance(economyController.getCurrencyHolder().getDefaultCurrency())) + .map(balance -> new EconomyResponse(0, balance.doubleValue(), SUCCESS, null)) + .orElseGet(() -> new EconomyResponse(0, 0, FAILURE, "Bank not found")); } @Override public EconomyResponse bankHas(String name, double amount) { - try { - var bank = bankController().tryGetBank(name).join(); - var balance = bank.getBalance(economyController.getDefaultCurrency()).doubleValue(); - var response = balance >= amount ? SUCCESS : FAILURE; - return new EconomyResponse(amount, balance, response, null); - } catch (Exception e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + return bankController().tryGetBank(name).join() + .map(bank -> bank.getBalance(economyController.getCurrencyHolder().getDefaultCurrency())) + .map(BigDecimal::doubleValue) + .map(balance -> new EconomyResponse(amount, balance, balance >= amount ? SUCCESS : FAILURE, null)) + .orElseGet(() -> new EconomyResponse(0, 0, FAILURE, "Bank not found")); } @Override public EconomyResponse bankWithdraw(String name, double amount) { - try { - var bank = bankController().tryGetBank(name).join(); - var balance = bank.withdraw(amount, economyController.getDefaultCurrency()).doubleValue(); - var response = balance >= amount ? SUCCESS : FAILURE; - return new EconomyResponse(amount, balance, response, null); - } catch (Exception e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + return bankController().tryGetBank(name).join() + .map(bank -> bank.withdraw(amount, economyController.getCurrencyHolder().getDefaultCurrency())) + .map(BigDecimal::doubleValue) + .map(balance -> new EconomyResponse(amount, balance, balance >= amount ? SUCCESS : FAILURE, null)) + .orElseGet(() -> new EconomyResponse(0, 0, FAILURE, "Bank not found")); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java index fb2382bd..8f46393e 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/BankServiceWrapper.java @@ -4,7 +4,9 @@ import net.milkbowl.vault.economy.EconomyResponse; import net.thenextlvl.service.api.economy.bank.Bank; import net.thenextlvl.service.api.economy.bank.BankController; +import net.thenextlvl.service.api.economy.currency.Currency; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; +import net.thenextlvl.service.wrapper.Wrapper; import net.thenextlvl.service.wrapper.service.model.WrappedBank; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -30,6 +32,7 @@ public BankServiceWrapper(CurrencyHolder holder, Economy economy, Plugin provide this.holder = holder; this.economy = economy; this.provider = provider; + this.currency = holder.getDefaultCurrency(); } @Override @@ -77,14 +80,14 @@ public CompletableFuture deleteBank(UUID uuid, @Nullable World world) { @Override public @Unmodifiable Set getBanks(@Nullable World world) { return world != null ? Set.of() : economy.getBanks().stream() - .map(bank -> new WrappedBank(bank, null, economy, plugin)) + .map(bank -> new WrappedBank(bank, null, economy, provider)) .collect(Collectors.toUnmodifiableSet()); } @Override public Optional getBank(String name) { if (!economy.getBanks().contains(name)) return Optional.empty(); - return Optional.of(new WrappedBank(this, name, null, economy, provider)); + return Optional.of(new WrappedBank(name, null, economy, provider)); } @Override @@ -96,7 +99,7 @@ public Optional getBank(OfflinePlayer player, @Nullable World world) { @Override public Optional getBank(UUID uuid, @Nullable World world) { - return getBank(plugin.getServer().getOfflinePlayer(uuid), world); + return getBank(provider.getServer().getOfflinePlayer(uuid), world); } @Override @@ -106,7 +109,7 @@ public boolean hasBank(OfflinePlayer player, @Nullable World world) { @Override public boolean hasBank(UUID uuid, @Nullable World world) { - return hasBank(plugin.getServer().getOfflinePlayer(uuid), world); + return hasBank(provider.getServer().getOfflinePlayer(uuid), world); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index aaf9b3c1..8b4643ca 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -4,6 +4,8 @@ import net.thenextlvl.service.api.economy.Account; import net.thenextlvl.service.api.economy.EconomyController; import net.thenextlvl.service.api.economy.currency.Currency; +import net.thenextlvl.service.api.economy.currency.CurrencyHolder; +import net.thenextlvl.service.wrapper.Wrapper; import net.thenextlvl.service.wrapper.service.model.WrappedAccount; import net.thenextlvl.service.wrapper.service.model.WrappedCurrency; import org.bukkit.OfflinePlayer; @@ -73,7 +75,7 @@ public CompletableFuture createAccount(OfflinePlayer player, @Nullable @Override public CompletableFuture createAccount(UUID uuid, @Nullable World world) { - return createAccount(plugin.getServer().getOfflinePlayer(uuid), world); + return createAccount(provider.getServer().getOfflinePlayer(uuid), world); } @Override diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java index 35018621..c41244ad 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java @@ -1,7 +1,6 @@ package net.thenextlvl.service.wrapper.service.model; import net.milkbowl.vault.economy.Economy; -import net.thenextlvl.service.ServicePlugin; import net.thenextlvl.service.api.economy.bank.Bank; import net.thenextlvl.service.api.economy.currency.Currency; import org.bukkit.OfflinePlayer; @@ -115,7 +114,7 @@ public boolean canDeposit(OfflinePlayer player, Number amount, Currency currency @Override public boolean canDeposit(UUID uuid, Number amount, Currency currency) { - return canDeposit(plugin.getServer().getOfflinePlayer(uuid), amount, currency); + return canDeposit(provider.getServer().getOfflinePlayer(uuid), amount, currency); } @Override @@ -125,6 +124,6 @@ public boolean canWithdraw(OfflinePlayer player, Number amount, Currency currenc @Override public boolean canWithdraw(UUID uuid, Number amount, Currency currency) { - return canWithdraw(plugin.getServer().getOfflinePlayer(uuid), amount, currency); + return canWithdraw(provider.getServer().getOfflinePlayer(uuid), amount, currency); } } From 5fa9bba5b9312073cc9bc71241bc0882a7ae4a4f Mon Sep 17 00:00:00 2001 From: david Date: Fri, 24 Oct 2025 17:32:06 +0200 Subject: [PATCH 30/32] Restore backwards compatibility --- .../service/api/economy/Account.java | 67 +++++++++++++++++-- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/thenextlvl/service/api/economy/Account.java b/src/main/java/net/thenextlvl/service/api/economy/Account.java index 656dde1c..e54b55a4 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/Account.java +++ b/src/main/java/net/thenextlvl/service/api/economy/Account.java @@ -3,6 +3,7 @@ import net.thenextlvl.service.api.economy.currency.Currency; import org.bukkit.World; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.math.BigDecimal; import java.util.Optional; @@ -14,7 +15,17 @@ * @since 1.0.0 */ @NullMarked -public interface Account { +public interface Account extends Comparable { + /** + * Deposits the specified amount into the account balance. + * + * @param amount the amount to be deposited + * @return the new balance after the deposit + */ + default BigDecimal deposit(Number amount) { + return deposit(amount, null); + } + /** * Deposits the specified amount of the given currency into the account balance. *

@@ -25,10 +36,17 @@ public interface Account { * @return the new balance after the deposit * @since 3.0.0 */ - default BigDecimal deposit(Number amount, Currency currency) { + default BigDecimal deposit(Number amount, @Nullable Currency currency) { return setBalance(getBalance(currency).add(BigDecimal.valueOf(amount.doubleValue())), currency); } + /** + * Retrieves the balance of the account. + * + * @return the balance of the account + */ + BigDecimal getBalance(); + /** * Retrieves the balance of the account for the specified currency. * @@ -36,7 +54,19 @@ default BigDecimal deposit(Number amount, Currency currency) { * @return the balance of the account for the specified currency * @since 3.0.0 */ - BigDecimal getBalance(Currency currency); + default BigDecimal getBalance(@Nullable Currency currency) { + return getBalance(); + } + + /** + * Withdraws the specified amount from the account balance. + * + * @param amount the amount to be withdrawn + * @return the new balance after the withdrawal + */ + default BigDecimal withdraw(Number amount) { + return withdraw(amount, null); + } /** * Withdraws the specified amount of the given currency from the account balance. @@ -48,7 +78,7 @@ default BigDecimal deposit(Number amount, Currency currency) { * @return the new balance after the withdrawal * @since 3.0.0 */ - default BigDecimal withdraw(Number amount, Currency currency) { + default BigDecimal withdraw(Number amount, @Nullable Currency currency) { return setBalance(getBalance(currency).subtract(BigDecimal.valueOf(amount.doubleValue())), currency); } @@ -66,6 +96,18 @@ default BigDecimal withdraw(Number amount, Currency currency) { */ UUID getOwner(); + /** + * Compares this account to the specified account based on their balance. + * + * @param account the account to be compared + * @return a negative integer, zero, or a positive integer if this account is + * less than, equal to, or greater than the specified account + */ + @Override + default int compareTo(Account account) { + return compareTo(account, null); + } + /** * Compares this account with another account based on their balances in the specified currency. * @@ -75,10 +117,17 @@ default BigDecimal withdraw(Number amount, Currency currency) { * is less than, equal to, or greater than the specified account's balance * @since 3.0.0 */ - default int compareTo(Account account, Currency currency) { + default int compareTo(Account account, @Nullable Currency currency) { return getBalance(currency).compareTo(account.getBalance(currency)); } + /** + * Sets the balance of the account to the specified value. + * + * @param balance the new balance of the account + */ + BigDecimal setBalance(Number balance); + /** * Sets the balance of the account to the specified value in the given currency. *

@@ -90,7 +139,9 @@ default int compareTo(Account account, Currency currency) { * @see #canHold(Currency) * @since 3.0.0 */ - BigDecimal setBalance(Number balance, Currency currency); + default BigDecimal setBalance(Number balance, @Nullable Currency currency) { + return setBalance(balance); + } /** * Checks if the account can hold the specified currency. @@ -99,5 +150,7 @@ default int compareTo(Account account, Currency currency) { * @return {@code true} if the account can hold the specified currency, otherwise {@code false} * @since 3.0.0 */ - boolean canHold(Currency currency); + default boolean canHold(@Nullable Currency currency) { + return true; + } } From 26a2b42107c505b7346858af5d77c50c2675ad45 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 24 Oct 2025 17:32:23 +0200 Subject: [PATCH 31/32] Refactored bank response handling with Optionals --- .../wrapper/VaultEconomyServiceWrapper.java | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java index 29e806c4..121aef82 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java @@ -240,14 +240,10 @@ public EconomyResponse bankWithdraw(String name, double amount) { @Override public EconomyResponse bankDeposit(String name, double amount) { - try { - var bank = bankController().tryGetBank(name).join(); - var balance = bank.deposit(amount, economyController.getDefaultCurrency()).doubleValue(); - var response = balance >= amount ? SUCCESS : FAILURE; - return new EconomyResponse(amount, balance, response, null); - } catch (Exception e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + return bankController().tryGetBank(name).join() + .map(bank -> bank.deposit(amount, economyController.getCurrencyHolder().getDefaultCurrency()).doubleValue()) + .map(balance -> new EconomyResponse(amount, balance, balance >= amount ? SUCCESS : FAILURE, null)) + .orElseGet(() -> new EconomyResponse(0, 0, FAILURE, "Bank not found")); } @Override @@ -258,14 +254,11 @@ public EconomyResponse isBankOwner(String name, String playerName) { @Override public EconomyResponse isBankOwner(String name, @Nullable OfflinePlayer player) { - try { - var bank = bankController().tryGetBank(name).join(); + return bankController().tryGetBank(name).join().map(bank -> { var response = player != null && bank.getOwner().equals(player.getUniqueId()) ? SUCCESS : FAILURE; - var balance = bank.getBalance(economyController.getDefaultCurrency()); + var balance = bank.getBalance(economyController.getCurrencyHolder().getDefaultCurrency()); return new EconomyResponse(0, balance.doubleValue(), response, null); - } catch (Exception e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, "Bank not found")); } @Override @@ -276,14 +269,11 @@ public EconomyResponse isBankMember(String name, @Nullable String playerName) { @Override public EconomyResponse isBankMember(String name, @Nullable OfflinePlayer player) { - try { - var bank = bankController().tryGetBank(name).join(); + return bankController().tryGetBank(name).join().map(bank -> { var response = player != null && bank.isMember(player.getUniqueId()) ? SUCCESS : FAILURE; - var balance = bank.getBalance(economyController.getDefaultCurrency()); + var balance = bank.getBalance(economyController.getCurrencyHolder().getDefaultCurrency()); return new EconomyResponse(0, balance.doubleValue(), response, null); - } catch (Exception e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, "Bank not found")); } @Override From 52aac8f641a91fdab55257ecd46b4168d0a790e6 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 24 Oct 2025 19:46:41 +0200 Subject: [PATCH 32/32] unbreak more abi --- .../service/EconomyServiceWrapper.java | 5 + .../wrapper/service/model/WrappedAccount.java | 33 ++--- .../wrapper/service/model/WrappedBank.java | 31 ++--- .../api/economy/EconomyController.java | 86 ++++++++++-- .../service/api/economy/bank/Bank.java | 8 +- .../api/economy/bank/BankController.java | 5 +- .../api/economy/currency/SimpleCurrency.java | 129 ++++++++++++++++++ .../currency/SimpleCurrencyHolder.java | 18 +++ 8 files changed, 258 insertions(+), 57 deletions(-) create mode 100644 src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrency.java create mode 100644 src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrencyHolder.java diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java index 8b4643ca..6439710f 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/EconomyServiceWrapper.java @@ -44,6 +44,11 @@ public CurrencyHolder getCurrencyHolder() { return CompletableFuture.completedFuture(getAccounts(world)); } + @Override + public @Unmodifiable Set getAccounts() { + return getAccounts(null); + } + @Override public @Unmodifiable Set getAccounts(@Nullable World world) { return Arrays.stream(provider.getServer().getOfflinePlayers()) diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java index f6c8d346..2c74327e 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedAccount.java @@ -2,7 +2,6 @@ import net.milkbowl.vault.economy.Economy; import net.thenextlvl.service.api.economy.Account; -import net.thenextlvl.service.api.economy.currency.Currency; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jspecify.annotations.NullMarked; @@ -25,23 +24,11 @@ public WrappedAccount(@Nullable World world, Economy economy, OfflinePlayer hold } @Override - public BigDecimal deposit(Number amount, Currency currency) { - var response = economy.depositPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); - return new BigDecimal(response.balance); - } - - @Override - public BigDecimal getBalance(Currency currency) { + public BigDecimal getBalance() { var balance = economy.getBalance(holder, world != null ? world.getName() : null); return new BigDecimal(balance); } - @Override - public BigDecimal withdraw(Number amount, Currency currency) { - var response = economy.withdrawPlayer(holder, world != null ? world.getName() : null, amount.doubleValue()); - return new BigDecimal(response.balance); - } - @Override public Optional getWorld() { return Optional.ofNullable(world); @@ -53,15 +40,15 @@ public UUID getOwner() { } @Override - public BigDecimal setBalance(Number balance, Currency currency) { - var difference = balance.doubleValue() - getBalance(currency).doubleValue(); - if (difference > 0) return deposit(difference, currency); - else if (difference < 0) return withdraw(-difference, currency); + public BigDecimal setBalance(Number balance) { + var difference = balance.doubleValue() - getBalance().doubleValue(); + if (difference > 0) { + var response = economy.depositPlayer(holder, world != null ? world.getName() : null, difference); + return new BigDecimal(response.balance); + } else if (difference < 0) { + var response = economy.withdrawPlayer(holder, world != null ? world.getName() : null, -difference); + return new BigDecimal(response.balance); + } return BigDecimal.ZERO; } - - @Override - public boolean canHold(Currency currency) { - return true; - } } diff --git a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java index c41244ad..73dd4630 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedBank.java @@ -32,20 +32,10 @@ public WrappedBank(String name, @Nullable World world, Economy economy, Plugin p } @Override - public BigDecimal deposit(Number amount, Currency currency) { - return new BigDecimal(economy.bankDeposit(name, amount.doubleValue()).balance); - } - - @Override - public BigDecimal getBalance(Currency currency) { + public BigDecimal getBalance() { return new BigDecimal(economy.bankBalance(name).balance); } - @Override - public BigDecimal withdraw(Number amount, Currency currency) { - return new BigDecimal(economy.bankWithdraw(name, amount.doubleValue()).balance); - } - @Override public Optional getWorld() { return Optional.ofNullable(world); @@ -61,17 +51,14 @@ public UUID getOwner() { } @Override - public BigDecimal setBalance(Number balance, Currency currency) { - var current = getBalance(currency); - var difference = balance.doubleValue() - current.doubleValue(); - if (difference > 0) return deposit(difference, currency); - else if (difference < 0) return withdraw(-difference, currency); - return current; - } - - @Override - public boolean canHold(Currency currency) { - return false; + public BigDecimal setBalance(Number balance) { + var difference = balance.doubleValue() - getBalance().doubleValue(); + if (difference > 0) { + return new BigDecimal(economy.bankDeposit(name, difference).balance); + } else if (difference < 0) { + return new BigDecimal(economy.bankWithdraw(name, -difference).balance); + } + return BigDecimal.ZERO; } @Override diff --git a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java index 4f2230dc..70730f19 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/EconomyController.java @@ -1,5 +1,6 @@ package net.thenextlvl.service.api.economy; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.thenextlvl.service.api.Controller; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; import org.bukkit.OfflinePlayer; @@ -9,10 +10,12 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import java.util.Locale; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; /** * EconomyController is an interface that provides methods for managing and interacting @@ -22,6 +25,67 @@ */ @NullMarked public interface EconomyController extends Controller { + /** + * Formats the specified amount as a string. + * + * @param amount the number amount to be formatted + * @return the formatted amount as a string + * @deprecated Use {@link net.thenextlvl.service.api.economy.currency.Currency#format(Number, Locale)} instead + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default String format(Number amount) { + return PlainTextComponentSerializer.plainText().serialize(getCurrencyHolder().getDefaultCurrency().format(amount, Locale.getDefault())); + } + + /** + * Retrieves the number of fractional digits used for formatting currency amounts. + * + * @return the number of fractional digits used for formatting currency amounts + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default int fractionalDigits() { + return getCurrencyHolder().getDefaultCurrency().getFractionalDigits(); + } + + /** + * Retrieves the plural form of the currency name based on the provided locale. + * + * @param locale the locale for which to retrieve the plural currency name + * @return the plural form of the currency name as a string + * @deprecated Use {@link net.thenextlvl.service.api.economy.currency.Currency#getDisplayNamePlural(Locale)} instead + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default String getCurrencyNamePlural(Locale locale) { + return getCurrencyHolder().getDefaultCurrency().getDisplayNamePlural(locale) + .map(PlainTextComponentSerializer.plainText()::serialize) + .orElse(""); + } + + /** + * Retrieves the name of the currency associated with the specified locale. + * + * @param locale the locale for which to retrieve the currency name + * @return the name of the currency as a string + * @deprecated Use {@link net.thenextlvl.service.api.economy.currency.Currency#getDisplayNameSingular(Locale)} instead + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default String getCurrencyNameSingular(Locale locale) { + return getCurrencyHolder().getDefaultCurrency().getDisplayNameSingular(locale) + .map(PlainTextComponentSerializer.plainText()::serialize) + .orElse(""); + } + + /** + * Retrieves the currency symbol associated with the economy controller. + * + * @return the currency symbol as a string + * @deprecated Use {@link net.thenextlvl.service.api.economy.currency.Currency#getSymbol()} instead + */ + @Deprecated(forRemoval = true, since = "2.4.0") + default String getCurrencySymbol() { + return PlainTextComponentSerializer.plainText().serialize(getCurrencyHolder().getDefaultCurrency().getSymbol()); + } + /** * Retrieves the {@code CurrencyHolder} associated with the economy controller. * @@ -54,20 +118,26 @@ public interface EconomyController extends Controller { * Retrieves all the accounts that are currently loaded. * * @return an unmodifiable set of accounts + * @see #getAccounts(World) * @since 2.2.0 */ - default @Unmodifiable Set getAccounts() { - return getAccounts(null); - } + @Unmodifiable + Set getAccounts(); /** * Retrieves all the accounts associated with the specified world that are currently loaded. * * @param world the world for which the accounts are to be retrieved * @return an unmodifiable set of accounts for the given world + * @implSpec Implementations should override this method for performance reasons. + * @since 2.4.0 */ @Unmodifiable - Set getAccounts(@Nullable World world); + default Set getAccounts(@Nullable World world) { + return world != null ? getAccounts().stream().filter(account -> { + return account.getWorld().map(world::equals).orElse(false); + }).collect(Collectors.toUnmodifiableSet()) : getAccounts(); + } /** * Retrieve the account for the specified player. @@ -161,7 +231,6 @@ default CompletableFuture> tryGetAccount(UUID uuid, @Nullable * @param player the player for whom the account will be created * @return a CompletableFuture that will complete with the created account */ - @Contract("_ -> new") default CompletableFuture createAccount(OfflinePlayer player) { return createAccount(player, null); } @@ -175,7 +244,6 @@ default CompletableFuture createAccount(OfflinePlayer player) { * @param world the world in which the player's account will be created * @return a CompletableFuture that will complete with the created account */ - @Contract("_, _ -> new") default CompletableFuture createAccount(OfflinePlayer player, @Nullable World world) { return createAccount(player.getUniqueId(), world); } @@ -188,7 +256,6 @@ default CompletableFuture createAccount(OfflinePlayer player, @Nullable * @param uuid the uuid of the account to be created * @return a CompletableFuture that will complete with the created account */ - @Contract("_ -> new") default CompletableFuture createAccount(UUID uuid) { return createAccount(uuid, null); } @@ -202,7 +269,6 @@ default CompletableFuture createAccount(UUID uuid) { * @param world the world in which the account will be created * @return a CompletableFuture that will complete with the created account */ - @Contract("_, _ -> new") CompletableFuture createAccount(UUID uuid, @Nullable World world); /** @@ -304,5 +370,7 @@ default CompletableFuture deleteAccount(UUID uuid) { * @since 3.0.0 */ @Contract(pure = true) - boolean hasMultiWorldSupport(); + default boolean hasMultiWorldSupport() { + return false; + } } diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java index 7239c100..74c374aa 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/Bank.java @@ -136,7 +136,9 @@ default boolean canDeposit(OfflinePlayer player, Number amount, Currency currenc * @return {@code true} if the player can deposit the specified amount, otherwise {@code false} * @since 3.0.0 */ - boolean canDeposit(UUID uuid, Number amount, Currency currency); + default boolean canDeposit(UUID uuid, Number amount, Currency currency) { + return getOwner().equals(uuid) || isMember(uuid); + } /** * Checks whether the specified player can withdraw the specified amount in the given currency. @@ -164,5 +166,7 @@ default boolean canWithdraw(OfflinePlayer player, Number amount, Currency curren * @return {@code true} if the player can withdraw the specified amount, otherwise {@code false} * @since 3.0.0 */ - boolean canWithdraw(UUID uuid, Number amount, Currency currency); + default boolean canWithdraw(UUID uuid, Number amount, Currency currency) { + return getOwner().equals(uuid); + } } diff --git a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java index 37194c6e..ca212cea 100644 --- a/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java +++ b/src/main/java/net/thenextlvl/service/api/economy/bank/BankController.java @@ -2,6 +2,7 @@ import net.thenextlvl.service.api.Controller; import net.thenextlvl.service.api.economy.currency.CurrencyHolder; +import net.thenextlvl.service.api.economy.currency.SimpleCurrencyHolder; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jetbrains.annotations.Contract; @@ -27,7 +28,9 @@ public interface BankController extends Controller { * @return the {@code CurrencyHolder} instance that manages the defined currencies for the controller */ @Contract(pure = true) - CurrencyHolder getCurrencyHolder(); + default CurrencyHolder getCurrencyHolder() { + return SimpleCurrencyHolder.INSTANCE; + } /** * Creates a bank for the specified player with the given name. diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrency.java b/src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrency.java new file mode 100644 index 00000000..1e165db2 --- /dev/null +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrency.java @@ -0,0 +1,129 @@ +package net.thenextlvl.service.api.economy.currency; + +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.function.Consumer; + +@NullMarked +@ApiStatus.Internal +public final class SimpleCurrency implements Currency { + public static final SimpleCurrency INSTANCE = new SimpleCurrency(); + + private SimpleCurrency() { + } + + @Override + public CurrencyHolder getHolder() { + return SimpleCurrencyHolder.INSTANCE; + } + + @Override + public String getName() { + return "default"; + } + + @Override + public Optional getDisplayNameSingular(Locale locale) { + return Optional.empty(); + } + + @Override + public Optional getDisplayNamePlural(Locale locale) { + return Optional.empty(); + } + + @Override + public Component getSymbol() { + return Component.empty(); + } + + @Override + public Component format(Number amount, Locale locale) { + return Component.text(String.format(locale, "%,.2f", amount.doubleValue())); + } + + @Override + public int getFractionalDigits() { + return 2; + } + + @Override + public boolean editCurrency(Consumer consumer) throws IllegalArgumentException { + return false; + } + + @Override + public Builder toBuilder() { + return new SimpleCurrency.Builder(); + } + + public static final class Builder implements Currency.Builder { + @Override + public Currency.Builder name(String name) { + return this; + } + + @Override + public String name() { + return ""; + } + + @Override + public @Unmodifiable Map displayNamesSingular() { + return Map.of(); + } + + @Override + public Currency.Builder displayNameSingular(Locale locale, @Nullable Component name) { + return this; + } + + @Override + public Optional displayNameSingular(Locale locale) { + return Optional.empty(); + } + + @Override + public @Unmodifiable Map displayNamesPlural() { + return Map.of(); + } + + @Override + public Currency.Builder displayNamePlural(Locale locale, @Nullable Component name) { + return this; + } + + @Override + public Optional displayNamePlural(Locale locale) { + return Optional.empty(); + } + + @Override + public Currency.Builder symbol(@Nullable Component symbol) { + return this; + } + + @Override + public Optional symbol() { + return Optional.empty(); + } + + @Override + public Currency.Builder fractionalDigits(@Nullable Integer fractionalDigits) throws IllegalArgumentException { + return this; + } + + @Override + public OptionalInt fractionalDigits() { + return OptionalInt.empty(); + } + } +} diff --git a/src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrencyHolder.java b/src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrencyHolder.java new file mode 100644 index 00000000..4ec18195 --- /dev/null +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/SimpleCurrencyHolder.java @@ -0,0 +1,18 @@ +package net.thenextlvl.service.api.economy.currency; + +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@ApiStatus.Internal +public final class SimpleCurrencyHolder implements CurrencyHolder { + public static final SimpleCurrencyHolder INSTANCE = new SimpleCurrencyHolder(); + + private SimpleCurrencyHolder() { + } + + @Override + public Currency getDefaultCurrency() { + return SimpleCurrency.INSTANCE; + } +}