diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c2d567e2..df7405fb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,10 +12,10 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Cache Gradle dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/FancyHologramsPlugin.java b/api/src/main/java/de/oliver/fancyholograms/api/FancyHolograms.java similarity index 56% rename from api/src/main/java/de/oliver/fancyholograms/api/FancyHologramsPlugin.java rename to api/src/main/java/de/oliver/fancyholograms/api/FancyHolograms.java index 82cd3da7..c33ca908 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/FancyHologramsPlugin.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/FancyHolograms.java @@ -1,15 +1,20 @@ package de.oliver.fancyholograms.api; import de.oliver.fancyanalytics.logger.ExtendedFancyLogger; +import de.oliver.fancyholograms.api.data.HologramData; +import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.api.trait.HologramTraitRegistry; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.ApiStatus; import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Function; -public interface FancyHologramsPlugin { +public interface FancyHolograms { - static FancyHologramsPlugin get() { + static FancyHolograms get() { if (isEnabled()) { return EnabledChecker.getPlugin(); } @@ -25,45 +30,24 @@ static boolean isEnabled() { ExtendedFancyLogger getFancyLogger(); - HologramManager getHologramManager(); - - /** - * Returns the configuration of the plugin. - * - * @return The configuration. - */ HologramConfiguration getHologramConfiguration(); - /** - * Sets the configuration of the plugin. - * - * @param configuration The new configuration. - * @param reload Whether the configuration should be reloaded. - */ - void setHologramConfiguration(HologramConfiguration configuration, boolean reload); - - /** - * @return The hologram storage. - */ - HologramStorage getHologramStorage(); - - /** - * @return The hologram thread - */ + @ApiStatus.Internal + Function getHologramFactory(); + ScheduledExecutorService getHologramThread(); - /** - * Sets the hologram storage. - * - * @param storage The new hologram storage. - * @param reload Whether the current hologram cache should be reloaded. - */ - void setHologramStorage(HologramStorage storage, boolean reload); + HologramRegistry getRegistry(); + + HologramController getController(); + + @ApiStatus.Experimental + HologramTraitRegistry getTraitRegistry(); class EnabledChecker { private static Boolean enabled; - private static FancyHologramsPlugin plugin; + private static FancyHolograms plugin; public static Boolean isFancyHologramsEnabled() { if (enabled != null) return enabled; @@ -72,7 +56,7 @@ public static Boolean isFancyHologramsEnabled() { if (pl != null && pl.isEnabled()) { try { - plugin = (FancyHologramsPlugin) pl; + plugin = (FancyHolograms) pl; } catch (ClassCastException e) { throw new IllegalStateException("API failed to access plugin, if using the FancyHolograms API make sure to set the dependency to compile only."); } @@ -84,7 +68,7 @@ public static Boolean isFancyHologramsEnabled() { return false; } - public static FancyHologramsPlugin getPlugin() { + public static FancyHolograms getPlugin() { return plugin; } } diff --git a/api/src/main/java/de/oliver/fancyholograms/api/HologramConfiguration.java b/api/src/main/java/de/oliver/fancyholograms/api/HologramConfiguration.java index d5fba997..fa0a5b17 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/HologramConfiguration.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/HologramConfiguration.java @@ -9,7 +9,7 @@ public interface HologramConfiguration { * * @param plugin The plugin instance. */ - void reload(@NotNull FancyHologramsPlugin plugin); + void reload(@NotNull FancyHolograms plugin); /** * Returns whether version notifications are muted. diff --git a/api/src/main/java/de/oliver/fancyholograms/api/HologramController.java b/api/src/main/java/de/oliver/fancyholograms/api/HologramController.java new file mode 100644 index 00000000..3c1145a3 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/HologramController.java @@ -0,0 +1,43 @@ +package de.oliver.fancyholograms.api; + +import de.oliver.fancyholograms.api.hologram.Hologram; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +/** + * The controller for holograms, responsible for showing and hiding them to players. + */ +public interface HologramController { + + /** + * Shows the hologram to the given players, if they should see it, and it is not already shown to them. + */ + @ApiStatus.Internal + void showHologramTo(@NotNull final Hologram hologram, @NotNull final Player ...players); + + /** + * Hides the hologram from the given players, if they should not see it, and it is shown to them. + */ + @ApiStatus.Internal + void hideHologramFrom(@NotNull final Hologram hologram, @NotNull final Player ...players); + + /** + * Returns whether the given player should see the hologram. + */ + @ApiStatus.Internal + boolean shouldSeeHologram(@NotNull final Hologram hologram, @NotNull final Player player); + + /** + * Spawns the hologram to the given players, if they should see it, and it is not already shown to them. + * Hide the hologram from the players that should not see it. + */ + void refreshHologram(@NotNull final Hologram hologram, @NotNull final Player ...players); + + default void refreshHologram(@NotNull final Hologram hologram, @NotNull final Collection players) { + refreshHologram(hologram, players.toArray(new Player[0])); + } + +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/HologramManager.java b/api/src/main/java/de/oliver/fancyholograms/api/HologramManager.java deleted file mode 100644 index 483077b7..00000000 --- a/api/src/main/java/de/oliver/fancyholograms/api/HologramManager.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.oliver.fancyholograms.api; - -import de.oliver.fancyholograms.api.data.HologramData; -import de.oliver.fancyholograms.api.hologram.Hologram; - -import java.util.Collection; -import java.util.Optional; - -public interface HologramManager { - - Optional getHologram(String name); - - Collection getPersistentHolograms(); - - Collection getHolograms(); - - void addHologram(Hologram hologram); - - void removeHologram(Hologram hologram); - - Hologram create(HologramData hologramData); - - void loadHolograms(); - - void saveHolograms(); - - void reloadHolograms(); - -} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/HologramRegistry.java b/api/src/main/java/de/oliver/fancyholograms/api/HologramRegistry.java new file mode 100644 index 00000000..bad11e59 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/HologramRegistry.java @@ -0,0 +1,74 @@ +package de.oliver.fancyholograms.api; + +import de.oliver.fancyholograms.api.hologram.Hologram; + +import java.util.Collection; +import java.util.Optional; + +/** + * An interface for managing the registration and retrieval of holograms. + * Provides methods to register, unregister, and query holograms by their name. + */ +public interface HologramRegistry { + + /** + * Registers a hologram in the registry. + * + * @param hologram the hologram to be registered + * @return {@code true} if the registration was successful, otherwise {@code false} + */ + boolean register(Hologram hologram); + + /** + * Unregisters the specified hologram from the registry. + * + * @param hologram the hologram to be unregistered + * @return {@code true} if the hologram was successfully unregistered, otherwise {@code false} + */ + boolean unregister(Hologram hologram); + + /** + * Checks if a hologram with the specified name exists in the registry. + * + * @param name the name of the hologram to check for existence + * @return {@code true} if a hologram with the specified name exists, otherwise {@code false} + */ + boolean contains(String name); + + /** + * Retrieves a hologram by its name from the registry. + * + * @param name the name of the hologram to retrieve + * @return an {@code Optional} containing the hologram if found, or an empty {@code Optional} if no hologram exists with the specified name + */ + Optional get(String name); + + /** + * Retrieves a hologram by its name from the registry, ensuring that the hologram exists. + * If no hologram exists with the specified name, this method will throw an exception. + * + * @param name the name of the hologram to retrieve + * @return the hologram associated with the specified name + * @throws IllegalArgumentException if no hologram exists with the given name + */ + Hologram mustGet(String name); + + /** + * Retrieves all holograms currently registered in the registry. + * + * @return a collection containing all registered holograms + */ + Collection getAll(); + + /** + * Retrieves all persistent holograms currently registered in the registry. + * + * @return a collection containing all persistent holograms + */ + Collection getAllPersistent(); + + /** + * Removes all holograms from the registry, effectively clearing its contents. + */ + void clear(); +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/BlockHologramData.java b/api/src/main/java/de/oliver/fancyholograms/api/data/BlockHologramData.java index 70c46b68..9017a22e 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/data/BlockHologramData.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/BlockHologramData.java @@ -4,6 +4,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.ApiStatus; import java.util.Objects; @@ -36,6 +37,7 @@ public BlockHologramData setBlock(Material block) { } @Override + @ApiStatus.Internal public boolean read(ConfigurationSection section, String name) { super.read(section, name); block = Material.getMaterial(section.getString("block", "GRASS_BLOCK").toUpperCase()); @@ -44,6 +46,7 @@ public boolean read(ConfigurationSection section, String name) { } @Override + @ApiStatus.Internal public boolean write(ConfigurationSection section, String name) { super.write(section, name); section.set("block", block.name()); diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/DisplayHologramData.java b/api/src/main/java/de/oliver/fancyholograms/api/data/DisplayHologramData.java index 5ae62f6c..22df5dc1 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/data/DisplayHologramData.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/DisplayHologramData.java @@ -131,6 +131,7 @@ public DisplayHologramData setInterpolationDuration(int interpolationDuration) { } @Override + @ApiStatus.Internal public boolean read(ConfigurationSection section, String name) { super.read(section, name); scale = new Vector3f( @@ -170,6 +171,7 @@ public boolean read(ConfigurationSection section, String name) { } @Override + @ApiStatus.Internal public boolean write(ConfigurationSection section, String name) { super.write(section, name); section.set("scale_x", scale.x); diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java b/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java index 3c14aa36..17a3a758 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java @@ -1,12 +1,13 @@ package de.oliver.fancyholograms.api.data; -import de.oliver.fancyholograms.api.FancyHologramsPlugin; +import de.oliver.fancyholograms.api.FancyHolograms; import de.oliver.fancyholograms.api.data.property.Visibility; import de.oliver.fancyholograms.api.hologram.HologramType; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,7 +24,7 @@ public class HologramData implements YamlData { private final String name; private final HologramType type; private Location location; - private boolean hasChanges; + private boolean hasChanges = false; private int visibilityDistance = DEFAULT_VISIBILITY_DISTANCE; private Visibility visibility = DEFAULT_VISIBILITY; private boolean persistent = DEFAULT_PERSISTENCE; @@ -78,7 +79,7 @@ public int getVisibilityDistance() { return visibilityDistance; } - return FancyHologramsPlugin.get().getHologramConfiguration().getDefaultVisibilityDistance(); + return FancyHolograms.get().getHologramConfiguration().getDefaultVisibilityDistance(); } public HologramData setVisibilityDistance(int visibilityDistance) { @@ -135,6 +136,7 @@ public HologramData setLinkedNpcName(String linkedNpcName) { } @Override + @ApiStatus.Internal public boolean read(ConfigurationSection section, String name) { String worldName = section.getString("location.world", "world"); float x = (float) section.getDouble("location.x", 0); @@ -145,7 +147,7 @@ public boolean read(ConfigurationSection section, String name) { World world = Bukkit.getWorld(worldName); if (world == null) { - FancyHologramsPlugin.get().getFancyLogger().warn("Could not load hologram '" + name + "', because the world '" + worldName + "' is not loaded"); + FancyHolograms.get().getFancyLogger().warn("Could not load hologram '" + name + "', because the world '" + worldName + "' is not loaded"); return false; } @@ -163,6 +165,7 @@ public boolean read(ConfigurationSection section, String name) { } @Override + @ApiStatus.Internal public boolean write(ConfigurationSection section, String name) { section.set("type", type.name()); section.set("location.world", location.getWorld().getName()); diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/ItemHologramData.java b/api/src/main/java/de/oliver/fancyholograms/api/data/ItemHologramData.java index 5c311e20..29b21646 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/data/ItemHologramData.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/ItemHologramData.java @@ -5,6 +5,7 @@ import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.ApiStatus; import java.util.Objects; @@ -37,6 +38,7 @@ public ItemHologramData setItemStack(ItemStack item) { } @Override + @ApiStatus.Internal public boolean read(ConfigurationSection section, String name) { super.read(section, name); item = section.getItemStack("item", DEFAULT_ITEM); @@ -45,6 +47,7 @@ public boolean read(ConfigurationSection section, String name) { } @Override + @ApiStatus.Internal public boolean write(ConfigurationSection section, String name) { super.write(section, name); section.set("item", item); diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/TextHologramData.java b/api/src/main/java/de/oliver/fancyholograms/api/data/TextHologramData.java index 83f64213..dfe9d1b3 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/data/TextHologramData.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/TextHologramData.java @@ -7,6 +7,7 @@ import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.TextDisplay; +import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; import java.util.List; @@ -15,13 +16,14 @@ public class TextHologramData extends DisplayHologramData { + public static final List DEFAULT_TEXT = List.of("Edit this line with /hologram edit "); public static final TextDisplay.TextAlignment DEFAULT_TEXT_ALIGNMENT = TextDisplay.TextAlignment.CENTER; public static final boolean DEFAULT_TEXT_SHADOW_STATE = false; public static final boolean DEFAULT_SEE_THROUGH = false; public static final int DEFAULT_TEXT_UPDATE_INTERVAL = -1; - private List text; - private Color background; + private List text = new ArrayList<>(DEFAULT_TEXT); + private Color background = null; private TextDisplay.TextAlignment textAlignment = DEFAULT_TEXT_ALIGNMENT; private boolean textShadow = DEFAULT_TEXT_SHADOW_STATE; private boolean seeThrough = DEFAULT_SEE_THROUGH; @@ -34,7 +36,6 @@ public class TextHologramData extends DisplayHologramData { */ public TextHologramData(String name, Location location) { super(name, HologramType.TEXT, location); - text = new ArrayList<>(List.of("Edit this line with /hologram edit " + name)); } public List getText() { @@ -50,14 +51,28 @@ public TextHologramData setText(List text) { return this; } - public void addLine(String line) { + public TextHologramData addLine(String line) { text.add(line); setHasChanges(true); + return this; } - public void removeLine(int index) { + public TextHologramData removeLine(int index) { text.remove(index); setHasChanges(true); + return this; + } + + public TextHologramData setLine(int index, String line) { + text.set(index, line); + setHasChanges(true); + return this; + } + + public TextHologramData clearText() { + text.clear(); + setHasChanges(true); + return this; } public Color getBackground() { @@ -126,6 +141,7 @@ public TextHologramData setTextUpdateInterval(int textUpdateInterval) { } @Override + @ApiStatus.Internal public boolean read(ConfigurationSection section, String name) { super.read(section, name); text = section.getStringList("text"); @@ -163,6 +179,7 @@ public boolean read(ConfigurationSection section, String name) { } @Override + @ApiStatus.Internal public boolean write(ConfigurationSection section, String name) { super.write(section, name); section.set("text", text); diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/builder/BlockHologramBuilder.java b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/BlockHologramBuilder.java new file mode 100644 index 00000000..a8a0bf96 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/BlockHologramBuilder.java @@ -0,0 +1,30 @@ +package de.oliver.fancyholograms.api.data.builder; + +import de.oliver.fancyholograms.api.data.BlockHologramData; +import org.bukkit.Location; +import org.bukkit.Material; + +public class BlockHologramBuilder extends HologramBuilder{ + + private BlockHologramBuilder(String name, Location location) { + super(); + this.data = new BlockHologramData(name, location); + } + + /** + * Creates a new instance of BlockHologramBuilder with the specified name and location. + * + * @param name the name of the block hologram + * @param location the location of the block hologram + * @return a new instance of BlockHologramBuilder + */ + public static BlockHologramBuilder create(String name, Location location) { + return new BlockHologramBuilder(name, location); + } + + public BlockHologramBuilder block(Material block) { + ((BlockHologramData) data).setBlock(block); + return this; + } + +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/builder/HologramBuilder.java b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/HologramBuilder.java new file mode 100644 index 00000000..07b01e40 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/HologramBuilder.java @@ -0,0 +1,97 @@ +package de.oliver.fancyholograms.api.data.builder; + +import de.oliver.fancyholograms.api.FancyHolograms; +import de.oliver.fancyholograms.api.data.DisplayHologramData; +import de.oliver.fancyholograms.api.data.property.Visibility; +import de.oliver.fancyholograms.api.hologram.Hologram; +import org.bukkit.entity.Display; +import org.joml.Vector3f; + +public abstract class HologramBuilder { + + protected DisplayHologramData data; + + protected HologramBuilder() { + } + + /** + * Builds and returns a new Hologram instance using the current configuration + * in the HologramBuilder. + * + * @return a new instance of Hologram created based on the configured data + */ + public Hologram build() { + return FancyHolograms.get().getHologramFactory().apply(data); + } + + /** + * Builds a new Hologram instance using the current configuration in the HologramBuilder + * and registers it. + * + * @return a new instance of Hologram that has been registered with the registry + */ + public Hologram buildAndRegister() { + Hologram hologram = build(); + FancyHolograms.get().getRegistry().register(hologram); + return hologram; + } + + // The following methods are setters for the HologramData class + + public HologramBuilder visibilityDistance(int distance) { + data.setVisibilityDistance(distance); + return this; + } + + public HologramBuilder visibility(Visibility visibility) { + data.setVisibility(visibility); + return this; + } + + public HologramBuilder persistent(boolean persistent) { + data.setPersistent(persistent); + return this; + } + + public HologramBuilder linkedNpcName(String linkedNpcName) { + data.setLinkedNpcName(linkedNpcName); + return this; + } + + // The following methods are specific to the DisplayHologramData class + + public HologramBuilder billboard(Display.Billboard billboard) { + data.setBillboard(billboard); + return this; + } + + public HologramBuilder scale(float x, float y, float z) { + data.setScale(new Vector3f(x, y, z)); + return this; + } + + public HologramBuilder translation(float x, float y, float z) { + data.setTranslation(new Vector3f(x, y, z)); + return this; + } + + public HologramBuilder brightness(int blockLight, int skyLight) { + data.setBrightness(new Display.Brightness(blockLight, skyLight)); + return this; + } + + public HologramBuilder shadowRadius(float shadowRadius) { + data.setShadowRadius(shadowRadius); + return this; + } + + public HologramBuilder shadowStrength(float shadowStrength) { + data.setShadowStrength(shadowStrength); + return this; + } + + public HologramBuilder interpolationDuration(int interpolationDuration) { + data.setInterpolationDuration(interpolationDuration); + return this; + } +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/builder/ItemHologramBuilder.java b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/ItemHologramBuilder.java new file mode 100644 index 00000000..79d28f89 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/ItemHologramBuilder.java @@ -0,0 +1,30 @@ +package de.oliver.fancyholograms.api.data.builder; + +import de.oliver.fancyholograms.api.data.ItemHologramData; +import org.bukkit.Location; +import org.bukkit.inventory.ItemStack; + +public class ItemHologramBuilder extends HologramBuilder{ + + private ItemHologramBuilder(String name, Location location) { + super(); + this.data = new ItemHologramData(name, location); + } + + /** + * Creates a new instance of ItemHologramBuilder with the specified name and location. + * + * @param name the name of the item hologram + * @param location the location of the item hologram + * @return a new instance of ItemHologramBuilder + */ + public static ItemHologramBuilder create(String name, Location location) { + return new ItemHologramBuilder(name, location); + } + + public ItemHologramBuilder item(ItemStack item) { + ((ItemHologramData) data).setItemStack(item); + return this; + } + +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/builder/TextHologramBuilder.java b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/TextHologramBuilder.java new file mode 100644 index 00000000..c2b53982 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/builder/TextHologramBuilder.java @@ -0,0 +1,77 @@ +package de.oliver.fancyholograms.api.data.builder; + +import de.oliver.fancyholograms.api.data.TextHologramData; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.entity.TextDisplay; + +import java.util.List; + +public class TextHologramBuilder extends HologramBuilder{ + + private TextHologramBuilder(String name, Location location) { + super(); + this.data = new TextHologramData(name, location); + } + + /** + * Creates a new instance of TextHologramBuilder with the specified name and location. + * + * @param name the name of the text hologram + * @param location the location of the text hologram + * @return a new instance of TextHologramBuilder + */ + public static TextHologramBuilder create(String name, Location location) { + return new TextHologramBuilder(name, location); + } + + public TextHologramBuilder text(List text) { + ((TextHologramData) data).setText(text); + return this; + } + + public TextHologramBuilder text(String text) { + return text(List.of(text)); + } + + public TextHologramBuilder text(String ... text) { + return text(List.of(text)); + } + + public TextHologramBuilder background(Color background) { + ((TextHologramData) data).setBackground(background); + return this; + } + + /** + * Sets the background color of the text hologram using a color code in ARGB format. + * + * @param background the ARGB color code as a string (#AARRGGBB) + * @return the updated instance of TextHologramBuilder for method chaining + */ + public TextHologramBuilder background(String background) { + int argb = Integer.parseInt(background.substring(1), 16); + return background(Color.fromARGB(argb)); + } + + public TextHologramBuilder textAlignment(TextDisplay.TextAlignment textAlignment) { + ((TextHologramData) data).setTextAlignment(textAlignment); + return this; + } + + public TextHologramBuilder textShadow(boolean textShadow) { + ((TextHologramData) data).setTextShadow(textShadow); + return this; + } + + public TextHologramBuilder seeThrough(boolean seeThrough) { + ((TextHologramData) data).setSeeThrough(seeThrough); + return this; + } + + public TextHologramBuilder updateTextInterval(int updateTextInterval) { + ((TextHologramData) data).setTextUpdateInterval(updateTextInterval); + return this; + } + +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/data/property/Visibility.java b/api/src/main/java/de/oliver/fancyholograms/api/data/property/Visibility.java index 3e7b2133..878f43d4 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/data/property/Visibility.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/data/property/Visibility.java @@ -54,11 +54,11 @@ public static class ManualVisibility { private static final HashMultimap distantViewers = HashMultimap.create(); public static boolean canSee(Player player, Hologram hologram) { - return hologram.isViewer(player) || distantViewers.containsEntry(hologram.getName(), player.getUniqueId()); + return hologram.isViewer(player) || distantViewers.containsEntry(hologram.getData().getName(), player.getUniqueId()); } public static void addDistantViewer(Hologram hologram, UUID uuid) { - addDistantViewer(hologram.getName(), uuid); + addDistantViewer(hologram.getData().getName(), uuid); } public static void addDistantViewer(String hologramName, UUID uuid) { @@ -66,7 +66,7 @@ public static void addDistantViewer(String hologramName, UUID uuid) { } public static void removeDistantViewer(Hologram hologram, UUID uuid) { - removeDistantViewer(hologram.getName(), uuid); + removeDistantViewer(hologram.getData().getName(), uuid); } public static void removeDistantViewer(String hologramName, UUID uuid) { @@ -74,7 +74,7 @@ public static void removeDistantViewer(String hologramName, UUID uuid) { } public static void remove(Hologram hologram) { - remove(hologram.getName()); + remove(hologram.getData().getName()); } public static void remove(String hologramName) { diff --git a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramHideEvent.java b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramDespawnEvent.java similarity index 82% rename from api/src/main/java/de/oliver/fancyholograms/api/events/HologramHideEvent.java rename to api/src/main/java/de/oliver/fancyholograms/api/events/HologramDespawnEvent.java index cdfb0a4d..549ddd0a 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramHideEvent.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramDespawnEvent.java @@ -9,7 +9,7 @@ /** * Called when a hologram is being hidden from a player */ -public final class HologramHideEvent extends HologramEvent { +public final class HologramDespawnEvent extends HologramEvent { private static final HandlerList handlerList = new HandlerList(); @@ -17,7 +17,7 @@ public final class HologramHideEvent extends HologramEvent { @NotNull private final Player player; - public HologramHideEvent(@NotNull final Hologram hologram, @NotNull final Player player) { + public HologramDespawnEvent(@NotNull final Hologram hologram, @NotNull final Player player) { super(hologram, !Bukkit.isPrimaryThread()); this.player = player; diff --git a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramShowEvent.java b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramSpawnEvent.java similarity index 82% rename from api/src/main/java/de/oliver/fancyholograms/api/events/HologramShowEvent.java rename to api/src/main/java/de/oliver/fancyholograms/api/events/HologramSpawnEvent.java index 88e02927..2a432f15 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramShowEvent.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramSpawnEvent.java @@ -9,7 +9,7 @@ /** * Called when a hologram is being shown to a player */ -public final class HologramShowEvent extends HologramEvent { +public final class HologramSpawnEvent extends HologramEvent { private static final HandlerList handlerList = new HandlerList(); @@ -17,7 +17,7 @@ public final class HologramShowEvent extends HologramEvent { @NotNull private final Player player; - public HologramShowEvent(@NotNull final Hologram hologram, @NotNull final Player player) { + public HologramSpawnEvent(@NotNull final Hologram hologram, @NotNull final Player player) { super(hologram, !Bukkit.isPrimaryThread()); this.player = player; diff --git a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsUnloadedEvent.java b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsLoadEvent.java similarity index 51% rename from api/src/main/java/de/oliver/fancyholograms/api/events/HologramsUnloadedEvent.java rename to api/src/main/java/de/oliver/fancyholograms/api/events/HologramsLoadEvent.java index a3711f7a..916255ba 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsUnloadedEvent.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsLoadEvent.java @@ -7,13 +7,23 @@ import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; -public final class HologramsUnloadedEvent extends Event { +/** + * Represents an event triggered when all holograms are loaded. + * This event contains a list of all holograms that have been loaded in the current context. + * The event is asynchronous if it does not execute on the main server thread. + *

+ * This event may serve as a notification mechanism to inform listeners that the loading operation + * for holograms has completed. + *

+ * This event extends the {@link Event} class, utilizing the Bukkit event system. + */ +public final class HologramsLoadEvent extends Event { private static final HandlerList handlerList = new HandlerList(); private final ImmutableList holograms; - public HologramsUnloadedEvent(@NotNull final ImmutableList holograms) { + public HologramsLoadEvent(@NotNull final ImmutableList holograms) { super(!Bukkit.isPrimaryThread()); this.holograms = holograms; @@ -23,7 +33,7 @@ public static HandlerList getHandlerList() { return handlerList; } - public @NotNull ImmutableList getManager() { + public @NotNull ImmutableList getHolograms() { return this.holograms; } diff --git a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsLoadedEvent.java b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsUnloadEvent.java similarity index 65% rename from api/src/main/java/de/oliver/fancyholograms/api/events/HologramsLoadedEvent.java rename to api/src/main/java/de/oliver/fancyholograms/api/events/HologramsUnloadEvent.java index 31b2ead6..cacc9d4a 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsLoadedEvent.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/events/HologramsUnloadEvent.java @@ -7,13 +7,19 @@ import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; -public final class HologramsLoadedEvent extends Event { +/** + * Represents an event that is triggered when holograms are unloaded in the system. + * This event contains the list of holograms that are being unloaded. + *

+ * This event is not cancellable. + */ +public final class HologramsUnloadEvent extends Event { private static final HandlerList handlerList = new HandlerList(); private final ImmutableList holograms; - public HologramsLoadedEvent(@NotNull final ImmutableList holograms) { + public HologramsUnloadEvent(@NotNull final ImmutableList holograms) { super(!Bukkit.isPrimaryThread()); this.holograms = holograms; @@ -23,7 +29,7 @@ public static HandlerList getHandlerList() { return handlerList; } - public @NotNull ImmutableList getManager() { + public @NotNull ImmutableList getHolograms() { return this.holograms; } diff --git a/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java b/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java index e9f2319c..4bceeb39 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java +++ b/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java @@ -1,32 +1,28 @@ package de.oliver.fancyholograms.api.hologram; +import com.google.common.collect.Sets; +import de.oliver.fancyholograms.api.FancyHolograms; import de.oliver.fancyholograms.api.data.HologramData; import de.oliver.fancyholograms.api.data.TextHologramData; -import de.oliver.fancyholograms.api.data.property.Visibility; +import de.oliver.fancyholograms.api.trait.HologramTrait; +import de.oliver.fancyholograms.api.trait.HologramTraitTrait; import net.kyori.adventure.text.Component; -import org.bukkit.Bukkit; import org.bukkit.Color; -import org.bukkit.World; -import org.bukkit.entity.Display; import org.bukkit.entity.Player; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lushplugins.chatcolorhandler.ModernChatColorHandler; -import java.util.*; +import java.lang.reflect.InvocationTargetException; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import java.util.function.Consumer; + /** - * Abstract base class for creating, updating, and managing holograms. - *

- * This class provides the basic functionality needed to work with holograms - * across multiple versions of Minecraft. To create a hologram specific to a version of Minecraft, - * extend this class and implement the abstract methods. - *

- * Note that the specific way holograms are created, updated, and deleted - * will vary depending on the Minecraft version. - *

- * A Hologram object includes data about the hologram and maintains a set of players to whom the hologram is shown. + * This class provides core functionalities for managing viewers, spawning, despawning, and updating holograms. */ public abstract class Hologram { @@ -35,212 +31,56 @@ public abstract class Hologram { protected static final int MINIMUM_PROTOCOL_VERSION = 762; protected final @NotNull HologramData data; - /** - * Set of UUIDs of players to whom the hologram is currently shown. - */ - protected final @NotNull Set viewers = new HashSet<>(); + protected final @NotNull Set viewers; + protected final @NotNull HologramTraitTrait traitTrait; protected Hologram(@NotNull final HologramData data) { this.data = data; + this.viewers = new HashSet<>(); + this.traitTrait = new HologramTraitTrait(this); } - @NotNull - public String getName() { - return data.getName(); - } - - public final @NotNull HologramData getData() { - return this.data; - } - - /** - * Returns the entity id of this hologram - * This id is for packet use only as the entity is not registered to the server - * @return entity id - */ - public abstract int getEntityId(); - /** - * Returns the Display entity of this Hologram object. - * The entity is not registered in the world or server. - * Only use this method if you know what you're doing. - *

- * This method will return null in 1.20.5 and newer versions + * Forcefully spawns the hologram and makes it visible to the specified player. * - * @return the Display entity of this Hologram object + * @param player the player to whom the hologram should be shown; must not be null */ @ApiStatus.Internal - @Deprecated(forRemoval = true, since = "2.4.1") - public abstract @Nullable Display getDisplayEntity(); - - protected abstract void create(); - - protected abstract void delete(); - - protected abstract void update(); - - protected abstract boolean show(@NotNull final Player player); - - protected abstract boolean hide(@NotNull final Player player); - - protected abstract void refresh(@NotNull final Player player); - - /** - * Create the hologram entity. - * Only run this if creating custom Hologram implementations as this is run in - * {@link de.oliver.fancyholograms.api.HologramManager#create(HologramData)}. - */ - public final void createHologram() { - create(); - } - - /** - * Deletes the hologram entity. - */ - public final void deleteHologram() { - delete(); - } - - /** - * Shows the hologram to a collection of players. - * Use {@link #forceShowHologram(Player)} if this hologram is not registered to the HologramManager. - * - * @param players The players to show the hologram to - */ - public final void showHologram(Collection players) { - players.forEach(this::showHologram); - } - - /** - * Shows the hologram to a player. - * Use {@link #forceShowHologram(Player)} if this hologram is not registered to the HologramManager. - * - * @param player The player to show the hologram to - */ - public final void showHologram(Player player) { - viewers.add(player.getUniqueId()); - } - - /** - * Forcefully shows the hologram to a player. - * - * @param player The player to show the hologram to - */ - public final void forceShowHologram(Player player) { - show(player); - - if (this.getData().getVisibility().equals(Visibility.MANUAL)) { - Visibility.ManualVisibility.addDistantViewer(this, player.getUniqueId()); - } - } - - /** - * Hides the hologram from a collection of players. - * Use {@link #forceHideHologram(Player)} if this hologram is not registered to the HologramManager. - * - * @param players The players to hide the hologram from - */ - public final void hideHologram(Collection players) { - players.forEach(this::hideHologram); - } - - /** - * Hides the hologram from a player. - * Use {@link #forceHideHologram(Player)} if this hologram is not registered to the HologramManager. - * - * @param player The player to hide the hologram from - */ - public final void hideHologram(Player player) { - viewers.remove(player.getUniqueId()); - } + public abstract void spawnTo(@NotNull final Player player); /** - * Forcefully hides the hologram from a player. + * Forcefully despawns the hologram and makes it invisible to the specified player. * - * @param player The player to show the hologram to + * @param player the player from whom the hologram should be hidden; must not be null */ - public final void forceHideHologram(Player player) { - hide(player); - - if (this.getData().getVisibility().equals(Visibility.MANUAL)) { - Visibility.ManualVisibility.removeDistantViewer(this, player.getUniqueId()); - } - } + @ApiStatus.Internal + public abstract void despawnFrom(@NotNull final Player player); /** - * Queues hologram to update and refresh for players. + * Updates the hologram for the specified player. * - * @deprecated in favour of {@link #queueUpdate()} - */ - @Deprecated(forRemoval = true) - public final void updateHologram() { - queueUpdate(); - } - - /** - * Queues hologram to update and refresh for players - * Use {@link #forceUpdate()} if this hologram is not registered to the HologramManager. - */ - public final void queueUpdate() { - data.setHasChanges(true); - } - - /** - * Forcefully updates and refreshes hologram for players. + * @param player the player for whom the hologram should be updated; must not be null */ - public final void forceUpdate() { - update(); - } - - /** - * Refreshes the hologram for the players currently viewing it. - */ - public void refreshForViewers() { - final var players = getViewers() - .stream() - .map(Bukkit::getPlayer) - .toList(); - - refreshHologram(players); - } - - /** - * Refreshes the hologram for players currently viewing it in the same world as the hologram. - */ - public void refreshForViewersInWorld() { - World world = data.getLocation().getWorld(); - final var players = getViewers() - .stream() - .map(Bukkit::getPlayer) - .filter(player -> player != null && player.getWorld().equals(world)) - .toList(); + @ApiStatus.Internal + public abstract void updateFor(@NotNull final Player player); - refreshHologram(players); - } /** - * Refreshes the hologram's data for a player. - * - * @param player the player to refresh for + * @return a copy of the set of UUIDs of players currently viewing the hologram */ - public final void refreshHologram(@NotNull final Player player) { - refresh(player); + public final @NotNull Set getViewers() { + return Sets.newHashSet(this.viewers); } - /** - * Refreshes the hologram's data for a collection of players. - * - * @param players the collection of players to refresh for - */ - public final void refreshHologram(@NotNull final Collection players) { - players.forEach(this::refreshHologram); + @ApiStatus.Internal + public void setViewers(@NotNull final Set viewers) { + this.viewers.clear(); + this.viewers.addAll(viewers); } - /** - * @return a copy of the set of UUIDs of players currently viewing the hologram - */ - public final @NotNull Set getViewers() { - return new HashSet<>(this.viewers); + @ApiStatus.Internal + public void removeViewer(@NotNull final UUID viewer) { + this.viewers.remove(viewer); } /** @@ -259,84 +99,77 @@ public final boolean isViewer(@NotNull final UUID player) { return this.viewers.contains(player); } - protected boolean shouldShowTo(@NotNull final Player player) { - if (!meetsVisibilityConditions(player)) { - return false; - } - - return isWithinVisibilityDistance(player); + @ApiStatus.Experimental + public @NotNull HologramTraitTrait getTraitTrait() { + return traitTrait; } - public boolean meetsVisibilityConditions(@NotNull final Player player) { - return this.getData().getVisibility().canSee(player, this); + @ApiStatus.Experimental + public HologramData addTrait(HologramTrait trait) { + traitTrait.addTrait(trait); + return data; } - public boolean isWithinVisibilityDistance(@NotNull final Player player) { - final var location = getData().getLocation(); - if (!location.getWorld().equals(player.getWorld())) { - return false; + @ApiStatus.Experimental + public HologramData addTrait(Class traitClass) { + HologramTrait trait = null; + try { + trait = traitClass.getConstructor(null).newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | + NoSuchMethodException e) { + FancyHolograms.get().getFancyLogger().error("Failed to instantiate trait " + traitClass.getSimpleName()); + FancyHolograms.get().getFancyLogger().error(e); } - int visibilityDistance = data.getVisibilityDistance(); - double distanceSquared = location.distanceSquared(player.getLocation()); + traitTrait.addTrait(trait); + return data; + } - return distanceSquared <= visibilityDistance * visibilityDistance; + public final @NotNull HologramData getData() { + return this.data; } /** - * Checks and updates the shown state for a player. - * If the hologram is shown and should not be, it hides it. - * If the hologram is not shown and should be, it shows it. - * Use {@link #forceUpdateShownStateFor(Player)} if this hologram is not registered to the HologramManager. + * Retrieves the data associated with the hologram and casts it to the specified type. * - * @param player the player to check and update the shown state for + * @param the type of {@code HologramData} to retrieve + * @param clazz the class of the data type to retrieve; must not be null + * @return the hologram data cast to the specified type */ - public void updateShownStateFor(Player player) { - boolean isShown = isViewer(player); - boolean shouldBeShown = shouldShowTo(player); + @ApiStatus.Experimental + public final @NotNull T getData(@NotNull Class clazz) { + return clazz.cast(this.data); + } - if (isShown && !shouldBeShown) { - showHologram(player); - } else if (!isShown && shouldBeShown) { - hideHologram(player); + /** + * Retrieves the data associated with the hologram, if it can be cast to the specified type. + * + * @param the type of {@code HologramData} + * @param clazz the class of the data type to retrieve; must not be null + * @return the hologram data cast to the specified type, or null if the cast fails + */ + @ApiStatus.Experimental + public final @Nullable T getDataNullable(@NotNull Class clazz) { + try { + return clazz.cast(this.data); + } catch (ClassCastException ignored) { + return null; } } /** - * Checks and forcefully updates the shown state for a player. - * If the hologram is shown and should not be, it hides it. - * If the hologram is not shown and should be, it shows it. + * Consumes the data associated with the hologram if it can be cast to the specified type. * - * @param player the player to check and update the shown state for + * @param the type of {@link HologramData} to consume + * @param clazz the class of the data type to consume; must not be null + * @param consumer the action to perform with the consumed data; must not be null */ - public void forceUpdateShownStateFor(Player player) { - boolean isShown = isViewer(player); - - if (meetsVisibilityConditions(player)) { - if (isWithinVisibilityDistance(player)) { - // Ran if the player meets the visibility conditions and is within visibility distance - if (!isShown) { - show(player); + @ApiStatus.Experimental + public final void consumeData(@NotNull Class clazz, @NotNull Consumer consumer) { + final T data = getDataNullable(clazz); - if (getData().getVisibility().equals(Visibility.MANUAL)) { - Visibility.ManualVisibility.removeDistantViewer(this, player.getUniqueId()); - } - } - } else { - // Ran if the player meets the visibility conditions but is not within visibility distance - if (isShown) { - hide(player); - - if (getData().getVisibility().equals(Visibility.MANUAL)) { - Visibility.ManualVisibility.addDistantViewer(this, player.getUniqueId()); - } - } - } - } else { - // Ran if the player does not meet visibility conditions - if (isShown) { - hide(player); - } + if (data != null) { + consumer.accept(data); } } @@ -356,17 +189,4 @@ public final Component getShownText(@Nullable final Player player) { return ModernChatColorHandler.translate(text, player); } - - @Override - public final boolean equals(@Nullable final Object o) { - if (this == o) return true; - if (!(o instanceof Hologram that)) return false; - - return Objects.equals(this.getData(), that.getData()); - } - - @Override - public final int hashCode() { - return Objects.hash(this.getData()); - } } diff --git a/api/src/main/java/de/oliver/fancyholograms/api/trait/DefaultTrait.java b/api/src/main/java/de/oliver/fancyholograms/api/trait/DefaultTrait.java new file mode 100644 index 00000000..fd4db755 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/trait/DefaultTrait.java @@ -0,0 +1,8 @@ +package de.oliver.fancyholograms.api.trait; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface DefaultTrait { +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTrait.java b/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTrait.java new file mode 100644 index 00000000..cbbabd99 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTrait.java @@ -0,0 +1,106 @@ +package de.oliver.fancyholograms.api.trait; + +import de.oliver.fancyanalytics.logger.ExtendedFancyLogger; +import de.oliver.fancyholograms.api.FancyHolograms; +import de.oliver.fancyholograms.api.HologramController; +import de.oliver.fancyholograms.api.HologramRegistry; +import de.oliver.fancyholograms.api.hologram.Hologram; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.ApiStatus; + +import java.util.concurrent.ScheduledExecutorService; + +/** + * Represents a trait that can be attached to a hologram. This class provides a structure for + * managing the lifecycle of traits related to holograms. It defines methods to handle + * initialization, attachment, updates, and data persistence. + *

+ * Subclasses of this abstract class must implement the specific behavior of the trait by + * overriding the provided lifecycle methods. + */ +@ApiStatus.Experimental +public abstract class HologramTrait { + + protected final String name; + protected final FancyHolograms api = FancyHolograms.get(); + protected final ExtendedFancyLogger logger = api.getFancyLogger(); + protected final HologramController controller = api.getController(); + protected final HologramRegistry registry = api.getRegistry(); + protected final ScheduledExecutorService hologramThread = api.getHologramThread(); + protected Hologram hologram; + + + /** + * Creates a new hologram trait with the given name. + * @param name the name of the trait + */ + public HologramTrait(String name) { + this.name = name; + } + + public HologramTrait() { + this.name = getClass().getSimpleName(); + } + + public void attachHologram(Hologram hologram) { + if (this.hologram != null) { + throw new IllegalStateException("Trait is already attached to a hologram"); + } + + this.hologram = hologram; + } + + /** + * Called when the trait is attached to a hologram. + * The hologram is available at this point. + */ + public void onAttach() { + } + + /** + * Called when the hologram is spawned to a player. + */ + public void onSpawn(Player player) { + } + + /** + * Called when the hologram is despawned from a player. + */ + public void onDespawn(Player player) { + } + + /** + * Called when the hologram is registered in the registry. + */ + public void onRegister() { + + } + + /** + * Called when the hologram is unregistered from the registry. + */ + public void onUnregister() { + } + + /** + * Called when the hologram is being loaded. + * In this method you should load all necessary data for the trait. + */ + public void load() { + } + + /** + * Called when the hologram is being saved. + * In this method you should save all necessary data for the trait. + */ + public void save() { + } + + public String getName() { + return name; + } + + public Hologram getHologram() { + return hologram; + } +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTraitRegistry.java b/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTraitRegistry.java new file mode 100644 index 00000000..9936c7a9 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTraitRegistry.java @@ -0,0 +1,21 @@ +package de.oliver.fancyholograms.api.trait; + +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; + +@ApiStatus.Experimental +public interface HologramTraitRegistry { + + @ApiStatus.Experimental + boolean register(Class trait); + + @ApiStatus.Experimental + boolean unregister(Class trait); + + @ApiStatus.Experimental + boolean isRegistered(Class trait); + + @ApiStatus.Experimental + List> getRegisteredTraits(); +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTraitTrait.java b/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTraitTrait.java new file mode 100644 index 00000000..cb4b9362 --- /dev/null +++ b/api/src/main/java/de/oliver/fancyholograms/api/trait/HologramTraitTrait.java @@ -0,0 +1,86 @@ +package de.oliver.fancyholograms.api.trait; + +import de.oliver.fancyholograms.api.hologram.Hologram; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class HologramTraitTrait extends HologramTrait { + + private final List traits; + + public HologramTraitTrait(Hologram hologram) { + super("trait"); + attachHologram(hologram); + this.traits = new ArrayList<>(); + } + + public void addTrait(HologramTrait trait) { + this.traits.add(trait); + trait.attachHologram(hologram); + trait.onAttach(); + } + + @Override + public void onAttach() { + List> registeredTraits = api.getTraitRegistry().getRegisteredTraits(); + for (Class traitClass : registeredTraits) { + if (!traitClass.isAnnotationPresent(DefaultTrait.class)) { + continue; + } + + try { + HologramTrait trait = traitClass.getConstructor().newInstance(); + this.traits.add(trait); + logger.debug("Attached default trait " + traitClass.getName() + " to hologram " + hologram.getData().getName()); + trait.onAttach(); + } catch (Exception e) { + logger.error("Failed to instantiate trait " + traitClass.getName()); + logger.error(e); + } + } + } + + @Override + public void onSpawn(Player player) { + for (HologramTrait trait : this.traits) { + trait.onSpawn(player); + } + } + + @Override + public void onDespawn(Player player) { + for (HologramTrait trait : this.traits) { + trait.onDespawn(player); + } + } + + @Override + public void onRegister() { + for (HologramTrait trait : this.traits) { + trait.onRegister(); + } + } + + @Override + public void onUnregister() { + for (HologramTrait trait : this.traits) { + trait.onUnregister(); + } + } + + @Override + public void load() { + for (HologramTrait trait : this.traits) { + trait.load(); + } + } + + @Override + public void save() { + for (HologramTrait trait : this.traits) { + trait.save(); + } + } +} diff --git a/build.gradle.kts b/build.gradle.kts index 7666c09b..ef3bc206 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -70,13 +70,14 @@ dependencies { compileOnly("de.oliver:FancyNpcs:2.4.2") compileOnly("org.lushplugins:ChatColorHandler:5.1.2") + compileOnly("com.viaversion:viaversion-api:5.2.0") compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT") } paper { - main = "de.oliver.fancyholograms.FancyHolograms" - bootstrapper = "de.oliver.fancyholograms.loaders.FancyHologramsBootstrapper" - loader = "de.oliver.fancyholograms.loaders.FancyHologramsLoader" + main = "de.oliver.fancyholograms.main.FancyHologramsPlugin" + bootstrapper = "de.oliver.fancyholograms.main.FancyHologramsBootstrapper" + loader = "de.oliver.fancyholograms.main.FancyHologramsLoader" foliaSupported = true version = rootProject.version.toString() description = "Simple, lightweight and fast hologram plugin using display entities" @@ -100,6 +101,11 @@ paper { load = PaperPluginDescription.RelativeLoadOrder.BEFORE joinClasspath = true } + register("ViaVersion") { + required = false + load = PaperPluginDescription.RelativeLoadOrder.BEFORE + joinClasspath = true + } } } diff --git a/implementation_1_19_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_19_4.java b/implementation_1_19_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_19_4.java index 74837bd9..2179fba4 100644 --- a/implementation_1_19_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_19_4.java +++ b/implementation_1_19_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_19_4.java @@ -2,8 +2,8 @@ import com.mojang.math.Transformation; import de.oliver.fancyholograms.api.data.*; -import de.oliver.fancyholograms.api.events.HologramHideEvent; -import de.oliver.fancyholograms.api.events.HologramShowEvent; +import de.oliver.fancyholograms.api.events.HologramDespawnEvent; +import de.oliver.fancyholograms.api.events.HologramSpawnEvent; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancylib.ReflectionUtils; import io.papermc.paper.adventure.PaperAdventure; @@ -43,19 +43,10 @@ public final class Hologram1_19_4 extends Hologram { public Hologram1_19_4(@NotNull final HologramData data) { super(data); - } - @Override - public int getEntityId() { - return display.getId(); + create(); } - @Override - public @Nullable org.bukkit.entity.Display getDisplayEntity() { - return display != null ? (org.bukkit.entity.Display) display.getBukkitEntity() : null; - } - - @Override public void create() { final var location = data.getLocation(); if (location.getWorld() == null) { @@ -69,25 +60,9 @@ public void create() { case BLOCK -> this.display = new Display.BlockDisplay(EntityType.BLOCK_DISPLAY, world); case ITEM -> this.display = new Display.ItemDisplay(EntityType.ITEM_DISPLAY, world); } - - if (data instanceof DisplayHologramData dd) { - final var DATA_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_19_4.DATA_INTERPOLATION_DURATION_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_DURATION_ID, dd.getInterpolationDuration()); - - final var DATA_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_19_4.DATA_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_START_DELTA_TICKS_ID, 0); - } - - update(); } - @Override - public void delete() { - this.display = null; - } - - @Override - public void update() { + public void syncWithData() { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to update @@ -157,6 +132,13 @@ public void update() { } if (data instanceof DisplayHologramData displayData) { + // interpolation + final var DATA_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_19_4.DATA_INTERPOLATION_DURATION_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_DURATION_ID, displayData.getInterpolationDuration()); + + final var DATA_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_19_4.DATA_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_START_DELTA_TICKS_ID, 0); + // billboard data display.setBillboardConstraints(switch (displayData.getBillboard()) { case FIXED -> Display.BillboardConstraints.FIXED; @@ -189,9 +171,9 @@ public void update() { @Override - public boolean show(@NotNull final Player player) { - if (!new HologramShowEvent(this, player).callEvent()) { - return false; + public void spawnTo(@NotNull final Player player) { + if (!new HologramSpawnEvent(this, player).callEvent()) { + return; } if (this.display == null) { @@ -200,11 +182,11 @@ public boolean show(@NotNull final Player player) { final var display = this.display; if (display == null) { - return false; // could not be created, nothing to show + return; // could not be created, nothing to show } if (!data.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) { - return false; + return; } ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -218,31 +200,29 @@ public boolean show(@NotNull final Player player) { serverPlayer.connection.send(new ClientboundAddEntityPacket(display)); this.viewers.add(player.getUniqueId()); - refreshHologram(player); + updateFor(player); - return true; } @Override - public boolean hide(@NotNull final Player player) { - if (!new HologramHideEvent(this, player).callEvent()) { - return false; + public void despawnFrom(@NotNull final Player player) { + if (!new HologramDespawnEvent(this, player).callEvent()) { + return; } final var display = this.display; if (display == null) { - return false; // doesn't exist, nothing to hide + return; // doesn't exist, nothing to hide } ((CraftPlayer) player).getHandle().connection.send(new ClientboundRemoveEntitiesPacket(display.getId())); this.viewers.remove(player.getUniqueId()); - return true; } @Override - public void refresh(@NotNull final Player player) { + public void updateFor(@NotNull final Player player) { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to refresh @@ -252,6 +232,8 @@ public void refresh(@NotNull final Player player) { return; } + syncWithData(); + ((CraftPlayer) player).getHandle().connection.send(new ClientboundTeleportEntityPacket(display)); if (display instanceof TextDisplay textDisplay) { diff --git a/implementation_1_20_1/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_1.java b/implementation_1_20_1/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_1.java index d7afb5c9..19fb5467 100644 --- a/implementation_1_20_1/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_1.java +++ b/implementation_1_20_1/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_1.java @@ -2,8 +2,8 @@ import com.mojang.math.Transformation; import de.oliver.fancyholograms.api.data.*; -import de.oliver.fancyholograms.api.events.HologramHideEvent; -import de.oliver.fancyholograms.api.events.HologramShowEvent; +import de.oliver.fancyholograms.api.events.HologramDespawnEvent; +import de.oliver.fancyholograms.api.events.HologramSpawnEvent; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancylib.ReflectionUtils; import io.papermc.paper.adventure.PaperAdventure; @@ -43,22 +43,13 @@ public final class Hologram1_20_1 extends Hologram { public Hologram1_20_1(@NotNull final HologramData data) { super(data); - } - @Override - public int getEntityId() { - return display.getId(); + create(); } - @Override - public @Nullable org.bukkit.entity.Display getDisplayEntity() { - return display != null ? (org.bukkit.entity.Display) display.getBukkitEntity() : null; - } - - @Override public void create() { final var location = data.getLocation(); - if (!location.isWorldLoaded()) { + if (location.getWorld() == null) { return; // no location data, cannot be created } @@ -69,25 +60,9 @@ public void create() { case BLOCK -> this.display = new Display.BlockDisplay(EntityType.BLOCK_DISPLAY, world); case ITEM -> this.display = new Display.ItemDisplay(EntityType.ITEM_DISPLAY, world); } - - if (data instanceof DisplayHologramData dd){ - final var DATA_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_1.DATA_INTERPOLATION_DURATION_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_DURATION_ID, dd.getInterpolationDuration()); - - final var DATA_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_1.DATA_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_START_DELTA_TICKS_ID, 0); - } - - update(); } - @Override - public void delete() { - this.display = null; - } - - @Override - public void update() { + public void syncWithData() { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to update @@ -95,7 +70,7 @@ public void update() { // location data final var location = data.getLocation(); - if (location.getWorld() == null || !location.isWorldLoaded()) { + if (!location.isWorldLoaded()) { return; } else { display.setPosRaw(location.x(), location.y(), location.z()); @@ -157,6 +132,13 @@ public void update() { } if (data instanceof DisplayHologramData displayData) { + // interpolation + final var DATA_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_1.DATA_INTERPOLATION_DURATION_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_DURATION_ID, displayData.getInterpolationDuration()); + + final var DATA_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_1.DATA_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_START_DELTA_TICKS_ID, 0); + // billboard data display.setBillboardConstraints(switch (displayData.getBillboard()) { case FIXED -> Display.BillboardConstraints.FIXED; @@ -189,9 +171,9 @@ public void update() { @Override - public boolean show(@NotNull final Player player) { - if (!new HologramShowEvent(this, player).callEvent()) { - return false; + public void spawnTo(@NotNull final Player player) { + if (!new HologramSpawnEvent(this, player).callEvent()) { + return; } if (this.display == null) { @@ -200,11 +182,11 @@ public boolean show(@NotNull final Player player) { final var display = this.display; if (display == null) { - return false; // could not be created, nothing to show + return; // could not be created, nothing to show } if (!data.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) { - return false; + return; } ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -218,31 +200,29 @@ public boolean show(@NotNull final Player player) { serverPlayer.connection.send(new ClientboundAddEntityPacket(display)); this.viewers.add(player.getUniqueId()); - refreshHologram(player); + updateFor(player); - return true; } @Override - public boolean hide(@NotNull final Player player) { - if (!new HologramHideEvent(this, player).callEvent()) { - return false; + public void despawnFrom(@NotNull final Player player) { + if (!new HologramDespawnEvent(this, player).callEvent()) { + return; } final var display = this.display; if (display == null) { - return false; // doesn't exist, nothing to hide + return; // doesn't exist, nothing to hide } ((CraftPlayer) player).getHandle().connection.send(new ClientboundRemoveEntitiesPacket(display.getId())); this.viewers.remove(player.getUniqueId()); - return true; } @Override - public void refresh(@NotNull final Player player) { + public void updateFor(@NotNull final Player player) { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to refresh @@ -252,6 +232,8 @@ public void refresh(@NotNull final Player player) { return; } + syncWithData(); + ((CraftPlayer) player).getHandle().connection.send(new ClientboundTeleportEntityPacket(display)); if (display instanceof TextDisplay textDisplay) { diff --git a/implementation_1_20_2/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_2.java b/implementation_1_20_2/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_2.java index f7d248fe..e04b5ce5 100644 --- a/implementation_1_20_2/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_2.java +++ b/implementation_1_20_2/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_2.java @@ -2,8 +2,8 @@ import com.mojang.math.Transformation; import de.oliver.fancyholograms.api.data.*; -import de.oliver.fancyholograms.api.events.HologramHideEvent; -import de.oliver.fancyholograms.api.events.HologramShowEvent; +import de.oliver.fancyholograms.api.events.HologramDespawnEvent; +import de.oliver.fancyholograms.api.events.HologramSpawnEvent; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancylib.ReflectionUtils; import io.papermc.paper.adventure.PaperAdventure; @@ -43,22 +43,13 @@ public final class Hologram1_20_2 extends Hologram { public Hologram1_20_2(@NotNull final HologramData data) { super(data); - } - @Override - public int getEntityId() { - return display.getId(); + create(); } - @Override - public @Nullable org.bukkit.entity.Display getDisplayEntity() { - return display != null ? (org.bukkit.entity.Display) display.getBukkitEntity() : null; - } - - @Override public void create() { final var location = data.getLocation(); - if (!location.isWorldLoaded()) { + if (location.getWorld() == null) { return; // no location data, cannot be created } @@ -69,25 +60,9 @@ public void create() { case BLOCK -> this.display = new Display.BlockDisplay(EntityType.BLOCK_DISPLAY, world); case ITEM -> this.display = new Display.ItemDisplay(EntityType.ITEM_DISPLAY, world); } - - if (data instanceof DisplayHologramData dd) { - final var DATA_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_2.DATA_INTERPOLATION_DURATION_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_DURATION_ID, dd.getInterpolationDuration()); - - final var DATA_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_2.DATA_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_START_DELTA_TICKS_ID, 0); - } - - update(); } - @Override - public void delete() { - this.display = null; - } - - @Override - public void update() { + public void syncWithData() { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to update @@ -95,7 +70,7 @@ public void update() { // location data final var location = data.getLocation(); - if (location.getWorld() == null || !location.isWorldLoaded()) { + if (!location.isWorldLoaded()) { return; } else { display.setPosRaw(location.x(), location.y(), location.z()); @@ -109,7 +84,7 @@ public void update() { display.getEntityData().set((EntityDataAccessor) DATA_LINE_WIDTH_ID, Hologram.LINE_WIDTH); // background - final var DATA_BACKGROUND_COLOR_ID = ReflectionUtils.getStaticValue(TextDisplay.class, MappingKeys1_20_2.DATA_BACKGROUND_COLOR_ID.getMapping()); + final var DATA_BACKGROUND_COLOR_ID = ReflectionUtils.getStaticValue(TextDisplay.class, MappingKeys1_20_2.DATA_BACKGROUND_COLOR_ID.getMapping()); //DATA_BACKGROUND_COLOR_ID final var background = textData.getBackground(); if (background == null) { @@ -157,6 +132,13 @@ public void update() { } if (data instanceof DisplayHologramData displayData) { + // interpolation + final var DATA_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_2.DATA_INTERPOLATION_DURATION_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_DURATION_ID, displayData.getInterpolationDuration()); + + final var DATA_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_2.DATA_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_START_DELTA_TICKS_ID, 0); + // billboard data display.setBillboardConstraints(switch (displayData.getBillboard()) { case FIXED -> Display.BillboardConstraints.FIXED; @@ -189,9 +171,9 @@ public void update() { @Override - public boolean show(@NotNull final Player player) { - if (!new HologramShowEvent(this, player).callEvent()) { - return false; + public void spawnTo(@NotNull final Player player) { + if (!new HologramSpawnEvent(this, player).callEvent()) { + return; } if (this.display == null) { @@ -200,11 +182,11 @@ public boolean show(@NotNull final Player player) { final var display = this.display; if (display == null) { - return false; // could not be created, nothing to show + return; // could not be created, nothing to show } if (!data.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) { - return false; + return; } ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -218,31 +200,29 @@ public boolean show(@NotNull final Player player) { serverPlayer.connection.send(new ClientboundAddEntityPacket(display)); this.viewers.add(player.getUniqueId()); - refreshHologram(player); + updateFor(player); - return true; } @Override - public boolean hide(@NotNull final Player player) { - if (!new HologramHideEvent(this, player).callEvent()) { - return false; + public void despawnFrom(@NotNull final Player player) { + if (!new HologramDespawnEvent(this, player).callEvent()) { + return; } final var display = this.display; if (display == null) { - return false; // doesn't exist, nothing to hide + return; // doesn't exist, nothing to hide } ((CraftPlayer) player).getHandle().connection.send(new ClientboundRemoveEntitiesPacket(display.getId())); this.viewers.remove(player.getUniqueId()); - return true; } @Override - public void refresh(@NotNull final Player player) { + public void updateFor(@NotNull final Player player) { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to refresh @@ -252,6 +232,8 @@ public void refresh(@NotNull final Player player) { return; } + syncWithData(); + ((CraftPlayer) player).getHandle().connection.send(new ClientboundTeleportEntityPacket(display)); if (display instanceof TextDisplay textDisplay) { diff --git a/implementation_1_20_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_4.java b/implementation_1_20_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_4.java index 4f1faaea..1383fac3 100644 --- a/implementation_1_20_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_4.java +++ b/implementation_1_20_4/src/main/java/de/oliver/fancyholograms/hologram/version/Hologram1_20_4.java @@ -2,8 +2,8 @@ import com.mojang.math.Transformation; import de.oliver.fancyholograms.api.data.*; -import de.oliver.fancyholograms.api.events.HologramHideEvent; -import de.oliver.fancyholograms.api.events.HologramShowEvent; +import de.oliver.fancyholograms.api.events.HologramDespawnEvent; +import de.oliver.fancyholograms.api.events.HologramSpawnEvent; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancylib.ReflectionUtils; import io.papermc.paper.adventure.PaperAdventure; @@ -43,22 +43,13 @@ public final class Hologram1_20_4 extends Hologram { public Hologram1_20_4(@NotNull final HologramData data) { super(data); - } - - @Override - public int getEntityId() { - return display.getId(); - } - @Override - public @Nullable org.bukkit.entity.Display getDisplayEntity() { - return display != null ? (org.bukkit.entity.Display) display.getBukkitEntity() : null; + create(); } - @Override public void create() { final var location = data.getLocation(); - if (!location.isWorldLoaded()) { + if (location.getWorld() == null) { return; // no location data, cannot be created } @@ -69,25 +60,9 @@ public void create() { case BLOCK -> this.display = new Display.BlockDisplay(EntityType.BLOCK_DISPLAY, world); case ITEM -> this.display = new Display.ItemDisplay(EntityType.ITEM_DISPLAY, world); } - - if (data instanceof DisplayHologramData dd) { - final var DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_4.DISPLAY__DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID, dd.getInterpolationDuration()); - - final var DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_4.DISPLAY__DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); - display.getEntityData().set((EntityDataAccessor) DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID, 0); - } - - update(); } - @Override - public void delete() { - this.display = null; - } - - @Override - public void update() { + public void syncWithData() { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to update @@ -95,7 +70,7 @@ public void update() { // location data final var location = data.getLocation(); - if (location.getWorld() == null || !location.isWorldLoaded()) { + if (!location.isWorldLoaded()) { return; } else { display.setPosRaw(location.x(), location.y(), location.z()); @@ -109,7 +84,7 @@ public void update() { display.getEntityData().set((EntityDataAccessor) DATA_LINE_WIDTH_ID, Hologram.LINE_WIDTH); // background - final var DATA_BACKGROUND_COLOR_ID = ReflectionUtils.getStaticValue(TextDisplay.class, MappingKeys1_20_4.TEXT_DISPLAY__DATA_BACKGROUND_COLOR_ID.getMapping()); + final var DATA_BACKGROUND_COLOR_ID = ReflectionUtils.getStaticValue(TextDisplay.class, MappingKeys1_20_4.TEXT_DISPLAY__DATA_BACKGROUND_COLOR_ID.getMapping()); //DATA_BACKGROUND_COLOR_ID final var background = textData.getBackground(); if (background == null) { @@ -157,6 +132,13 @@ public void update() { } if (data instanceof DisplayHologramData displayData) { + // interpolation + final var DATA_INTERPOLATION_DURATION_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_4.DISPLAY__DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_DURATION_ID, displayData.getInterpolationDuration()); + + final var DATA_INTERPOLATION_START_DELTA_TICKS_ID = ReflectionUtils.getStaticValue(Display.class, MappingKeys1_20_4.DISPLAY__DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID.getMapping()); + display.getEntityData().set((EntityDataAccessor) DATA_INTERPOLATION_START_DELTA_TICKS_ID, 0); + // billboard data display.setBillboardConstraints(switch (displayData.getBillboard()) { case FIXED -> Display.BillboardConstraints.FIXED; @@ -189,9 +171,9 @@ public void update() { @Override - public boolean show(@NotNull final Player player) { - if (!new HologramShowEvent(this, player).callEvent()) { - return false; + public void spawnTo(@NotNull final Player player) { + if (!new HologramSpawnEvent(this, player).callEvent()) { + return; } if (this.display == null) { @@ -200,50 +182,47 @@ public boolean show(@NotNull final Player player) { final var display = this.display; if (display == null) { - return false; // could not be created, nothing to show + return; // could not be created, nothing to show } if (!data.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) { - return false; + return; } ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); // TODO: cache player protocol version // TODO: fix this -// final var protocolVersion = FancyHologramsPlugin.get().isUsingViaVersion() ? Via.getAPI().getPlayerVersion(player.getUniqueId()) : MINIMUM_PROTOCOL_VERSION; +// final var protocolVersion = FancyHologramsPlugin.get().isUsingViaVersion() ? Via.getAPI().getPlayerVersion(player) : MINIMUM_PROTOCOL_VERSION; // if (protocolVersion < MINIMUM_PROTOCOL_VERSION) { -// System.out.println("nope protocol"); // return false; // } serverPlayer.connection.send(new ClientboundAddEntityPacket(display)); this.viewers.add(player.getUniqueId()); - refreshHologram(player); + updateFor(player); - return true; } @Override - public boolean hide(@NotNull final Player player) { - if (!new HologramHideEvent(this, player).callEvent()) { - return false; + public void despawnFrom(@NotNull final Player player) { + if (!new HologramDespawnEvent(this, player).callEvent()) { + return; } final var display = this.display; if (display == null) { - return false; // doesn't exist, nothing to hide + return; // doesn't exist, nothing to hide } ((CraftPlayer) player).getHandle().connection.send(new ClientboundRemoveEntitiesPacket(display.getId())); this.viewers.remove(player.getUniqueId()); - return true; } @Override - public void refresh(@NotNull final Player player) { + public void updateFor(@NotNull final Player player) { final var display = this.display; if (display == null) { return; // doesn't exist, nothing to refresh @@ -253,6 +232,8 @@ public void refresh(@NotNull final Player player) { return; } + syncWithData(); + ((CraftPlayer) player).getHandle().connection.send(new ClientboundTeleportEntityPacket(display)); if (display instanceof TextDisplay textDisplay) { diff --git a/src/main/java/de/oliver/fancyholograms/HologramManagerImpl.java b/src/main/java/de/oliver/fancyholograms/HologramManagerImpl.java deleted file mode 100644 index dd543b65..00000000 --- a/src/main/java/de/oliver/fancyholograms/HologramManagerImpl.java +++ /dev/null @@ -1,313 +0,0 @@ -package de.oliver.fancyholograms; - -import com.google.common.cache.CacheBuilder; -import com.google.common.collect.ImmutableList; -import de.oliver.fancyholograms.api.HologramManager; -import de.oliver.fancyholograms.api.data.DisplayHologramData; -import de.oliver.fancyholograms.api.data.HologramData; -import de.oliver.fancyholograms.api.data.TextHologramData; -import de.oliver.fancyholograms.api.events.HologramsLoadedEvent; -import de.oliver.fancyholograms.api.events.HologramsUnloadedEvent; -import de.oliver.fancyholograms.api.hologram.Hologram; -import de.oliver.fancynpcs.api.FancyNpcsPlugin; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.UnmodifiableView; -import org.joml.Vector3f; - -import java.time.Duration; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; - -/** - * The FancyHologramsManager class is responsible for managing holograms in the FancyHolograms plugin. - * It provides methods for adding, removing, and retrieving holograms, as well as other related operations. - */ -public final class HologramManagerImpl implements HologramManager { - - private final @NotNull FancyHolograms plugin; - /** - * The adapter function used to create holograms from hologram data. - */ - private final @NotNull Function adapter; - /** - * A map of hologram names to their corresponding hologram instances. - */ - private final Map holograms = new ConcurrentHashMap<>(); - /** - * Whether holograms are loaded or not - */ - private boolean isLoaded = false; - - HologramManagerImpl(@NotNull final FancyHolograms plugin, @NotNull final Function adapter) { - this.plugin = plugin; - this.adapter = adapter; - } - - /** - * @return A read-only collection of loaded holograms. - */ - @Override - public @NotNull - @UnmodifiableView Collection getHolograms() { - return Collections.unmodifiableCollection(this.holograms.values()); - } - - /** - * Returns a read-only view of the currently loaded persistent holograms. - * - * @return A read-only collection of holograms. - */ - @Override - public @NotNull - @UnmodifiableView Collection getPersistentHolograms() { - return this.holograms.values().stream().filter(hologram -> hologram.getData().isPersistent()).toList(); - } - - - /** - * Finds a hologram by name. - * - * @param name The name of the hologram to lookup. - * @return An optional containing the found hologram, or empty if not found. - */ - public @NotNull Optional getHologram(@NotNull final String name) { - return Optional.ofNullable(this.holograms.get(name.toLowerCase(Locale.ROOT))); - } - - /** - * Adds a hologram to this manager. - * - * @param hologram The hologram to add. - */ - public void addHologram(@NotNull final Hologram hologram) { - this.holograms.put(hologram.getData().getName().toLowerCase(Locale.ROOT), hologram); - } - - /** - * Removes a hologram from this manager. - * - * @param hologram The hologram to remove. - */ - public void removeHologram(@NotNull final Hologram hologram) { - removeHologram(hologram.getData().getName()); - } - - /** - * Removes a hologram from this manager by name. - * - * @param name The name of the hologram to remove. - * @return An optional containing the removed hologram, or empty if not found. - */ - public @NotNull Optional removeHologram(@NotNull final String name) { - Optional optionalHologram = Optional.ofNullable(this.holograms.remove(name.toLowerCase(Locale.ROOT))); - - optionalHologram.ifPresent(hologram -> { - for (UUID viewer : hologram.getViewers()) { - Player player = Bukkit.getPlayer(viewer); - if (player != null) { - FancyHolograms.get().getHologramThread().submit(() -> hologram.forceHideHologram(player)); - } - } - - FancyHolograms.get().getHologramThread().submit(() -> plugin.getHologramStorage().delete(hologram)); - } - ); - - return optionalHologram; - } - - /** - * Creates a new hologram with the specified hologram data. - * - * @param data The hologram data for the new hologram. - * @return The created hologram. - */ - public @NotNull Hologram create(@NotNull final HologramData data) { - Hologram hologram = this.adapter.apply(data); - hologram.createHologram(); - return hologram; - } - - public void saveHolograms() { - if (!isLoaded) { - return; - } - - plugin.getHologramStorage().saveBatch(getPersistentHolograms(), false); - } - - @Override - public void loadHolograms() { - List allLoaded = new ArrayList<>(); - - for (World world : Bukkit.getWorlds()) { - Collection loaded = plugin.getHologramStorage().loadAll(world.getName()); - loaded.forEach(this::addHologram); - - allLoaded.addAll(loaded); - } - isLoaded = true; - - FancyHolograms.get().getHologramThread().submit(() -> Bukkit.getPluginManager().callEvent(new HologramsLoadedEvent(ImmutableList.copyOf(allLoaded)))); - - FancyHolograms.get().getFancyLogger().info(String.format("Loaded %d holograms for all loaded worlds", allLoaded.size())); - } - - public void loadHolograms(String world) { - ImmutableList loaded = ImmutableList.copyOf(plugin.getHologramStorage().loadAll(world)); - loaded.forEach(this::addHologram); - - isLoaded = true; - - Bukkit.getPluginManager().callEvent(new HologramsLoadedEvent(ImmutableList.copyOf(loaded))); - - FancyHolograms.get().getFancyLogger().info(String.format("Loaded %d holograms for world %s", loaded.size(), world)); - } - - /** - * Initializes tasks for managing holograms, such as loading and refreshing them. - *

- * This method is intended to be called internally by the plugin. - */ - void initializeTasks() { - ScheduledExecutorService hologramThread = plugin.getHologramThread(); - hologramThread.submit(() -> { - loadHolograms(); - - hologramThread.scheduleAtFixedRate(() -> { - for (final Hologram hologram : this.plugin.getHologramsManager().getHolograms()) { - for (final Player player : Bukkit.getOnlinePlayers()) { - hologram.forceUpdateShownStateFor(player); - } - } - }, 0, 1, TimeUnit.SECONDS); - }); - - final var updateTimes = CacheBuilder.newBuilder() - .expireAfterAccess(Duration.ofMinutes(5)) - .build(); - - hologramThread.scheduleAtFixedRate(() -> { - final var time = System.currentTimeMillis(); - - for (final var hologram : getHolograms()) { - HologramData data = hologram.getData(); - if (data.hasChanges()) { - hologram.forceUpdate(); - hologram.refreshForViewersInWorld(); - data.setHasChanges(false); - - if (data instanceof TextHologramData) { - updateTimes.put(hologram.getData().getName(), time); - } - } - } - }, 50, 1000, TimeUnit.MILLISECONDS); - - hologramThread.scheduleWithFixedDelay(() -> { - final var time = System.currentTimeMillis(); - - for (final var hologram : getHolograms()) { - if (hologram.getData() instanceof TextHologramData textData) { - final var interval = textData.getTextUpdateInterval(); - if (interval < 1) { - continue; // doesn't update - } - - final var lastUpdate = updateTimes.asMap().get(textData.getName()); - if (lastUpdate != null && time < (lastUpdate + interval)) { - continue; - } - - if (lastUpdate == null || time > (lastUpdate + interval)) { - hologram.refreshForViewersInWorld(); - updateTimes.put(textData.getName(), time); - } - } - } - }, 50, 50, TimeUnit.MILLISECONDS); - } - - /** - * Reloads holograms by clearing the existing holograms and loading them again from the plugin's configuration. - */ - public void reloadHolograms() { - unloadHolograms(); - loadHolograms(); - } - - public void unloadHolograms() { - FancyHolograms.get().getHologramThread().submit(() -> { - List unloaded = new ArrayList<>(); - - for (final var hologram : this.getPersistentHolograms()) { - this.holograms.remove(hologram.getName()); - unloaded.add(hologram); - - for (UUID viewer : hologram.getViewers()) { - Player player = Bukkit.getPlayer(viewer); - if (player != null) { - hologram.forceHideHologram(player); - } - } - } - - Bukkit.getPluginManager().callEvent(new HologramsUnloadedEvent(ImmutableList.copyOf(unloaded))); - }); - } - - public void unloadHolograms(String world) { - final var online = List.copyOf(Bukkit.getOnlinePlayers()); - - FancyHolograms.get().getHologramThread().submit(() -> { - List h = getPersistentHolograms().stream() - .filter(hologram -> hologram.getData().getLocation().getWorld().getName().equals(world)) - .toList(); - - FancyHolograms.get().getHologramStorage().saveBatch(h, false); - - for (final Hologram hologram : h) { - this.holograms.remove(hologram.getName()); - online.forEach(hologram::forceHideHologram); - } - - Bukkit.getPluginManager().callEvent(new HologramsUnloadedEvent(ImmutableList.copyOf(h))); - }); - } - - /** - * Syncs a hologram with its linked NPC, if any. - * - * @param hologram The hologram to sync. - */ - public void syncHologramWithNpc(@NotNull final Hologram hologram) { - final var linkedNpcName = hologram.getData().getLinkedNpcName(); - if (linkedNpcName == null) { - return; - } - - final var npc = FancyNpcsPlugin.get().getNpcManager().getNpc(linkedNpcName); - if (npc == null) { - return; - } - - npc.getData().setDisplayName(""); - npc.getData().setShowInTab(false); - npc.updateForAll(); - - final var npcScale = npc.getData().getScale(); - - if (hologram.getData() instanceof DisplayHologramData displayData) { - displayData.setScale(new Vector3f(npcScale)); - } - - final var location = npc.getData().getLocation().clone().add(0, (npc.getEyeHeight() * npcScale) + (0.5 * npcScale), 0); - hologram.getData().setLocation(location); - } -} diff --git a/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsCMD.java b/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsCMD.java index 13648770..e82cc12e 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsCMD.java @@ -1,28 +1,28 @@ package de.oliver.fancyholograms.commands; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.data.HologramData; import de.oliver.fancyholograms.api.hologram.Hologram; -import de.oliver.fancyholograms.storage.converter.ConverterTarget; -import de.oliver.fancyholograms.storage.converter.FHConversionRegistry; -import de.oliver.fancyholograms.storage.converter.HologramConversionSession; -import de.oliver.fancyholograms.util.Constants; +import de.oliver.fancyholograms.converter.ConverterTarget; +import de.oliver.fancyholograms.converter.FHConversionRegistry; +import de.oliver.fancyholograms.converter.HologramConversionSession; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; -import de.oliver.fancylib.translations.message.Message; +import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.util.*; -import java.util.regex.Pattern; -import java.util.stream.Stream; public final class FancyHologramsCMD extends Command { + public static final String FH_COMMAND_USAGE = "/fancyholograms "; + @NotNull - private final FancyHolograms plugin; + private final FancyHologramsPlugin plugin; - public FancyHologramsCMD(@NotNull final FancyHolograms plugin) { + public FancyHologramsCMD(@NotNull final FancyHologramsPlugin plugin) { super("fancyholograms"); setPermission("fancyholograms.admin"); this.plugin = plugin; @@ -35,25 +35,32 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No } if (args.length < 1) { - MessageHelper.info(sender, Constants.FH_COMMAND_USAGE); + MessageHelper.info(sender, FH_COMMAND_USAGE); return false; } switch (args[0].toLowerCase(Locale.ROOT)) { case "save" -> { - this.plugin.getHologramsManager().saveHolograms(); + this.plugin.savePersistentHolograms(); MessageHelper.success(sender, "Saved all holograms"); } case "reload" -> { this.plugin.getHologramConfiguration().reload(plugin); - this.plugin.getHologramsManager().reloadHolograms(); - this.plugin.reloadCommands(); + + this.plugin.getRegistry().clear(); + for (World world : Bukkit.getWorlds()) { + Collection hologramData = this.plugin.getStorage().loadAll(world.getName()); + for (HologramData data : hologramData) { + Hologram hologram = this.plugin.getHologramFactory().apply(data); + this.plugin.getRegistry().register(hologram); + } + } MessageHelper.success(sender, "Reloaded config and holograms"); } case "version" -> { - FancyHolograms.get().getHologramThread().submit(() -> { - FancyHolograms.get().getVersionConfig().checkVersionAndDisplay(sender, false); + FancyHologramsPlugin.get().getHologramThread().submit(() -> { + FancyHologramsPlugin.get().getVersionConfig().checkVersionAndDisplay(sender, false); }); } case "convert" -> { @@ -82,11 +89,11 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No final List holograms = converter.convert(session); for (final HologramData data : holograms) { - final Hologram hologram = this.plugin.getHologramsManager().create(data); - this.plugin.getHologramsManager().addHologram(hologram); + final Hologram hologram = this.plugin.getHologramFactory().apply(data); + this.plugin.getRegistry().register(hologram); } - this.plugin.getHologramsManager().saveHolograms(); + this.plugin.savePersistentHolograms(); // TODO(matt): Give options to delete them or teleport and a list of IDs please MessageHelper.success(sender, String.format("Converted successfully, produced %s total holograms!", holograms.size())); @@ -96,7 +103,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No }, () -> MessageHelper.error(sender, "That converter is not registered. Look at the developer documentation if you are adding converters.")); } default -> { - MessageHelper.info(sender, Constants.FH_COMMAND_USAGE); + MessageHelper.info(sender, FH_COMMAND_USAGE); return false; } } diff --git a/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsTestCMD.java b/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsTestCMD.java index 12dbc22f..7deca077 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsTestCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/FancyHologramsTestCMD.java @@ -1,28 +1,22 @@ package de.oliver.fancyholograms.commands; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; -import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancyholograms.tests.FHTests; import de.oliver.fancylib.MessageHelper; -import org.bukkit.Color; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Display; import org.bukkit.entity.Player; -import org.bukkit.entity.TextDisplay; import org.jetbrains.annotations.NotNull; -import org.joml.Vector3f; -import java.util.Arrays; import java.util.Collections; import java.util.List; public class FancyHologramsTestCMD extends Command { @NotNull - private final FancyHolograms plugin; + private final FancyHologramsPlugin plugin; - public FancyHologramsTestCMD(@NotNull final FancyHolograms plugin) { + public FancyHologramsTestCMD(@NotNull final FancyHologramsPlugin plugin) { super("FancyHologramsTest"); setPermission("fancyholograms.admin"); this.plugin = plugin; @@ -30,74 +24,91 @@ public FancyHologramsTestCMD(@NotNull final FancyHolograms plugin) { @Override public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException { - if (args.length == 1) { - return Arrays.asList("spawn100", "test1"); - } - return Collections.emptyList(); } @Override - public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { - if (!testPermission(sender)) { - return false; - } + public boolean execute(@NotNull CommandSender commandSender, @NotNull String s, @NotNull String[] strings) { + Player p = (Player) commandSender; - if (!(sender instanceof Player p)) { - MessageHelper.error(sender, "Only players can use this command!"); - return false; + FHTests tests = new FHTests(); + if(tests.runAllTests(p)) { + MessageHelper.success(p, "All tests have been successfully run!"); + } else { + MessageHelper.error(p, "There was an issue running the tests!"); } - if (args.length == 1 && args[0].equalsIgnoreCase("spawn100")) { - for (int i = 0; i < 10; i++) { - for (int j = 0; j < 10; j++) { - int n = (i * 10 + j) + 1; - TextHologramData textData = new TextHologramData("holo-" + n, p.getLocation().clone().add(5 * i + 1, 0, 5 * j + 1)); - textData.setText(Arrays.asList( - "This is a test hologram! (#" + n + ")", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris." - )); - textData.setTextUpdateInterval(100) - .setScale(new Vector3f(.5f, .5f, .5f)) - .setVisibilityDistance(100); - - Hologram hologram = this.plugin.getHologramsManager().create(textData); - hologram.createHologram(); - hologram.updateShownStateFor(p); - } - } - - return true; - } else if (args.length == 1 && args[0].equalsIgnoreCase("test1")) { - TextHologramData textData = new TextHologramData("holo-test1", p.getLocation()); - textData.setText(Arrays.asList( - "This is a test hologram!", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", - "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris." - )) - .setTextUpdateInterval(100) - .setTextAlignment(TextDisplay.TextAlignment.CENTER) - .setBackground(Color.fromARGB(15, 78, 237, 176)) - .setTextShadow(true) - .setScale(new Vector3f(2, 2, 2)) - .setBillboard(Display.Billboard.CENTER) - .setBrightness(new Display.Brightness(15, 15)) - .setShadowRadius(3) - .setShadowStrength(3) - .setVisibilityDistance(100); + return true; + } - Hologram hologram = this.plugin.getHologramsManager().create(textData); - hologram.createHologram(); - hologram.updateShownStateFor(p); - } + // @Override +// public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) throws IllegalArgumentException { +// if (args.length == 1) { +// return Arrays.asList("spawn100", "test1"); +// } +// +// return Collections.emptyList(); +// } - return false; - } +// @Override +// public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) { +// if (!testPermission(sender)) { +// return false; +// } +// +// if (!(sender instanceof Player p)) { +// MessageHelper.error(sender, "Only players can use this command!"); +// return false; +// } +// +// if (args.length == 1 && args[0].equalsIgnoreCase("spawn100")) { +// for (int i = 0; i < 10; i++) { +// for (int j = 0; j < 10; j++) { +// int n = (i * 10 + j) + 1; +// TextHologramData textData = new TextHologramData("holo-" + n, p.getLocation().clone().add(5 * i + 1, 0, 5 * j + 1)); +// textData.setText(Arrays.asList( +// "This is a test hologram! (#" + n + ")", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris." +// )); +// textData.setTextUpdateInterval(100) +// .setScale(new Vector3f(.5f, .5f, .5f)) +// .setVisibilityDistance(100); +// +// Hologram hologram = this.plugin.getHologramFactory().apply(textData); +// hologram.spawnTo(p); +// } +// } +// +// return true; +// } else if (args.length == 1 && args[0].equalsIgnoreCase("test1")) { +// TextHologramData textData = new TextHologramData("holo-test1", p.getLocation()); +// textData.setText(Arrays.asList( +// "This is a test hologram!", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris.", +// "Lorem ipsum dolor sit amet, consec tetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris." +// )) +// .setTextUpdateInterval(100) +// .setTextAlignment(TextDisplay.TextAlignment.CENTER) +// .setBackground(Color.fromARGB(15, 78, 237, 176)) +// .setTextShadow(true) +// .setScale(new Vector3f(2, 2, 2)) +// .setBillboard(Display.Billboard.CENTER) +// .setBrightness(new Display.Brightness(15, 15)) +// .setShadowRadius(3) +// .setShadowStrength(3) +// .setVisibilityDistance(100); +// +// Hologram hologram = this.plugin.getHologramFactory().apply(textData); +// hologram.spawnTo(p); +// } +// +// return false; +// } } diff --git a/src/main/java/de/oliver/fancyholograms/commands/HologramCMD.java b/src/main/java/de/oliver/fancyholograms/commands/HologramCMD.java index 6e0821a3..075a3af9 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/HologramCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/HologramCMD.java @@ -1,7 +1,6 @@ package de.oliver.fancyholograms.commands; import com.google.common.primitives.Ints; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.data.DisplayHologramData; import de.oliver.fancyholograms.api.data.HologramData; import de.oliver.fancyholograms.api.data.TextHologramData; @@ -9,7 +8,7 @@ import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.hologram.HologramType; import de.oliver.fancyholograms.commands.hologram.*; -import de.oliver.fancyholograms.util.Constants; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancyholograms.util.PluginUtils; import de.oliver.fancylib.MessageHelper; import de.oliver.fancynpcs.api.FancyNpcsPlugin; @@ -28,10 +27,44 @@ public final class HologramCMD extends Command { + private static final String HELP_TEXT = """ + <%primary_color%>FancyHolograms commands help: + <%primary_color%>- /hologram help - Shows all (sub)commands + <%primary_color%>- /hologram list - Shows you a overview of all holograms + <%primary_color%>- /hologram nearby - Shows all holograms nearby you in a range + <%primary_color%>- /hologram teleport - Teleports you to a hologram + <%primary_color%>- /hologram create - Creates a new hologram + <%primary_color%>- /hologram remove - Removes a hologram + <%primary_color%>- /hologram copy - Copies a hologram + <%primary_color%>- /hologram edit addLine - Adds a line at the bottom + <%primary_color%>- /hologram edit removeLine - Removes a line at the bottom + <%primary_color%>- /hologram edit insertBefore - Inserts a line before another + <%primary_color%>- /hologram edit insertAfter - Inserts a line after another + <%primary_color%>- /hologram edit setLine - Edits the line + <%primary_color%>- /hologram edit position - Teleports the hologram to you + <%primary_color%>- /hologram edit moveTo [yaw] [pitch] - Teleports the hologram to the coordinates + <%primary_color%>- /hologram edit rotate - Rotates the hologram + <%primary_color%>- /hologram edit scale - Changes the scale of the hologram + <%primary_color%>- /hologram edit billboard - Changes the billboard of the hologram + <%primary_color%>- /hologram edit background - Changes the background of the hologram + <%primary_color%>- /hologram edit textShadow - Enables/disables the text shadow + <%primary_color%>- /hologram edit textAlignment - Sets the text alignment + <%primary_color%>- /hologram edit seeThrough - Enables/disables whether the text can be seen through blocks + <%primary_color%>- /hologram edit shadowRadius - Changes the shadow radius of the hologram + <%primary_color%>- /hologram edit shadowStrength - Changes the shadow strength of the hologram + <%primary_color%>- /hologram edit brightness <0-15> - Changes the brightness of the hologram + <%primary_color%>- /hologram edit updateTextInterval - Sets the interval for updating the text + """.replace("%primary_color%", MessageHelper.getPrimaryColor()); + + private static final String HELP_TEXT_NPCS = """ + <%primary_color%>- /hologram edit linkWithNpc - Links the hologram with an NPC + <%primary_color%>- /hologram edit unlinkWithNpc - Unlinks the hologram with an NPC + """.replace("%primary_color%", MessageHelper.getPrimaryColor()); + @NotNull - private final FancyHolograms plugin; + private final FancyHologramsPlugin plugin; - public HologramCMD(@NotNull final FancyHolograms plugin) { + public HologramCMD(@NotNull final FancyHologramsPlugin plugin) { super("hologram", "Main command for the FancyHolograms plugin", "/hologram help", List.of("holograms", "holo", "fholo")); setPermission("fancyholograms.admin"); @@ -56,7 +89,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No } if (args.length == 0 || args[0].equalsIgnoreCase("help")) { - MessageHelper.info(sender, Constants.HELP_TEXT + (!PluginUtils.isFancyNpcsEnabled() ? "" : "\n" + Constants.HELP_TEXT_NPCS)); + MessageHelper.info(sender, HELP_TEXT + (!PluginUtils.isFancyNpcsEnabled() ? "" : "\n" + HELP_TEXT_NPCS)); return false; } @@ -80,7 +113,7 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No return new NearbyCMD().run(sender, null, args); } - final var hologram = this.plugin.getHologramsManager().getHologram(args[1]).orElse(null); + final var hologram = this.plugin.getRegistry().get(args[1]).orElse(null); if (hologram == null) { MessageHelper.error(sender, "Could not find hologram: '" + args[1] + "'"); return false; @@ -102,10 +135,11 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No if (updated) { if (sender instanceof Player p) { - hologram.forceUpdate(); - hologram.refreshHologram(p); + plugin.getController().refreshHologram(hologram, p); } - hologram.queueUpdate(); + + //TODO: idk + // hologram.queueUpdate(); } yield updated; @@ -138,10 +172,14 @@ public boolean execute(@NotNull CommandSender sender, @NotNull String label, @No return Collections.emptyList(); } - return this.plugin.getHologramsManager().getPersistentHolograms().stream().map(hologram -> hologram.getData().getName()).filter(input -> input.toLowerCase().startsWith(args[1].toLowerCase(Locale.ROOT))).toList(); + return this.plugin.getRegistry().getAllPersistent() + .stream() + .map(hologram -> hologram.getData().getName()) + .filter(input -> input.toLowerCase().startsWith(args[1].toLowerCase(Locale.ROOT))) + .toList(); } - final var hologram = this.plugin.getHologramsManager().getHologram(args[1]).orElse(null); + final var hologram = this.plugin.getRegistry().get(args[1]).orElse(null); if (hologram == null) { return Collections.emptyList(); } diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/BackgroundCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/BackgroundCMD.java index 1c3a9f5f..ff12f004 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/BackgroundCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/BackgroundCMD.java @@ -1,11 +1,11 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Color; @@ -81,8 +81,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ textData.setBackground(copied.getBackground()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed background color"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/BillboardCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/BillboardCMD.java index b76762e5..6e2ae09b 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/BillboardCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/BillboardCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.base.Enums; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.DisplayHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.apache.commons.lang3.StringUtils; import org.bukkit.command.CommandSender; @@ -63,8 +63,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ displayData.setBillboard(copied.getBillboard()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed the billboard to " + StringUtils.capitalize(billboard.name().toLowerCase(Locale.ROOT))); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/BlockCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/BlockCMD.java index a26269a3..02cba224 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/BlockCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/BlockCMD.java @@ -1,11 +1,11 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.BlockHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.Material; import org.bukkit.command.CommandSender; @@ -58,8 +58,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ blockData.setBlock(block); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Set block to '" + block.name() + "'"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/BrightnessCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/BrightnessCMD.java index 688054b0..61cbdad9 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/BrightnessCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/BrightnessCMD.java @@ -1,9 +1,9 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.data.DisplayHologramData; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancyholograms.util.NumberHelper; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; @@ -61,8 +61,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ displayData.setBrightness(new Display.Brightness(blockBrightness, skyBrightness)); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed " + brightnessType.toLowerCase() + " brightness to " + brightnessValue); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/CenterCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/CenterCMD.java index 83f97cf2..00b72a28 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/CenterCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/CenterCMD.java @@ -1,9 +1,9 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; -import de.oliver.fancyholograms.util.Constants; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancyholograms.util.Formats; import de.oliver.fancylib.MessageHelper; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -36,16 +36,16 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ hologram.getData().setLocation(location); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Centered the hologram to %s/%s/%s %s\u00B0 %s\u00B0".formatted( - Constants.COORDINATES_DECIMAL_FORMAT.format(location.x()), - Constants.COORDINATES_DECIMAL_FORMAT.format(location.y()), - Constants.COORDINATES_DECIMAL_FORMAT.format(location.z()), - Constants.COORDINATES_DECIMAL_FORMAT.format((location.getYaw() + 180f) % 360f), - Constants.COORDINATES_DECIMAL_FORMAT.format((location.getPitch()) % 360f) + Formats.COORDINATES_DECIMAL.format(location.x()), + Formats.COORDINATES_DECIMAL.format(location.y()), + Formats.COORDINATES_DECIMAL.format(location.z()), + Formats.COORDINATES_DECIMAL.format((location.getYaw() + 180f) % 360f), + Formats.COORDINATES_DECIMAL.format((location.getPitch()) % 360f) )); return true; } diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/CopyCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/CopyCMD.java index e1e7117d..1a66bc41 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/CopyCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/CopyCMD.java @@ -1,9 +1,9 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.events.HologramCreateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -41,7 +41,7 @@ public boolean run(@NotNull CommandSender sender, @Nullable Hologram hologram, @ String name = args[2]; - if (FancyHolograms.get().getHologramsManager().getHologram(name).isPresent()) { + if (FancyHologramsPlugin.get().getRegistry().get(name).isPresent()) { MessageHelper.error(sender, "There already exists a hologram with this name"); return false; } @@ -58,22 +58,19 @@ public boolean run(@NotNull CommandSender sender, @Nullable Hologram hologram, @ location.setYaw(originalLocation.getYaw()); data.setLocation(location); - final var copy = FancyHolograms.get().getHologramsManager().create(data); + final var copy = FancyHologramsPlugin.get().getHologramFactory().apply(data); if (!new HologramCreateEvent(copy, player).callEvent()) { MessageHelper.error(sender, "Creating the copied hologram was cancelled"); return false; } - copy.createHologram(); - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - copy.updateShownStateFor(onlinePlayer); - } + FancyHologramsPlugin.get().getController().refreshHologram(copy, Bukkit.getOnlinePlayers()); - FancyHolograms.get().getHologramsManager().addHologram(copy); + FancyHologramsPlugin.get().getRegistry().register(copy); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(sender, "Copied the hologram"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/CreateCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/CreateCMD.java index d85ccf65..1a798635 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/CreateCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/CreateCMD.java @@ -1,11 +1,14 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; +import de.oliver.fancyholograms.api.data.BlockHologramData; +import de.oliver.fancyholograms.api.data.DisplayHologramData; +import de.oliver.fancyholograms.api.data.ItemHologramData; +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.api.events.HologramCreateEvent; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.hologram.HologramType; -import de.oliver.fancyholograms.api.data.*; -import de.oliver.fancyholograms.api.events.HologramCreateEvent; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -48,7 +51,7 @@ public boolean run(@NotNull CommandSender sender, @Nullable Hologram hologram, @ String name = args[2]; - if (FancyHolograms.get().getHologramsManager().getHologram(name).isPresent()) { + if (FancyHologramsPlugin.get().getRegistry().get(name).isPresent()) { MessageHelper.error(player, "There already exists a hologram with this name"); return false; } @@ -71,18 +74,15 @@ public boolean run(@NotNull CommandSender sender, @Nullable Hologram hologram, @ } } - final var holo = FancyHolograms.get().getHologramsManager().create(displayData); + final var holo = FancyHologramsPlugin.get().getHologramFactory().apply(displayData); if (!new HologramCreateEvent(holo, player).callEvent()) { MessageHelper.error(player, "Creating the hologram was cancelled"); return false; } - holo.createHologram(); - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { - holo.updateShownStateFor(onlinePlayer); - } + FancyHologramsPlugin.get().getController().refreshHologram(holo, Bukkit.getOnlinePlayers()); - FancyHolograms.get().getHologramsManager().addHologram(holo); + FancyHologramsPlugin.get().getRegistry().register(holo); MessageHelper.success(player, "Created the hologram"); return true; diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertAfterCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertAfterCMD.java index 7b468434..65235495 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertAfterCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertAfterCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Ints; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -70,8 +70,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ textData.setText(copied.getText()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Inserted line"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertBeforeCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertBeforeCMD.java index 2affa56d..63e6b238 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertBeforeCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/InsertBeforeCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Ints; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -72,8 +72,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ textData.setText(copied.getText()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Inserted line"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/ItemCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/ItemCMD.java index 3a8323b1..2cf63798 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/ItemCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/ItemCMD.java @@ -1,11 +1,11 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.ItemHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.Material; import org.bukkit.command.CommandSender; @@ -66,8 +66,8 @@ public boolean run(@NotNull CommandSender sender, @Nullable Hologram hologram, @ itemData.setItemStack(item); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Set the item to '" + item.getType().name() + "'"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/LinkWithNpcCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/LinkWithNpcCMD.java index 284fe0d4..5cf24d4d 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/LinkWithNpcCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/LinkWithNpcCMD.java @@ -1,8 +1,8 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancyholograms.util.PluginUtils; import de.oliver.fancylib.MessageHelper; import de.oliver.fancynpcs.api.FancyNpcsPlugin; @@ -48,10 +48,10 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ hologram.getData().setLinkedNpcName(npc.getData().getName()); - FancyHolograms.get().getHologramsManager().syncHologramWithNpc(hologram); + FancyHologramsPlugin.get().getControllerImpl().syncHologramWithNpc(hologram); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Linked hologram with NPC"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/ListCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/ListCMD.java index bf296ded..16a62a58 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/ListCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/ListCMD.java @@ -1,10 +1,10 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Ints; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; -import de.oliver.fancyholograms.util.Constants; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancyholograms.util.Formats; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -27,7 +27,7 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ return false; } - final var holograms = FancyHolograms.get().getHologramsManager().getPersistentHolograms(); + final var holograms = FancyHologramsPlugin.get().getRegistry().getAllPersistent(); if (holograms.isEmpty()) { MessageHelper.warning(player, "There are no holograms. Use '/hologram create' to create one"); @@ -64,9 +64,9 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ "Click to teleport'> - %s (%s/%s/%s in %s)" .formatted("/hologram teleport " + holo.getData().getName(), holo.getData().getName(), - Constants.DECIMAL_FORMAT.format(location.x()), - Constants.DECIMAL_FORMAT.format(location.y()), - Constants.DECIMAL_FORMAT.format(location.z()), + Formats.DECIMAL.format(location.x()), + Formats.DECIMAL.format(location.y()), + Formats.DECIMAL.format(location.z()), location.getWorld().getName() )); }); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/MoveHereCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/MoveHereCMD.java index dd603cc7..3d6312f7 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/MoveHereCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/MoveHereCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Doubles; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; -import de.oliver.fancyholograms.util.Constants; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancyholograms.util.Formats; import de.oliver.fancylib.MessageHelper; import org.apache.commons.lang3.StringUtils; import org.bukkit.Location; @@ -27,7 +27,7 @@ public static boolean setLocation(Player player, Hologram hologram, Location loc return false; } - final var copied = hologram.getData().copy(hologram.getName()); + final var copied = hologram.getData().copy(hologram.getData().getName()); final Location newLocation = (applyRotation) ? location : new Location(location.getWorld(), location.x(), location.y(), location.z(), copied.getLocation().getYaw(), copied.getLocation().getPitch()); @@ -39,16 +39,16 @@ public static boolean setLocation(Player player, Hologram hologram, Location loc hologram.getData().setLocation(copied.getLocation()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Moved the hologram to %s/%s/%s %s\u00B0 %s\u00B0".formatted( - Constants.COORDINATES_DECIMAL_FORMAT.format(newLocation.x()), - Constants.COORDINATES_DECIMAL_FORMAT.format(newLocation.y()), - Constants.COORDINATES_DECIMAL_FORMAT.format(newLocation.z()), - Constants.COORDINATES_DECIMAL_FORMAT.format((newLocation.getYaw() + 180f) % 360f), - Constants.COORDINATES_DECIMAL_FORMAT.format((newLocation.getPitch()) % 360f) + Formats.COORDINATES_DECIMAL.format(newLocation.x()), + Formats.COORDINATES_DECIMAL.format(newLocation.y()), + Formats.COORDINATES_DECIMAL.format(newLocation.z()), + Formats.COORDINATES_DECIMAL.format((newLocation.getYaw() + 180f) % 360f), + Formats.COORDINATES_DECIMAL.format((newLocation.getPitch()) % 360f) )); return true; diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/NearbyCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/NearbyCMD.java index bd1868c3..3fcd2b60 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/NearbyCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/NearbyCMD.java @@ -1,9 +1,9 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; -import de.oliver.fancyholograms.util.Constants; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancyholograms.util.Formats; import de.oliver.fancyholograms.util.NumberHelper; import de.oliver.fancylib.MessageHelper; import org.bukkit.Location; @@ -19,6 +19,8 @@ public class NearbyCMD implements Subcommand { + public static final String INVALID_NEARBY_RANGE = "Provide an integer radius to search for holograms nearby."; + @Override public List tabcompletion(@NotNull CommandSender player, @Nullable Hologram hologram, @NotNull String[] args) { return null; @@ -39,22 +41,22 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ if (args.length < 2) { - MessageHelper.error(player, Constants.INVALID_NEARBY_RANGE); + MessageHelper.error(player, INVALID_NEARBY_RANGE); return false; } Optional range = NumberHelper.parseInt(args[1]); if (range.isEmpty()) { - MessageHelper.error(player, Constants.INVALID_NEARBY_RANGE); + MessageHelper.error(player, INVALID_NEARBY_RANGE); return false; } Location playerLocation = ((Player) player).getLocation().clone(); - List> nearby = FancyHolograms.get() - .getHologramsManager() - .getPersistentHolograms() + List> nearby = FancyHologramsPlugin.get() + .getRegistry() + .getAllPersistent() .stream() .filter((holo) -> holo.getData().getLocation().getWorld() == playerLocation.getWorld()) .map((holo) -> Map.entry(holo, holo.getData().getLocation().distance(playerLocation))) @@ -82,11 +84,11 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ .formatted( "/hologram teleport " + holo.getData().getName(), holo.getData().getName(), - Constants.DECIMAL_FORMAT.format(location.x()), - Constants.DECIMAL_FORMAT.format(location.y()), - Constants.DECIMAL_FORMAT.format(location.z()), + Formats.DECIMAL.format(location.x()), + Formats.DECIMAL.format(location.y()), + Formats.DECIMAL.format(location.z()), location.getWorld().getName(), - Constants.DECIMAL_FORMAT.format(distance) + Formats.DECIMAL.format(distance) )); }); return true; diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/RemoveCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/RemoveCMD.java index d978ad66..e94edd0b 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/RemoveCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/RemoveCMD.java @@ -1,10 +1,10 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.FancyHologramsPlugin; +import de.oliver.fancyholograms.api.FancyHolograms; import de.oliver.fancyholograms.api.events.HologramDeleteEvent; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -32,8 +32,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ return false; } - FancyHologramsPlugin.get().getHologramThread().submit(() -> { - FancyHolograms.get().getHologramsManager().removeHologram(hologram); + FancyHolograms.get().getHologramThread().submit(() -> { + FancyHologramsPlugin.get().getRegistry().unregister(hologram); MessageHelper.success(player, "Removed the hologram"); }); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/ScaleCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/ScaleCMD.java index 38612f93..3e665950 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/ScaleCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/ScaleCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Floats; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.DisplayHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -70,8 +70,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ copied.getScale().y(), copied.getScale().z())); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed scale to " + scaleX + ", " + scaleY + ", " + scaleZ); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/SeeThroughCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/SeeThroughCMD.java index a4468440..1b75f611 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/SeeThroughCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/SeeThroughCMD.java @@ -1,11 +1,11 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -64,8 +64,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ textData.setSeeThrough(copied.isSeeThrough()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed see through"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/SetLineCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/SetLineCMD.java index a240cc3e..630a1cc8 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/SetLineCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/SetLineCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Ints; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -48,8 +48,8 @@ public static boolean setLine(CommandSender player, Hologram hologram, int index textData.setText(copied.getText()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed text for line " + (Math.min(index, lines.size() - 1) + 1)); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowRadiusCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowRadiusCMD.java index 28105469..429ab600 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowRadiusCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowRadiusCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Floats; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.DisplayHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -60,8 +60,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ displayData.setShadowRadius(copied.getShadowRadius()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed shadow radius"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowStrengthCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowStrengthCMD.java index 40daac04..221e869f 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowStrengthCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/ShadowStrengthCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Floats; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.DisplayHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -60,8 +60,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ displayData.setShadowStrength(copied.getShadowStrength()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed shadow strength"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/TextAlignmentCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/TextAlignmentCMD.java index a4e3e259..0d26a247 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/TextAlignmentCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/TextAlignmentCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.base.Enums; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.bukkit.entity.TextDisplay; @@ -62,8 +62,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ textData.setTextAlignment(((TextHologramData) copied).getTextAlignment()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed text alignment"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/TextShadowCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/TextShadowCMD.java index 2564497d..6d8b2663 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/TextShadowCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/TextShadowCMD.java @@ -1,11 +1,11 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -64,8 +64,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ textData.setTextShadow(copied.hasTextShadow()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed text shadow"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/TranslateCommand.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/TranslateCommand.java index 0e405489..a8b1effd 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/TranslateCommand.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/TranslateCommand.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Floats; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.DisplayHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -70,8 +70,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ copied.getTranslation().y(), copied.getTranslation().z())); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed translation to " + translateX + ", " + translateY + ", " + translateZ); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/UnlinkWithNpcCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/UnlinkWithNpcCMD.java index 09d9a3ef..c1e56469 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/UnlinkWithNpcCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/UnlinkWithNpcCMD.java @@ -1,8 +1,8 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancyholograms.util.PluginUtils; import de.oliver.fancylib.MessageHelper; import de.oliver.fancynpcs.api.FancyNpcsPlugin; @@ -47,8 +47,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ npc.updateForAll(); } - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Unlinked hologram with NPC"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/UpdateTextIntervalCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/UpdateTextIntervalCMD.java index 712b1a9f..da44c899 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/UpdateTextIntervalCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/UpdateTextIntervalCMD.java @@ -1,12 +1,12 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Ints; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.TextHologramData; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -87,8 +87,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ textData.setTextUpdateInterval(copied.getTextUpdateInterval()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed the text update interval"); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityCMD.java index 2152c213..41657fd0 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityCMD.java @@ -1,9 +1,9 @@ package de.oliver.fancyholograms.commands.hologram; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.data.property.Visibility; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -36,7 +36,7 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ } final var visibility = optionalVisibility.get(); - final var copied = hologram.getData().copy(hologram.getName()); + final var copied = hologram.getData().copy(hologram.getData().getName()); copied.setVisibility(visibility); if (hologram.getData().getVisibility() == copied.getVisibility()) { @@ -46,8 +46,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ hologram.getData().setVisibility(copied.getVisibility()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed visibility to " + visibility); diff --git a/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityDistanceCMD.java b/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityDistanceCMD.java index 97c092b1..c78a5001 100644 --- a/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityDistanceCMD.java +++ b/src/main/java/de/oliver/fancyholograms/commands/hologram/VisibilityDistanceCMD.java @@ -1,11 +1,11 @@ package de.oliver.fancyholograms.commands.hologram; import com.google.common.primitives.Ints; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.api.events.HologramUpdateEvent; +import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.HologramCMD; import de.oliver.fancyholograms.commands.Subcommand; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.MessageHelper; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -44,7 +44,7 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ return false; } - final var copied = hologram.getData().copy(hologram.getName()); + final var copied = hologram.getData().copy(hologram.getData().getName()); copied.setVisibilityDistance(visibilityDistance); if (!HologramCMD.callModificationEvent(hologram, player, copied, HologramUpdateEvent.HologramModification.UPDATE_VISIBILITY_DISTANCE)) { @@ -58,8 +58,8 @@ public boolean run(@NotNull CommandSender player, @Nullable Hologram hologram, @ hologram.getData().setVisibilityDistance(copied.getVisibilityDistance()); - if (FancyHolograms.get().getHologramConfiguration().isSaveOnChangedEnabled()) { - FancyHolograms.get().getHologramStorage().save(hologram); + if (FancyHologramsPlugin.get().getHologramConfiguration().isSaveOnChangedEnabled()) { + FancyHologramsPlugin.get().getStorage().save(hologram.getData()); } MessageHelper.success(player, "Changed visibility distance"); diff --git a/src/main/java/de/oliver/fancyholograms/FancyHologramsConfiguration.java b/src/main/java/de/oliver/fancyholograms/config/FHConfiguration.java similarity index 91% rename from src/main/java/de/oliver/fancyholograms/FancyHologramsConfiguration.java rename to src/main/java/de/oliver/fancyholograms/config/FHConfiguration.java index 97cd7084..24723983 100644 --- a/src/main/java/de/oliver/fancyholograms/FancyHologramsConfiguration.java +++ b/src/main/java/de/oliver/fancyholograms/config/FHConfiguration.java @@ -1,7 +1,8 @@ -package de.oliver.fancyholograms; +package de.oliver.fancyholograms.config; -import de.oliver.fancyholograms.api.FancyHologramsPlugin; +import de.oliver.fancyholograms.api.FancyHolograms; import de.oliver.fancyholograms.api.HologramConfiguration; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.ConfigHelper; import org.jetbrains.annotations.NotNull; @@ -11,7 +12,7 @@ * The FancyHologramsConfig class is responsible for managing the configuration of the FancyHolograms plugin. * It handles loading and saving hologram data, as well as providing access to various configuration settings. */ -public final class FancyHologramsConfiguration implements HologramConfiguration { +public final class FHConfiguration implements HologramConfiguration { /** * Indicates whether version notifications are muted. @@ -51,8 +52,8 @@ public final class FancyHologramsConfiguration implements HologramConfiguration private String logLevel; @Override - public void reload(@NotNull FancyHologramsPlugin plugin) { - FancyHolograms pluginImpl = (FancyHolograms) plugin; + public void reload(@NotNull FancyHolograms plugin) { + FancyHologramsPlugin pluginImpl = (FancyHologramsPlugin) plugin; pluginImpl.reloadConfig(); final var config = pluginImpl.getConfig(); diff --git a/src/main/java/de/oliver/fancyholograms/FHFeatureFlags.java b/src/main/java/de/oliver/fancyholograms/config/FHFeatureFlags.java similarity index 57% rename from src/main/java/de/oliver/fancyholograms/FHFeatureFlags.java rename to src/main/java/de/oliver/fancyholograms/config/FHFeatureFlags.java index e5b4a05b..f3fdd363 100644 --- a/src/main/java/de/oliver/fancyholograms/FHFeatureFlags.java +++ b/src/main/java/de/oliver/fancyholograms/config/FHFeatureFlags.java @@ -1,15 +1,18 @@ -package de.oliver.fancyholograms; +package de.oliver.fancyholograms.config; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.featureFlags.FeatureFlag; import de.oliver.fancylib.featureFlags.FeatureFlagConfig; public class FHFeatureFlags { public static final FeatureFlag DISABLE_HOLOGRAMS_FOR_BEDROCK_PLAYERS = new FeatureFlag("disable-holograms-for-bedrock-players", "Do not show holograms to bedrock players", false); + public static final FeatureFlag DISABLE_HOLOGRAMS_FOR_OLD_CLIENTS = new FeatureFlag("disable-holograms-for-old-clients", "Do not show holograms to clients with a version older than 1.19.4", false); public static void load() { - FeatureFlagConfig config = new FeatureFlagConfig(FancyHolograms.get()); + FeatureFlagConfig config = new FeatureFlagConfig(FancyHologramsPlugin.get()); config.addFeatureFlag(DISABLE_HOLOGRAMS_FOR_BEDROCK_PLAYERS); + config.addFeatureFlag(DISABLE_HOLOGRAMS_FOR_OLD_CLIENTS); config.load(); } diff --git a/src/main/java/de/oliver/fancyholograms/controller/HologramControllerImpl.java b/src/main/java/de/oliver/fancyholograms/controller/HologramControllerImpl.java new file mode 100644 index 00000000..6777c697 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/controller/HologramControllerImpl.java @@ -0,0 +1,168 @@ +package de.oliver.fancyholograms.controller; + +import com.google.common.cache.CacheBuilder; +import de.oliver.fancyholograms.api.HologramController; +import de.oliver.fancyholograms.api.data.DisplayHologramData; +import de.oliver.fancyholograms.api.data.HologramData; +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancynpcs.api.FancyNpcsPlugin; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; + +public class HologramControllerImpl implements HologramController { + + @Override + public void showHologramTo(@NotNull final Hologram hologram, @NotNull final Player... players) { + for (Player player : players) { + boolean isVisible = hologram.isViewer(player); + boolean shouldSee = shouldSeeHologram(hologram, player); + + if (isVisible || !shouldSee) { + continue; + } + + hologram.spawnTo(player); + } + } + + @Override + public void hideHologramFrom(@NotNull final Hologram hologram, @NotNull final Player... players) { + for (Player player : players) { + boolean isVisible = hologram.isViewer(player); + boolean shouldSee = shouldSeeHologram(hologram, player); + + if (!isVisible || shouldSee) { + continue; + } + + hologram.despawnFrom(player); + } + } + + @Override + public boolean shouldSeeHologram(@NotNull final Hologram hologram, @NotNull final Player player) { + if (!meetsVisibilityConditions(hologram, player)) { + return false; + } + + return isWithinVisibilityDistance(hologram, player); + } + + @Override + public void refreshHologram(@NotNull final Hologram hologram, @NotNull final Player... players) { + hideHologramFrom(hologram, players); + showHologramTo(hologram, players); + } + + private boolean meetsVisibilityConditions(@NotNull final Hologram hologram, @NotNull final Player player) { + return hologram.getData().getVisibility().canSee(player, hologram); + } + + private boolean isWithinVisibilityDistance(@NotNull final Hologram hologram, @NotNull final Player player) { + final var location = hologram.getData().getLocation(); + if (!location.getWorld().equals(player.getWorld())) { + return false; + } + + int visibilityDistance = hologram.getData().getVisibilityDistance(); + double distanceSquared = location.distanceSquared(player.getLocation()); + + return distanceSquared <= visibilityDistance * visibilityDistance; + } + + public void initRefreshTask() { + FancyHologramsPlugin.get().getHologramThread().scheduleWithFixedDelay(() -> { + for (Hologram hologram : FancyHologramsPlugin.get().getRegistry().getAll()) { + refreshHologram(hologram, Bukkit.getOnlinePlayers().toArray(new Player[0])); + } + }, 0, 1, TimeUnit.SECONDS); + } + + public void initUpdateTask() { + final var updateTimes = CacheBuilder.newBuilder() + .expireAfterAccess(Duration.ofMinutes(5)) + .build(); + + FancyHologramsPlugin.get().getHologramThread().scheduleWithFixedDelay(() -> { + final var time = System.currentTimeMillis(); + + for (final var hologram : FancyHologramsPlugin.get().getRegistry().getAll()) { + HologramData data = hologram.getData(); + if (data.hasChanges()) { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + hologram.updateFor(onlinePlayer); + } + + data.setHasChanges(false); + + if (data instanceof TextHologramData) { + updateTimes.put(hologram.getData().getName(), time); + } + } + } + }, 50, 1000, TimeUnit.MILLISECONDS); + + FancyHologramsPlugin.get().getHologramThread().scheduleWithFixedDelay(() -> { + final var time = System.currentTimeMillis(); + + for (final var hologram : FancyHologramsPlugin.get().getRegistry().getAll()) { + if (hologram.getData() instanceof TextHologramData textData) { + final var interval = textData.getTextUpdateInterval(); + if (interval < 1) { + continue; // doesn't update + } + + final var lastUpdate = updateTimes.asMap().get(textData.getName()); + if (lastUpdate != null && time < (lastUpdate + interval)) { + continue; + } + + if (lastUpdate == null || time > (lastUpdate + interval)) { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + hologram.updateFor(onlinePlayer); + } + + updateTimes.put(textData.getName(), time); + } + } + } + }, 50, 50, TimeUnit.MILLISECONDS); + } + + /** + * Syncs a hologram with its linked NPC, if any. + * + * @param hologram The hologram to sync. + */ + public void syncHologramWithNpc(@NotNull final Hologram hologram) { + final var linkedNpcName = hologram.getData().getLinkedNpcName(); + if (linkedNpcName == null) { + return; + } + + final var npc = FancyNpcsPlugin.get().getNpcManager().getNpc(linkedNpcName); + if (npc == null) { + return; + } + + npc.getData().setDisplayName(""); + npc.getData().setShowInTab(false); + npc.updateForAll(); + + final var npcScale = npc.getData().getScale(); + + if (hologram.getData() instanceof DisplayHologramData displayData) { + displayData.setScale(new Vector3f(npcScale)); + } + + final var location = npc.getData().getLocation().clone().add(0, (npc.getEyeHeight() * npcScale) + (0.5 * npcScale), 0); + hologram.getData().setLocation(location); + } +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/converter/ConverterTarget.java b/src/main/java/de/oliver/fancyholograms/converter/ConverterTarget.java similarity index 96% rename from src/main/java/de/oliver/fancyholograms/storage/converter/ConverterTarget.java rename to src/main/java/de/oliver/fancyholograms/converter/ConverterTarget.java index 3fd91912..095bad97 100644 --- a/src/main/java/de/oliver/fancyholograms/storage/converter/ConverterTarget.java +++ b/src/main/java/de/oliver/fancyholograms/converter/ConverterTarget.java @@ -1,4 +1,4 @@ -package de.oliver.fancyholograms.storage.converter; +package de.oliver.fancyholograms.converter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -6,21 +6,13 @@ import java.util.regex.Pattern; public class ConverterTarget { + private static final ConverterTarget ALL = new ConverterTarget(Pattern.compile(".*")); private final @NotNull Pattern hologramIdRegex; public ConverterTarget(@NotNull Pattern matching) { this.hologramIdRegex = matching; } - public @NotNull Pattern getRegex() { - return hologramIdRegex; - } - - public boolean matches(@NotNull String hologramId) { - return hologramIdRegex.asMatchPredicate().test(hologramId); - } - - private static final ConverterTarget ALL = new ConverterTarget(Pattern.compile(".*")); public static @NotNull ConverterTarget all() { return ALL; } @@ -54,4 +46,12 @@ public boolean matches(@NotNull String hologramId) { } } + public @NotNull Pattern getRegex() { + return hologramIdRegex; + } + + public boolean matches(@NotNull String hologramId) { + return hologramIdRegex.asMatchPredicate().test(hologramId); + } + } diff --git a/src/main/java/de/oliver/fancyholograms/storage/converter/DecentHologramsConverter.java b/src/main/java/de/oliver/fancyholograms/converter/DecentHologramsConverter.java similarity index 99% rename from src/main/java/de/oliver/fancyholograms/storage/converter/DecentHologramsConverter.java rename to src/main/java/de/oliver/fancyholograms/converter/DecentHologramsConverter.java index 21a36b4b..758377bf 100644 --- a/src/main/java/de/oliver/fancyholograms/storage/converter/DecentHologramsConverter.java +++ b/src/main/java/de/oliver/fancyholograms/converter/DecentHologramsConverter.java @@ -1,4 +1,4 @@ -package de.oliver.fancyholograms.storage.converter; +package de.oliver.fancyholograms.converter; import de.oliver.fancyholograms.api.data.HologramData; import de.oliver.fancyholograms.api.data.ItemHologramData; diff --git a/src/main/java/de/oliver/fancyholograms/storage/converter/FHConversionRegistry.java b/src/main/java/de/oliver/fancyholograms/converter/FHConversionRegistry.java similarity index 97% rename from src/main/java/de/oliver/fancyholograms/storage/converter/FHConversionRegistry.java rename to src/main/java/de/oliver/fancyholograms/converter/FHConversionRegistry.java index 366d4773..b2e9e726 100644 --- a/src/main/java/de/oliver/fancyholograms/storage/converter/FHConversionRegistry.java +++ b/src/main/java/de/oliver/fancyholograms/converter/FHConversionRegistry.java @@ -1,4 +1,4 @@ -package de.oliver.fancyholograms.storage.converter; +package de.oliver.fancyholograms.converter; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/de/oliver/fancyholograms/storage/converter/HologramConversionSession.java b/src/main/java/de/oliver/fancyholograms/converter/HologramConversionSession.java similarity index 90% rename from src/main/java/de/oliver/fancyholograms/storage/converter/HologramConversionSession.java rename to src/main/java/de/oliver/fancyholograms/converter/HologramConversionSession.java index 0c32739f..3b495e93 100644 --- a/src/main/java/de/oliver/fancyholograms/storage/converter/HologramConversionSession.java +++ b/src/main/java/de/oliver/fancyholograms/converter/HologramConversionSession.java @@ -1,11 +1,7 @@ -package de.oliver.fancyholograms.storage.converter; +package de.oliver.fancyholograms.converter; import de.oliver.fancyholograms.api.data.HologramData; import de.oliver.fancylib.MessageHelper; -import de.oliver.fancylib.translations.message.Message; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/de/oliver/fancyholograms/storage/converter/HologramConverter.java b/src/main/java/de/oliver/fancyholograms/converter/HologramConverter.java similarity index 87% rename from src/main/java/de/oliver/fancyholograms/storage/converter/HologramConverter.java rename to src/main/java/de/oliver/fancyholograms/converter/HologramConverter.java index 30e2c115..00b81cbb 100644 --- a/src/main/java/de/oliver/fancyholograms/storage/converter/HologramConverter.java +++ b/src/main/java/de/oliver/fancyholograms/converter/HologramConverter.java @@ -1,8 +1,8 @@ -package de.oliver.fancyholograms.storage.converter; +package de.oliver.fancyholograms.converter; import de.oliver.fancyanalytics.api.events.Event; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.data.HologramData; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -33,7 +33,7 @@ public abstract class HologramConverter { .withProperty("converter", getId()) .withProperty("target", spec.getTarget().getRegex().pattern()) .withProperty("amount", String.valueOf(converted.size())); - FancyHolograms.get().getFancyAnalytics().sendEvent(event); + FancyHologramsPlugin.get().getMetrics().getFancyAnalytics().sendEvent(event); return converted; } diff --git a/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java b/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java index 20325f56..7526765b 100644 --- a/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java +++ b/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java @@ -1,14 +1,17 @@ package de.oliver.fancyholograms.hologram.version; +import com.viaversion.viaversion.api.Via; +import de.oliver.fancyholograms.api.FancyHolograms; import de.oliver.fancyholograms.api.data.*; -import de.oliver.fancyholograms.api.events.HologramHideEvent; -import de.oliver.fancyholograms.api.events.HologramShowEvent; +import de.oliver.fancyholograms.api.events.HologramDespawnEvent; +import de.oliver.fancyholograms.api.events.HologramSpawnEvent; import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.config.FHFeatureFlags; +import de.oliver.fancyholograms.util.PluginUtils; import de.oliver.fancysitula.api.entities.*; import de.oliver.fancysitula.factories.FancySitula; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; public final class HologramImpl extends Hologram { @@ -17,20 +20,7 @@ public final class HologramImpl extends Hologram { public HologramImpl(@NotNull final HologramData data) { super(data); - } - @Override - public int getEntityId() { - return fsDisplay.getId(); - } - - @Override - public @Nullable org.bukkit.entity.Display getDisplayEntity() { - return null; - } - - @Override - public void create() { final var location = data.getLocation(); if (!location.isWorldLoaded()) { return; @@ -41,22 +31,92 @@ public void create() { case ITEM -> this.fsDisplay = new FS_ItemDisplay(); case BLOCK -> this.fsDisplay = new FS_BlockDisplay(); } + } - if (data instanceof DisplayHologramData dd) { - fsDisplay.setTransformationInterpolationDuration(dd.getInterpolationDuration()); - fsDisplay.setTransformationInterpolationStartDeltaTicks(0); + + @Override + public void spawnTo(@NotNull final Player player) { + if (!new HologramSpawnEvent(this, player).callEvent()) { + return; + } + + if (fsDisplay == null) { + return; // could not be created, nothing to show + } + + if (!data.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) { + return; } - update(); + if (FHFeatureFlags.DISABLE_HOLOGRAMS_FOR_OLD_CLIENTS.isEnabled()) { + final var protocolVersion = PluginUtils.isViaVersionEnabled() ? Via.getAPI().getPlayerVersion(player.getUniqueId()) : MINIMUM_PROTOCOL_VERSION; + if (protocolVersion < MINIMUM_PROTOCOL_VERSION) { + FancyHolograms.get().getFancyLogger().debug("Player " + player.getName() + " is using an outdated protocol version (" + protocolVersion + "). Hologram will not be shown."); + return; + } + } + + FS_RealPlayer fsPlayer = new FS_RealPlayer(player); + FancySitula.ENTITY_FACTORY.spawnEntityFor(fsPlayer, fsDisplay); + + this.viewers.add(player.getUniqueId()); + updateFor(player); + + traitTrait.onSpawn(player); } @Override - public void delete() { - this.fsDisplay = null; + public void despawnFrom(@NotNull final Player player) { + if (!new HologramDespawnEvent(this, player).callEvent()) { + return; + } + + if (fsDisplay == null) { + return; // doesn't exist, nothing to hide + } + + FS_RealPlayer fsPlayer = new FS_RealPlayer(player); + FancySitula.ENTITY_FACTORY.despawnEntityFor(fsPlayer, fsDisplay); + + this.viewers.remove(player.getUniqueId()); + + traitTrait.onDespawn(player); } + @Override - public void update() { + public void updateFor(@NotNull final Player player) { + if (fsDisplay == null) { + return; // doesn't exist, nothing to refresh + } + + syncWithData(); + + if (!isViewer(player)) { + return; + } + + FS_RealPlayer fsPlayer = new FS_RealPlayer(player); + + FancySitula.PACKET_FACTORY.createTeleportEntityPacket( + fsDisplay.getId(), + data.getLocation().x(), + data.getLocation().y(), + data.getLocation().z(), + data.getLocation().getYaw(), + data.getLocation().getPitch(), + true) + .send(fsPlayer); + + + if (fsDisplay instanceof FS_TextDisplay textDisplay) { + textDisplay.setText(getShownText(player)); + } + + FancySitula.ENTITY_FACTORY.setEntityDataFor(fsPlayer, fsDisplay); + } + + private void syncWithData() { if (fsDisplay == null) { return; } @@ -105,6 +165,10 @@ public void update() { } if (data instanceof DisplayHologramData displayData) { + // interpolation + fsDisplay.setTransformationInterpolationDuration(displayData.getInterpolationDuration()); + fsDisplay.setTransformationInterpolationStartDeltaTicks(0); + // billboard data fsDisplay.setBillboard(FS_Display.Billboard.valueOf(displayData.getBillboard().name())); @@ -127,87 +191,4 @@ public void update() { } } - - @Override - public boolean show(@NotNull final Player player) { - if (!new HologramShowEvent(this, player).callEvent()) { - return false; - } - - if (this.fsDisplay == null) { - create(); // try to create it if it doesn't exist every time - } - - if (fsDisplay == null) { - return false; // could not be created, nothing to show - } - - if (!data.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) { - return false; - } - - // TODO: cache player protocol version - // TODO: fix this -// final var protocolVersion = FancyHologramsPlugin.get().isUsingViaVersion() ? Via.getAPI().getPlayerVersion(player) : MINIMUM_PROTOCOL_VERSION; -// if (protocolVersion < MINIMUM_PROTOCOL_VERSION) { -// return false; -// } - - FS_RealPlayer fsPlayer = new FS_RealPlayer(player); - FancySitula.ENTITY_FACTORY.spawnEntityFor(fsPlayer, fsDisplay); - - this.viewers.add(player.getUniqueId()); - refreshHologram(player); - - return true; - } - - @Override - public boolean hide(@NotNull final Player player) { - if (!new HologramHideEvent(this, player).callEvent()) { - return false; - } - - if (fsDisplay == null) { - return false; // doesn't exist, nothing to hide - } - - FS_RealPlayer fsPlayer = new FS_RealPlayer(player); - FancySitula.ENTITY_FACTORY.despawnEntityFor(fsPlayer, fsDisplay); - - this.viewers.remove(player.getUniqueId()); - return true; - } - - - @Override - public void refresh(@NotNull final Player player) { - if (fsDisplay == null) { - return; // doesn't exist, nothing to refresh - } - - if (!isViewer(player)) { - return; - } - - FS_RealPlayer fsPlayer = new FS_RealPlayer(player); - - FancySitula.PACKET_FACTORY.createTeleportEntityPacket( - fsDisplay.getId(), - data.getLocation().x(), - data.getLocation().y(), - data.getLocation().z(), - data.getLocation().getYaw(), - data.getLocation().getPitch(), - true) - .send(fsPlayer); - - - if (fsDisplay instanceof FS_TextDisplay textDisplay) { - textDisplay.setText(getShownText(player)); - } - - FancySitula.ENTITY_FACTORY.setEntityDataFor(fsPlayer, fsDisplay); - } - } diff --git a/src/main/java/de/oliver/fancyholograms/listeners/BedrockPlayerListener.java b/src/main/java/de/oliver/fancyholograms/listeners/BedrockPlayerListener.java index 92e532ef..b78bf810 100644 --- a/src/main/java/de/oliver/fancyholograms/listeners/BedrockPlayerListener.java +++ b/src/main/java/de/oliver/fancyholograms/listeners/BedrockPlayerListener.java @@ -1,7 +1,7 @@ package de.oliver.fancyholograms.listeners; -import de.oliver.fancyholograms.FHFeatureFlags; -import de.oliver.fancyholograms.api.events.HologramShowEvent; +import de.oliver.fancyholograms.api.events.HologramSpawnEvent; +import de.oliver.fancyholograms.config.FHFeatureFlags; import de.oliver.fancyholograms.util.PluginUtils; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -10,7 +10,7 @@ public class BedrockPlayerListener implements Listener { @EventHandler - public void onHologramShow(final HologramShowEvent event) { + public void onHologramShow(final HologramSpawnEvent event) { if (FHFeatureFlags.DISABLE_HOLOGRAMS_FOR_BEDROCK_PLAYERS.isEnabled() && PluginUtils.isFloodgateEnabled()) { boolean isBedrockPlayer = FloodgateApi.getInstance().isFloodgatePlayer(event.getPlayer().getUniqueId()); if (isBedrockPlayer) { diff --git a/src/main/java/de/oliver/fancyholograms/listeners/NpcListener.java b/src/main/java/de/oliver/fancyholograms/listeners/NpcListener.java index dc8ae301..2cbf1d3d 100644 --- a/src/main/java/de/oliver/fancyholograms/listeners/NpcListener.java +++ b/src/main/java/de/oliver/fancyholograms/listeners/NpcListener.java @@ -1,8 +1,8 @@ package de.oliver.fancyholograms.listeners; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.data.HologramData; import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import de.oliver.fancylib.FancyLib; import de.oliver.fancylib.MessageHelper; import de.oliver.fancynpcs.api.events.NpcModifyEvent; @@ -14,16 +14,16 @@ public final class NpcListener implements Listener { - private final @NotNull FancyHolograms plugin; + private final @NotNull FancyHologramsPlugin plugin; - public NpcListener(@NotNull final FancyHolograms plugin) { + public NpcListener(@NotNull final FancyHologramsPlugin plugin) { this.plugin = plugin; } @EventHandler public void onRemove(@NotNull final NpcRemoveEvent event) { - this.plugin.getHologramsManager() - .getHolograms() + this.plugin.getRegistry() + .getAll() .stream() .filter(hologram -> event.getNpc().getData().getName().equals(hologram.getData().getLinkedNpcName())) .forEach(hologram -> hologram.getData().setLinkedNpcName(null)); @@ -31,7 +31,7 @@ public void onRemove(@NotNull final NpcRemoveEvent event) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onModify(@NotNull final NpcModifyEvent event) { - final var holograms = this.plugin.getHologramsManager().getHolograms(); + final var holograms = this.plugin.getRegistry().getAll(); switch (event.getModification()) { case TYPE, LOCATION, SCALE -> { @@ -39,7 +39,7 @@ public void onModify(@NotNull final NpcModifyEvent event) { .filter(hologram -> event.getNpc().getData().getName().equals(hologram.getData().getLinkedNpcName())) .toList(); - FancyLib.getInstance().getScheduler().runTaskLater(null, 1L, () -> needsToBeUpdated.forEach(this.plugin.getHologramsManager()::syncHologramWithNpc)); + FancyLib.getInstance().getScheduler().runTaskLater(null, 1L, () -> needsToBeUpdated.forEach(this.plugin.getControllerImpl()::syncHologramWithNpc)); } case DISPLAY_NAME, SHOW_IN_TAB -> { final var isLinked = holograms.stream() diff --git a/src/main/java/de/oliver/fancyholograms/listeners/PlayerListener.java b/src/main/java/de/oliver/fancyholograms/listeners/PlayerListener.java index fad939aa..da8b2080 100644 --- a/src/main/java/de/oliver/fancyholograms/listeners/PlayerListener.java +++ b/src/main/java/de/oliver/fancyholograms/listeners/PlayerListener.java @@ -1,64 +1,72 @@ package de.oliver.fancyholograms.listeners; -import de.oliver.fancyholograms.FancyHolograms; import de.oliver.fancyholograms.api.hologram.Hologram; -import net.kyori.adventure.resource.ResourcePackStatus; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.*; import org.bukkit.event.player.PlayerResourcePackStatusEvent.Status; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - import org.jetbrains.annotations.NotNull; +import java.util.*; + public final class PlayerListener implements Listener { - private final @NotNull FancyHolograms plugin; + private final @NotNull FancyHologramsPlugin plugin; private final Map> loadingResourcePacks; - public PlayerListener(@NotNull final FancyHolograms plugin) { + public PlayerListener(@NotNull final FancyHologramsPlugin plugin) { this.plugin = plugin; this.loadingResourcePacks = new HashMap<>(); } + // For 1.20.2 and higher this method returns actual pack identifier, while for older versions, the identifier is a dummy UUID full of zeroes. + // Versions prior 1.20.2 supports sending and receiving only one resource-pack and a dummy, constant identifier can be used as a key. + private static @NotNull UUID getResourcePackID(final @NotNull PlayerResourcePackStatusEvent event) { + try { + event.getClass().getMethod("getID"); + return event.getID(); + } catch (final @NotNull NoSuchMethodException e) { + return new UUID(0,0); + } + } + @EventHandler(priority = EventPriority.MONITOR) public void onJoin(@NotNull final PlayerJoinEvent event) { - for (final var hologram : this.plugin.getHologramsManager().getHolograms()) { - hologram.updateShownStateFor(event.getPlayer()); + for (final var hologram : this.plugin.getRegistry().getAll()) { + hologram.removeViewer(event.getPlayer().getUniqueId()); + FancyHologramsPlugin.get().getController().refreshHologram(hologram, event.getPlayer()); } if (!this.plugin.getHologramConfiguration().areVersionNotificationsMuted() && event.getPlayer().hasPermission("fancyholograms.admin")) { - FancyHolograms.get().getHologramThread().submit(() -> FancyHolograms.get().getVersionConfig().checkVersionAndDisplay(event.getPlayer(), true)); + FancyHologramsPlugin.get().getHologramThread().submit(() -> FancyHologramsPlugin.get().getVersionConfig().checkVersionAndDisplay(event.getPlayer(), true)); } } @EventHandler(priority = EventPriority.MONITOR) public void onQuit(@NotNull final PlayerQuitEvent event) { - FancyHolograms.get().getHologramThread().submit(() -> { - for (final var hologram : this.plugin.getHologramsManager().getHolograms()) { - hologram.hideHologram(event.getPlayer()); + FancyHologramsPlugin.get().getHologramThread().submit(() -> { + for (final var hologram : this.plugin.getRegistry().getAll()) { + hologram.removeViewer(event.getPlayer().getUniqueId()); + FancyHologramsPlugin.get().getController().refreshHologram(hologram, event.getPlayer()); } }); } @EventHandler(priority = EventPriority.MONITOR) public void onTeleport(@NotNull final PlayerTeleportEvent event) { - for (final Hologram hologram : this.plugin.getHologramsManager().getHolograms()) { - hologram.updateShownStateFor(event.getPlayer()); + for (final Hologram hologram : this.plugin.getRegistry().getAll()) { + FancyHologramsPlugin.get().getController().refreshHologram(hologram, event.getPlayer()); } } @EventHandler(priority = EventPriority.MONITOR) public void onWorldChange(@NotNull final PlayerChangedWorldEvent event) { - for (final Hologram hologram : this.plugin.getHologramsManager().getHolograms()) { - hologram.updateShownStateFor(event.getPlayer()); + for (final Hologram hologram : this.plugin.getRegistry().getAll()) { + hologram.removeViewer(event.getPlayer().getUniqueId()); + FancyHologramsPlugin.get().getController().refreshHologram(hologram, event.getPlayer()); } } @@ -81,22 +89,11 @@ else if (event.getStatus() == Status.SUCCESSFULLY_LOADED || event.getStatus() == // Removing player from the map, as they're no longer needed here. loadingResourcePacks.remove(playerUniqueId); // Refreshing holograms as to make sure custom textures are loaded. - for (final Hologram hologram : this.plugin.getHologramsManager().getHolograms()) { - hologram.refreshHologram(event.getPlayer()); + for (final Hologram hologram : this.plugin.getRegistry().getAll()) { + FancyHologramsPlugin.get().getController().refreshHologram(hologram, event.getPlayer()); } } } } - // For 1.20.2 and higher this method returns actual pack identifier, while for older versions, the identifier is a dummy UUID full of zeroes. - // Versions prior 1.20.2 supports sending and receiving only one resource-pack and a dummy, constant identifier can be used as a key. - private static @NotNull UUID getResourcePackID(final @NotNull PlayerResourcePackStatusEvent event) { - try { - event.getClass().getMethod("getID"); - return event.getID(); - } catch (final @NotNull NoSuchMethodException e) { - return new UUID(0,0); - } - } - } diff --git a/src/main/java/de/oliver/fancyholograms/listeners/WorldListener.java b/src/main/java/de/oliver/fancyholograms/listeners/WorldListener.java index 84d55edf..f4ebd6db 100644 --- a/src/main/java/de/oliver/fancyholograms/listeners/WorldListener.java +++ b/src/main/java/de/oliver/fancyholograms/listeners/WorldListener.java @@ -1,26 +1,43 @@ package de.oliver.fancyholograms.listeners; -import de.oliver.fancyholograms.FancyHolograms; +import de.oliver.fancyholograms.api.data.HologramData; +import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; +import java.util.Collection; +import java.util.List; + public class WorldListener implements Listener { @EventHandler public void onWorldLoad(WorldLoadEvent event) { - FancyHolograms.get().getHologramThread().submit(() -> { - FancyHolograms.get().getFancyLogger().info("Loading holograms for world " + event.getWorld().getName()); - FancyHolograms.get().getHologramsManager().loadHolograms(event.getWorld().getName()); + FancyHologramsPlugin.get().getHologramThread().submit(() -> { + FancyHologramsPlugin.get().getFancyLogger().info("Loading holograms for world " + event.getWorld().getName()); + + Collection data = FancyHologramsPlugin.get().getStorage().loadAll(event.getWorld().getName()); + for (HologramData d : data) { + Hologram hologram = FancyHologramsPlugin.get().getHologramFactory().apply(d); + FancyHologramsPlugin.get().getRegistry().register(hologram); + } }); } @EventHandler public void onWorldUnload(WorldUnloadEvent event) { - FancyHolograms.get().getHologramThread().submit(() -> { - FancyHolograms.get().getFancyLogger().info("Unloading holograms for world " + event.getWorld().getName()); - FancyHolograms.get().getHologramsManager().unloadHolograms(event.getWorld().getName()); + FancyHologramsPlugin.get().getHologramThread().submit(() -> { + FancyHologramsPlugin.get().getFancyLogger().info("Unloading holograms for world " + event.getWorld().getName()); + + List toUnload = FancyHologramsPlugin.get().getRegistry().getAll().stream() + .filter(hologram -> hologram.getData().getLocation().getWorld().equals(event.getWorld())) + .toList(); + + for (Hologram hologram : toUnload) { + FancyHologramsPlugin.get().getRegistry().unregister(hologram); + } }); } diff --git a/src/main/java/de/oliver/fancyholograms/loaders/FancyHologramsBootstrapper.java b/src/main/java/de/oliver/fancyholograms/main/FancyHologramsBootstrapper.java similarity index 93% rename from src/main/java/de/oliver/fancyholograms/loaders/FancyHologramsBootstrapper.java rename to src/main/java/de/oliver/fancyholograms/main/FancyHologramsBootstrapper.java index e6ee815e..84063e7b 100644 --- a/src/main/java/de/oliver/fancyholograms/loaders/FancyHologramsBootstrapper.java +++ b/src/main/java/de/oliver/fancyholograms/main/FancyHologramsBootstrapper.java @@ -1,4 +1,4 @@ -package de.oliver.fancyholograms.loaders; +package de.oliver.fancyholograms.main; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import io.papermc.paper.plugin.bootstrap.PluginBootstrap; diff --git a/src/main/java/de/oliver/fancyholograms/loaders/FancyHologramsLoader.java b/src/main/java/de/oliver/fancyholograms/main/FancyHologramsLoader.java similarity index 88% rename from src/main/java/de/oliver/fancyholograms/loaders/FancyHologramsLoader.java rename to src/main/java/de/oliver/fancyholograms/main/FancyHologramsLoader.java index a4c0c716..171fca53 100644 --- a/src/main/java/de/oliver/fancyholograms/loaders/FancyHologramsLoader.java +++ b/src/main/java/de/oliver/fancyholograms/main/FancyHologramsLoader.java @@ -1,4 +1,4 @@ -package de.oliver.fancyholograms.loaders; +package de.oliver.fancyholograms.main; import io.papermc.paper.plugin.loader.PluginClasspathBuilder; import io.papermc.paper.plugin.loader.PluginLoader; diff --git a/src/main/java/de/oliver/fancyholograms/FancyHolograms.java b/src/main/java/de/oliver/fancyholograms/main/FancyHologramsPlugin.java similarity index 55% rename from src/main/java/de/oliver/fancyholograms/FancyHolograms.java rename to src/main/java/de/oliver/fancyholograms/main/FancyHologramsPlugin.java index 541f7f53..f535de10 100644 --- a/src/main/java/de/oliver/fancyholograms/FancyHolograms.java +++ b/src/main/java/de/oliver/fancyholograms/main/FancyHologramsPlugin.java @@ -1,32 +1,37 @@ -package de.oliver.fancyholograms; +package de.oliver.fancyholograms.main; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import de.oliver.fancyanalytics.api.FancyAnalyticsAPI; -import de.oliver.fancyanalytics.api.metrics.MetricSupplier; import de.oliver.fancyanalytics.logger.ExtendedFancyLogger; import de.oliver.fancyanalytics.logger.LogLevel; import de.oliver.fancyanalytics.logger.appender.Appender; import de.oliver.fancyanalytics.logger.appender.ConsoleAppender; import de.oliver.fancyanalytics.logger.appender.JsonAppender; -import de.oliver.fancyholograms.api.FancyHologramsPlugin; +import de.oliver.fancyholograms.api.FancyHolograms; import de.oliver.fancyholograms.api.HologramConfiguration; -import de.oliver.fancyholograms.api.HologramManager; -import de.oliver.fancyholograms.api.HologramStorage; +import de.oliver.fancyholograms.api.HologramController; +import de.oliver.fancyholograms.api.HologramRegistry; import de.oliver.fancyholograms.api.data.HologramData; import de.oliver.fancyholograms.api.hologram.Hologram; import de.oliver.fancyholograms.commands.FancyHologramsCMD; import de.oliver.fancyholograms.commands.FancyHologramsTestCMD; import de.oliver.fancyholograms.commands.HologramCMD; +import de.oliver.fancyholograms.config.FHConfiguration; +import de.oliver.fancyholograms.config.FHFeatureFlags; +import de.oliver.fancyholograms.controller.HologramControllerImpl; +import de.oliver.fancyholograms.converter.FHConversionRegistry; import de.oliver.fancyholograms.hologram.version.*; import de.oliver.fancyholograms.listeners.BedrockPlayerListener; import de.oliver.fancyholograms.listeners.NpcListener; import de.oliver.fancyholograms.listeners.PlayerListener; import de.oliver.fancyholograms.listeners.WorldListener; -import de.oliver.fancyholograms.storage.FlatFileHologramStorage; -import de.oliver.fancyholograms.storage.converter.FHConversionRegistry; +import de.oliver.fancyholograms.metrics.FHMetrics; +import de.oliver.fancyholograms.registry.HologramRegistryImpl; +import de.oliver.fancyholograms.storage.HologramStorage; +import de.oliver.fancyholograms.storage.YamlHologramStorage; +import de.oliver.fancyholograms.trait.HologramTraitRegistryImpl; +import de.oliver.fancyholograms.trait.builtin.MultiplePagesTrait; import de.oliver.fancyholograms.util.PluginUtils; import de.oliver.fancylib.FancyLib; -import de.oliver.fancylib.Metrics; import de.oliver.fancylib.VersionConfig; import de.oliver.fancylib.serverSoftware.ServerSoftware; import de.oliver.fancylib.versionFetcher.MasterVersionFetcher; @@ -35,9 +40,9 @@ import de.oliver.fancysitula.api.utils.ServerVersion; import org.apache.maven.artifact.versioning.ComparableVersion; import org.bukkit.Bukkit; +import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.plugin.java.JavaPlugin; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,30 +57,30 @@ import static java.util.concurrent.CompletableFuture.supplyAsync; -public final class FancyHolograms extends JavaPlugin implements FancyHologramsPlugin { +public final class FancyHologramsPlugin extends JavaPlugin implements FancyHolograms { + + private static @Nullable FancyHologramsPlugin INSTANCE; - private static @Nullable FancyHolograms INSTANCE; private final ExtendedFancyLogger fancyLogger; - private final VersionFetcher versionFetcher = new MasterVersionFetcher("FancyHolograms"); - private final VersionConfig versionConfig = new VersionConfig(this, versionFetcher); - private final ScheduledExecutorService hologramThread = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder() - .setNameFormat("FancyHolograms-Holograms") - .build() - ); - private final ExecutorService fileStorageExecutor = Executors.newSingleThreadExecutor( - new ThreadFactoryBuilder() - .setDaemon(true) - .setPriority(Thread.MIN_PRIORITY + 1) - .setNameFormat("FancyHolograms-FileStorageExecutor") - .build() - ); - private FancyAnalyticsAPI fancyAnalytics; - private HologramConfiguration configuration = new FancyHologramsConfiguration(); - private HologramStorage hologramStorage = new FlatFileHologramStorage(); - private @Nullable HologramManagerImpl hologramsManager; - - public FancyHolograms() { + + private final FHMetrics metrics; + + private final VersionFetcher versionFetcher; + private final VersionConfig versionConfig; + + private final ScheduledExecutorService hologramThread; + private final ExecutorService storageThread; + + private final HologramConfiguration configuration; + + private Function hologramFactory; + + private HologramStorage storage; + private HologramRegistryImpl registry; + private HologramControllerImpl controller; + private HologramTraitRegistryImpl traitRegistry; + + public FancyHologramsPlugin() { INSTANCE = this; Appender consoleAppender = new ConsoleAppender("[{loggerName}] ({threadName}) {logLevel}: {message}"); @@ -90,10 +95,31 @@ public FancyHolograms() { } } JsonAppender jsonAppender = new JsonAppender(false, false, true, logsFile.getPath()); - this.fancyLogger = new ExtendedFancyLogger("FancyHolograms", LogLevel.INFO, List.of(consoleAppender, jsonAppender), new ArrayList<>()); + fancyLogger = new ExtendedFancyLogger("FancyHolograms", LogLevel.INFO, List.of(consoleAppender, jsonAppender), new ArrayList<>()); + + versionFetcher = new MasterVersionFetcher("FancyHolograms"); + versionConfig = new VersionConfig(this, versionFetcher); + + metrics = new FHMetrics(); + + hologramThread = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder() + .setNameFormat("FancyHolograms-Hologram") + .build() + ); + + storageThread = Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder() + .setDaemon(true) + .setPriority(Thread.MIN_PRIORITY + 1) + .setNameFormat("FancyHolograms-Storage") + .build() + ); + + configuration = new FHConfiguration(); } - public static @NotNull FancyHolograms get() { + public static @NotNull FancyHologramsPlugin get() { return Objects.requireNonNull(INSTANCE, "plugin is not initialized"); } @@ -103,9 +129,35 @@ public static boolean canGet() { @Override public void onLoad() { - final var adapter = resolveHologramAdapter(); + FHFeatureFlags.load(); + configuration.reload(this); + + LogLevel logLevel; + try { + logLevel = LogLevel.valueOf(configuration.getLogLevel()); + } catch (IllegalArgumentException e) { + logLevel = LogLevel.INFO; + } + fancyLogger.setCurrentLevel(logLevel); + IFancySitula.LOGGER.setCurrentLevel(logLevel); - if (adapter == null) { + storage = new YamlHologramStorage(); + registry = new HologramRegistryImpl(); + controller = new HologramControllerImpl(); + traitRegistry = new HologramTraitRegistryImpl(); + + if (!ServerSoftware.isPaper()) { + fancyLogger.warn(""" + -------------------------------------------------- + It is recommended to use Paper as server software. + Because you are not using paper, the plugin + might not work correctly. + -------------------------------------------------- + """); + } + + hologramFactory = resolveHologramFactory(); + if (hologramFactory == null) { List supportedVersions = new ArrayList<>(List.of("1.19.4", "1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4")); supportedVersions.addAll(ServerVersion.getSupportedVersions()); @@ -120,140 +172,61 @@ Please update the server to one of (%s). return; } - hologramsManager = new HologramManagerImpl(this, adapter); - fancyLogger.info("Successfully loaded FancyHolograms version %s".formatted(getDescription().getVersion())); } @Override public void onEnable() { - getHologramConfiguration().reload(this); // initialize configuration - - new FancyLib(INSTANCE); // initialize FancyLib - - if (!ServerSoftware.isPaper()) { - fancyLogger.warn(""" - -------------------------------------------------- - It is recommended to use Paper as server software. - Because you are not using paper, the plugin - might not work correctly. - -------------------------------------------------- - """); - } - - LogLevel logLevel; - try { - logLevel = LogLevel.valueOf(getHologramConfiguration().getLogLevel()); - } catch (IllegalArgumentException e) { - logLevel = LogLevel.INFO; - } - fancyLogger.setCurrentLevel(logLevel); - IFancySitula.LOGGER.setCurrentLevel(logLevel); - - FHFeatureFlags.load(); - - reloadCommands(); + new FancyLib(INSTANCE); + registerCommands(); registerListeners(); versionConfig.load(); - if (!getHologramConfiguration().areVersionNotificationsMuted()) { + if (!configuration.areVersionNotificationsMuted()) { checkForNewerVersion(); } - registerMetrics(); + metrics.register(); + metrics.registerLegacy(); - getHologramsManager().initializeTasks(); + for (World world : Bukkit.getWorlds()) { + Collection data = storage.loadAll(world.getName()); + for (HologramData d : data) { + Hologram hologram = hologramFactory.apply(d); + registry.register(hologram); + } + } + + controller.initRefreshTask(); + controller.initUpdateTask(); - if (getHologramConfiguration().isAutosaveEnabled()) { - getHologramThread().scheduleAtFixedRate(() -> { - if (hologramsManager != null) { - hologramsManager.saveHolograms(); - } - }, getHologramConfiguration().getAutosaveInterval(), getHologramConfiguration().getAutosaveInterval() * 60L, TimeUnit.SECONDS); + if (configuration.isAutosaveEnabled()) { + getHologramThread().scheduleWithFixedDelay( + this::savePersistentHolograms, + configuration.getAutosaveInterval(), + 120L, TimeUnit.SECONDS + ); } FHConversionRegistry.registerBuiltInConverters(); + traitRegistry.register(MultiplePagesTrait.class); + fancyLogger.info("Successfully enabled FancyHolograms version %s".formatted(getDescription().getVersion())); } @Override public void onDisable() { - hologramsManager.saveHolograms(); hologramThread.shutdown(); - fileStorageExecutor.shutdown(); - INSTANCE = null; + storageThread.shutdown(); fancyLogger.info("Successfully disabled FancyHolograms version %s".formatted(getDescription().getVersion())); - } - - @Override - public JavaPlugin getPlugin() { - return INSTANCE; - } - @Override - public ExtendedFancyLogger getFancyLogger() { - return fancyLogger; - } - - public @NotNull VersionFetcher getVersionFetcher() { - return versionFetcher; - } - - public @NotNull VersionConfig getVersionConfig() { - return versionConfig; - } - - @ApiStatus.Internal - public @NotNull HologramManagerImpl getHologramsManager() { - return Objects.requireNonNull(this.hologramsManager, "plugin is not initialized"); - } - - @Override - public HologramManager getHologramManager() { - return Objects.requireNonNull(this.hologramsManager, "plugin is not initialized"); - } - - @Override - public HologramConfiguration getHologramConfiguration() { - return configuration; - } - - @Override - public void setHologramConfiguration(HologramConfiguration configuration, boolean reload) { - this.configuration = configuration; - - if (reload) { - configuration.reload(this); - reloadCommands(); - } - } - - @Override - public HologramStorage getHologramStorage() { - return hologramStorage; - } - - @Override - public void setHologramStorage(HologramStorage storage, boolean reload) { - this.hologramStorage = storage; - - if (reload) { - getHologramsManager().reloadHolograms(); - } - } - - public ScheduledExecutorService getHologramThread() { - return hologramThread; - } - - public ExecutorService getFileStorageExecutor() { - return this.fileStorageExecutor; + INSTANCE = null; } - private @Nullable Function resolveHologramAdapter() { + private @Nullable Function resolveHologramFactory() { final var version = Bukkit.getMinecraftVersion(); // check if the server version is supported by FancySitula @@ -270,10 +243,10 @@ public ExecutorService getFileStorageExecutor() { }; } - public void reloadCommands() { + private void registerCommands() { Collection commands = Arrays.asList(new HologramCMD(this), new FancyHologramsCMD(this)); - if (getHologramConfiguration().isRegisterCommands()) { + if (configuration.isRegisterCommands()) { commands.forEach(command -> getServer().getCommandMap().register("fancyholograms", command)); } else { commands.stream().filter(Command::isRegistered).forEach(command -> @@ -318,70 +291,80 @@ Please update to the newest version (%s). }); } - private void registerMetrics() { - boolean isDevelopmentBuild = !versionConfig.getBuild().equalsIgnoreCase("undefined"); + public void savePersistentHolograms() { + List toSave = registry.getAllPersistent() + .stream() + .map(Hologram::getData) + .toList(); - Metrics metrics = new Metrics(this, 17990); - metrics.addCustomChart(new Metrics.SingleLineChart("total_holograms", () -> hologramsManager.getHolograms().size())); - metrics.addCustomChart(new Metrics.SimplePie("update_notifications", () -> configuration.areVersionNotificationsMuted() ? "No" : "Yes")); - metrics.addCustomChart(new Metrics.SimplePie("using_development_build", () -> isDevelopmentBuild ? "Yes" : "No")); + storage.saveBatch(toSave); + } - fancyAnalytics = new FancyAnalyticsAPI("3b77bd59-2b01-46f2-b3aa-a9584401797f", "E2gW5zc2ZTk1OGFkNGY2ZDQ0ODlM6San"); - fancyAnalytics.getConfig().setDisableLogging(true); + @Override + public JavaPlugin getPlugin() { + return INSTANCE; + } - if (!isDevelopmentBuild) { - return; - } + @Override + public ExtendedFancyLogger getFancyLogger() { + return fancyLogger; + } - fancyAnalytics.registerMinecraftPluginMetrics(INSTANCE); - fancyAnalytics.getExceptionHandler().registerLogger(getLogger()); - fancyAnalytics.getExceptionHandler().registerLogger(Bukkit.getLogger()); - fancyAnalytics.getExceptionHandler().registerLogger(fancyLogger); + public FHMetrics getMetrics() { + return metrics; + } - fancyAnalytics.registerStringMetric(new MetricSupplier<>("commit_hash", () -> versionConfig.getHash().substring(0, 7))); + public @NotNull VersionFetcher getVersionFetcher() { + return versionFetcher; + } - fancyAnalytics.registerStringMetric(new MetricSupplier<>("server_size", () -> { - long onlinePlayers = Bukkit.getOnlinePlayers().size(); + public @NotNull VersionConfig getVersionConfig() { + return versionConfig; + } - if (onlinePlayers == 0) { - return "empty"; - } + @Override + public HologramController getController() { + return controller; + } - if (onlinePlayers <= 25) { - return "small"; - } + public HologramControllerImpl getControllerImpl() { + return controller; + } - if (onlinePlayers <= 100) { - return "medium"; - } - if (onlinePlayers <= 500) { - return "large"; - } + @Override + public HologramRegistry getRegistry() { + return registry; + } - return "very_large"; - })); + @Override + public HologramTraitRegistryImpl getTraitRegistry() { + return traitRegistry; + } - fancyAnalytics.registerNumberMetric(new MetricSupplier<>("amount_holograms", () -> (double) hologramsManager.getHolograms().size())); - fancyAnalytics.registerStringMetric(new MetricSupplier<>("enabled_update_notifications", () -> configuration.areVersionNotificationsMuted() ? "false" : "true")); - fancyAnalytics.registerStringMetric(new MetricSupplier<>("fflag_disable_holograms_for_bedrock_players", () -> FHFeatureFlags.DISABLE_HOLOGRAMS_FOR_BEDROCK_PLAYERS.isEnabled() ? "true" : "false")); - fancyAnalytics.registerStringMetric(new MetricSupplier<>("using_development_build", () -> isDevelopmentBuild ? "true" : "false")); + @Override + public HologramConfiguration getHologramConfiguration() { + return configuration; + } - fancyAnalytics.registerStringArrayMetric(new MetricSupplier<>("hologram_type", () -> { - if (hologramsManager == null) { - return new String[0]; - } + @Override + public Function getHologramFactory() { + return hologramFactory; + } - return hologramsManager.getHolograms().stream() - .map(h -> h.getData().getType().name()) - .toArray(String[]::new); - })); + public HologramStorage getStorage() { + return storage; + } + public ScheduledExecutorService getHologramThread() { + return hologramThread; + } - fancyAnalytics.initialize(); + public ExecutorService getStorageThread() { + return this.storageThread; } - public FancyAnalyticsAPI getFancyAnalytics() { - return fancyAnalytics; + public HologramConfiguration getFHConfiguration() { + return configuration; } } diff --git a/src/main/java/de/oliver/fancyholograms/metrics/FHMetrics.java b/src/main/java/de/oliver/fancyholograms/metrics/FHMetrics.java new file mode 100644 index 00000000..c148265d --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/metrics/FHMetrics.java @@ -0,0 +1,88 @@ +package de.oliver.fancyholograms.metrics; + +import de.oliver.fancyanalytics.api.FancyAnalyticsAPI; +import de.oliver.fancyanalytics.api.metrics.MetricSupplier; +import de.oliver.fancyanalytics.logger.ExtendedFancyLogger; +import de.oliver.fancyholograms.api.HologramRegistry; +import de.oliver.fancyholograms.config.FHFeatureFlags; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancylib.Metrics; +import org.bukkit.Bukkit; + +public class FHMetrics { + + private ExtendedFancyLogger logger; + private FancyAnalyticsAPI fancyAnalytics; + private boolean isDevelopmentBuild = true; + + public FHMetrics() { + logger = FancyHologramsPlugin.get().getFancyLogger(); + } + + public void register() { + isDevelopmentBuild = !FancyHologramsPlugin.get().getVersionConfig().getBuild().equalsIgnoreCase("undefined"); + + fancyAnalytics = new FancyAnalyticsAPI("3b77bd59-2b01-46f2-b3aa-a9584401797f", "E2gW5zc2ZTk1OGFkNGY2ZDQ0ODlM6San"); + fancyAnalytics.getConfig().setDisableLogging(true); + + fancyAnalytics.registerMinecraftPluginMetrics(FancyHologramsPlugin.get()); + fancyAnalytics.getExceptionHandler().registerLogger(FancyHologramsPlugin.get().getLogger()); + fancyAnalytics.getExceptionHandler().registerLogger(Bukkit.getLogger()); + fancyAnalytics.getExceptionHandler().registerLogger(logger); + + HologramRegistry registry = FancyHologramsPlugin.get().getRegistry(); + + fancyAnalytics.registerStringMetric(new MetricSupplier<>("commit_hash", () -> FancyHologramsPlugin.get().getVersionConfig().getHash().substring(0, 7))); + + fancyAnalytics.registerStringMetric(new MetricSupplier<>("server_size", () -> { + long onlinePlayers = Bukkit.getOnlinePlayers().size(); + + if (onlinePlayers == 0) { + return "empty"; + } + + if (onlinePlayers <= 25) { + return "small"; + } + + if (onlinePlayers <= 100) { + return "medium"; + } + + if (onlinePlayers <= 500) { + return "large"; + } + + return "very_large"; + })); + + fancyAnalytics.registerNumberMetric(new MetricSupplier<>("amount_holograms", () -> (double) registry.getAll().size())); + fancyAnalytics.registerStringMetric(new MetricSupplier<>("enabled_update_notifications", () -> FancyHologramsPlugin.get().getFHConfiguration().areVersionNotificationsMuted() ? "false" : "true")); + fancyAnalytics.registerStringMetric(new MetricSupplier<>("fflag_disable_holograms_for_bedrock_players", () -> FHFeatureFlags.DISABLE_HOLOGRAMS_FOR_BEDROCK_PLAYERS.isEnabled() ? "true" : "false")); + fancyAnalytics.registerStringMetric(new MetricSupplier<>("using_development_build", () -> isDevelopmentBuild ? "true" : "false")); + + fancyAnalytics.registerStringArrayMetric(new MetricSupplier<>("hologram_type", () -> { + if (registry == null) { + return new String[0]; + } + + return registry.getAll().stream() + .map(h -> h.getData().getType().name()) + .toArray(String[]::new); + })); + + + fancyAnalytics.initialize(); + } + + public void registerLegacy() { + Metrics metrics = new Metrics(FancyHologramsPlugin.get(), 17990); + metrics.addCustomChart(new Metrics.SingleLineChart("total_holograms", () -> FancyHologramsPlugin.get().getRegistry().getAll().size())); + metrics.addCustomChart(new Metrics.SimplePie("update_notifications", () -> FancyHologramsPlugin.get().getFHConfiguration().areVersionNotificationsMuted() ? "No" : "Yes")); + metrics.addCustomChart(new Metrics.SimplePie("using_development_build", () -> isDevelopmentBuild ? "Yes" : "No")); + } + + public FancyAnalyticsAPI getFancyAnalytics() { + return fancyAnalytics; + } +} diff --git a/src/main/java/de/oliver/fancyholograms/registry/HologramRegistryImpl.java b/src/main/java/de/oliver/fancyholograms/registry/HologramRegistryImpl.java new file mode 100644 index 00000000..3e7a95aa --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/registry/HologramRegistryImpl.java @@ -0,0 +1,85 @@ +package de.oliver.fancyholograms.registry; + +import de.oliver.fancyholograms.api.HologramRegistry; +import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class HologramRegistryImpl implements HologramRegistry { + + private final Map holograms; + + public HologramRegistryImpl() { + this.holograms = new ConcurrentHashMap<>(); + } + + @Override + public boolean register(Hologram hologram) { + FancyHologramsPlugin.get().getController().refreshHologram(hologram, Bukkit.getOnlinePlayers()); + + boolean registered = holograms.putIfAbsent(hologram.getData().getName(), hologram) != null; + + hologram.getTraitTrait().onRegister(); + + return registered; + } + + @Override + public boolean unregister(Hologram hologram) { + boolean removed = holograms.remove(hologram.getData().getName(), hologram); + + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + hologram.despawnFrom(onlinePlayer); + } + + FancyHologramsPlugin.get().getStorage().delete(hologram.getData()); + + hologram.getTraitTrait().onUnregister(); + + return removed; + } + + @Override + public boolean contains(String name) { + return holograms.containsKey(name); + } + + @Override + public Optional get(String name) { + return Optional.ofNullable(holograms.get(name)); + } + + @Override + public Hologram mustGet(String name) { + if (!contains(name)) { + throw new IllegalArgumentException("Hologram with name " + name + " does not exist!"); + } + + return holograms.get(name); + } + + @Override + public Collection getAll() { + return Collections.unmodifiableCollection(holograms.values()); + } + + @Override + public Collection getAllPersistent() { + return getAll() + .stream() + .filter(hologram -> hologram.getData().isPersistent()) + .toList(); + } + + @Override + public void clear() { + holograms.clear(); + } +} diff --git a/api/src/main/java/de/oliver/fancyholograms/api/HologramStorage.java b/src/main/java/de/oliver/fancyholograms/storage/HologramStorage.java similarity index 52% rename from api/src/main/java/de/oliver/fancyholograms/api/HologramStorage.java rename to src/main/java/de/oliver/fancyholograms/storage/HologramStorage.java index f545fc74..9b07f3b9 100644 --- a/api/src/main/java/de/oliver/fancyholograms/api/HologramStorage.java +++ b/src/main/java/de/oliver/fancyholograms/storage/HologramStorage.java @@ -1,6 +1,6 @@ -package de.oliver.fancyholograms.api; +package de.oliver.fancyholograms.storage; -import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.api.data.HologramData; import java.util.Collection; @@ -10,30 +10,22 @@ public interface HologramStorage { * Saves a collection of holograms. * * @param holograms The holograms to save. - * @param override Whether to override existing holograms. */ - void saveBatch(Collection holograms, boolean override); + void saveBatch(Collection holograms); /** * Saves a hologram. * * @param hologram The hologram to save. */ - void save(Hologram hologram); + void save(HologramData hologram); /** * Deletes a hologram. * * @param hologram The hologram to delete. */ - void delete(Hologram hologram); - - /** - * Loads all holograms from all worlds - * - * @return A collection of all loaded holograms. - */ - Collection loadAll(); + void delete(HologramData hologram); /** * Loads all holograms from a specific world @@ -41,5 +33,5 @@ public interface HologramStorage { * @param world The world to load the holograms from. * @return A collection of all loaded holograms. */ - Collection loadAll(String world); + Collection loadAll(String world); } diff --git a/src/main/java/de/oliver/fancyholograms/storage/StorageType.java b/src/main/java/de/oliver/fancyholograms/storage/StorageType.java new file mode 100644 index 00000000..27d4a378 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/StorageType.java @@ -0,0 +1,8 @@ +package de.oliver.fancyholograms.storage; + +public enum StorageType { + + @Deprecated YAML, + JSON, + +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/FlatFileHologramStorage.java b/src/main/java/de/oliver/fancyholograms/storage/YamlHologramStorage.java similarity index 61% rename from src/main/java/de/oliver/fancyholograms/storage/FlatFileHologramStorage.java rename to src/main/java/de/oliver/fancyholograms/storage/YamlHologramStorage.java index aad9ecf7..6bdd432e 100644 --- a/src/main/java/de/oliver/fancyholograms/storage/FlatFileHologramStorage.java +++ b/src/main/java/de/oliver/fancyholograms/storage/YamlHologramStorage.java @@ -1,13 +1,8 @@ package de.oliver.fancyholograms.storage; -import de.oliver.fancyholograms.FancyHolograms; -import de.oliver.fancyholograms.api.HologramStorage; -import de.oliver.fancyholograms.api.data.BlockHologramData; -import de.oliver.fancyholograms.api.data.DisplayHologramData; -import de.oliver.fancyholograms.api.data.ItemHologramData; -import de.oliver.fancyholograms.api.data.TextHologramData; -import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.api.data.*; import de.oliver.fancyholograms.api.hologram.HologramType; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -23,13 +18,12 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -public class FlatFileHologramStorage implements HologramStorage { +public class YamlHologramStorage implements HologramStorage { private static final ReadWriteLock lock = new ReentrantReadWriteLock(); private static final File HOLOGRAMS_CONFIG_FILE = new File("plugins/FancyHolograms/holograms.yml"); - @Override - public void saveBatch(Collection holograms, boolean override) { + public void saveBatch(Collection holograms) { lock.readLock().lock(); boolean success = false; @@ -37,10 +31,6 @@ public void saveBatch(Collection holograms, boolean override) { try { config = YamlConfiguration.loadConfiguration(HOLOGRAMS_CONFIG_FILE); - if (override) { - config.set("holograms", null); - } - for (final var hologram : holograms) { writeHologram(config, hologram); } @@ -53,11 +43,10 @@ public void saveBatch(Collection holograms, boolean override) { } } - FancyHolograms.get().getFancyLogger().debug("Saved " + holograms.size() + " holograms to file (override=" + override + ")"); + FancyHologramsPlugin.get().getFancyLogger().debug("Saved " + holograms.size() + " holograms to file"); } - @Override - public void save(Hologram hologram) { + public void save(HologramData hologram) { lock.readLock().lock(); boolean success = false; @@ -74,18 +63,17 @@ public void save(Hologram hologram) { } } - FancyHolograms.get().getFancyLogger().debug("Saved hologram " + hologram.getData().getName() + " to file"); + FancyHologramsPlugin.get().getFancyLogger().debug("Saved hologram " + hologram.getName() + " to file"); } - @Override - public void delete(Hologram hologram) { + public void delete(HologramData hologram) { lock.readLock().lock(); boolean success = false; YamlConfiguration config = null; try { config = YamlConfiguration.loadConfiguration(HOLOGRAMS_CONFIG_FILE); - config.set("holograms." + hologram.getData().getName(), null); + config.set("holograms." + hologram.getName(), null); success = true; } finally { @@ -95,50 +83,48 @@ public void delete(Hologram hologram) { } } - FancyHolograms.get().getFancyLogger().debug("Deleted hologram " + hologram.getData().getName() + " from file"); + FancyHologramsPlugin.get().getFancyLogger().debug("Deleted hologram " + hologram.getName() + " from file"); } - @Override - public Collection loadAll() { - List holograms = readHolograms(FlatFileHologramStorage.HOLOGRAMS_CONFIG_FILE, null); - FancyHolograms.get().getFancyLogger().debug("Loaded " + holograms.size() + " holograms from file"); + public Collection loadAll() { + List holograms = readHolograms(YamlHologramStorage.HOLOGRAMS_CONFIG_FILE, null); + FancyHologramsPlugin.get().getFancyLogger().debug("Loaded " + holograms.size() + " holograms from file"); return holograms; } - @Override - public Collection loadAll(String world) { - List holograms = readHolograms(FlatFileHologramStorage.HOLOGRAMS_CONFIG_FILE, world); - FancyHolograms.get().getFancyLogger().debug("Loaded " + holograms.size() + " holograms from file (world=" + world + ")"); + public Collection loadAll(String world) { + List holograms = readHolograms(YamlHologramStorage.HOLOGRAMS_CONFIG_FILE, world); + FancyHologramsPlugin.get().getFancyLogger().debug("Loaded " + holograms.size() + " holograms from file (world=" + world + ")"); return holograms; } /** * @param world The world to load the holograms from. (null for all worlds) */ - private List readHolograms(@NotNull File configFile, @Nullable String world) { + private List readHolograms(@NotNull File configFile, @Nullable String world) { lock.readLock().lock(); try { YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); if (!config.isConfigurationSection("holograms")) { - FancyHolograms.get().getFancyLogger().warn("No holograms section found in config"); + FancyHologramsPlugin.get().getFancyLogger().warn("No holograms section found in config"); return new ArrayList<>(0); } int configVersion = config.getInt("version", 1); if (configVersion != 2) { - FancyHolograms.get().getFancyLogger().warn("Config version is not 2, skipping loading holograms"); - FancyHolograms.get().getFancyLogger().warn("Old config version detected, skipping loading holograms"); + FancyHologramsPlugin.get().getFancyLogger().warn("Config version is not 2, skipping loading holograms"); + FancyHologramsPlugin.get().getFancyLogger().warn("Old config version detected, skipping loading holograms"); return new ArrayList<>(0); } - List holograms = new ArrayList<>(); + List holograms = new ArrayList<>(); ConfigurationSection hologramsSection = config.getConfigurationSection("holograms"); for (String name : hologramsSection.getKeys(false)) { ConfigurationSection holoSection = hologramsSection.getConfigurationSection(name); if (holoSection == null) { - FancyHolograms.get().getFancyLogger().warn("Could not load hologram section in config"); + FancyHologramsPlugin.get().getFancyLogger().warn("Could not load hologram section in config"); continue; } @@ -148,13 +134,13 @@ private List readHolograms(@NotNull File configFile, @Nullable String String typeName = holoSection.getString("type"); if (typeName == null) { - FancyHolograms.get().getFancyLogger().warn("HologramType was not saved"); + FancyHologramsPlugin.get().getFancyLogger().warn("HologramType was not saved"); continue; } HologramType type = HologramType.getByName(typeName); if (type == null) { - FancyHolograms.get().getFancyLogger().warn("Could not parse HologramType"); + FancyHologramsPlugin.get().getFancyLogger().warn("Could not parse HologramType"); continue; } @@ -166,22 +152,21 @@ private List readHolograms(@NotNull File configFile, @Nullable String } if (!displayData.read(holoSection, name)) { - FancyHolograms.get().getFancyLogger().warn("Could not read hologram data - skipping hologram"); + FancyHologramsPlugin.get().getFancyLogger().warn("Could not read hologram data - skipping hologram"); continue; } - Hologram hologram = FancyHolograms.get().getHologramManager().create(displayData); - holograms.add(hologram); + holograms.add(displayData); } - FancyHolograms.get().getFancyLogger().debug("Loaded " + holograms.size() + " holograms from file"); + FancyHologramsPlugin.get().getFancyLogger().debug("Loaded " + holograms.size() + " holograms from file"); return holograms; } finally { lock.readLock().unlock(); } } - private void writeHologram(YamlConfiguration config, Hologram hologram) { + private void writeHologram(YamlConfiguration config, HologramData hologram) { @NotNull ConfigurationSection section; if (!config.isConfigurationSection("holograms")) { section = config.createSection("holograms"); @@ -189,22 +174,22 @@ private void writeHologram(YamlConfiguration config, Hologram hologram) { section = Objects.requireNonNull(config.getConfigurationSection("holograms")); } - String holoName = hologram.getData().getName(); + String holoName = hologram.getName(); ConfigurationSection holoSection = section.getConfigurationSection(holoName); if (holoSection == null) { holoSection = section.createSection(holoName); } - hologram.getData().write(holoSection, holoName); - FancyHolograms.get().getFancyLogger().debug("Wrote hologram " + holoName + " to config"); + hologram.write(holoSection, holoName); + FancyHologramsPlugin.get().getFancyLogger().debug("Wrote hologram " + holoName + " to config"); } private void saveConfig(YamlConfiguration config) { config.set("version", 2); config.setInlineComments("version", List.of("DO NOT CHANGE")); - FancyHolograms.get().getFileStorageExecutor().execute(() -> { + FancyHologramsPlugin.get().getStorageThread().execute(() -> { lock.writeLock().lock(); try { config.save(HOLOGRAMS_CONFIG_FILE); @@ -214,11 +199,11 @@ private void saveConfig(YamlConfiguration config) { lock.writeLock().unlock(); } - if(!FancyHolograms.canGet()) { + if(!FancyHologramsPlugin.canGet()) { return; } - FancyHolograms.get().getFancyLogger().debug("Saved config to file"); + FancyHologramsPlugin.get().getFancyLogger().debug("Saved config to file"); }); } } diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/JsonAdapter.java b/src/main/java/de/oliver/fancyholograms/storage/json/JsonAdapter.java new file mode 100644 index 00000000..545bf3cd --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/JsonAdapter.java @@ -0,0 +1,116 @@ +package de.oliver.fancyholograms.storage.json; + +import de.oliver.fancyholograms.api.data.*; +import de.oliver.fancyholograms.storage.json.model.*; + +public class JsonAdapter { + + public static JsonHologramData hologramDataToJson(HologramData data) { + return new JsonHologramData( + data.getName(), + data.getType(), + new JsonLocation( + data.getLocation().getWorld().getName(), + data.getLocation().getX(), + data.getLocation().getY(), + data.getLocation().getZ(), + data.getLocation().getYaw(), + data.getLocation().getPitch() + ), + data.getVisibilityDistance(), + data.getVisibility(), + data.getLinkedNpcName() + ); + } + + public static JsonDisplayHologramData displayHologramDataToJson(DisplayHologramData data) { + return new JsonDisplayHologramData( + new JsonVec3f( + data.getScale().x(), + data.getScale().y(), + data.getScale().z() + ), + new JsonVec3f( + data.getTranslation().x(), + data.getTranslation().y(), + data.getTranslation().z() + ), + data.getShadowRadius(), + data.getShadowStrength(), + data.getBrightness() == null ? null : new JsonBrightness( + data.getBrightness().getBlockLight(), + data.getBrightness().getSkyLight() + ), + data.getBillboard() + ); + } + + public static JsonTextHologramData textHologramDataToJson(TextHologramData data) { + return new JsonTextHologramData( + data.getText(), + data.hasTextShadow(), + data.isSeeThrough(), + data.getTextAlignment(), + data.getTextUpdateInterval(), + data.getBackground() == null ? "" : data.getBackground().toString() + ); + } + + public static JsonBlockHologramData blockHologramDataToJson(BlockHologramData data) { + return new JsonBlockHologramData( + data.getBlock().name() + ); + } + + public static JsonItemHologramData itemHologramDataToJson(ItemHologramData data) { + return new JsonItemHologramData( + new String(data.getItemStack().serializeAsBytes()) + ); + } + + public static JsonDataUnion toUnion(TextHologramData data) { + JsonHologramData hologramData = hologramDataToJson(data); + JsonDisplayHologramData displayHologramData = displayHologramDataToJson(data); + JsonTextHologramData textHologramData = textHologramDataToJson(data); + + return new JsonDataUnion( + hologramData, + displayHologramData, + textHologramData, + null, + null + ); + } + + public static JsonDataUnion toUnion(ItemHologramData data) { + JsonHologramData hologramData = hologramDataToJson(data); + JsonDisplayHologramData displayHologramData = displayHologramDataToJson(data); + JsonItemHologramData itemHologramData = itemHologramDataToJson(data); + + return new JsonDataUnion( + hologramData, + displayHologramData, + null, + itemHologramData, + null + ); + } + + public static JsonDataUnion toUnion(BlockHologramData data) { + JsonHologramData hologramData = hologramDataToJson(data); + JsonDisplayHologramData displayHologramData = displayHologramDataToJson(data); + JsonBlockHologramData blockHologramData = blockHologramDataToJson(data); + + return new JsonDataUnion( + hologramData, + displayHologramData, + null, + null, + blockHologramData + ); + } + + public static HologramData fromJson(JsonDataUnion data) { + return null; + } +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/JsonStorage.java b/src/main/java/de/oliver/fancyholograms/storage/json/JsonStorage.java new file mode 100644 index 00000000..eaf941b2 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/JsonStorage.java @@ -0,0 +1,68 @@ +package de.oliver.fancyholograms.storage.json; + +import de.oliver.fancyholograms.api.FancyHolograms; +import de.oliver.fancyholograms.api.data.BlockHologramData; +import de.oliver.fancyholograms.api.data.HologramData; +import de.oliver.fancyholograms.api.data.ItemHologramData; +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.storage.HologramStorage; +import de.oliver.fancyholograms.storage.json.model.JsonDataUnion; +import de.oliver.fancylib.jdb.JDB; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class JsonStorage implements HologramStorage { + + private final JDB jdb; + + public JsonStorage() { + this.jdb = new JDB("plugins/FancyHolograms/data/holograms"); + } + + @Override + public void saveBatch(Collection holograms) { + for (HologramData hologram : holograms) { + save(hologram); + } + } + + @Override + public void save(HologramData hologram) { + JsonDataUnion union = switch (hologram.getType()) { + case TEXT -> JsonAdapter.toUnion((TextHologramData) hologram); + case ITEM -> JsonAdapter.toUnion((ItemHologramData) hologram); + case BLOCK -> JsonAdapter.toUnion((BlockHologramData) hologram); + }; + + try { + jdb.set("worlds/" + hologram.getLocation().getWorld().getName() + "/" + hologram.getType() + "/" + hologram.getName(), union); + } catch (IOException e) { + FancyHolograms.get().getFancyLogger().error("Failed to save hologram " + hologram.getName()); + FancyHolograms.get().getFancyLogger().error(e); + } + } + + @Override + public void delete(HologramData hologram) { + jdb.delete("worlds/" + hologram.getLocation().getWorld().getName() + "/" + hologram.getName()); + } + + @Override + public Collection loadAll(String world) { + List holograms = new ArrayList<>(); + + try { + holograms.addAll(jdb.getAll("worlds/" + world + "/text", TextHologramData.class)); + holograms.addAll(jdb.getAll("worlds/" + world + "/item", ItemHologramData.class)); + holograms.addAll(jdb.getAll("worlds/" + world + "/block", BlockHologramData.class)); + } catch (IOException e) { + FancyHolograms.get().getFancyLogger().error("Failed to load all holograms from world " + world); + FancyHolograms.get().getFancyLogger().error(e); + } + + return holograms; + } +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonBlockHologramData.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonBlockHologramData.java new file mode 100644 index 00000000..9342cd70 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonBlockHologramData.java @@ -0,0 +1,6 @@ +package de.oliver.fancyholograms.storage.json.model; + +public record JsonBlockHologramData( + String block_material +) { +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonBrightness.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonBrightness.java new file mode 100644 index 00000000..156f6681 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonBrightness.java @@ -0,0 +1,7 @@ +package de.oliver.fancyholograms.storage.json.model; + +public record JsonBrightness( + int block_light, + int sky_light +) { +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonDataUnion.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonDataUnion.java new file mode 100644 index 00000000..24d9aaed --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonDataUnion.java @@ -0,0 +1,11 @@ +package de.oliver.fancyholograms.storage.json.model; + +public record JsonDataUnion( + JsonHologramData hologram_data, + JsonDisplayHologramData display_hologram_data, + + JsonTextHologramData text_hologram_data, + JsonItemHologramData item_hologram_data, + JsonBlockHologramData block_hologram_data +) { +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonDisplayHologramData.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonDisplayHologramData.java new file mode 100644 index 00000000..e2d130c7 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonDisplayHologramData.java @@ -0,0 +1,14 @@ +package de.oliver.fancyholograms.storage.json.model; + +import org.bukkit.entity.Display; + +public record JsonDisplayHologramData( + JsonVec3f scale, + JsonVec3f translation, + float shadow_radius, + float shadow_strength, + JsonBrightness brightness, + Display.Billboard billboard +) { +} + diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonHologramData.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonHologramData.java new file mode 100644 index 00000000..70eb1084 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonHologramData.java @@ -0,0 +1,15 @@ +package de.oliver.fancyholograms.storage.json.model; + +import de.oliver.fancyholograms.api.data.property.Visibility; +import de.oliver.fancyholograms.api.hologram.HologramType; + +public record JsonHologramData( + String name, + HologramType type, + JsonLocation location, + int visibilityDistance, + Visibility visibility, + String linkedNpcName +) { +} + diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonItemHologramData.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonItemHologramData.java new file mode 100644 index 00000000..07ba4fe5 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonItemHologramData.java @@ -0,0 +1,6 @@ +package de.oliver.fancyholograms.storage.json.model; + +public record JsonItemHologramData( + String item +) { +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonLocation.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonLocation.java new file mode 100644 index 00000000..fcc74581 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonLocation.java @@ -0,0 +1,11 @@ +package de.oliver.fancyholograms.storage.json.model; + +public record JsonLocation( + String world, + double x, + double y, + double z, + float yaw, + float pitch +) { +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonTextHologramData.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonTextHologramData.java new file mode 100644 index 00000000..4bb26216 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonTextHologramData.java @@ -0,0 +1,15 @@ +package de.oliver.fancyholograms.storage.json.model; + +import org.bukkit.entity.TextDisplay; + +import java.util.List; + +public record JsonTextHologramData( + List text, + boolean text_shadow, + boolean see_through, + TextDisplay.TextAlignment text_alignment, + int text_update_interval, + String background_color +) { +} diff --git a/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonVec3f.java b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonVec3f.java new file mode 100644 index 00000000..563fec90 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/storage/json/model/JsonVec3f.java @@ -0,0 +1,8 @@ +package de.oliver.fancyholograms.storage.json.model; + +public record JsonVec3f( + float x, + float y, + float z +) { +} diff --git a/src/main/java/de/oliver/fancyholograms/tests/FHTests.java b/src/main/java/de/oliver/fancyholograms/tests/FHTests.java new file mode 100644 index 00000000..b692785b --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/tests/FHTests.java @@ -0,0 +1,67 @@ +package de.oliver.fancyholograms.tests; + +import de.oliver.fancyholograms.tests.api.HologramBuilderTest; +import de.oliver.fancyholograms.tests.api.HologramControllerTest; +import de.oliver.fancyholograms.tests.api.HologramRegistryTest; +import de.oliver.fancylib.tests.FPTestClass; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +public class FHTests { + + private final List tests = new ArrayList<>(); + + public FHTests() { + addTest(HologramRegistryTest.class); + addTest(HologramControllerTest.class); + addTest(HologramBuilderTest.class); + } + + /** + * Adds a test class to the list of test classes to be run. + * + * @param testClass the test class to be added + * @return this instance, allowing for method chaining + */ + public FHTests addTest(Class testClass) { + tests.add(FPTestClass.fromClass(testClass)); + return this; + } + + /** + * Runs all registered test classes using the provided player context. + * + * @param player The player context to pass to the test methods. + * @return true if all tests completed successfully, false if any test failed or an unexpected exception occurred. + */ + public boolean runAllTests(Player player) { + for (FPTestClass test : tests) { + try { + if (!test.runTests(player)) { + return false; + } + } catch (Exception e) { + return false; + } + } + return true; + } + + /** + * Returns the current count of test classes registered to be run. + * + * @return the number of test classes in the list + */ + public int getTestCount() { + int count = 0; + + for (FPTestClass test : tests) { + count += test.testMethods().size(); + } + + return count; + } + +} diff --git a/src/main/java/de/oliver/fancyholograms/tests/api/HologramBuilderTest.java b/src/main/java/de/oliver/fancyholograms/tests/api/HologramBuilderTest.java new file mode 100644 index 00000000..15ab79ef --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/tests/api/HologramBuilderTest.java @@ -0,0 +1,194 @@ +package de.oliver.fancyholograms.tests.api; + +import de.oliver.fancyholograms.api.HologramRegistry; +import de.oliver.fancyholograms.api.data.BlockHologramData; +import de.oliver.fancyholograms.api.data.ItemHologramData; +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.api.data.builder.BlockHologramBuilder; +import de.oliver.fancyholograms.api.data.builder.ItemHologramBuilder; +import de.oliver.fancyholograms.api.data.builder.TextHologramBuilder; +import de.oliver.fancyholograms.api.data.property.Visibility; +import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.api.hologram.HologramType; +import de.oliver.fancyholograms.main.FancyHologramsPlugin; +import de.oliver.fancylib.tests.annotations.FPTest; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.entity.Display; +import org.bukkit.entity.Player; +import org.bukkit.entity.TextDisplay; +import org.bukkit.inventory.ItemStack; +import org.joml.Vector3f; + +import java.util.List; +import java.util.UUID; + +import static de.oliver.fancylib.tests.Expectable.expect; + +public class HologramBuilderTest { + + @FPTest(name = "Test basic text hologram builder") + public void testTextHologramBuilder(Player player) { + Hologram hologram = TextHologramBuilder.create("Test", player.getLocation()) + .build(); + + expect(hologram).toBeDefined(); + expect(hologram.getData()).toBeDefined(); + expect(hologram.getData().getName()).toBe("Test"); + expect(hologram.getData().getLocation()).toEqual(player.getLocation()); + expect(hologram.getData().getType()).toEqual(HologramType.TEXT); + } + + @FPTest(name = "Test text hologram builder with one line") + public void testTextHologramBuilderWithOneLine(Player player) { + Hologram hologram = TextHologramBuilder.create("Test", player.getLocation()) + .text("Custom line") + .build(); + + if(!(hologram.getData() instanceof TextHologramData data)) { + throw new AssertionError("Hologram is not a text hologram"); + } + + expect(data.getText().size()).toEqual(1); + expect(data.getText().getFirst()).toEqual("Custom line"); + } + + @FPTest(name = "Test text hologram builder with multiple line") + public void testTextHologramBuilderWithMultipleLines(Player player) { + Hologram hologram = TextHologramBuilder.create("Test", player.getLocation()) + .text("Custom line", "Another line", "Yet another line") + .build(); + + if(!(hologram.getData() instanceof TextHologramData data)) { + throw new AssertionError("Hologram is not a text hologram"); + } + + expect(data.getText().size()).toEqual(3); + expect(data.getText().getFirst()).toEqual("Custom line"); + expect(data.getText().get(1)).toEqual("Another line"); + expect(data.getText().getLast()).toEqual("Yet another line"); + } + + @FPTest(name = "Test text hologram builder with multiple line 2") + public void testTextHologramBuilderWithMultipleLines2(Player player) { + Hologram hologram = TextHologramBuilder.create("Test", player.getLocation()) + .text(List.of("Custom line", "Another line", "Yet another line")) + .build(); + + if(!(hologram.getData() instanceof TextHologramData data)) { + throw new AssertionError("Hologram is not a text hologram"); + } + + expect(data.getText().size()).toEqual(3); + expect(data.getText().getFirst()).toEqual("Custom line"); + expect(data.getText().get(1)).toEqual("Another line"); + expect(data.getText().getLast()).toEqual("Yet another line"); + } + + @FPTest(name = "Test text hologram builder with properties") + public void testTextHologramBuilderWithProperties(Player player) { + Hologram hologram = TextHologramBuilder.create("Test", player.getLocation()) + .text("Custom line") + .background(Color.BLACK) + .textAlignment(TextDisplay.TextAlignment.LEFT) + .textShadow(true) + .seeThrough(true) + .updateTextInterval(420) + .visibilityDistance(42) + .visibility(Visibility.ALL) + .persistent(false) + .linkedNpcName("TestNPC") + .billboard(Display.Billboard.FIXED) + .scale(3,5,6) + .translation(1,2,3) + .brightness(7, 3) + .shadowRadius(0.5f) + .shadowStrength(0.7f) + .interpolationDuration(100) + .build(); + + if(!(hologram.getData() instanceof TextHologramData data)) { + throw new AssertionError("Hologram is not a text hologram"); + } + + expect(data.getText().size()).toEqual(1); + expect(data.getText().getFirst()).toEqual("Custom line"); + expect(data.getBackground()).toEqual(Color.BLACK); + expect(data.getTextAlignment()).toEqual(TextDisplay.TextAlignment.LEFT); + expect(data.hasTextShadow()).toBe(true); + expect(data.isSeeThrough()).toBe(true); + expect(data.getTextUpdateInterval()).toEqual(420); + expect(data.getVisibilityDistance()).toEqual(42); + expect(data.getVisibility()).toEqual(Visibility.ALL); + expect(data.isPersistent()).toBe(false); + expect(data.getLinkedNpcName()).toEqual("TestNPC"); + expect(data.getBillboard()).toEqual(Display.Billboard.FIXED); + expect(data.getScale()).toEqual(new Vector3f(3,5,6)); + expect(data.getTranslation()).toEqual(new Vector3f(1,2,3)); + expect(data.getBrightness()).toEqual(new Display.Brightness(7,3)); + expect(data.getShadowRadius()).toEqual(0.5f); + expect(data.getShadowStrength()).toEqual(0.7f); + expect(data.getInterpolationDuration()).toEqual(100); + } + + @FPTest(name = "Test item hologram builder") + public void testItemHologramBuilder(Player player) { + ItemStack item = new ItemStack(Material.DIAMOND_PICKAXE); + + Hologram hologram = ItemHologramBuilder.create("Test", player.getLocation()) + .item(item) + .build(); + + expect(hologram).toBeDefined(); + expect(hologram.getData()).toBeDefined(); + expect(hologram.getData().getName()).toBe("Test"); + expect(hologram.getData().getLocation()).toEqual(player.getLocation()); + expect(hologram.getData().getType()).toEqual(HologramType.ITEM); + + if(!(hologram.getData() instanceof ItemHologramData data)) { + throw new AssertionError("Hologram is not an item hologram"); + } + + expect(data.getItemStack()).toEqual(item); + } + + @FPTest(name = "Test block hologram builder") + public void testBlockHologramBuilder(Player player) { + Hologram hologram = BlockHologramBuilder.create("Test", player.getLocation()) + .block(Material.DIRT) + .build(); + + expect(hologram).toBeDefined(); + expect(hologram.getData()).toBeDefined(); + expect(hologram.getData().getName()).toBe("Test"); + expect(hologram.getData().getLocation()).toEqual(player.getLocation()); + expect(hologram.getData().getType()).toEqual(HologramType.BLOCK); + + if(!(hologram.getData() instanceof BlockHologramData data)) { + throw new AssertionError("Hologram is not a block hologram"); + } + + expect(data.getBlock()).toEqual(Material.DIRT); + } + + @FPTest(name = "Test hologram builder registering") + public void testHologramBuilderRegistering(Player player) { + String hologramName = UUID.randomUUID().toString(); + + Hologram hologram = TextHologramBuilder.create(hologramName, player.getLocation()) + .text("Custom line") + .buildAndRegister(); + + expect(hologram).toBeDefined(); + expect(hologram.getData()).toBeDefined(); + expect(hologram.getData().getName()).toBe(hologramName); + expect(hologram.getData().getLocation()).toEqual(player.getLocation()); + expect(hologram.getData().getType()).toEqual(HologramType.TEXT); + + HologramRegistry registry = FancyHologramsPlugin.get().getRegistry(); + expect(registry.contains(hologramName)).toBe(true); + + registry.unregister(hologram); + } + +} diff --git a/src/main/java/de/oliver/fancyholograms/tests/api/HologramControllerTest.java b/src/main/java/de/oliver/fancyholograms/tests/api/HologramControllerTest.java new file mode 100644 index 00000000..0e40a8a7 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/tests/api/HologramControllerTest.java @@ -0,0 +1,65 @@ +package de.oliver.fancyholograms.tests.api; + +import de.oliver.fancyholograms.api.HologramController; +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.controller.HologramControllerImpl; +import de.oliver.fancyholograms.tests.mocks.HologramMock; +import de.oliver.fancylib.tests.annotations.FPBeforeEach; +import de.oliver.fancylib.tests.annotations.FPTest; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import static de.oliver.fancylib.tests.Expectable.expect; + +public class HologramControllerTest { + + private HologramController controller; + private Hologram hologram; + + private int spawnTo; + private int despawnFrom; + + @FPBeforeEach + public void setUp(Player player) { + this.controller = new HologramControllerImpl(); + + this.hologram = new HologramMock( + new TextHologramData("Test", player.getLocation().clone()), + () -> spawnTo++, + () -> despawnFrom++, + () -> {} + ); + + this.spawnTo = 0; + this.despawnFrom = 0; + } + + @FPTest(name = "Test showHologramTo") + public void testShowHologramTo(Player player) { + controller.showHologramTo(hologram, player); + expect(spawnTo).toBe(1); + expect(hologram.isViewer(player)).toBe(true); + + controller.showHologramTo(hologram, player); + expect(spawnTo).toBe(1); // Should not spawn again + } + + @FPTest(name = "Test hideHologramFrom") + public void testHideHologramFrom(Player player) { + controller.showHologramTo(hologram, player); + expect(spawnTo).toBe(1); + expect(hologram.isViewer(player)).toBe(true); + + + hologram.getData().setLocation(new Location(player.getWorld(),0,10000, 0)); + + controller.hideHologramFrom(hologram, player); + expect(despawnFrom).toBe(1); + expect(hologram.isViewer(player)).toBe(false); + + controller.hideHologramFrom(hologram, player); + expect(despawnFrom).toBe(1); // Should not despawn again + } + +} diff --git a/src/main/java/de/oliver/fancyholograms/tests/api/HologramRegistryTest.java b/src/main/java/de/oliver/fancyholograms/tests/api/HologramRegistryTest.java new file mode 100644 index 00000000..1dfdcfae --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/tests/api/HologramRegistryTest.java @@ -0,0 +1,156 @@ +package de.oliver.fancyholograms.tests.api; + +import de.oliver.fancyholograms.api.HologramRegistry; +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.api.hologram.Hologram; +import de.oliver.fancyholograms.registry.HologramRegistryImpl; +import de.oliver.fancyholograms.tests.mocks.HologramMock; +import de.oliver.fancylib.tests.annotations.FPBeforeEach; +import de.oliver.fancylib.tests.annotations.FPTest; +import org.bukkit.entity.Player; + +import java.util.Optional; + +import static de.oliver.fancylib.tests.Expectable.expect; + +public class HologramRegistryTest { + + private HologramRegistry registry; + + @FPBeforeEach + public void setUp(Player player) { + registry = new HologramRegistryImpl(); + } + + @FPTest(name = "Register hologram to registry") + public void testRegister(Player player) { + Hologram hologram = new HologramMock( + new TextHologramData("Test", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + + registry.register(hologram); + + Optional got = registry.get("Test"); + expect(got.isPresent()).toBe(true); + expect(got.get()).toEqual(hologram); + } + + @FPTest(name = "Unregister hologram from registry") + public void testUnregister(Player player) { + Hologram hologram = new HologramMock( + new TextHologramData("Test", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + + registry.register(hologram); + expect(registry.get("Test").isPresent()).toBe(true); + + registry.unregister(hologram); + + Optional got = registry.get("Test"); + expect(got.isPresent()).toBe(false); + } + + @FPTest(name = "Check if hologram exists in registry") + public void testContains(Player player) { + Hologram hologram = new HologramMock( + new TextHologramData("Test", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + + registry.register(hologram); + expect(registry.contains("Test")).toBe(true); + } + + @FPTest(name = "Retrieve hologram from registry") + public void testGet(Player player) { + Hologram hologram = new HologramMock( + new TextHologramData("Test", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + + registry.register(hologram); + + Optional got = registry.get("Test"); + expect(got.isPresent()).toBe(true); + expect(got.get()).toEqual(hologram); + } + + @FPTest(name = "Retrieve all holograms from registry") + public void testGetAll(Player player) { + Hologram hologram1 = new HologramMock( + new TextHologramData("Test1", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + Hologram hologram2 = new HologramMock( + new TextHologramData("Test2", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + + registry.register(hologram1); + registry.register(hologram2); + + expect(registry.getAll().size()).toBe(2); + expect(registry.getAll().contains(hologram1)).toBe(true); + expect(registry.getAll().contains(hologram2)).toBe(true); + } + + @FPTest(name = "Retrieve all persistent holograms from registry") + public void testGetAllPersistent(Player player) { + Hologram hologram1 = new HologramMock( + new TextHologramData("Test1", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + + TextHologramData data2 = new TextHologramData("Test2", player.getLocation()); + data2.setPersistent(false); + Hologram hologram2 = new HologramMock( + data2, + () -> {}, + () -> {}, + () -> {} + ); + + registry.register(hologram1); + registry.register(hologram2); + + expect(registry.getAllPersistent()).toHaveLength(1); + expect(registry.getAllPersistent().contains(hologram1)).toBe(true); + expect(registry.getAllPersistent().contains(hologram2)).toBe(false); + } + + @FPTest(name = "Retrieve hologram from registry, ensuring it exists") + public void testMustGet(Player player) { + Hologram hologram = new HologramMock( + new TextHologramData("Test", player.getLocation()), + () -> {}, + () -> {}, + () -> {} + ); + + registry.register(hologram); + + expect(registry.mustGet("Test")).toBeDefined(); + + try { + registry.mustGet("NonExistent"); + } catch (IllegalArgumentException e) { + expect(e).toBeDefined(); + } + } +} diff --git a/src/main/java/de/oliver/fancyholograms/tests/mocks/HologramMock.java b/src/main/java/de/oliver/fancyholograms/tests/mocks/HologramMock.java new file mode 100644 index 00000000..a0151e51 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/tests/mocks/HologramMock.java @@ -0,0 +1,37 @@ +package de.oliver.fancyholograms.tests.mocks; + +import de.oliver.fancyholograms.api.data.HologramData; +import de.oliver.fancyholograms.api.hologram.Hologram; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class HologramMock extends Hologram { + + private final Runnable spawnToCallback; + private final Runnable despawnFromCallback; + private final Runnable updateForCallback; + + public HologramMock(@NotNull HologramData data, Runnable spawnToCallback, Runnable despawnFromCallback, Runnable updateForCallback) { + super(data); + this.spawnToCallback = spawnToCallback; + this.despawnFromCallback = despawnFromCallback; + this.updateForCallback = updateForCallback; + } + + @Override + public void spawnTo(@NotNull Player player) { + spawnToCallback.run(); + viewers.add(player.getUniqueId()); + } + + @Override + public void despawnFrom(@NotNull Player player) { + despawnFromCallback.run(); + viewers.remove(player.getUniqueId()); + } + + @Override + public void updateFor(@NotNull Player player) { + updateForCallback.run(); + } +} diff --git a/src/main/java/de/oliver/fancyholograms/trait/HologramTraitRegistryImpl.java b/src/main/java/de/oliver/fancyholograms/trait/HologramTraitRegistryImpl.java new file mode 100644 index 00000000..08af99ee --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/trait/HologramTraitRegistryImpl.java @@ -0,0 +1,30 @@ +package de.oliver.fancyholograms.trait; + +import de.oliver.fancyholograms.api.trait.HologramTrait; +import de.oliver.fancyholograms.api.trait.HologramTraitRegistry; + +import java.util.List; + +public class HologramTraitRegistryImpl implements HologramTraitRegistry { + + + @Override + public boolean register(Class trait) { + return false; + } + + @Override + public boolean unregister(Class trait) { + return false; + } + + @Override + public boolean isRegistered(Class trait) { + return false; + } + + @Override + public List> getRegisteredTraits() { + return List.of(); + } +} diff --git a/src/main/java/de/oliver/fancyholograms/trait/builtin/MultiplePagesTrait.java b/src/main/java/de/oliver/fancyholograms/trait/builtin/MultiplePagesTrait.java new file mode 100644 index 00000000..c50df035 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/trait/builtin/MultiplePagesTrait.java @@ -0,0 +1,63 @@ +package de.oliver.fancyholograms.trait.builtin; + +import de.oliver.fancyholograms.api.data.TextHologramData; +import de.oliver.fancyholograms.api.trait.HologramTrait; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@ApiStatus.Experimental +public class MultiplePagesTrait extends HologramTrait { + + private static final int NEXT_PAGE_DELAY_SECONDS = 5; + + private final List pages; + private int currentPageIdx; + + public MultiplePagesTrait() { + super("multiple_pages"); + this.pages = new ArrayList<>(); + this.currentPageIdx = 0; + + this.pages.add(new Page(List.of("Page 1", "Line 1", "Line 2"))); + this.pages.add(new Page(List.of("Page 2", "Line 1", "Line 2"))); + this.pages.add(new Page(List.of("Page 3", "Line 1", "Line 2"))); + } + + @Override + public void onAttach() { + if (!(hologram.getData() instanceof TextHologramData td)) { + throw new IllegalStateException("Hologram must be text hologram to use MultiplePagesTrait"); + } + + hologramThread.scheduleWithFixedDelay(() -> { + Page currentPage = pages.get(currentPageIdx); + td.setText(new ArrayList<>(currentPage.lines())); + + currentPageIdx = (currentPageIdx + 1) % pages.size(); // cycle through pages + }, 0, NEXT_PAGE_DELAY_SECONDS, TimeUnit.SECONDS); + } + + @Override + public void save() { + //TODO save pages to data + } + + @Override + public void load() { + //TODO load pages from data + } + + record Page(List lines) { + + public void addLine(String line) { + lines.add(line); + } + + public void removeLine(int index) { + lines.remove(index); + } + } +} diff --git a/src/main/java/de/oliver/fancyholograms/util/Constants.java b/src/main/java/de/oliver/fancyholograms/util/Constants.java deleted file mode 100644 index 6e62d967..00000000 --- a/src/main/java/de/oliver/fancyholograms/util/Constants.java +++ /dev/null @@ -1,52 +0,0 @@ -package de.oliver.fancyholograms.util; - -import de.oliver.fancylib.MessageHelper; - -import java.text.DecimalFormat; - -public enum Constants { - ; - - public static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#########.##"); - - public final static DecimalFormat COORDINATES_DECIMAL_FORMAT = new DecimalFormat("#########.##"); - - public static final String FH_COMMAND_USAGE = "/fancyholograms "; - - public static final String HELP_TEXT = """ - <%primary_color%>FancyHolograms commands help: - <%primary_color%>- /hologram help - Shows all (sub)commands - <%primary_color%>- /hologram list - Shows you a overview of all holograms - <%primary_color%>- /hologram nearby - Shows all holograms nearby you in a range - <%primary_color%>- /hologram teleport - Teleports you to a hologram - <%primary_color%>- /hologram create - Creates a new hologram - <%primary_color%>- /hologram remove - Removes a hologram - <%primary_color%>- /hologram copy - Copies a hologram - <%primary_color%>- /hologram edit addLine - Adds a line at the bottom - <%primary_color%>- /hologram edit removeLine - Removes a line at the bottom - <%primary_color%>- /hologram edit insertBefore - Inserts a line before another - <%primary_color%>- /hologram edit insertAfter - Inserts a line after another - <%primary_color%>- /hologram edit setLine - Edits the line - <%primary_color%>- /hologram edit position - Teleports the hologram to you - <%primary_color%>- /hologram edit moveTo [yaw] [pitch] - Teleports the hologram to the coordinates - <%primary_color%>- /hologram edit rotate - Rotates the hologram - <%primary_color%>- /hologram edit scale - Changes the scale of the hologram - <%primary_color%>- /hologram edit billboard - Changes the billboard of the hologram - <%primary_color%>- /hologram edit background - Changes the background of the hologram - <%primary_color%>- /hologram edit textShadow - Enables/disables the text shadow - <%primary_color%>- /hologram edit textAlignment - Sets the text alignment - <%primary_color%>- /hologram edit seeThrough - Enables/disables whether the text can be seen through blocks - <%primary_color%>- /hologram edit shadowRadius - Changes the shadow radius of the hologram - <%primary_color%>- /hologram edit shadowStrength - Changes the shadow strength of the hologram - <%primary_color%>- /hologram edit brightness <0-15> - Changes the brightness of the hologram - <%primary_color%>- /hologram edit updateTextInterval - Sets the interval for updating the text - """.replace("%primary_color%", MessageHelper.getPrimaryColor()); - - public static final String HELP_TEXT_NPCS = """ - <%primary_color%>- /hologram edit linkWithNpc - Links the hologram with an NPC - <%primary_color%>- /hologram edit unlinkWithNpc - Unlinks the hologram with an NPC - """.replace("%primary_color%", MessageHelper.getPrimaryColor()); - - public static final String INVALID_NEARBY_RANGE = "Provide an integer radius to search for holograms nearby."; - -} diff --git a/src/main/java/de/oliver/fancyholograms/util/Formats.java b/src/main/java/de/oliver/fancyholograms/util/Formats.java new file mode 100644 index 00000000..7fc343b5 --- /dev/null +++ b/src/main/java/de/oliver/fancyholograms/util/Formats.java @@ -0,0 +1,13 @@ +package de.oliver.fancyholograms.util; + +import java.text.DecimalFormat; + +public class Formats { + + public static final DecimalFormat DECIMAL = new DecimalFormat("#########.##"); + public final static DecimalFormat COORDINATES_DECIMAL = new DecimalFormat("#########.##"); + + private Formats() { + throw new IllegalStateException("Utility class"); + } +}