diff --git a/api/src/main/java/net/thenextlvl/hologram/action/ClickAction.java b/api/src/main/java/net/thenextlvl/hologram/action/ClickAction.java index 27b1bd8f..426872a0 100644 --- a/api/src/main/java/net/thenextlvl/hologram/action/ClickAction.java +++ b/api/src/main/java/net/thenextlvl/hologram/action/ClickAction.java @@ -127,6 +127,25 @@ public interface ClickAction extends Copyable> { @Contract(mutates = "this") boolean setPermission(@Nullable String permission); + /** + * Gets the currency name used for transactions of this click action. + * + * @return an {@code Optional} containing the name of the currency + * @since 1.2.0 + */ + @Contract(pure = true) + Optional getCurrency(); + + /** + * Sets the currency name used for transaction of this click action. + * + * @param currency the name of the new currency + * @return {@code true} if the currency was successfully set, {@code false} otherwise + * @since 1.2.0 + */ + @Contract(mutates = "this") + boolean setCurrency(@Nullable String currency); + /** * Gets the cost of this click action. * diff --git a/build.gradle.kts b/build.gradle.kts index 56cddca8..a83e912e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,6 +27,7 @@ configurations.compileClasspath { } repositories { + mavenLocal() mavenCentral() maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") maven("https://repo.thenextlvl.net/releases") @@ -40,7 +41,7 @@ dependencies { compileOnly("me.clip:placeholderapi:2.12.2") compileOnly("net.thenextlvl:vault-api:1.7.1") - compileOnly("net.thenextlvl:service-io:2.6.0") + compileOnly("net.thenextlvl:service-io:3.0.0-pre8") implementation("net.thenextlvl.version-checker:modrinth-paper:1.0.1") implementation("net.thenextlvl:i18n:1.2.0") @@ -151,19 +152,19 @@ paper { } serverDependencies { register("MiniPlaceholders") { - load = PaperPluginDescription.RelativeLoadOrder.BEFORE + load = PaperPluginDescription.RelativeLoadOrder.AFTER required = false } register("PlaceholderAPI") { - load = PaperPluginDescription.RelativeLoadOrder.BEFORE + load = PaperPluginDescription.RelativeLoadOrder.AFTER required = false } register("ServiceIO") { - load = PaperPluginDescription.RelativeLoadOrder.BEFORE + load = PaperPluginDescription.RelativeLoadOrder.AFTER required = false } register("Vault") { - load = PaperPluginDescription.RelativeLoadOrder.BEFORE + load = PaperPluginDescription.RelativeLoadOrder.AFTER required = false } } diff --git a/src/main/java/net/thenextlvl/hologram/action/SimpleClickAction.java b/src/main/java/net/thenextlvl/hologram/action/SimpleClickAction.java index fc2fb1e6..8f035b5c 100644 --- a/src/main/java/net/thenextlvl/hologram/action/SimpleClickAction.java +++ b/src/main/java/net/thenextlvl/hologram/action/SimpleClickAction.java @@ -25,9 +25,10 @@ final class SimpleClickAction implements ClickAction { private volatile EnumSet clickTypes; private volatile T input; + private volatile @Nullable String currency = null; + private volatile @Nullable String permission = null; private volatile @Range(from = 0, to = 100) int chance = 100; private volatile Duration cooldown = Duration.ZERO; - private volatile @Nullable String permission = null; private volatile double cost = 0; public SimpleClickAction(final HologramPlugin plugin, final ActionType actionType, final EnumSet clickTypes, final T input) { @@ -95,6 +96,18 @@ public boolean setPermission(@Nullable final String permission) { return true; } + @Override + public Optional getCurrency() { + return Optional.ofNullable(currency); + } + + @Override + public boolean setCurrency(@Nullable final String currency) { + if (Objects.equals(this.currency, currency)) return false; + this.currency = currency; + return true; + } + @Override public double getCost() { return cost; @@ -137,7 +150,7 @@ public boolean invoke(final HologramLine line, final Player player) { if (isOnCooldown(player)) return false; if (!getPermission().map(player::hasPermission).orElse(true)) return false; if (chance < 100 && ThreadLocalRandom.current().nextInt(100) > chance) return false; - if (cost > 0 && !plugin.economyProvider.withdraw(player, cost)) return false; + if (cost > 0 && !plugin.economyProvider.withdraw(player, currency, cost)) return false; actionType.action().invoke(line, player, input); if (cooldown.isPositive()) cooldowns.put(player.getUniqueId(), System.currentTimeMillis()); return true; diff --git a/src/main/java/net/thenextlvl/hologram/commands/action/ActionCostCommand.java b/src/main/java/net/thenextlvl/hologram/commands/action/ActionCostCommand.java index 21f00874..ef923bc2 100644 --- a/src/main/java/net/thenextlvl/hologram/commands/action/ActionCostCommand.java +++ b/src/main/java/net/thenextlvl/hologram/commands/action/ActionCostCommand.java @@ -37,14 +37,14 @@ static LiteralArgumentBuilder create( public int run(final CommandContext context, final Hologram hologram, final HologramLine line, final ClickAction action, final String actionName, final TagResolver... placeholders) { final var cost = tryGetArgument(context, "cost", double.class); final var success = cost.map(action::setCost).orElse(false); - final var message = success ? "hologram.action.cost.set" : cost.isEmpty() - ? "hologram.action.cost" : "nothing.changed"; + final var message = success ? "hologram.action.cost.set" + : cost.isEmpty() ? "hologram.action.cost" : "nothing.changed"; final var sender = context.getSource().getSender(); - final var formatted = plugin.economyProvider.format(sender, cost.orElse(action.getCost())); + final var formatted = plugin.economyProvider.format(sender, action.getCurrency().orElse(null), cost.orElse(action.getCost())); plugin.bundle().sendMessage(sender, message, TagResolver.resolver(placeholders), Placeholder.unparsed("action", actionName), - Placeholder.parsed("cost", formatted)); + Placeholder.component("cost", formatted)); return SINGLE_SUCCESS; } } diff --git a/src/main/java/net/thenextlvl/hologram/commands/action/ActionListCommand.java b/src/main/java/net/thenextlvl/hologram/commands/action/ActionListCommand.java index 6fa61b29..929768b9 100644 --- a/src/main/java/net/thenextlvl/hologram/commands/action/ActionListCommand.java +++ b/src/main/java/net/thenextlvl/hologram/commands/action/ActionListCommand.java @@ -134,8 +134,8 @@ private TagResolver actionResolvers(final Audience audience, final ClickAction getController() { return Optional.ofNullable(plugin.getServer().getServicesManager().load(EconomyController.class)); } + private Optional getCurrency(@Nullable final String name) { + return getController().map(controller -> getCurrency(controller, name)); + } + + private Currency getCurrency(final EconomyController controller, @Nullable final String name) { + final var currencyController = controller.getCurrencyController(); + if (name == null) return currencyController.getDefaultCurrency(); + return currencyController.getCurrency(name).orElseGet(currencyController::getDefaultCurrency); + } + @Override - public String format(final Locale locale, final double amount) { - return getController().map(controller -> controller.format(amount)) - .orElseGet(() -> EconomyProvider.super.format(locale, amount)); + public Component format(final Locale locale, @Nullable final String currency, final double amount) { + return getCurrency(currency).map(c -> c.format(amount, locale)) + .orElseGet(() -> Component.text(String.format(locale, "%.2f", amount))); } @Override - public boolean withdraw(final Player player, final double amount) { + public boolean withdraw(final Player player, @Nullable final String currency, final double amount) { return getController().flatMap(controller -> controller.getAccount(player).map(account -> { - return !account.getBalance().equals(account.withdraw(amount)); + return account.withdraw(amount, getCurrency(controller, currency)).successful(); })).orElse(false); } } diff --git a/src/main/java/net/thenextlvl/hologram/economy/VaultEconomyProvider.java b/src/main/java/net/thenextlvl/hologram/economy/VaultEconomyProvider.java index 7d0de6ab..0741284a 100644 --- a/src/main/java/net/thenextlvl/hologram/economy/VaultEconomyProvider.java +++ b/src/main/java/net/thenextlvl/hologram/economy/VaultEconomyProvider.java @@ -1,9 +1,11 @@ package net.thenextlvl.hologram.economy; +import net.kyori.adventure.text.Component; import net.milkbowl.vault.economy.Economy; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import java.util.Locale; import java.util.Optional; @@ -21,13 +23,13 @@ private Optional getEconomy() { } @Override - public String format(final Locale locale, final double amount) { - return getEconomy().map(economy -> economy.format(amount)) - .orElseGet(() -> EconomyProvider.super.format(locale, amount)); + public Component format(final Locale locale, @Nullable final String currency, final double amount) { + return Component.text(getEconomy().map(economy -> economy.format(amount)) + .orElseGet(() -> String.format(locale, "%.2f", amount))); } @Override - public boolean withdraw(final Player player, final double amount) { + public boolean withdraw(final Player player, @Nullable final String currency, final double amount) { return getEconomy().map(economy -> { return economy.withdrawPlayer(player, amount).transactionSuccess(); }).orElse(false); diff --git a/src/main/java/net/thenextlvl/hologram/listeners/PluginListener.java b/src/main/java/net/thenextlvl/hologram/listeners/PluginListener.java index e88cfed3..e40eacb6 100644 --- a/src/main/java/net/thenextlvl/hologram/listeners/PluginListener.java +++ b/src/main/java/net/thenextlvl/hologram/listeners/PluginListener.java @@ -5,11 +5,14 @@ import net.thenextlvl.hologram.economy.VaultEconomyProvider; import net.thenextlvl.hologram.locale.MiniPlaceholdersFormatter; import net.thenextlvl.hologram.locale.PlaceholderAPIFormatter; +import net.thenextlvl.hologram.service.ServiceHologramController; +import net.thenextlvl.service.hologram.HologramController; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.server.PluginEnableEvent; import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.ServicePriority; import org.jspecify.annotations.NullMarked; @NullMarked @@ -30,16 +33,23 @@ public void onPluginEnable(final PluginEnableEvent event) { plugin.miniFormatter = new MiniPlaceholdersFormatter(); plugin.getComponentLogger().info("MiniPlaceholders detected, using for placeholders"); } - + if (isPlugin(event.getPlugin(), "ServiceIO")) { + plugin.getServer().getServicesManager().register( + HologramController.class, + new ServiceHologramController(plugin), + plugin, + ServicePriority.Highest + ); + plugin.economyProvider = new ServiceEconomyProvider(event.getPlugin()); - plugin.getComponentLogger().info("ServiceIO detected, using for economy"); + plugin.getComponentLogger().info("ServiceIO detected, using for all services"); } else if (isPlugin(event.getPlugin(), "Vault")) { plugin.economyProvider = new VaultEconomyProvider(event.getPlugin()); plugin.getComponentLogger().info("Vault detected, using for economy"); } } - + private boolean isPlugin(final Plugin plugin, final String name) { return plugin.getName().equals(name) || plugin.getPluginMeta().getProvidedPlugins().contains(name); } diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceBlockHologramLine.java b/src/main/java/net/thenextlvl/hologram/service/ServiceBlockHologramLine.java new file mode 100644 index 00000000..48d18d66 --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceBlockHologramLine.java @@ -0,0 +1,22 @@ +package net.thenextlvl.hologram.service; + +import net.thenextlvl.hologram.line.BlockHologramLine; +import org.bukkit.block.data.BlockData; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public final class ServiceBlockHologramLine extends ServiceDisplayHologramLine implements net.thenextlvl.service.hologram.line.BlockHologramLine { + public ServiceBlockHologramLine(final ServiceHologram hologram, final BlockHologramLine line) { + super(hologram, line); + } + + @Override + public BlockData getBlock() { + return line.getBlock(); + } + + @Override + public boolean setBlock(final BlockData block) { + return line.setBlock(block); + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceDisplayHologramLine.java b/src/main/java/net/thenextlvl/hologram/service/ServiceDisplayHologramLine.java new file mode 100644 index 00000000..9aaa8fc5 --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceDisplayHologramLine.java @@ -0,0 +1,182 @@ +package net.thenextlvl.hologram.service; + +import net.kyori.adventure.text.format.TextColor; +import net.thenextlvl.hologram.line.DisplayHologramLine; +import net.thenextlvl.service.hologram.line.PagedHologramLine; +import org.bukkit.entity.Display; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.util.Transformation; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Optional; + +@NullMarked +abstract class ServiceDisplayHologramLine extends ServiceHologramLine implements net.thenextlvl.service.hologram.line.DisplayHologramLine { + protected ServiceDisplayHologramLine(final ServiceHologram hologram, final L line) { + super(hologram, line); + } + + @Override + public Transformation getTransformation() { + return line.getTransformation(); + } + + @Override + public boolean setTransformation(final Transformation transformation) { + return line.setTransformation(transformation); + } + + @Override + public boolean setTransformationMatrix(final Matrix4f transformationMatrix) { + return line.setTransformationMatrix(transformationMatrix); + } + + @Override + public int getInterpolationDuration() { + return line.getInterpolationDuration(); + } + + @Override + public boolean setInterpolationDuration(final int duration) { + return line.setInterpolationDuration(duration); + } + + @Override + public int getTeleportDuration() { + return line.getTeleportDuration(); + } + + @Override + public boolean setTeleportDuration(final int duration) { + return line.setTeleportDuration(duration); + } + + @Override + public float getViewRange() { + return line.getViewRange(); + } + + @Override + public boolean setViewRange(final float range) { + return line.setViewRange(range); + } + + @Override + public float getShadowRadius() { + return line.getShadowRadius(); + } + + @Override + public boolean setShadowRadius(final float radius) { + return line.setShadowRadius(radius); + } + + @Override + public float getShadowStrength() { + return line.getShadowStrength(); + } + + @Override + public boolean setShadowStrength(final float strength) { + return line.setShadowStrength(strength); + } + + @Override + public float getDisplayWidth() { + return line.getDisplayWidth(); + } + + @Override + public boolean setDisplayWidth(final float width) { + return line.setDisplayWidth(width); + } + + @Override + public float getDisplayHeight() { + return line.getDisplayHeight(); + } + + @Override + public boolean setDisplayHeight(final float height) { + return line.setDisplayHeight(height); + } + + @Override + public int getInterpolationDelay() { + return line.getInterpolationDelay(); + } + + @Override + public boolean setInterpolationDelay(final int ticks) { + return line.setInterpolationDelay(ticks); + } + + @Override + public Optional getBrightness() { + return line.getBrightness(); + } + + @Override + public boolean setBrightness(final Display.@Nullable Brightness brightness) { + return line.setBrightness(brightness); + } + + @Override + public Class getEntityClass() { + return line.getEntityClass(); + } + + @Override + public EntityType getEntityType() { + return line.getEntityType(); + } + + @Override + public boolean isGlowing() { + return line.isGlowing(); + } + + @Override + public boolean setGlowing(final boolean glowing) { + return line.setGlowing(glowing); + } + + @Override + public Optional getGlowColor() { + return line.getGlowColor(); + } + + @Override + public boolean setGlowColor(@Nullable final TextColor color) { + return line.setGlowColor(color); + } + + @Override + public Display.Billboard getBillboard() { + return line.getBillboard(); + } + + @Override + public boolean setBillboard(final Display.Billboard billboard) { + return line.setBillboard(billboard); + } + + @Override + public Optional getParentLine() { + return line.getParentLine().map(pagedLine -> new ServicePagedHologramLine(hologram, pagedLine)); + } + + @Override + public Vector3f getOffset() { + return line.getOffset(); + } + + @Override + public boolean setOffset(final Vector3f offset) { + return line.setOffset(offset); + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceEntityHologramLine.java b/src/main/java/net/thenextlvl/hologram/service/ServiceEntityHologramLine.java new file mode 100644 index 00000000..66910577 --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceEntityHologramLine.java @@ -0,0 +1,90 @@ +package net.thenextlvl.hologram.service; + +import net.kyori.adventure.text.format.TextColor; +import net.thenextlvl.hologram.line.EntityHologramLine; +import net.thenextlvl.service.hologram.line.PagedHologramLine; +import org.bukkit.entity.Display; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.joml.Vector3f; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Optional; + +@NullMarked +public final class ServiceEntityHologramLine extends ServiceHologramLine implements net.thenextlvl.service.hologram.line.EntityHologramLine { + public ServiceEntityHologramLine(final ServiceHologram hologram, final EntityHologramLine line) { + super(hologram, line); + } + + @Override + public boolean setEntityType(final EntityType entityType) { + return line.setEntityType(entityType); + } + + @Override + public double getScale() { + return line.getScale(); + } + + @Override + public boolean setScale(final double scale) { + return line.setScale(scale); + } + + @Override + public Class getEntityClass() { + return line.getEntityClass(); + } + + @Override + public EntityType getEntityType() { + return line.getEntityType(); + } + + @Override + public boolean isGlowing() { + return line.isGlowing(); + } + + @Override + public boolean setGlowing(final boolean glowing) { + return line.setGlowing(glowing); + } + + @Override + public Optional getGlowColor() { + return line.getGlowColor(); + } + + @Override + public boolean setGlowColor(@Nullable final TextColor color) { + return line.setGlowColor(color); + } + + @Override + public Display.Billboard getBillboard() { + return line.getBillboard(); + } + + @Override + public boolean setBillboard(final Display.Billboard billboard) { + return line.setBillboard(billboard); + } + + @Override + public Optional getParentLine() { + return line.getParentLine().map(line -> new ServicePagedHologramLine(hologram, line)); + } + + @Override + public Vector3f getOffset() { + return line.getOffset(); + } + + @Override + public boolean setOffset(final Vector3f offset) { + return line.setOffset(offset); + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceHologram.java b/src/main/java/net/thenextlvl/hologram/service/ServiceHologram.java new file mode 100644 index 00000000..81a64395 --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceHologram.java @@ -0,0 +1,288 @@ +package net.thenextlvl.hologram.service; + +import net.thenextlvl.hologram.Hologram; +import net.thenextlvl.service.capability.CapabilityException; +import net.thenextlvl.service.hologram.line.BlockHologramLine; +import net.thenextlvl.service.hologram.line.EntityHologramLine; +import net.thenextlvl.service.hologram.line.HologramLine; +import net.thenextlvl.service.hologram.line.ItemHologramLine; +import net.thenextlvl.service.hologram.line.PagedHologramLine; +import net.thenextlvl.service.hologram.line.TextHologramLine; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +@NullMarked +public record ServiceHologram(Hologram hologram) implements net.thenextlvl.service.hologram.Hologram { + @Override + public CompletableFuture teleportAsync(final Location location) { + return hologram.teleportAsync(location); + } + + @Override + public Stream getLines() { + return hologram.getLines().map(this::wrapLine); + } + + private HologramLine wrapLine(final net.thenextlvl.hologram.line.HologramLine line) { + return switch (line) { + case final net.thenextlvl.hologram.line.BlockHologramLine l -> new ServiceBlockHologramLine(this, l); + case final net.thenextlvl.hologram.line.ItemHologramLine l -> new ServiceItemHologramLine(this, l); + case final net.thenextlvl.hologram.line.TextHologramLine l -> new ServiceTextHologramLine(this, l); + case final net.thenextlvl.hologram.line.EntityHologramLine l -> new ServiceEntityHologramLine(this, l); + case final net.thenextlvl.hologram.line.PagedHologramLine l -> new ServicePagedHologramLine(this, l); + default -> throw new IllegalStateException("Unexpected value: " + line); + }; + } + + @Override + public Location getLocation() { + return hologram.getLocation(); + } + + @Override + public World getWorld() { + return hologram.getWorld(); + } + + @Override + public boolean removeLine(final int index) throws CapabilityException { + return hologram.removeLine(index); + } + + @Override + public boolean removeLines(final Collection lines) { + return hologram.removeLines(lines.stream() + .filter(ServiceHologramLine.class::isInstance) + .map(ServiceHologramLine.class::cast) + .map(serviceLine -> serviceLine.line) + .toList()); + } + + @Override + public boolean clearLines() { + return hologram.clearLines(); + } + + @Override + public boolean hasLine(final HologramLine line) { + return line instanceof final ServiceHologramLine serviceLine && hologram.hasLine(serviceLine.line); + } + + @Override + public boolean moveLine(final int from, final int to) { + return hologram.moveLine(from, to); + } + + @Override + public boolean swapLines(final int line1, final int line2) { + return hologram.swapLines(line1, line2); + } + + @Override + public EntityHologramLine addEntityLine(final EntityType entityType) throws IllegalArgumentException, CapabilityException { + return new ServiceEntityHologramLine(this, hologram.addEntityLine(entityType)); + } + + @Override + public EntityHologramLine addEntityLine(final int index, final EntityType entityType) throws IllegalArgumentException, IndexOutOfBoundsException, CapabilityException { + return new ServiceEntityHologramLine(this, hologram.addEntityLine(index, entityType)); + } + + @Override + public BlockHologramLine addBlockLine() throws CapabilityException { + return new ServiceBlockHologramLine(this, hologram.addBlockLine()); + } + + @Override + public BlockHologramLine addBlockLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceBlockHologramLine(this, hologram.addBlockLine(index)); + } + + @Override + public ItemHologramLine addItemLine() throws CapabilityException { + return new ServiceItemHologramLine(this, hologram.addItemLine()); + } + + @Override + public ItemHologramLine addItemLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceItemHologramLine(this, hologram.addItemLine(index)); + } + + @Override + public TextHologramLine addTextLine() throws CapabilityException { + return new ServiceTextHologramLine(this, hologram.addTextLine()); + } + + @Override + public TextHologramLine addTextLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceTextHologramLine(this, hologram.addTextLine(index)); + } + + @Override + public PagedHologramLine addPagedLine() throws CapabilityException { + return new ServicePagedHologramLine(this, hologram.addPagedLine()); + } + + @Override + public PagedHologramLine addPagedLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServicePagedHologramLine(this, hologram.addPagedLine(index)); + } + + @Override + public PagedHologramLine setPagedLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServicePagedHologramLine(this, hologram.setPagedLine(index)); + } + + @Override + public EntityHologramLine setEntityLine(final int index, final EntityType entityType) throws IllegalArgumentException, IndexOutOfBoundsException, CapabilityException { + return new ServiceEntityHologramLine(this, hologram.setEntityLine(index, entityType)); + } + + @Override + public BlockHologramLine setBlockLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceBlockHologramLine(this, hologram.setBlockLine(index)); + } + + @Override + public ItemHologramLine setItemLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceItemHologramLine(this, hologram.setItemLine(index)); + } + + @Override + public TextHologramLine setTextLine(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceTextHologramLine(this, hologram.setTextLine(index)); + } + + @Override + public Optional getViewPermission() { + return hologram.getViewPermission(); + } + + @Override + public boolean setViewPermission(@Nullable final String permission) { + return hologram.setViewPermission(permission); + } + + @Override + public Stream getTrackedBy() { + return hologram.getTrackedBy(); + } + + @Override + public @Unmodifiable Set getViewers() { + return hologram.getViewers(); + } + + @Override + public boolean addViewer(final UUID player) { + return hologram.addViewer(player); + } + + @Override + public boolean addViewers(final Collection players) { + return hologram.addViewers(players); + } + + @Override + public boolean removeViewer(final UUID player) { + return hologram.removeViewer(player); + } + + @Override + public boolean removeViewers(final Collection players) { + return hologram.removeViewers(players); + } + + @Override + public boolean isViewer(final UUID player) { + return hologram.isViewer(player); + } + + @Override + public int getLineCount() { + return hologram.getLineCount(); + } + + @Override + public Optional getLine(final int index) { + return hologram.getLine(index).map(this::wrapLine); + } + + @Override + public Optional getLine(final int index, final Class type) { + return getLine(index).filter(type::isInstance).map(type::cast); + } + + @Override + public int getLineIndex(final HologramLine line) { + return line instanceof final ServiceHologramLine serviceLine ? hologram.getLineIndex(serviceLine.line) : -1; + } + + @Override + public boolean removeLine(final HologramLine line) { + return line instanceof final ServiceHologramLine serviceLine && hologram.removeLine(serviceLine.line); + } + + @Override + public String getName() { + return hologram.getName(); + } + + @Override + public boolean setName(final String name) { + return hologram.setName(name); + } + + @Override + public boolean isPersistent() { + return hologram.isPersistent(); + } + + @Override + public boolean setPersistent(final boolean persistent) { + return hologram.setPersistent(persistent); + } + + @Override + public boolean persist() { + return hologram.persist(); + } + + @Override + public boolean isTrackedBy(final Player player) { + return hologram.isTrackedBy(player); + } + + @Override + public boolean canSee(final Player player) { + return hologram.canSee(player); + } + + @Override + public boolean isVisibleByDefault() { + return hologram.isVisibleByDefault(); + } + + @Override + public boolean setVisibleByDefault(final boolean visible) { + return hologram.setVisibleByDefault(visible); + } + + @Override + public Iterator iterator() { + return getLines().iterator(); + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceHologramController.java b/src/main/java/net/thenextlvl/hologram/service/ServiceHologramController.java new file mode 100644 index 00000000..2b43b407 --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceHologramController.java @@ -0,0 +1,94 @@ +package net.thenextlvl.hologram.service; + +import net.thenextlvl.hologram.HologramPlugin; +import net.thenextlvl.hologram.HologramProvider; +import net.thenextlvl.service.hologram.Hologram; +import net.thenextlvl.service.hologram.HologramCapability; +import net.thenextlvl.service.hologram.HologramController; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@NullMarked +public final class ServiceHologramController implements HologramController { + private final HologramProvider provider = HologramProvider.instance(); + private final Set capabilities = EnumSet.allOf(HologramCapability.class); + private final HologramPlugin plugin; + + public ServiceHologramController(final HologramPlugin plugin) { + this.plugin = plugin; + } + + @Override + public Hologram createHologram(final String name, final Location location) { + return new ServiceHologram(provider.createHologram(name, location)); + } + + @Override + public boolean deleteHologram(final Hologram hologram) { + return hologram instanceof ServiceHologram( + final net.thenextlvl.hologram.Hologram service + ) && provider.deleteHologram(service); + } + + @Override + public @Unmodifiable List getHolograms() { + return provider.getHolograms() + .map(ServiceHologram::new) + .collect(Collectors.toUnmodifiableList()); + } + + @Override + public @Unmodifiable List getHolograms(final Player player) { + return provider.getHolograms(player) + .map(ServiceHologram::new) + .collect(Collectors.toUnmodifiableList()); + } + + @Override + public @Unmodifiable List getHolograms(final World world) { + return provider.getHolograms(world) + .map(ServiceHologram::new) + .collect(Collectors.toUnmodifiableList()); + } + + @Override + public Optional getHologram(final String name) { + return provider.getHologram(name).map(ServiceHologram::new); + } + + @Override + public @Unmodifiable Set getCapabilities() { + return Set.copyOf(capabilities); + } + + @Override + public boolean hasCapabilities(final Collection capabilities) { + return this.capabilities.containsAll(capabilities); + } + + @Override + public boolean hasCapability(final HologramCapability capability) { + return capabilities.contains(capability); + } + + @Override + public Plugin getPlugin() { + return plugin; + } + + @Override + public String getName() { + return "Holograms"; + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceHologramLine.java b/src/main/java/net/thenextlvl/hologram/service/ServiceHologramLine.java new file mode 100644 index 00000000..73d616bd --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceHologramLine.java @@ -0,0 +1,57 @@ +package net.thenextlvl.hologram.service; + +import net.thenextlvl.service.hologram.Hologram; +import net.thenextlvl.service.hologram.LineType; +import net.thenextlvl.service.hologram.line.HologramLine; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Optional; + +@NullMarked +abstract class ServiceHologramLine implements HologramLine { + protected final ServiceHologram hologram; + protected final L line; + + protected ServiceHologramLine(final ServiceHologram hologram, final L line) { + this.hologram = hologram; + this.line = line; + } + + @Override + public LineType getType() { + return switch (line.getType()) { + case BLOCK -> LineType.BLOCK; + case ITEM -> LineType.ITEM; + case TEXT -> LineType.TEXT; + default -> LineType.ENTITY; + }; + } + + @Override + public World getWorld() { + return line.getWorld(); + } + + @Override + public Hologram getHologram() { + return hologram; + } + + @Override + public Optional getViewPermission() { + return line.getViewPermission(); + } + + @Override + public boolean setViewPermission(@Nullable final String permission) { + return line.setViewPermission(permission); + } + + @Override + public boolean canSee(final Player player) { + return line.canSee(player); + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceItemHologramLine.java b/src/main/java/net/thenextlvl/hologram/service/ServiceItemHologramLine.java new file mode 100644 index 00000000..1fe98a68 --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceItemHologramLine.java @@ -0,0 +1,44 @@ +package net.thenextlvl.hologram.service; + +import net.thenextlvl.hologram.line.ItemHologramLine; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.inventory.ItemStack; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +public final class ServiceItemHologramLine extends ServiceDisplayHologramLine implements net.thenextlvl.service.hologram.line.ItemHologramLine { + public ServiceItemHologramLine(final ServiceHologram hologram, final ItemHologramLine line) { + super(hologram, line); + } + + @Override + public ItemStack getItemStack() { + return line.getItemStack(); + } + + @Override + public boolean setItemStack(@Nullable final ItemStack item) { + return line.setItemStack(item); + } + + @Override + public boolean isPlayerHead() { + return line.isPlayerHead(); + } + + @Override + public boolean setPlayerHead(final boolean playerHead) { + return line.setPlayerHead(playerHead); + } + + @Override + public ItemDisplay.ItemDisplayTransform getItemDisplayTransform() { + return line.getItemDisplayTransform(); + } + + @Override + public boolean setItemDisplayTransform(final ItemDisplay.ItemDisplayTransform display) { + return line.setItemDisplayTransform(display); + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServicePagedHologramLine.java b/src/main/java/net/thenextlvl/hologram/service/ServicePagedHologramLine.java new file mode 100644 index 00000000..4de483eb --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServicePagedHologramLine.java @@ -0,0 +1,213 @@ +package net.thenextlvl.hologram.service; + +import net.thenextlvl.hologram.line.PagedHologramLine; +import net.thenextlvl.service.capability.CapabilityException; +import net.thenextlvl.service.hologram.line.BlockHologramLine; +import net.thenextlvl.service.hologram.line.EntityHologramLine; +import net.thenextlvl.service.hologram.line.HologramLine; +import net.thenextlvl.service.hologram.line.ItemHologramLine; +import net.thenextlvl.service.hologram.line.StaticHologramLine; +import net.thenextlvl.service.hologram.line.TextHologramLine; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.jspecify.annotations.NullMarked; + +import java.time.Duration; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.stream.Stream; + +@NullMarked +public final class ServicePagedHologramLine extends ServiceHologramLine implements net.thenextlvl.service.hologram.line.PagedHologramLine { + public ServicePagedHologramLine(final ServiceHologram hologram, final PagedHologramLine line) { + super(hologram, line); + } + + @Override + public Stream getPages() { + return line.getPages().map(this::wrapPage); + } + + private StaticHologramLine wrapPage(final net.thenextlvl.hologram.line.StaticHologramLine line) { + return switch (line) { + case final net.thenextlvl.hologram.line.ItemHologramLine l -> new ServiceItemHologramLine(hologram, l); + case final net.thenextlvl.hologram.line.BlockHologramLine l -> new ServiceBlockHologramLine(hologram, l); + case final net.thenextlvl.hologram.line.EntityHologramLine l -> new ServiceEntityHologramLine(hologram, l); + case final net.thenextlvl.hologram.line.TextHologramLine l -> new ServiceTextHologramLine(hologram, l); + default -> throw new IllegalStateException("Unexpected value: " + line); + }; + } + + @Override + public Optional getPage(final int index) { + return line.getPage(index).map(this::wrapPage); + } + + @Override + public Optional getPage(final int index, final Class type) { + return getPage(index).map(type::isInstance).map(type::cast); + } + + @Override + public int getPageCount() { + return line.getPageCount(); + } + + @Override + public int getPageIndex(final HologramLine line) { + return line instanceof final ServiceHologramLine service ? this.line.getPageIndex(service.line) : -1; + } + + @Override + public TextHologramLine addTextPage() throws CapabilityException { + return new ServiceTextHologramLine(hologram, line.addTextPage()); + } + + @Override + public ItemHologramLine addItemPage() throws CapabilityException { + return new ServiceItemHologramLine(hologram, line.addItemPage()); + } + + @Override + public BlockHologramLine addBlockPage() throws CapabilityException { + return new ServiceBlockHologramLine(hologram, line.addBlockPage()); + } + + @Override + public EntityHologramLine addEntityPage(final EntityType entityType) throws IllegalArgumentException, CapabilityException { + return new ServiceEntityHologramLine(hologram, line.addEntityPage(entityType)); + } + + @Override + public boolean removePage(final int index) { + return line.removePage(index); + } + + @Override + public boolean removePage(final HologramLine page) { + return page instanceof final ServiceHologramLine service && line.removePage(service.line); + } + + @Override + public boolean clearPages() { + return line.clearPages(); + } + + @Override + public boolean swapPages(final int first, final int second) { + return line.swapPages(first, second); + } + + @Override + public boolean movePage(final int from, final int to) { + return line.movePage(from, to); + } + + @Override + public TextHologramLine setTextPage(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceTextHologramLine(hologram, line.setTextPage(index)); + } + + @Override + public ItemHologramLine setItemPage(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceItemHologramLine(hologram, line.setItemPage(index)); + } + + @Override + public BlockHologramLine setBlockPage(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceBlockHologramLine(hologram, line.setBlockPage(index)); + } + + @Override + public EntityHologramLine setEntityPage(final int index, final EntityType entityType) throws IllegalArgumentException, IndexOutOfBoundsException, CapabilityException { + return new ServiceEntityHologramLine(hologram, line.setEntityPage(index, entityType)); + } + + @Override + public TextHologramLine insertTextPage(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceTextHologramLine(hologram, line.insertTextPage(index)); + } + + @Override + public ItemHologramLine insertItemPage(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceItemHologramLine(hologram, line.insertItemPage(index)); + } + + @Override + public BlockHologramLine insertBlockPage(final int index) throws IndexOutOfBoundsException, CapabilityException { + return new ServiceBlockHologramLine(hologram, line.insertBlockPage(index)); + } + + @Override + public EntityHologramLine insertEntityPage(final int index, final EntityType entityType) throws IllegalArgumentException, IndexOutOfBoundsException, CapabilityException { + return new ServiceEntityHologramLine(hologram, line.insertEntityPage(index, entityType)); + } + + @Override + public Duration getInterval() { + return line.getInterval(); + } + + @Override + public boolean setInterval(final Duration interval) throws IllegalArgumentException { + if (getInterval().equals(interval)) return false; + line.setInterval(interval); + return true; + } + + @Override + public boolean isRandomOrder() { + return line.isRandomOrder(); + } + + @Override + public boolean setRandomOrder(final boolean random) { + if (isRandomOrder() == random) return false; + line.setRandomOrder(random); + return true; + } + + @Override + public boolean isPaused() { + return line.isPaused(); + } + + @Override + public boolean setPaused(final boolean paused) { + if (isPaused() == paused) return false; + line.setPaused(paused); + return true; + } + + @Override + public CompletableFuture cyclePage(final Player player) { + return line.cyclePage(player); + } + + @Override + public CompletableFuture cyclePage(final Player player, final int amount) { + return line.cyclePage(player, amount); + } + + @Override + public CompletableFuture setPage(final Player player, final int page) throws IndexOutOfBoundsException { + return line.setPage(player, page); + } + + @Override + public OptionalInt getCurrentPageIndex(final Player player) { + return line.getCurrentPageIndex(player); + } + + @Override + public Optional getCurrentPage(final Player player) { + return line.getCurrentPage(player).map(this::wrapPage); + } + + @Override + public void forEachPage(final Consumer action) { + line.getPages().map(this::wrapPage).forEach(action); + } +} diff --git a/src/main/java/net/thenextlvl/hologram/service/ServiceTextHologramLine.java b/src/main/java/net/thenextlvl/hologram/service/ServiceTextHologramLine.java new file mode 100644 index 00000000..b9f9ba1c --- /dev/null +++ b/src/main/java/net/thenextlvl/hologram/service/ServiceTextHologramLine.java @@ -0,0 +1,108 @@ +package net.thenextlvl.hologram.service; + +import net.kyori.adventure.text.Component; +import net.thenextlvl.hologram.line.TextHologramLine; +import org.bukkit.Color; +import org.bukkit.entity.Player; +import org.bukkit.entity.TextDisplay; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Optional; + +@NullMarked +public final class ServiceTextHologramLine extends ServiceDisplayHologramLine implements net.thenextlvl.service.hologram.line.TextHologramLine { + public ServiceTextHologramLine(final ServiceHologram hologram, final TextHologramLine line) { + super(hologram, line); + } + + @Override + public Optional getText(final Player player) { + return line.getText(player); + } + + @Override + public Optional getUnparsedText() { + return line.getUnparsedText(); + } + + @Override + public boolean setText(@Nullable final Component text) { + return line.setText(text); + } + + @Override + public boolean setUnparsedText(@Nullable final String text) { + return line.setUnparsedText(text); + } + + @Override + public int getLineWidth() { + return line.getLineWidth(); + } + + @Override + public boolean setLineWidth(final int width) { + return line.setLineWidth(width); + } + + @Override + public Optional getBackgroundColor() { + return line.getBackgroundColor(); + } + + @Override + public boolean setBackgroundColor(@Nullable final Color color) { + return line.setBackgroundColor(color); + } + + @Override + public int getTextOpacity() { + return line.getTextOpacity(); + } + + @Override + public boolean setTextOpacity(final int opacity) { + return line.setTextOpacity(opacity); + } + + @Override + public boolean isShadowed() { + return line.isShadowed(); + } + + @Override + public boolean setShadowed(final boolean shadow) { + return line.setShadowed(shadow); + } + + @Override + public boolean isSeeThrough() { + return line.isSeeThrough(); + } + + @Override + public boolean setSeeThrough(final boolean seeThrough) { + return line.setSeeThrough(seeThrough); + } + + @Override + public boolean isDefaultBackground() { + return line.isDefaultBackground(); + } + + @Override + public boolean setDefaultBackground(final boolean defaultBackground) { + return line.setDefaultBackground(defaultBackground); + } + + @Override + public TextDisplay.TextAlignment getAlignment() { + return line.getAlignment(); + } + + @Override + public boolean setAlignment(final TextDisplay.TextAlignment alignment) { + return line.setAlignment(alignment); + } +}