diff --git a/build.gradle.kts b/build.gradle.kts index 84a57ef5..b0deb4ec 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "net.thenextlvl.services" -version = "2.3.1" +version = "3.0.0-pre7" java { toolchain.languageVersion = JavaLanguageVersion.of(21) diff --git a/plugin/src/main/java/net/thenextlvl/service/ServicePlugin.java b/plugin/src/main/java/net/thenextlvl/service/ServicePlugin.java index e74fba5e..c3ea8d85 100644 --- a/plugin/src/main/java/net/thenextlvl/service/ServicePlugin.java +++ b/plugin/src/main/java/net/thenextlvl/service/ServicePlugin.java @@ -214,7 +214,7 @@ private void loadServiceEconomyWrapper() { services.register(EconomyController.class, wrapper, economy.getPlugin(), economy.getPriority()); if (!economy.getProvider().hasBankSupport()) return; - var banks = new BankServiceWrapper(economy.getProvider(), economy.getPlugin(), this); + var banks = new BankServiceWrapper(wrapper.getCurrencyHolder(), economy.getProvider(), economy.getPlugin(), this); services.register(BankController.class, banks, economy.getPlugin(), economy.getPriority()); }); } 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 9acd142f..d2de411b 100644 --- a/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java +++ b/plugin/src/main/java/net/thenextlvl/service/command/ServiceConvertCommand.java @@ -48,6 +48,12 @@ LiteralArgumentBuilder create() { .then(Commands.literal("permissions").then(permissions())); } + // todo: clean this whole mess up + // create a proper conversion api + // compare source and target and warn about potential data loss + // implement proper error handling + // add progress tracking + private ArgumentBuilder banks() { return Commands.argument("source", new ControllerArgumentType<>(plugin, BankController.class, (c, e) -> true)) .then(Commands.argument("target", new ControllerArgumentType<>(plugin, BankController.class, (context, controller) -> @@ -128,13 +134,17 @@ private int convertPermissions(CommandContext context) { private 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 -> { - 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); + // }))); } } @@ -185,14 +195,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()))); } } 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/placeholder/economy/ServiceBankPlaceholderStore.java b/plugin/src/main/java/net/thenextlvl/service/placeholder/economy/ServiceBankPlaceholderStore.java index 9b9060f5..7700a772 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 @@ -17,6 +19,8 @@ public ServiceBankPlaceholderStore(ServicePlugin plugin) { @Override protected void registerResolvers(BankController provider) { + // todo: currency based placeholders + // %serviceio_bank% registerResolver("bank", (player, matcher) -> { return provider.getBank(player).map(Bank::getName).orElse(""); @@ -24,12 +28,17 @@ protected void registerResolvers(BankController provider) { // %serviceio_bank_balance% registerResolver("bank_balance", (player, matcher) -> { - return provider.getBank(player).map(Bank::getBalance).orElse(BigDecimal.ZERO).toPlainString(); + return provider.getBank(player) + .map(bank -> bank.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) + .orElse(BigDecimal.ZERO).toPlainString(); }); // %serviceio_bank_balance_formatted% registerResolver("bank_balance_formatted", (player, matcher) -> { - return provider.format(provider.getBank(player).map(Bank::getBalance).orElse(BigDecimal.ZERO)); + 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); }); // %serviceio_bank_% @@ -43,14 +52,20 @@ protected void registerResolvers(BankController provider) { registerResolver("bank_%s_balance", (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.getCurrencyHolder().getDefaultCurrency())) + .orElse(BigDecimal.ZERO) + .toPlainString(); }); - + // %serviceio_bank__balance_formatted% registerResolver("bank_%s_balance_formatted", (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.getCurrencyHolder().getDefaultCurrency().format(provider.getBank(player, world) + .map(bank -> bank.getBalance(provider.getCurrencyHolder().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 1aacfd4e..57c7b250 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(EconomyController provider) { // %serviceio_balance% registerResolver("balance", (player, matcher) -> { - return provider.getAccount(player).map(Account::getBalance).orElse(BigDecimal.ZERO).toPlainString(); + return provider.getAccount(player) + .map(account -> account.getBalance(provider.getCurrencyHolder().getDefaultCurrency())) + .orElse(BigDecimal.ZERO) + .toPlainString(); }); // %serviceio_balance_% registerResolver("balance_%s", (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.getCurrencyHolder().getDefaultCurrency())) + .orElse(BigDecimal.ZERO) + .toPlainString(); }); // %serviceio_balance_formatted% registerResolver("balance_formatted", (player, matcher) -> { - return provider.format(provider.getAccount(player).map(Account::getBalance).orElse(BigDecimal.ZERO)); + 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); }); // %serviceio_balance_formatted% registerResolver("balance_formatted_%s", (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.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/VaultEconomyServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java index 76047cde..6b1a0522 100644 --- a/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/VaultEconomyServiceWrapper.java @@ -1,11 +1,13 @@ 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; import net.thenextlvl.service.api.economy.EconomyController; 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 org.bukkit.OfflinePlayer; import org.bukkit.plugin.Plugin; import org.jspecify.annotations.NonNull; @@ -14,7 +16,6 @@ import java.util.List; import java.util.Locale; import java.util.Optional; -import java.util.concurrent.ExecutionException; import static net.milkbowl.vault.economy.EconomyResponse.ResponseType.FAILURE; import static net.milkbowl.vault.economy.EconomyResponse.ResponseType.SUCCESS; @@ -29,6 +30,10 @@ public VaultEconomyServiceWrapper(@NonNull EconomyController economyController, this.economyController = economyController; this.plugin = plugin; } + + private CurrencyHolder currencyHolder() { + return economyController.getCurrencyHolder(); + } @Override public boolean isEnabled() { @@ -52,22 +57,25 @@ public boolean hasBankSupport() { @Override public int fractionalDigits() { - return economyController.fractionalDigits(); + return currencyHolder().getDefaultCurrency().getFractionalDigits(); } @Override public String format(double amount) { - return economyController.format(amount); + var format = currencyHolder().getDefaultCurrency().format(amount, Locale.US); + return PlainTextComponentSerializer.plainText().serialize(format); } @Override public String currencyNamePlural() { - return economyController.getCurrencyNamePlural(Locale.US); + return currencyHolder().getDefaultCurrency().getDisplayNamePlural(Locale.US) + .map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } @Override public String currencyNameSingular() { - return economyController.getCurrencyNameSingular(Locale.US); + return currencyHolder().getDefaultCurrency().getDisplayNameSingular(Locale.US) + .map(PlainTextComponentSerializer.plainText()::serialize).orElse(""); } @Override @@ -110,7 +118,7 @@ public double getBalance(String playerName, String worldName) { @Override public double getBalance(OfflinePlayer player, String worldName) { return getAccount(player, worldName) - .map(Account::getBalance) + .map(account -> account.getBalance(currencyHolder().getDefaultCurrency())) .map(Number::doubleValue) .orElse(0.0); } @@ -154,8 +162,8 @@ public EconomyResponse withdrawPlayer(String playerName, String worldName, doubl @Override public EconomyResponse withdrawPlayer(OfflinePlayer player, String worldName, double amount) { return getAccount(player, worldName).map(account -> { - var balance = account.getBalance(); - var withdraw = account.withdraw(amount); + var balance = account.getBalance(currencyHolder().getDefaultCurrency()); + var withdraw = account.withdraw(amount, currencyHolder().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 +188,8 @@ public EconomyResponse depositPlayer(String name, String worldName, double amoun @Override public EconomyResponse depositPlayer(OfflinePlayer player, String worldName, double amount) { return getAccount(player, worldName).map(account -> { - var balance = account.getBalance(); - var deposit = account.deposit(amount); + var balance = account.getBalance(currencyHolder().getDefaultCurrency()); + var deposit = account.deposit(amount, currencyHolder().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)); @@ -209,48 +217,37 @@ public EconomyResponse deleteBank(String name) { @Override public EconomyResponse bankBalance(String name) { - try { - var bank = bankController().tryGetBank(name).get(); - return new EconomyResponse(0, bank.getBalance().doubleValue(), SUCCESS, null); - } catch (InterruptedException | ExecutionException e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + return bankController().tryGetBank(name).join().map(bank -> { + var balance = bank.getBalance(currencyHolder().getDefaultCurrency()); + return new EconomyResponse(0, balance.doubleValue(), SUCCESS, null); + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, null)); } @Override public EconomyResponse bankHas(String name, double amount) { - try { - var bank = bankController().tryGetBank(name).get(); - var balance = bank.getBalance().doubleValue(); + return bankController().tryGetBank(name).join().map(bank -> { + var balance = bank.getBalance(currencyHolder().getDefaultCurrency()).doubleValue(); var response = balance >= amount ? SUCCESS : FAILURE; return new EconomyResponse(amount, balance, response, null); - } catch (InterruptedException | ExecutionException e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, null)); } @Override public EconomyResponse bankWithdraw(String name, double amount) { - try { - var bank = bankController().tryGetBank(name).get(); - var balance = bank.withdraw(amount).doubleValue(); + return bankController().tryGetBank(name).join().map(bank -> { + var balance = bank.withdraw(amount, currencyHolder().getDefaultCurrency()).doubleValue(); var response = balance >= amount ? SUCCESS : FAILURE; return new EconomyResponse(amount, balance, response, null); - } catch (InterruptedException | ExecutionException e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, null)); } @Override public EconomyResponse bankDeposit(String name, double amount) { - try { - var bank = bankController().tryGetBank(name).get(); - var balance = bank.deposit(amount).doubleValue(); + return bankController().tryGetBank(name).join().map(bank -> { + var balance = bank.deposit(amount, currencyHolder().getDefaultCurrency()).doubleValue(); var response = balance >= amount ? SUCCESS : FAILURE; return new EconomyResponse(amount, balance, response, null); - } catch (InterruptedException | ExecutionException e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, null)); } @Override @@ -261,13 +258,11 @@ public EconomyResponse isBankOwner(String name, String playerName) { @Override public EconomyResponse isBankOwner(String name, OfflinePlayer player) { - try { - var bank = bankController().tryGetBank(name).get(); + return bankController().tryGetBank(name).join().map(bank -> { var response = player != null && bank.getOwner().equals(player.getUniqueId()) ? SUCCESS : FAILURE; - return new EconomyResponse(0, bank.getBalance().doubleValue(), response, null); - } catch (InterruptedException | ExecutionException e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + var balance = bank.getBalance(currencyHolder().getDefaultCurrency()); + return new EconomyResponse(0, balance.doubleValue(), response, null); + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, null)); } @Override @@ -278,13 +273,11 @@ public EconomyResponse isBankMember(String name, String playerName) { @Override public EconomyResponse isBankMember(String name, OfflinePlayer player) { - try { - var bank = bankController().tryGetBank(name).get(); + return bankController().tryGetBank(name).join().map(bank -> { var response = player != null && bank.isMember(player.getUniqueId()) ? SUCCESS : FAILURE; - return new EconomyResponse(0, bank.getBalance().doubleValue(), response, null); - } catch (InterruptedException | ExecutionException e) { - return new EconomyResponse(0, 0, FAILURE, e.getMessage()); - } + var balance = bank.getBalance(currencyHolder().getDefaultCurrency()); + return new EconomyResponse(0, balance.doubleValue(), response, null); + }).orElseGet(() -> new EconomyResponse(0, 0, FAILURE, null)); } @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 75baabf3..fec5e195 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,12 +5,14 @@ import net.thenextlvl.service.ServicePlugin; 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 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.Optional; import java.util.Set; @@ -20,69 +22,46 @@ @NullMarked public class BankServiceWrapper implements BankController { + private final CurrencyHolder holder; private final Economy economy; private final Plugin provider; private final ServicePlugin plugin; - public BankServiceWrapper(Economy economy, Plugin provider, ServicePlugin plugin) { + public BankServiceWrapper(CurrencyHolder holder, Economy economy, Plugin provider, ServicePlugin plugin) { + this.holder = holder; this.economy = economy; this.plugin = plugin; this.provider = provider; } @Override - public String format(Number amount) { - return economy.format(amount.doubleValue()); + public CurrencyHolder getCurrencyHolder() { + return holder; } @Override - public int fractionalDigits() { - return economy.fractionalDigits(); - } - - @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(plugin.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(plugin.getServer().getOfflinePlayer(uuid), name, world); } @Override - public CompletableFuture loadBank(String name) { - return CompletableFuture.completedFuture(getBank(name).orElse(null)); - } - - @Override - public CompletableFuture loadBank(UUID uuid) { - return CompletableFuture.completedFuture(getBank(uuid).orElse(null)); - } - - @Override - public CompletableFuture loadBank(UUID uuid, World world) { - return CompletableFuture.completedFuture(getBank(uuid, world).orElse(null)); + public CompletableFuture> loadBank(String name) { + return CompletableFuture.completedFuture(getBank(name)); } @Override - public CompletableFuture<@Unmodifiable Set> loadBanks() { - return CompletableFuture.completedFuture(getBanks()); + public CompletableFuture> loadBank(UUID uuid, @Nullable World world) { + return CompletableFuture.completedFuture(getBank(uuid, world)); } @Override - public CompletableFuture<@Unmodifiable Set> loadBanks(World world) { + public CompletableFuture<@Unmodifiable Set> loadBanks(@Nullable World world) { return CompletableFuture.completedFuture(getBanks(world)); } @@ -93,40 +72,48 @@ 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() + 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()); } @Override - public @Unmodifiable Set getBanks(World world) { - return getBanks(); + public Optional getBank(String name) { + if (!economy.getBanks().contains(name)) return Optional.empty(); + return Optional.of(new WrappedBank(name, null, economy, plugin)); } @Override - public Optional getBank(String name) { - return Optional.of(new WrappedBank(name, null, economy, plugin)); + 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 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 Optional getBank(UUID uuid) { - return Optional.empty(); + public boolean hasBank(UUID uuid, @Nullable World world) { + return hasBank(plugin.getServer().getOfflinePlayer(uuid), world); } @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/ChatServiceWrapper.java b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/ChatServiceWrapper.java index 9c8d8dbf..f0a18bab 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; @@ -27,42 +28,22 @@ public ChatServiceWrapper(Chat chat, Plugin provider, ServicePlugin plugin) { } @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(plugin.getServer().getOfflinePlayer(uuid)); - } - - @Override - public CompletableFuture loadProfile(UUID uuid, World world) { + public CompletableFuture loadProfile(UUID uuid, @Nullable World world) { return loadProfile(plugin.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(plugin.getServer().getOfflinePlayer(uuid)); - } - - @Override - public Optional getProfile(UUID uuid, World world) { + public Optional getProfile(UUID uuid, @Nullable World world) { return getProfile(plugin.getServer().getOfflinePlayer(uuid), world); } 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 db5b01e6..ba071035 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,15 +4,18 @@ import net.thenextlvl.service.ServicePlugin; 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.service.model.WrappedAccount; +import net.thenextlvl.service.wrapper.service.model.WrappedCurrency; 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.Locale; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -21,126 +24,80 @@ @NullMarked public class EconomyServiceWrapper implements EconomyController { + private final CurrencyHolder holder; private final Economy economy; private final Plugin provider; private final ServicePlugin plugin; public EconomyServiceWrapper(Economy economy, Plugin provider, ServicePlugin plugin) { + this.holder = new WrappedCurrencyHolder(economy); this.economy = economy; this.plugin = plugin; this.provider = provider; } @Override - public String format(Number amount) { - return economy.format(amount.doubleValue()); + public CurrencyHolder getCurrencyHolder() { + return holder; } @Override - public String getCurrencyNamePlural(Locale locale) { - return economy.currencyNamePlural(); + public CompletableFuture<@Unmodifiable Set> loadAccounts(@Nullable World world) { + return CompletableFuture.completedFuture(getAccounts(world)); } @Override - public String getCurrencyNameSingular(Locale locale) { - return economy.currencyNameSingular(); - } - - @Override - public String getCurrencySymbol() { - return ""; - } - - @Override - public CompletableFuture<@Unmodifiable Set> loadAccounts() { - return CompletableFuture.completedFuture(getAccounts()); - } - - @Override - public @Unmodifiable Set getAccounts() { + public @Unmodifiable Set getAccounts(@Nullable World world) { return Arrays.stream(plugin.getServer().getOfflinePlayers()) - .filter(economy::hasAccount) - .map(player -> new WrappedAccount(null, economy, player)) + .filter(player -> economy.hasAccount(player, world != null ? world.getName() : null)) + .map(player -> new WrappedAccount(world, 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)); - } - - @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(world, economy, player)); } @Override - public Optional getAccount(UUID uuid) { - return getAccount(plugin.getServer().getOfflinePlayer(uuid)); - } - - @Override - public Optional getAccount(UUID uuid, World world) { + public Optional getAccount(UUID uuid, @Nullable World world) { return getAccount(plugin.getServer().getOfflinePlayer(uuid), world); } @Override - public CompletableFuture createAccount(OfflinePlayer player) { - return CompletableFuture.completedFuture(economy.createPlayerAccount(player)) - .thenApply(account -> getAccount(player).orElseThrow()); - } - - @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(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(UUID uuid) { - return createAccount(plugin.getServer().getOfflinePlayer(uuid)); - } - - @Override - public CompletableFuture createAccount(UUID uuid, World world) { + public CompletableFuture createAccount(UUID uuid, @Nullable World world) { return createAccount(plugin.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(plugin.getServer().getOfflinePlayer(uuid)); - } - - @Override - public CompletableFuture> loadAccount(UUID uuid, World world) { + public CompletableFuture> loadAccount(UUID uuid, @Nullable World world) { return loadAccount(plugin.getServer().getOfflinePlayer(uuid), world); } @Override - public CompletableFuture deleteAccount(UUID uuid) { + public CompletableFuture deleteAccount(UUID uuid, @Nullable World world) { return CompletableFuture.completedFuture(false); } @Override - public CompletableFuture deleteAccount(UUID uuid, World world) { - return CompletableFuture.completedFuture(false); - } - - @Override - public int fractionalDigits() { - return economy.fractionalDigits(); + public boolean hasMultiWorldSupport() { + return false; } @Override @@ -152,4 +109,17 @@ public Plugin getPlugin() { public String getName() { return economy.getName(); } + + private static class WrappedCurrencyHolder implements CurrencyHolder { + private final Currency currency; + + private WrappedCurrencyHolder(Economy economy) { + this.currency = new WrappedCurrency(this, economy); + } + + @Override + public Currency getDefaultCurrency() { + return currency; + } + } } 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 e96f1fc6..5b19dbbc 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; @@ -27,42 +28,22 @@ public PermissionServiceWrapper(Permission permission, Plugin provider, ServiceP } @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(plugin.getServer().getOfflinePlayer(uuid)); - } - - @Override - public CompletableFuture loadPermissionHolder(UUID uuid, World world) { + public CompletableFuture loadPermissionHolder(UUID uuid, @Nullable World world) { return loadPermissionHolder(plugin.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(plugin.getServer().getOfflinePlayer(uuid)); - } - - @Override - public Optional getPermissionHolder(UUID uuid, World world) { + public Optional getPermissionHolder(UUID uuid, @Nullable World world) { return getPermissionHolder(plugin.getServer().getOfflinePlayer(uuid), world); } 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..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 @@ -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 org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jspecify.annotations.NullMarked; @@ -24,19 +25,19 @@ public WrappedAccount(@Nullable World world, Economy economy, OfflinePlayer hold } @Override - public BigDecimal deposit(Number amount) { + 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); } @@ -52,9 +53,15 @@ 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 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); + 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 92953bc0..218b2934 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 org.bukkit.OfflinePlayer; import org.bukkit.World; import org.jetbrains.annotations.Unmodifiable; @@ -31,17 +32,17 @@ public WrappedBank(String name, @Nullable World world, Economy economy, ServiceP } @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,10 +61,17 @@ 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 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; } @Override @@ -98,4 +106,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/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 new file mode 100644 index 00000000..6bb53642 --- /dev/null +++ b/plugin/src/main/java/net/thenextlvl/service/wrapper/service/model/WrappedCurrency.java @@ -0,0 +1,133 @@ +package net.thenextlvl.service.wrapper.service.model; + +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; + +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.function.Consumer; + +@NullMarked +public class WrappedCurrency implements Currency { + private final CurrencyHolder holder; + private final Economy economy; + + public WrappedCurrency(CurrencyHolder holder, Economy economy) { + this.economy = economy; + this.holder = holder; + } + + @Override + public CurrencyHolder getHolder() { + return holder; + } + + @Override + public String getName() { + return economy.getName(); + } + + @Override + public Optional getDisplayNameSingular(Locale locale) { + return Optional.ofNullable(economy.currencyNameSingular()).map(Component::text); + } + + @Override + public Optional getDisplayNamePlural(Locale locale) { + return Optional.ofNullable(economy.currencyNamePlural()).map(Component::text); + } + + @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(); + } + + @Override + 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/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..d7696c0e 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 { @@ -154,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); } 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..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; @@ -11,6 +12,8 @@ /** * The ChatController interface provides methods to retrieve a chat profile of a player. + * + * @since 1.0.0 */ @NullMarked public interface ChatController extends Controller { @@ -21,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); } /** @@ -31,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); } @@ -41,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. @@ -50,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. @@ -59,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); } /** @@ -71,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); } /** @@ -84,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); } /** @@ -96,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)); @@ -109,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); } /** @@ -119,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); } @@ -129,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. @@ -138,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/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 427d8e9b..656dde1c 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 org.bukkit.World; import org.jspecify.annotations.NullMarked; @@ -9,62 +10,94 @@ /** * Account is an interface representing a financial account. + * + * @since 1.0.0 */ @NullMarked -public interface Account extends Comparable { +public interface Account { /** - * Deposits the specified amount into the account balance. + * 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 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); + default BigDecimal deposit(Number amount, Currency currency) { + return setBalance(getBalance(currency).add(BigDecimal.valueOf(amount.doubleValue())), currency); + } /** - * Retrieves the balance of the account. + * Retrieves the balance of the account for the specified currency. * - * @return the balance of the account + * @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(); + BigDecimal getBalance(Currency currency); /** - * Withdraws the specified amount from the account balance. + * 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 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); + 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. + * 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(); /** - * Compares this account to the specified account based on their balance. + * Compares this account with another account based on their balances in the specified currency. * - * @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 + * @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 + * @since 3.0.0 */ - @Override - default int compareTo(Account account) { - return getBalance().compareTo(account.getBalance()); + default int compareTo(Account account, Currency currency) { + return getBalance(currency).compareTo(account.getBalance(currency)); } /** - * Sets the balance of the account to the specified value. + * 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); + + /** + * Checks if the account can hold the specified currency. * - * @param balance the new balance of the account + * @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 */ - void setBalance(Number balance); + boolean canHold(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 51891942..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,75 +1,73 @@ 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.Contract; import org.jetbrains.annotations.Unmodifiable; 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; /** - * 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. + * + * @since 1.0.0 */ @NullMarked public interface EconomyController extends Controller { /** - * Formats the specified amount as a string. + * Retrieves the {@code CurrencyHolder} associated with the economy controller. * - * @param amount the number amount to be formatted - * @return the formatted amount as a string + * @return the {@code CurrencyHolder} instance that manages the defined currencies for the controller */ - String format(Number amount); + @Contract(pure = true) + CurrencyHolder getCurrencyHolder(); /** - * Retrieves the number of fractional digits used for formatting currency amounts. + * Loads all accounts. * - * @return the number of fractional digits used for formatting currency amounts + * @return a {@link CompletableFuture} that completes with an unmodifiable {@link Set} of {@link Account} objects + * representing all available accounts + * @since 2.2.0 */ - int fractionalDigits(); - - /** - * 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 - */ - String getCurrencyNamePlural(Locale 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 - */ - String getCurrencyNameSingular(Locale locale); + default CompletableFuture<@Unmodifiable Set> loadAccounts() { + return loadAccounts(null); + } /** - * Retrieves the currency symbol associated with the economy controller. + * Loads all accounts associated with the specified world. * - * @return the currency symbol as a string + * @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 */ - String getCurrencySymbol(); + CompletableFuture<@Unmodifiable Set> loadAccounts(@Nullable World world); /** - * Loads all accounts asynchronously. + * Retrieves all the accounts that are currently loaded. * - * @return a {@link CompletableFuture} that, when completed, will provide a {@link Set} of {@link Account} objects representing - * all the accounts available. + * @return an unmodifiable set of accounts + * @since 2.2.0 */ - CompletableFuture<@Unmodifiable Set> loadAccounts(); + 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. @@ -78,7 +76,7 @@ public interface EconomyController extends Controller { * @return an optional containing the account, or empty */ default Optional getAccount(OfflinePlayer player) { - return getAccount(player.getUniqueId()); + return getAccount(player, null); } /** @@ -88,7 +86,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); } @@ -98,7 +96,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. @@ -107,7 +107,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. @@ -116,9 +116,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); } /** @@ -128,10 +126,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); } /** @@ -141,9 +137,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); } /** @@ -153,7 +147,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)); @@ -161,42 +155,55 @@ default CompletableFuture> tryGetAccount(UUID uuid, World worl /** * 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) { - return createAccount(player.getUniqueId()); + return createAccount(player, null); } /** * 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 * @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); } /** * 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 */ - CompletableFuture createAccount(UUID uuid); + @Contract("_ -> new") + default CompletableFuture createAccount(UUID uuid) { + return createAccount(uuid, null); + } /** * 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 * @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. @@ -205,7 +212,7 @@ default CompletableFuture createAccount(OfflinePlayer player, World wor * @return a CompletableFuture that will complete with the retrieved account */ default CompletableFuture> loadAccount(OfflinePlayer player) { - return loadAccount(player.getUniqueId()); + return loadAccount(player, null); } /** @@ -215,7 +222,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); } @@ -225,7 +232,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. @@ -234,55 +243,66 @@ 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. * * @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 account.getWorld() - .map(world -> deleteAccount(account.getOwner(), world)) - .orElseGet(() -> deleteAccount(account.getOwner())); + 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.getUniqueId()); + 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, World world) { + 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 */ - CompletableFuture deleteAccount(UUID uuid); + 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); + + /** + * 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. + * @since 3.0.0 */ - CompletableFuture deleteAccount(UUID uuid, World world); + @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 023d72e4..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 @@ -1,7 +1,9 @@ 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; import org.jspecify.annotations.NullMarked; @@ -12,6 +14,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 { @@ -19,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(); @@ -28,13 +33,14 @@ public interface Bank extends Account { * * @return the name of the bank. */ + @Contract(pure = true) String getName(); /** * 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()); @@ -43,62 +49,120 @@ 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); + + /** + * 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} + * @since 3.0.0 + */ + 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} + * @since 3.0.0 + */ + 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} + * @since 3.0.0 + */ + 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} + * @since 3.0.0 + */ + boolean canWithdraw(UUID uuid, Number amount, Currency currency); } 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..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 @@ -1,32 +1,33 @@ 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.Contract; import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.Set; 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 { /** - * Formats the specified amount as a string. + * Retrieves the {@code CurrencyHolder} associated with the economy controller. * - * @param amount the number amount to be formatted - * @return the formatted amount as a string + * @return the {@code CurrencyHolder} instance that manages the defined currencies for the controller */ - 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(); + @Contract(pure = true) + CurrencyHolder getCurrencyHolder(); /** * Creates a bank for the specified player with the given name. @@ -37,8 +38,9 @@ public interface BankController extends Controller { * @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); + return createBank(player, name, null); } /** @@ -51,7 +53,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); } @@ -64,7 +67,10 @@ default CompletableFuture createBank(OfflinePlayer player, String name, Wo * @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. @@ -76,7 +82,8 @@ default CompletableFuture createBank(OfflinePlayer player, String name, Wo * @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. @@ -84,8 +91,8 @@ default CompletableFuture createBank(OfflinePlayer player, String name, Wo * @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); } /** @@ -95,7 +102,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); } @@ -105,7 +112,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. @@ -113,7 +120,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. @@ -122,14 +131,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. @@ -137,7 +148,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. @@ -146,10 +157,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); } /** @@ -159,10 +170,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); } /** @@ -173,10 +182,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); } /** @@ -186,10 +193,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); } /** @@ -200,10 +205,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); } /** @@ -213,9 +218,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)); } /** @@ -225,7 +228,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); } /** @@ -235,7 +238,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); } @@ -253,7 +256,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. @@ -262,15 +267,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}. @@ -279,7 +285,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. @@ -296,7 +302,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); } /** @@ -306,7 +312,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); } @@ -316,7 +322,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. @@ -325,5 +333,56 @@ 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); + + /** + * 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. + * + * @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 new file mode 100644 index 00000000..b06c84a7 --- /dev/null +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/Currency.java @@ -0,0 +1,252 @@ +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.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. + * + * @since 3.0.0 + */ +@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. + * + * @return the name of the currency as a string + */ + @Contract(pure = true) + 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 an {@code Optional} containing the singular display name as a {@code Component} for the audience's locale, or empty + */ + default Optional 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 an {@code Optional} containing the singular display name as a {@code Component} for the specified locale, or empty + */ + Optional 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 an {@code Optional} containing the plural display name as a {@code Component} for the audience's locale, or empty + */ + default Optional 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 an {@code Optional} containing the plural display name as a {@code Component} for the specified locale, or empty + */ + Optional 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) + */ + 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(); + + /** + * 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 + * @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) 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 + * 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. + * + * @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. + * + * @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 + * @return the builder instance for chaining + */ + @Contract(value = "_, _ -> this") + Builder displayNameSingular(Locale locale, @Nullable Component name); + + /** + * 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 + */ + @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. + * + * @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 + * @return the builder instance for chaining + */ + @Contract(value = "_, _ -> this") + Builder displayNamePlural(Locale locale, @Nullable Component name); + + /** + * 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 + */ + @Contract(value = "_ -> new") + Optional displayNamePlural(Locale locale); + + /** + * Sets the currency symbol as a {@code Component}. + * + * @param symbol the symbol component to represent the currency, or {@code null} to remove + * @return the builder instance for chaining + */ + @Contract(value = "_ -> this") + Builder symbol(@Nullable Component symbol); + + /** + * Retrieves the currency symbol set on the {@code Builder}. + * + * @return an {@code Optional} containing the symbol as a {@code Component}, or empty + */ + @Contract(value = "-> new") + 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), or {@code null} to remove + * @return the builder instance for chaining + * @throws IllegalArgumentException if {@code fractionalDigits} is negative + */ + @Contract(value = "_ -> this") + Builder fractionalDigits(@Nullable Integer 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 + */ + @Contract(value = "-> new") + OptionalInt fractionalDigits(); + } +} 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..21d6b0ca --- /dev/null +++ b/src/main/java/net/thenextlvl/service/api/economy/currency/CurrencyHolder.java @@ -0,0 +1,130 @@ +package net.thenextlvl.service.api.economy.currency; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; + +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. + * + * @since 3.0.0 + */ +public interface CurrencyHolder { + /** + * 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} + */ + 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}. + * + * @param name the name of the new currency + * @param builder a consumer to configure the {@link Currency.Builder} for 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 + */ + @Contract("_, _ -> new") + default Currency createCurrency(String name, Consumer builder) throws IllegalArgumentException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * 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 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 Currency createCurrency(Currency.Builder builder) { + 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); + }); + } + + /** + * 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. + * + * @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 + */ + @Contract(pure = true) + Currency getDefaultCurrency(); + + /** + * 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. + * @see #createCurrency(String, Consumer) + * @see #deleteCurrency(String) + * @see #getCurrencies() + * @see #getCurrency(String) + * @see #hasCurrency(String) + */ + @Contract(pure = true) + default boolean hasMultiCurrencySupport() { + return false; + } +} diff --git a/src/main/java/net/thenextlvl/service/api/group/Group.java b/src/main/java/net/thenextlvl/service/api/group/Group.java index 1718f2a0..46f24c3c 100644 --- a/src/main/java/net/thenextlvl/service/api/group/Group.java +++ b/src/main/java/net/thenextlvl/service/api/group/Group.java @@ -12,6 +12,8 @@ * The Group interface represents a group entity that holds permissions and display attributes such as * a display name, prefix, and suffix. It provides methods to manage these attributes as well as the * group weight and associated world. + * + * @since 1.0.0 */ @NullMarked public interface Group extends PermissionHolder, Display { 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 d36a26c2..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; @@ -15,6 +16,8 @@ * The GroupController interface provides methods for managing groups and group holders. * It allows creating, loading, deleting, and retrieving groups and group holders. * Operations can be performed asynchronously using CompletableFutures. + * + * @since 1.0.0 */ @NullMarked public interface GroupController extends Controller { @@ -24,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. @@ -33,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. @@ -41,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. @@ -50,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. @@ -59,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); } /** @@ -69,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); } @@ -79,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. @@ -88,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)); @@ -131,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. @@ -139,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. @@ -147,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. @@ -156,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. @@ -164,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. @@ -173,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. @@ -181,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. @@ -190,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. @@ -199,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); } /** @@ -209,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); } @@ -219,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. @@ -228,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. @@ -245,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/group/GroupHolder.java b/src/main/java/net/thenextlvl/service/api/group/GroupHolder.java index 1a97d29a..b3c9d1f0 100644 --- a/src/main/java/net/thenextlvl/service/api/group/GroupHolder.java +++ b/src/main/java/net/thenextlvl/service/api/group/GroupHolder.java @@ -10,6 +10,8 @@ * The {@code GroupHolder} interface represents an entity that holds groups. * It extends the {@link PermissionHolder} interface. * It provides methods to retrieve and manipulate groups for the holder. + * + * @since 1.0.0 */ @NullMarked public interface GroupHolder extends PermissionHolder { diff --git a/src/main/java/net/thenextlvl/service/api/hologram/Hologram.java b/src/main/java/net/thenextlvl/service/api/hologram/Hologram.java index 730d432c..5aef1ba8 100644 --- a/src/main/java/net/thenextlvl/service/api/hologram/Hologram.java +++ b/src/main/java/net/thenextlvl/service/api/hologram/Hologram.java @@ -16,6 +16,8 @@ * Represents a hologram object that can display multiple persistent and positional text or elements * in a virtual 3D space, providing interactivity functionality such as visibility and teleportation. * This interface incorporates persistence, viewability, and iterable capabilities. + * + * @since 2.2.0 */ @NullMarked public interface Hologram extends Persistable, Viewable, Iterable> { 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..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; @@ -13,6 +14,7 @@ * The PermissionController interface represents a controller for managing permissions for players. * * @see PermissionHolder + * @since 1.0.0 */ @NullMarked public interface PermissionController extends Controller { @@ -24,7 +26,7 @@ public interface PermissionController extends Controller { * @see PermissionHolder */ default CompletableFuture loadPermissionHolder(OfflinePlayer player) { - return loadPermissionHolder(player.getUniqueId()); + return loadPermissionHolder(player, null); } /** @@ -36,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); } @@ -47,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. @@ -57,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. @@ -67,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); } /** @@ -81,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); } /** @@ -95,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); } /** @@ -108,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)); @@ -122,7 +120,7 @@ default CompletableFuture tryGetPermissionHolder(UUID uuid, Wo * @see PermissionHolder */ default Optional getPermissionHolder(OfflinePlayer player) { - return getPermissionHolder(player.getUniqueId()); + return getPermissionHolder(player, null); } /** @@ -134,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); } @@ -145,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}. @@ -155,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); } 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 {