From 2389b1ee4757947ec344dc71a512240deca7779c Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Mon, 9 Dec 2024 00:17:31 +0000 Subject: [PATCH] Implement feature system and Hologram API On its own, this does not do anything, but allows for third party plugins (mainly arena extensions) to have access to APIs that act more as a service provider. As an example, the Hologram API offered in this commit lets third party plugins interface with a common API that currently creates holograms if *either* FancyHolograms or DecentHolograms is installed. This can realistically be expanded to work with any hologram plugin, but still use the same API. This prevents developers from needing to implement support for multiple hologram plugins in their arena extensions, and rather just offers a common system they can use instead. This may further be expanded in the future to other features, like NPCs. --- module/hologram-integration/build.gradle.kts | 9 ++ .../module/hologram/HologramIntegration.java | 33 +++++++ .../decentholograms/DecentHologram.java | 96 +++++++++++++++++++ .../DecentHologramsFeature.java | 48 ++++++++++ .../fancyholograms/FancyHologram.java | 68 +++++++++++++ .../fancyholograms/FancyHologramsFeature.java | 48 ++++++++++ .../arena/competition/CompetitionManager.java | 5 + .../arena/ArenaRemoveCompetitionEvent.java | 43 +++++++++ .../arena/feature/FeatureController.java | 52 ++++++++++ .../arena/feature/FeatureInstance.java | 25 +++++ .../arena/feature/PluginFeature.java | 21 ++++ .../arena/feature/hologram/Hologram.java | 60 ++++++++++++ .../feature/hologram/HologramFeature.java | 48 ++++++++++ .../feature/hologram/HologramListener.java | 48 ++++++++++ .../arena/feature/hologram/Holograms.java | 57 +++++++++++ .../arena/feature/hologram/NoopHologram.java | 47 +++++++++ settings.gradle.kts | 1 + 17 files changed, 709 insertions(+) create mode 100644 module/hologram-integration/build.gradle.kts create mode 100644 module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/HologramIntegration.java create mode 100644 module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologram.java create mode 100644 module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologramsFeature.java create mode 100644 module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologram.java create mode 100644 module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologramsFeature.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/event/arena/ArenaRemoveCompetitionEvent.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/FeatureController.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/FeatureInstance.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/PluginFeature.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/hologram/Hologram.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramFeature.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramListener.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/hologram/Holograms.java create mode 100644 plugin/src/main/java/org/battleplugins/arena/feature/hologram/NoopHologram.java diff --git a/module/hologram-integration/build.gradle.kts b/module/hologram-integration/build.gradle.kts new file mode 100644 index 00000000..b24c9b0d --- /dev/null +++ b/module/hologram-integration/build.gradle.kts @@ -0,0 +1,9 @@ +repositories { + maven("https://jitpack.io") + maven("https://repo.fancyplugins.de/releases") +} + +dependencies { + compileOnly("com.github.decentsoftware-eu:decentholograms:2.8.12") + compileOnly("de.oliver:FancyHolograms:2.4.0") +} diff --git a/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/HologramIntegration.java b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/HologramIntegration.java new file mode 100644 index 00000000..035631a2 --- /dev/null +++ b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/HologramIntegration.java @@ -0,0 +1,33 @@ +package org.battleplugins.arena.module.hologram; + +import org.battleplugins.arena.event.BattleArenaPostInitializeEvent; +import org.battleplugins.arena.feature.hologram.Holograms; +import org.battleplugins.arena.module.ArenaModule; +import org.battleplugins.arena.module.ArenaModuleInitializer; +import org.battleplugins.arena.module.hologram.decentholograms.DecentHologramsFeature; +import org.battleplugins.arena.module.hologram.fancyholograms.FancyHologramsFeature; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; + +/** + * A module that allows for hooking into various hologram plugin. + */ +@ArenaModule(id = HologramIntegration.ID, name = "Hologram", description = "Adds support for hooking into various Hologram plugins.", authors = "BattlePlugins") +public class HologramIntegration implements ArenaModuleInitializer { + public static final String ID = "hologram"; + + @EventHandler + public void onPostInitialize(BattleArenaPostInitializeEvent event) { + if (Bukkit.getPluginManager().isPluginEnabled("FancyHolograms")) { + Holograms.register(new FancyHologramsFeature()); + + event.getBattleArena().info("FancyHolograms found. Using FancyHolograms for hologram integration."); + } + + if (Bukkit.getPluginManager().isPluginEnabled("DecentHolograms")) { + Holograms.register(new DecentHologramsFeature()); + + event.getBattleArena().info("DecentHolograms found. Using DecentHolograms for hologram integration."); + } + } +} diff --git a/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologram.java b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologram.java new file mode 100644 index 00000000..4a115888 --- /dev/null +++ b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologram.java @@ -0,0 +1,96 @@ +package org.battleplugins.arena.module.hologram.decentholograms; + +import eu.decentsoftware.holograms.api.holograms.HologramLine; +import eu.decentsoftware.holograms.api.holograms.HologramPage; +import eu.decentsoftware.holograms.api.holograms.enums.HologramLineType; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.battleplugins.arena.competition.LiveCompetition; +import org.battleplugins.arena.feature.hologram.Hologram; +import org.bukkit.Location; + +import java.util.ArrayList; +import java.util.List; + +public class DecentHologram implements Hologram { + private static final LegacyComponentSerializer SERIALIZER = LegacyComponentSerializer.builder() + .hexColors() + .useUnusualXRepeatedCharacterHexFormat() + .build(); + + private final LiveCompetition competition; + private final eu.decentsoftware.holograms.api.holograms.Hologram impl; + + public DecentHologram(LiveCompetition competition, eu.decentsoftware.holograms.api.holograms.Hologram impl) { + this.competition = competition; + this.impl = impl; + } + + @Override + public LiveCompetition getCompetition() { + return this.competition; + } + + @Override + public Location getLocation() { + return this.impl.getLocation(); + } + + @Override + public List getLines() { + if (this.impl.getPages().isEmpty()) { + return List.of(); + } + + // TODO: Support multiple pages + HologramPage page = this.impl.getPage(0); + List lines = new ArrayList<>(); + for (HologramLine line : page.getLines()) { + if (line.getType() == HologramLineType.TEXT) { + lines.add(SERIALIZER.deserialize(line.getText())); + } + } + + return lines; + } + + @Override + public void setLines(Component... lines) { + if (this.impl.getPages().isEmpty()) { + return; + } + + HologramPage page = this.impl.getPage(0); + for (int i = 0; i < page.getLines().size(); i++) { + page.removeLine(i); + } + + for (Component line : lines) { + page.addLine(new HologramLine(page, this.getLocation(), SERIALIZER.serialize(line))); + } + } + + @Override + public void addLine(Component line) { + if (this.impl.getPages().isEmpty()) { + return; + } + + HologramPage page = this.impl.getPage(0); + page.addLine(new HologramLine(page, this.getLocation(), SERIALIZER.serialize(line))); + } + + @Override + public void removeLine(int index) { + if (this.impl.getPages().isEmpty()) { + return; + } + + HologramPage page = this.impl.getPage(0); + page.removeLine(index); + } + + public eu.decentsoftware.holograms.api.holograms.Hologram getImpl() { + return this.impl; + } +} diff --git a/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologramsFeature.java b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologramsFeature.java new file mode 100644 index 00000000..898b70b1 --- /dev/null +++ b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/decentholograms/DecentHologramsFeature.java @@ -0,0 +1,48 @@ +package org.battleplugins.arena.module.hologram.decentholograms; + +import eu.decentsoftware.holograms.api.DecentHologramsAPI; +import net.kyori.adventure.text.Component; +import org.battleplugins.arena.competition.LiveCompetition; +import org.battleplugins.arena.feature.PluginFeature; +import org.battleplugins.arena.feature.hologram.Hologram; +import org.battleplugins.arena.feature.hologram.HologramFeature; +import org.bukkit.Location; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class DecentHologramsFeature extends PluginFeature implements HologramFeature { + private final List holograms = new ArrayList<>(); + + public DecentHologramsFeature() { + super(DecentHologramsAPI.get().getPlugin()); + } + + @Override + public Hologram createHologram(LiveCompetition competition, Location location, Component... lines) { + eu.decentsoftware.holograms.api.holograms.Hologram impl = new eu.decentsoftware.holograms.api.holograms.Hologram(UUID.randomUUID().toString(), location); + impl.setSaveToFile(false); + + DecentHologramsAPI.get().getHologramManager().registerHologram(impl); + + DecentHologram hologram = new DecentHologram(competition, impl); + hologram.setLines(lines); + + this.holograms.add(hologram); + return hologram; + } + + @Override + public void removeHologram(Hologram hologram) { + this.holograms.remove(hologram); + + DecentHologram decentHologram = (DecentHologram) hologram; + DecentHologramsAPI.get().getHologramManager().removeHologram(decentHologram.getImpl().getName()); + } + + @Override + public List getHolograms() { + return this.holograms; + } +} diff --git a/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologram.java b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologram.java new file mode 100644 index 00000000..231314b9 --- /dev/null +++ b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologram.java @@ -0,0 +1,68 @@ +package org.battleplugins.arena.module.hologram.fancyholograms; + +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.libs.chatcolorhandler.ModernChatColorHandler; +import de.oliver.fancyholograms.libs.chatcolorhandler.messengers.MiniMessageMessenger; +import net.kyori.adventure.text.Component; +import org.battleplugins.arena.competition.LiveCompetition; +import org.battleplugins.arena.feature.hologram.Hologram; +import org.bukkit.Location; + +import java.util.Arrays; +import java.util.List; + +public class FancyHologram implements Hologram { + private final LiveCompetition competition; + private final de.oliver.fancyholograms.api.hologram.Hologram impl; + + public FancyHologram(LiveCompetition competition, de.oliver.fancyholograms.api.hologram.Hologram impl) { + this.competition = competition; + this.impl = impl; + } + + @Override + public LiveCompetition getCompetition() { + return this.competition; + } + + @Override + public Location getLocation() { + return this.impl.getData().getLocation(); + } + + @Override + public List getLines() { + if (this.impl.getData() instanceof TextHologramData data) { + List stringLines = data.getText(); + return ModernChatColorHandler.translate(stringLines); + } + + return List.of(); + } + + @Override + public void setLines(Component... lines) { + if (this.impl.getData() instanceof TextHologramData data) { + List stringLines = Arrays.stream(lines).map(MiniMessageMessenger.MINI_MESSAGE::serialize).toList(); + data.setText(stringLines); + } + } + + @Override + public void addLine(Component line) { + if (this.impl.getData() instanceof TextHologramData data) { + data.addLine(MiniMessageMessenger.MINI_MESSAGE.serialize(line)); + } + } + + @Override + public void removeLine(int index) { + if (this.impl.getData() instanceof TextHologramData data) { + data.removeLine(index); + } + } + + de.oliver.fancyholograms.api.hologram.Hologram getImpl() { + return this.impl; + } +} diff --git a/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologramsFeature.java b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologramsFeature.java new file mode 100644 index 00000000..2f77bf81 --- /dev/null +++ b/module/hologram-integration/src/main/java/org/battleplugins/arena/module/hologram/fancyholograms/FancyHologramsFeature.java @@ -0,0 +1,48 @@ +package org.battleplugins.arena.module.hologram.fancyholograms; + +import de.oliver.fancyholograms.api.FancyHologramsPlugin; +import de.oliver.fancyholograms.api.data.TextHologramData; +import net.kyori.adventure.text.Component; +import org.battleplugins.arena.competition.LiveCompetition; +import org.battleplugins.arena.feature.PluginFeature; +import org.battleplugins.arena.feature.hologram.Hologram; +import org.battleplugins.arena.feature.hologram.HologramFeature; +import org.bukkit.Location; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class FancyHologramsFeature extends PluginFeature implements HologramFeature { + private final List holograms = new ArrayList<>(); + + public FancyHologramsFeature() { + super(FancyHologramsPlugin.get().getPlugin()); + } + + @Override + public Hologram createHologram(LiveCompetition competition, Location location, Component... lines) { + de.oliver.fancyholograms.api.hologram.Hologram impl = FancyHologramsPlugin.get().getHologramManager().create(new TextHologramData(UUID.randomUUID().toString(), location)); + impl.getData().setPersistent(false); + + FancyHologram hologram = new FancyHologram(competition, impl); + hologram.setLines(lines); + FancyHologramsPlugin.get().getHologramManager().addHologram(impl); + + this.holograms.add(hologram); + return hologram; + } + + @Override + public void removeHologram(Hologram hologram) { + this.holograms.remove(hologram); + + FancyHologram fancyHologram = (FancyHologram) hologram; + FancyHologramsPlugin.get().getHologramManager().removeHologram(fancyHologram.getImpl()); + } + + @Override + public List getHolograms() { + return List.copyOf(this.holograms); + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java b/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java index d113e669..aa17036d 100644 --- a/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java +++ b/plugin/src/main/java/org/battleplugins/arena/competition/CompetitionManager.java @@ -8,6 +8,7 @@ import org.battleplugins.arena.competition.phase.CompetitionPhaseType; import org.battleplugins.arena.competition.phase.phases.VictoryPhase; import org.battleplugins.arena.event.arena.ArenaCreateCompetitionEvent; +import org.battleplugins.arena.event.arena.ArenaRemoveCompetitionEvent; import org.battleplugins.arena.event.player.ArenaLeaveEvent; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -199,6 +200,10 @@ public void removeCompetition(Arena arena, Competition competition) { } competitions.remove(competition); + + ArenaRemoveCompetitionEvent event = new ArenaRemoveCompetitionEvent(arena, competition); + this.plugin.getServer().getPluginManager().callEvent(event); + if (competition.getMap().getType() == MapType.DYNAMIC && competition.getMap() instanceof LiveCompetitionMap map) { this.clearDynamicMap(map); } diff --git a/plugin/src/main/java/org/battleplugins/arena/event/arena/ArenaRemoveCompetitionEvent.java b/plugin/src/main/java/org/battleplugins/arena/event/arena/ArenaRemoveCompetitionEvent.java new file mode 100644 index 00000000..fab52804 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/event/arena/ArenaRemoveCompetitionEvent.java @@ -0,0 +1,43 @@ +package org.battleplugins.arena.event.arena; + +import org.battleplugins.arena.Arena; +import org.battleplugins.arena.competition.Competition; +import org.battleplugins.arena.event.ArenaEvent; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +/** + * Called when a competition is removed from an {@link Arena}. + */ +public class ArenaRemoveCompetitionEvent extends Event implements ArenaEvent { + private final static HandlerList HANDLERS = new HandlerList(); + + private final Arena arena; + private final Competition competition; + + public ArenaRemoveCompetitionEvent(Arena arena, Competition competition) { + this.arena = arena; + this.competition = competition; + } + + @Override + public Arena getArena() { + return this.arena; + } + + @Override + public Competition getCompetition() { + return this.competition; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return HANDLERS; + } + + public static HandlerList getHandlerList() { + return HANDLERS; + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/FeatureController.java b/plugin/src/main/java/org/battleplugins/arena/feature/FeatureController.java new file mode 100644 index 00000000..3fd54f06 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/FeatureController.java @@ -0,0 +1,52 @@ +package org.battleplugins.arena.feature; + +import org.battleplugins.arena.BattleArena; +import org.bukkit.Bukkit; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class FeatureController { + private static final Map, List> FEATURES = new HashMap<>(); + + protected static void registerFeature(Class clazz, T feature) { + FEATURES.computeIfAbsent(clazz, k -> new ArrayList<>()).add(feature); + } + + protected static T createInstance(Class clazz) { + T instance = getBestFeature(clazz); + if (instance != null) { + Listener listener = instance.createListener(); + if (listener != null) { + Bukkit.getPluginManager().registerEvents(listener, BattleArena.getInstance()); + } + } + + return instance; + } + + private static T getBestFeature(Class clazz) { + List features = getFeatures(clazz); + if (features.isEmpty()) { + return null; + } + + for (T feature : features) { + if (!feature.isEnabled()) { + continue; + } + + return feature; + } + + return null; + } + + @SuppressWarnings("unchecked") + private static List getFeatures(Class clazz) { + return (List) FEATURES.getOrDefault(clazz, List.of()); + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/FeatureInstance.java b/plugin/src/main/java/org/battleplugins/arena/feature/FeatureInstance.java new file mode 100644 index 00000000..1be74075 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/FeatureInstance.java @@ -0,0 +1,25 @@ +package org.battleplugins.arena.feature; + +import org.bukkit.event.Listener; + +/** + * Represents a feature instance. + */ +public interface FeatureInstance { + + /** + * Returns if the feature is enabled. + * + * @return if the feature is enabled + */ + boolean isEnabled(); + + /** + * Creates a listener for this feature. + * + * @return the created listener + */ + default Listener createListener() { + return null; + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/PluginFeature.java b/plugin/src/main/java/org/battleplugins/arena/feature/PluginFeature.java new file mode 100644 index 00000000..e7151545 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/PluginFeature.java @@ -0,0 +1,21 @@ +package org.battleplugins.arena.feature; + +import org.bukkit.plugin.Plugin; + +/** + * Represents a {@link FeatureInstance} implemented by a plugin. + * + * @param the feature instance + */ +public abstract class PluginFeature implements FeatureInstance { + private final Plugin plugin; + + public PluginFeature(Plugin plugin) { + this.plugin = plugin; + } + + @Override + public boolean isEnabled() { + return this.plugin.isEnabled(); + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/hologram/Hologram.java b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/Hologram.java new file mode 100644 index 00000000..24d76d62 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/Hologram.java @@ -0,0 +1,60 @@ +package org.battleplugins.arena.feature.hologram; + +import net.kyori.adventure.text.Component; +import org.battleplugins.arena.competition.LiveCompetition; +import org.bukkit.Location; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +/** + * Represents a hologram in an {@link LiveCompetition}. + *

+ * Holograms are tied to an active competition, and will + * automatically be removed when the competition ends. + */ +@ApiStatus.Experimental +public interface Hologram { + + /** + * Gets the {@link LiveCompetition} this hologram is associated with. + * + * @return the live competition this hologram is associated with + */ + LiveCompetition getCompetition(); + + /** + * Gets the {@link Location} of this hologram. + * + * @return the location of this hologram + */ + Location getLocation(); + + /** + * Gets the lines of this hologram. + * + * @return the lines of this hologram + */ + List getLines(); + + /** + * Sets the lines of this hologram. + * + * @param lines the lines to set + */ + void setLines(Component... lines); + + /** + * Adds a line to the hologram. + * + * @param line the line to add + */ + void addLine(Component line); + + /** + * Removes a line from the hologram. + * + * @param index the index of the line to remove + */ + void removeLine(int index); +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramFeature.java b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramFeature.java new file mode 100644 index 00000000..e045e181 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramFeature.java @@ -0,0 +1,48 @@ +package org.battleplugins.arena.feature.hologram; + +import net.kyori.adventure.text.Component; +import org.battleplugins.arena.competition.LiveCompetition; +import org.battleplugins.arena.feature.FeatureInstance; +import org.bukkit.Location; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +/** + * Main entrypoint for holograms. Implementing plugins + * should implement this interface to provide hologram + * support. + */ +@ApiStatus.Experimental +public interface HologramFeature extends FeatureInstance { + + /** + * Creates a {@link Hologram} at the given location with the given lines. + * + * @param competition the competition to create the hologram for + * @param location the location to create the hologram at + * @param lines the lines of the hologram + * @return the created hologram + */ + Hologram createHologram(LiveCompetition competition, Location location, Component... lines); + + /** + * Removes a {@link Hologram} from a competition. + * + * @param hologram the hologram to remove + */ + void removeHologram(Hologram hologram); + + /** + * Gets all holograms created by this feature. + * + * @return all holograms created by this feature + */ + List getHolograms(); + + @Override + default Listener createListener() { + return new HologramListener(this); + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramListener.java b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramListener.java new file mode 100644 index 00000000..31d05c7e --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/HologramListener.java @@ -0,0 +1,48 @@ +package org.battleplugins.arena.feature.hologram; + +import org.battleplugins.arena.competition.Competition; +import org.battleplugins.arena.competition.phase.CompetitionPhaseType; +import org.battleplugins.arena.event.arena.ArenaPhaseCompleteEvent; +import org.battleplugins.arena.event.arena.ArenaRemoveCompetitionEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.ArrayList; + +class HologramListener implements Listener { + private final HologramFeature feature; + + public HologramListener(HologramFeature feature) { + this.feature = feature; + } + + @EventHandler + public void onPhaseComplete(ArenaPhaseCompleteEvent event) { + if (!CompetitionPhaseType.VICTORY.equals(event.getPhase().getType())) { + return; + } + + if (!this.feature.isEnabled()) { + return; + } + + this.clearHolograms(event.getCompetition()); + } + + @EventHandler + public void onRemoveCompetition(ArenaRemoveCompetitionEvent event) { + if (!this.feature.isEnabled()) { + return; + } + + this.clearHolograms(event.getCompetition()); + } + + private void clearHolograms(Competition competition) { + for (Hologram hologram : new ArrayList<>(this.feature.getHolograms())) { + if (hologram.getCompetition().equals(competition)) { + this.feature.removeHologram(hologram); + } + } + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/hologram/Holograms.java b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/Holograms.java new file mode 100644 index 00000000..4fdaf359 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/Holograms.java @@ -0,0 +1,57 @@ +package org.battleplugins.arena.feature.hologram; + +import net.kyori.adventure.text.Component; +import org.battleplugins.arena.competition.LiveCompetition; +import org.battleplugins.arena.feature.FeatureController; +import org.bukkit.Location; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +/** + * API for holograms used in BattleArena. + */ +@ApiStatus.Experimental +public class Holograms extends FeatureController { + private static HologramFeature instance; + + /** + * Creates a {@link Hologram} at the given location with the given lines. + * + * @param location the location to create the hologram at + * @param lines the lines of the hologram + * @return the created hologram + */ + public static Hologram createHologram(LiveCompetition competition, Location location, Component... lines) { + HologramFeature instance = instance(); + if (instance == null) { + return new NoopHologram(competition, location); + } + + return instance.createHologram(competition, location, lines); + } + + /** + * Removes a {@link Hologram} from a competition. + * + * @param hologram the hologram to remove + */ + public static void removeHologram(Hologram hologram) { + HologramFeature instance = instance(); + if (instance != null) { + instance.removeHologram(hologram); + } + } + + @Nullable + private static HologramFeature instance() { + if (instance == null) { + instance = createInstance(HologramFeature.class); + } + + return instance; + } + + public static void register(HologramFeature feature) { + registerFeature(HologramFeature.class, feature); + } +} diff --git a/plugin/src/main/java/org/battleplugins/arena/feature/hologram/NoopHologram.java b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/NoopHologram.java new file mode 100644 index 00000000..fb6e10e6 --- /dev/null +++ b/plugin/src/main/java/org/battleplugins/arena/feature/hologram/NoopHologram.java @@ -0,0 +1,47 @@ +package org.battleplugins.arena.feature.hologram; + +import net.kyori.adventure.text.Component; +import org.battleplugins.arena.competition.LiveCompetition; +import org.bukkit.Location; + +import java.util.List; + +class NoopHologram implements Hologram { + private final LiveCompetition competition; + private final Location location; + + public NoopHologram(LiveCompetition competition, Location location) { + this.competition = competition; + this.location = location; + } + + @Override + public LiveCompetition getCompetition() { + return this.competition; + } + + @Override + public Location getLocation() { + return this.location; + } + + @Override + public List getLines() { + return List.of(); + } + + @Override + public void setLines(Component... lines) { + // no-op + } + + @Override + public void addLine(Component line) { + // no-op + } + + @Override + public void removeLine(int index) { + // no-op + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 81b57d12..5b6230be 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -22,6 +22,7 @@ include("module:arena-restoration") include("module:boundary-enforcer") include("module:classes") include("module:duels") +include("module:hologram-integration") include("module:one-in-the-chamber") include("module:placeholderapi-integration") include("module:scoreboards")