From 184d3a0c4e6aebb1a1310845591ab6cc99e71838 Mon Sep 17 00:00:00 2001 From: Ian Tapply Date: Fri, 7 Jun 2024 17:09:17 -0400 Subject: [PATCH] feat: Version 1.1.0 Overhaul - Resture Codebase (#18) --- pom.xml | 7 +- src/main/java/net/jeqo/bloons/Bloons.java | 98 ++++---- .../jeqo/bloons/balloon/SingleBalloon.java | 220 ++++++++++++++++++ .../jeqo/bloons/commands/CommandEquip.java | 35 ++- .../bloons/commands/CommandForceEquip.java | 25 +- .../bloons/commands/CommandForceUnequip.java | 20 +- .../jeqo/bloons/commands/CommandReload.java | 10 +- .../jeqo/bloons/commands/CommandUnequip.java | 26 ++- .../jeqo/bloons/commands/manager/Command.java | 40 ++-- .../bloons/commands/manager/CommandCore.java | 219 +++++++++++++++++ .../commands/manager/CommandManager.java | 100 -------- .../manager/CommandTabCompleter.java} | 5 +- .../bloons/commands/utils/ErrorHandling.java | 28 ++- .../configuration/BalloonConfiguration.java | 6 + .../configuration/PluginConfiguration.java | 45 +--- .../net/jeqo/bloons/data/BalloonOwner.java | 146 ------------ .../net/jeqo/bloons/events/BloonsEvent.java | 62 +++++ src/main/java/net/jeqo/bloons/gui/GUI.java | 158 +++++++++++++ .../net/jeqo/bloons/gui/GUIClickableItem.java | 60 +++++ .../java/net/jeqo/bloons/gui/GUICore.java | 108 +++++++++ .../java/net/jeqo/bloons/gui/GUIHelpers.java | 15 ++ .../java/net/jeqo/bloons/gui/GUIListener.java | 37 +++ .../gui/item/border/BlackGlassPaneBorder.java | 37 +++ .../item/filler/BlackGlassPaneFillerItem.java | 37 +++ .../{data => gui/menus}/BalloonMenu.java | 37 +-- .../jeqo/bloons/gui/menus/ExampleMenu.java | 109 +++++++++ .../listeners/BalloonUnleashListener.java | 19 ++ .../jeqo/bloons/listeners/LeashHandlers.java | 21 -- .../jeqo/bloons/listeners/ListenerCore.java | 49 ++++ .../bloons/listeners/MenuClickListener.java | 126 ++++++++++ .../jeqo/bloons/listeners/MenuHandlers.java | 102 -------- .../jeqo/bloons/listeners/PlayerHandlers.java | 87 ------- .../jeqo/bloons/listeners/PlayerListener.java | 89 +++++++ .../java/net/jeqo/bloons/logger/Logger.java | 42 +++- .../jeqo/bloons/utils/BalloonManagement.java | 45 ++++ .../jeqo/bloons/utils/ColorCodeConverter.java | 56 +++++ .../jeqo/bloons/utils/ColorManagement.java | 45 ++++ .../bloons/utils/MessageTranslations.java | 34 +++ .../java/net/jeqo/bloons/utils/NBTItem.java | 152 ++++++++++++ .../bloons/{data => utils}/UpdateChecker.java | 9 +- .../java/net/jeqo/bloons/utils/Utils.java | 52 ----- src/main/resources/config.yml | 36 +-- 42 files changed, 1946 insertions(+), 708 deletions(-) create mode 100644 src/main/java/net/jeqo/bloons/balloon/SingleBalloon.java create mode 100644 src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java delete mode 100644 src/main/java/net/jeqo/bloons/commands/manager/CommandManager.java rename src/main/java/net/jeqo/bloons/{data/BalloonTab.java => commands/manager/CommandTabCompleter.java} (95%) create mode 100644 src/main/java/net/jeqo/bloons/configuration/BalloonConfiguration.java delete mode 100644 src/main/java/net/jeqo/bloons/data/BalloonOwner.java create mode 100644 src/main/java/net/jeqo/bloons/events/BloonsEvent.java create mode 100644 src/main/java/net/jeqo/bloons/gui/GUI.java create mode 100644 src/main/java/net/jeqo/bloons/gui/GUIClickableItem.java create mode 100644 src/main/java/net/jeqo/bloons/gui/GUICore.java create mode 100644 src/main/java/net/jeqo/bloons/gui/GUIHelpers.java create mode 100644 src/main/java/net/jeqo/bloons/gui/GUIListener.java create mode 100644 src/main/java/net/jeqo/bloons/gui/item/border/BlackGlassPaneBorder.java create mode 100644 src/main/java/net/jeqo/bloons/gui/item/filler/BlackGlassPaneFillerItem.java rename src/main/java/net/jeqo/bloons/{data => gui/menus}/BalloonMenu.java (63%) create mode 100644 src/main/java/net/jeqo/bloons/gui/menus/ExampleMenu.java create mode 100644 src/main/java/net/jeqo/bloons/listeners/BalloonUnleashListener.java delete mode 100644 src/main/java/net/jeqo/bloons/listeners/LeashHandlers.java create mode 100644 src/main/java/net/jeqo/bloons/listeners/ListenerCore.java create mode 100644 src/main/java/net/jeqo/bloons/listeners/MenuClickListener.java delete mode 100644 src/main/java/net/jeqo/bloons/listeners/MenuHandlers.java delete mode 100644 src/main/java/net/jeqo/bloons/listeners/PlayerHandlers.java create mode 100644 src/main/java/net/jeqo/bloons/listeners/PlayerListener.java create mode 100644 src/main/java/net/jeqo/bloons/utils/BalloonManagement.java create mode 100644 src/main/java/net/jeqo/bloons/utils/ColorCodeConverter.java create mode 100644 src/main/java/net/jeqo/bloons/utils/ColorManagement.java create mode 100644 src/main/java/net/jeqo/bloons/utils/MessageTranslations.java create mode 100644 src/main/java/net/jeqo/bloons/utils/NBTItem.java rename src/main/java/net/jeqo/bloons/{data => utils}/UpdateChecker.java (80%) delete mode 100644 src/main/java/net/jeqo/bloons/utils/Utils.java diff --git a/pom.xml b/pom.xml index c437f883..333783a0 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.jeqo bloons - 1.0.6-BETA + 1.1.0-BETA jar Bloons @@ -80,6 +80,11 @@ 1.20.4-R0.1-SNAPSHOT provided + + net.kyori + adventure-text-minimessage + 4.17.0 + org.projectlombok lombok diff --git a/src/main/java/net/jeqo/bloons/Bloons.java b/src/main/java/net/jeqo/bloons/Bloons.java index 5e21e91d..eb840cb1 100644 --- a/src/main/java/net/jeqo/bloons/Bloons.java +++ b/src/main/java/net/jeqo/bloons/Bloons.java @@ -2,87 +2,87 @@ import lombok.Getter; import lombok.Setter; -import net.jeqo.bloons.commands.manager.CommandManager; -import net.jeqo.bloons.data.BalloonOwner; -import net.jeqo.bloons.data.UpdateChecker; -import net.jeqo.bloons.listeners.LeashHandlers; -import net.jeqo.bloons.listeners.MenuHandlers; -import net.jeqo.bloons.listeners.PlayerHandlers; +import net.jeqo.bloons.balloon.SingleBalloon; +import net.jeqo.bloons.commands.manager.CommandCore; +import net.jeqo.bloons.utils.UpdateChecker; +import net.jeqo.bloons.listeners.BalloonUnleashListener; +import net.jeqo.bloons.listeners.ListenerCore; +import net.jeqo.bloons.listeners.MenuClickListener; +import net.jeqo.bloons.listeners.PlayerListener; +import net.jeqo.bloons.logger.Logger; import net.jeqo.bloons.utils.Metrics; -import net.jeqo.bloons.utils.Utils; -import org.bukkit.event.HandlerList; import org.bukkit.plugin.java.JavaPlugin; import java.util.HashMap; import java.util.UUID; public final class Bloons extends JavaPlugin { - - public static HashMap playerBalloons = new HashMap<>(); - public static HashMap playerBalloonID = new HashMap<>(); @Getter @Setter private static Bloons instance; + @Getter @Setter + private static CommandCore commandCore; + @Getter @Setter + private static ListenerCore listenerCore; + + @Getter @Setter + public static HashMap playerBalloons = new HashMap<>(); + @Getter @Setter + public static HashMap playerBalloonID = new HashMap<>(); @Override public void onEnable() { - Utils.log("|---[ BLOONS ]-------------------------------------------------------|"); - Utils.log("| Plugin loaded. |"); - Utils.log("|-------------------------------------------------[ MADE BY JEQO ]---|"); - + // Create an instance of the plugin setInstance(this); - new CommandManager(getInstance()); - loadListeners(); + // Send startup message + Logger.logStartup(); + + // Register core managers within the plugin + setCommandCore(new CommandCore(getInstance())); + setListenerCore(new ListenerCore(getInstance())); + + // Stage listeners + getListenerCore().stageListener(new PlayerListener()); + getListenerCore().stageListener(new BalloonUnleashListener()); + getListenerCore().stageListener(new MenuClickListener()); + // Register all handlers + getListenerCore().registerListeners(); + + // Startup the metrics and update checker + int pluginId = 16872; new Metrics(this, pluginId); updateChecker(); - getConfig().options().copyDefaults(); saveDefaultConfig(); + // Generate config(s) and set defaults + getConfig().options().copyDefaults(); + saveDefaultConfig(); } @Override public void onDisable() { - Utils.log("|---[ BLOONS ]-------------------------------------------------------|"); - Utils.log("| Shutting down... |"); - Utils.log("|-------------------------------------------------[ MADE BY JEQO ]---|"); + // Log shutdown message + Logger.logShutdown(); - for (BalloonOwner owner : playerBalloons.values()) { + // Unregister all balloons and stop the task + for (SingleBalloon owner : playerBalloons.values()) { owner.cancel(); } - HandlerList.unregisterAll(this); + // Unregister all listeners in the manager + getListenerCore().unregisterListeners(); } - int pluginId = 16872; + /** + * Checks for updates and notifies the user via a log to console + * getDescription() is still used because of the usage of a plugin.yml. + * Not planned to change + */ public void updateChecker() { new UpdateChecker(this, 106243).getVersion(version -> { if (!this.getDescription().getVersion().equals(version)) { - Utils.warn("|---[ BLOONS ]-------------------------------------------------------|"); - Utils.warn("| There is a new update available! |"); - Utils.warn("| https://jeqo.net/spigot/bloons |"); - Utils.warn("|-------------------------------------------------[ MADE BY JEQO ]---|"); + Logger.logUpdateNotificationConsole(); } }); } - - private void loadListeners() { - getServer().getPluginManager().registerEvents(new LeashHandlers(), this); - getServer().getPluginManager().registerEvents(new PlayerHandlers(), this); - getServer().getPluginManager().registerEvents(new MenuHandlers(), this); - } - public static String getMessage(String id, String arg) { - return Utils.hex(String.format(getInstance().getConfig().getString("messages." + id, ""), arg)); - } - - public static String getMessage(String id) { - return Utils.hex(getInstance().getConfig().getString("messages." + id, "")); - } - - public static String getString(String path) { - return getInstance().getConfig().getString(path); - } - - public static Integer getInt(String path) { - return getInstance().getConfig().getInt(path); - } } \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/balloon/SingleBalloon.java b/src/main/java/net/jeqo/bloons/balloon/SingleBalloon.java new file mode 100644 index 00000000..bbcc399e --- /dev/null +++ b/src/main/java/net/jeqo/bloons/balloon/SingleBalloon.java @@ -0,0 +1,220 @@ +package net.jeqo.bloons.balloon; + +import lombok.Getter; +import lombok.Setter; +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.configuration.BalloonConfiguration; +import net.jeqo.bloons.logger.Logger; +import net.jeqo.bloons.utils.BalloonManagement; +import net.jeqo.bloons.utils.ColorManagement; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.text.Component; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Chicken; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.EulerAngle; +import org.bukkit.util.Vector; + +import java.util.concurrent.ThreadLocalRandom; + +@Getter @Setter +public class SingleBalloon extends BukkitRunnable { + /** Al physical elements of balloon **/ + private Player player; + private ItemStack balloonVisual; + private ArmorStand balloonArmorStand; + public Chicken balloonChicken; + + /** Location Data **/ + private Location playerLocation; + private Location moveLocation; + + /** Movement Data **/ + private int ticks = 0; + private float targetYaw = 0.0F; + + public SingleBalloon(Player player, String balloonID) { + this.setPlayer(player); + + // Configure the balloon visual elements + this.setBalloonVisual(getConfiguredBalloonVisual(balloonID)); + } + + /** + * What runs inside the extended bukkit runnable + * Core functionality of how the balloon moves + */ + public void run() { + if (this.getBalloonArmorStand() == null) initializeBalloon(); + + Location playerLocation = this.getPlayerLocation(); + playerLocation.setYaw(this.getPlayerLocation().getYaw()); + + // If the ticks reach 20, set back to 0 and set a new target yaw + if (this.getTicks() == 20) { + this.setTargetYaw(ThreadLocalRandom.current().nextInt(10) - 5); + this.setTicks(0); + } + + if (this.getTargetYaw() > playerLocation.getYaw()) { + playerLocation.setYaw(playerLocation.getYaw() + 0.2F); + } else if (this.getTargetYaw() < playerLocation.getYaw()) { + playerLocation.setYaw(playerLocation.getYaw() - 0.2F); + } + + this.setMoveLocation(this.getBalloonArmorStand().getLocation().subtract(0.0D, 2.0D, 0.0D).clone()); + + Vector vector = playerLocation.toVector().subtract(this.getMoveLocation().toVector()); + vector.multiply(0.3D); + this.setMoveLocation(this.getMoveLocation().add(vector)); + double vectorZ = vector.getZ() * 50.0D * -1.0D; + double vectorX = vector.getX() * 50.0D * -1.0D; + this.getBalloonArmorStand().setHeadPose(new EulerAngle(Math.toRadians(vectorZ), Math.toRadians(playerLocation.getYaw()), Math.toRadians(vectorX))); + + this.teleport(this.getMoveLocation()); + this.setPlayerLocation(this.getPlayer().getLocation()); + this.getPlayerLocation().setYaw(playerLocation.getYaw()); + this.setTicks(this.getTicks() + 1); + } + + /** + * Cancels the current bukkit runnable instance and kills off the entities + * @throws IllegalStateException If the task has already been cancelled + */ + public synchronized void cancel() throws IllegalStateException { + this.getBalloonArmorStand().remove(); + this.getBalloonChicken().remove(); + super.cancel(); + } + + /** + * Spawns the particle effect when the balloon is removed + */ + public void spawnRemoveParticle() { + this.getMoveLocation().getWorld().spawnParticle(Particle.CLOUD, this.getMoveLocation(), 5, 0.0D, 0.0D, 0.0D, 0.1D); + } + + /** + * Teleports the balloon's entities to a specific location + * @param location The location to teleport the balloon to + */ + private void teleport(Location location) { + this.getBalloonArmorStand().teleport(location.add(0.0D, 2.0D, 0.0D)); + this.getBalloonChicken().teleport(location.add(0.0D, 1.2D, 0.0D)); + } + + /** + * Initializes the balloon. Sets the current players location, and initializes the armor stand, and chicken entities + */ + private void initializeBalloon() { + this.setPlayerLocation(this.getPlayer().getLocation()); + this.getPlayerLocation().setYaw(0.0F); + + ItemMeta meta = this.getBalloonVisual().getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + this.getBalloonVisual().setItemMeta(meta); + + this.initializeBalloonArmorStand(); + this.initializeBalloonChicken(); + } + + /** + * Gets the item stack object of the visual appearance of the balloon + * @param balloonID The balloon ID to get the visual appearance of + * @return The item stack object of the visual appearance of the balloon + */ + public ItemStack getConfiguredBalloonVisual(String balloonID) { + MessageTranslations messageTranslations = new MessageTranslations(Bloons.getInstance()); + + ConfigurationSection balloonConfiguration = Bloons.getInstance().getConfig().getConfigurationSection("balloons." + balloonID); + + if (balloonConfiguration == null) { + Logger.logWarning("The balloon " + balloonID + " is not set in the configuration!"); + return null; + } + + if (balloonConfiguration.getString("material") == null) { + Logger.logWarning("The material of the balloon " + balloonID + " is not set!"); + return null; + } + + ItemStack item = new ItemStack(Material.valueOf(balloonConfiguration.getString("material"))); + ItemMeta meta = item.getItemMeta(); + meta.setCustomModelData(balloonConfiguration.getInt("custom-model-data")); + + if (messageTranslations.getString("balloons." + balloonID + ".color") != null) { + if (!messageTranslations.getString("balloons." + balloonID + ".color").equalsIgnoreCase("potion")) { + LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) meta; + leatherArmorMeta.setColor(ColorManagement.hexToColor(messageTranslations.getString("balloons." + balloonID + ".color"))); + } else { + Logger.logWarning("The color of the balloonVisual " + balloonID + " is set, but the material is not a leather item!"); + } + } + item.setItemMeta(meta); + + return item; + } + + /** + * Initializes the balloon's armor stand entity + */ + public void initializeBalloonArmorStand() { + this.setBalloonArmorStand(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), ArmorStand.class)); + this.getBalloonArmorStand().setBasePlate(false); + this.getBalloonArmorStand().setVisible(false); + this.getBalloonArmorStand().setInvulnerable(true); + this.getBalloonArmorStand().setCanPickupItems(false); + this.getBalloonArmorStand().setGravity(false); + this.getBalloonArmorStand().setSmall(false); + this.getBalloonArmorStand().setMarker(true); + this.getBalloonArmorStand().setCollidable(false); + this.getBalloonArmorStand().getEquipment().setHelmet(this.getBalloonVisual()); + this.getBalloonArmorStand().customName(Component.text(BalloonConfiguration.BALLOON_ARMOR_STAND_ID)); + } + + /** + * Initializes the balloon's chicken entity + */ + public void initializeBalloonChicken() { + this.setBalloonChicken(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), Chicken.class)); + this.getBalloonChicken().setInvulnerable(true); + this.getBalloonChicken().setInvisible(true); + this.getBalloonChicken().setSilent(true); + this.getBalloonChicken().setBaby(); + this.getBalloonChicken().setAgeLock(true); + this.getBalloonChicken().setAware(false); + this.getBalloonChicken().setCollidable(false); + this.getBalloonChicken().setLeashHolder(this.getPlayer()); + this.getBalloonChicken().customName(Component.text(BalloonConfiguration.BALLOON_CHICKEN_ID)); + } + + /** + * Checks if a balloon needs to be removed or added + * @param player The player to check + * @param balloonID The balloon ID to check + */ + public static void checkBalloonRemovalOrAdd(final Player player, final String balloonID) { + new BukkitRunnable() { + public void run() { + SingleBalloon owner = Bloons.playerBalloons.get(player.getUniqueId()); + if (owner != null) return; + + BalloonManagement.removeBalloon(player, null); + SingleBalloon balloonOwner = new SingleBalloon(player, balloonID); + balloonOwner.runTaskTimer(Bloons.getInstance(), 0L, 1L); + Bloons.playerBalloons.put(player.getUniqueId(), balloonOwner); + Bloons.playerBalloonID.put(player.getUniqueId(), balloonID); + + } + }.runTaskLater(Bloons.getInstance(), 1L); + } +} diff --git a/src/main/java/net/jeqo/bloons/commands/CommandEquip.java b/src/main/java/net/jeqo/bloons/commands/CommandEquip.java index ad4dbdfe..fcbc3954 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandEquip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandEquip.java @@ -1,10 +1,14 @@ package net.jeqo.bloons.commands; import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.SingleBalloon; import net.jeqo.bloons.commands.manager.Command; import net.jeqo.bloons.commands.manager.enums.CommandPermission; -import net.jeqo.bloons.data.BalloonOwner; -import net.jeqo.bloons.utils.Utils; +import net.jeqo.bloons.utils.BalloonManagement; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.Sound; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -24,28 +28,35 @@ public CommandEquip(JavaPlugin plugin) { @Override public boolean execute(CommandSender sender, String[] args) { + if (!(sender instanceof Player player)) return false; + if (args.length < 1) { usage(sender); } - Player player = (Player) sender; - String str1 = args[0]; + String balloonID = args[0]; + MessageTranslations messageTranslations = new MessageTranslations(this.plugin); - if (!plugin.getConfig().contains("balloons." + str1)) { - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("balloon-not-found")); + if (!this.plugin.getConfig().contains("balloons." + balloonID)) { + Component balloonNotFoundMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("balloon-not-found")); + player.sendMessage(balloonNotFoundMessage); return false; } - if (!player.hasPermission(plugin.getConfig().getString("balloons." + str1 + ".permission", "balloons." + str1))) { - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("no-permission")); + if (!player.hasPermission(this.plugin.getConfig().getString("balloons." + balloonID + ".permission", "balloons." + balloonID))) { + Component noPermissionMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("no-permission")); + player.sendMessage(noPermissionMessage); return false; } - Utils.removeBalloon(player, Bloons.playerBalloons.get(player.getUniqueId())); - BalloonOwner.checkBalloonRemovalOrAdd(player, str1); + BalloonManagement.removeBalloon(player, Bloons.playerBalloons.get(player.getUniqueId())); + SingleBalloon.checkBalloonRemovalOrAdd(player, balloonID); player.playSound(player.getLocation(), Sound.ENTITY_CHICKEN_EGG, 1, 1); - String balloonName = Bloons.getString("balloons." + str1 + ".name"); - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("equipped", balloonName)); + + String balloonName = messageTranslations.getString("balloons." + balloonID + ".name"); + Component equippedMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("equipped", balloonName)); + player.sendMessage(equippedMessage); + return false; } } diff --git a/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java b/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java index 92aafca2..d83ecbd9 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java @@ -1,9 +1,10 @@ package net.jeqo.bloons.commands; -import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.SingleBalloon; import net.jeqo.bloons.commands.manager.Command; import net.jeqo.bloons.commands.manager.enums.CommandPermission; -import net.jeqo.bloons.data.BalloonOwner; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -25,24 +26,28 @@ public CommandForceEquip(JavaPlugin plugin) { public boolean execute(CommandSender sender, String[] args) { if (args.length < 1) { usage(sender); - System.out.println("args.length < 1"); } Player player = Bukkit.getPlayer(args[0]); + MessageTranslations messageTranslations = new MessageTranslations(this.plugin); if (player == null) { - sender.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("player-not-found")); + Component playerNotFoundMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("player-not-found")); + sender.sendMessage(playerNotFoundMessage); return false; } - String balloonId = args[1]; - if (!plugin.getConfig().contains("balloons." + balloonId)) { - sender.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("balloon-not-found")); + + String balloonID = args[1]; + if (!this.plugin.getConfig().contains("balloons." + balloonID)) { + Component balloonNotFoundMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("balloon-not-found")); + sender.sendMessage(balloonNotFoundMessage); return false; } - BalloonOwner.checkBalloonRemovalOrAdd(player.getPlayer(), balloonId); - String balloonName2 = Bloons.getString("balloons." + balloonId + ".name"); - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("equipped", balloonName2)); + SingleBalloon.checkBalloonRemovalOrAdd(player.getPlayer(), balloonID); + String balloonName = messageTranslations.getString("balloons." + balloonID + ".name"); + Component equippedMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("equipped", balloonName)); + player.sendMessage(equippedMessage); return false; } } diff --git a/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java b/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java index 8cb62ea6..4075562a 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java @@ -1,10 +1,12 @@ package net.jeqo.bloons.commands; import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.SingleBalloon; import net.jeqo.bloons.commands.manager.Command; import net.jeqo.bloons.commands.manager.enums.CommandPermission; -import net.jeqo.bloons.data.BalloonOwner; -import net.jeqo.bloons.utils.Utils; +import net.jeqo.bloons.utils.BalloonManagement; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.Sound; import org.bukkit.command.CommandSender; @@ -24,19 +26,23 @@ public CommandForceUnequip(JavaPlugin plugin) { @Override public boolean execute(CommandSender sender, String[] args) { Player player = Bukkit.getPlayer(args[0]); + MessageTranslations messageTranslations = new MessageTranslations(this.plugin); if (player == null) { - sender.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("player-not-found")); + Component playerNotFoundMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("player-not-found")); + sender.sendMessage(playerNotFoundMessage); return false; } - BalloonOwner owner = Bloons.playerBalloons.get(player.getUniqueId()); + SingleBalloon owner = Bloons.playerBalloons.get(player.getUniqueId()); if (owner == null) { player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); - sender.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("not-equipped")); + Component notEquippedMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("not-equipped")); + sender.sendMessage(notEquippedMessage); return false; } - Utils.removeBalloon(player, owner); - sender.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("unequipped")); + BalloonManagement.removeBalloon(player, owner); + Component unequipSuccessfulMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("unequipped")); + sender.sendMessage(unequipSuccessfulMessage); return false; } } diff --git a/src/main/java/net/jeqo/bloons/commands/CommandReload.java b/src/main/java/net/jeqo/bloons/commands/CommandReload.java index fcd9b2f5..23b5bfbe 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandReload.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandReload.java @@ -3,6 +3,10 @@ import net.jeqo.bloons.Bloons; import net.jeqo.bloons.commands.manager.Command; import net.jeqo.bloons.commands.manager.enums.CommandPermission; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; import org.bukkit.command.CommandSender; import org.bukkit.plugin.java.JavaPlugin; @@ -19,8 +23,12 @@ public CommandReload(JavaPlugin plugin) { @Override public boolean execute(CommandSender sender, String[] args) { + MessageTranslations messageTranslations = new MessageTranslations(this.plugin); + Bloons.getInstance().reloadConfig(); - sender.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("config-reloaded")); + Component configReloadedMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("config-reloaded")); + sender.sendMessage(configReloadedMessage); + return false; } } diff --git a/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java b/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java index c84072ba..df8929fc 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java @@ -1,10 +1,12 @@ package net.jeqo.bloons.commands; import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.SingleBalloon; import net.jeqo.bloons.commands.manager.Command; import net.jeqo.bloons.commands.manager.enums.CommandPermission; -import net.jeqo.bloons.data.BalloonOwner; -import net.jeqo.bloons.utils.Utils; +import net.jeqo.bloons.utils.BalloonManagement; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.text.Component; import org.bukkit.Sound; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -14,7 +16,7 @@ public class CommandUnequip extends Command { public CommandUnequip(JavaPlugin plugin) { super(plugin); - this.addCommandAlias("equip"); + this.addCommandAlias("unequip"); this.setCommandDescription("Equips a balloon to you"); this.setCommandSyntax("/bloons unequip "); this.setRequiredPermission(CommandPermission.UNEQUIP); @@ -22,15 +24,21 @@ public CommandUnequip(JavaPlugin plugin) { @Override public boolean execute(CommandSender sender, String[] args) { - Player player = (Player) sender; - BalloonOwner balloonOwner1 = Bloons.playerBalloons.get(player.getUniqueId()); - if (balloonOwner1 == null) { + if (!(sender instanceof Player player)) return false; + + SingleBalloon singleBalloon = Bloons.getPlayerBalloons().get(player.getUniqueId()); + MessageTranslations messageTranslations = new MessageTranslations(this.plugin); + + if (singleBalloon == null) { player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("not-equipped")); + Component notEquippedMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("not-equipped")); + player.sendMessage(notEquippedMessage); return false; } - Utils.removeBalloon(player, balloonOwner1); - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("unequipped")); + + BalloonManagement.removeBalloon(player, singleBalloon); + Component unequipSuccessfulMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("unequipped")); + player.sendMessage(unequipSuccessfulMessage); player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_HURT_SWEET_BERRY_BUSH, 1, 1); return false; } diff --git a/src/main/java/net/jeqo/bloons/commands/manager/Command.java b/src/main/java/net/jeqo/bloons/commands/manager/Command.java index 799a2709..46cdd64d 100644 --- a/src/main/java/net/jeqo/bloons/commands/manager/Command.java +++ b/src/main/java/net/jeqo/bloons/commands/manager/Command.java @@ -10,23 +10,23 @@ import java.util.ArrayList; +@Getter public abstract class Command { protected JavaPlugin plugin; - @Getter @Setter + @Setter private CommandPermission requiredPermission; - @Getter @Setter + @Setter private CommandAccess requiredAccess = CommandAccess.ENABLED; - @Getter @Setter + @Setter private String commandSyntax; - @Getter @Setter + @Setter private String commandDescription; - @Getter private final ArrayList commandAliases = new ArrayList<>(); public Command(JavaPlugin providedPlugin) { - plugin = providedPlugin; + this.plugin = providedPlugin; } /** @@ -35,43 +35,43 @@ public Command(JavaPlugin providedPlugin) { * @param alias The alias to add to the command */ public void addCommandAlias(String alias) { - commandAliases.add(alias); + this.getCommandAliases().add(alias); } public abstract boolean execute(CommandSender sender, String[] args) throws Exception; /** * Checks if the command meets the requirements to be executed - * @param s The sender of the command - * @param perm The permission required to execute the command - * @return Whether or not the command meets the requirements + * @param sender The sender of the command + * @param permission The permission required to execute the command + * @return Whether the command meets the requirements */ - public boolean hasRequirement(CommandSender s, CommandPermission perm) { - switch (perm) { + public boolean hasRequirement(CommandSender sender, CommandPermission permission) { + switch (permission) { case EQUIP -> { - if (s instanceof Player) { - if (!s.hasPermission("bloons.equip")) { + if (sender instanceof Player) { + if (!sender.hasPermission("bloons.equip")) { return false; } } } case UNEQUIP -> { - if (s instanceof Player) { - if (!s.hasPermission("bloons.unequip")) { + if (sender instanceof Player) { + if (!sender.hasPermission("bloons.unequip")) { return false; } } } case FORCE -> { - if (s instanceof Player) { - if (!s.hasPermission("bloons.force")) { + if (sender instanceof Player) { + if (!sender.hasPermission("bloons.force")) { return false; } } } case RELOAD -> { - if (s instanceof Player) { - if (!s.hasPermission("bloons.reload")) { + if (sender instanceof Player) { + if (!sender.hasPermission("bloons.reload")) { return false; } } diff --git a/src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java b/src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java new file mode 100644 index 00000000..436fdfb6 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java @@ -0,0 +1,219 @@ +package net.jeqo.bloons.commands.manager; + +import lombok.Getter; +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.commands.*; +import net.jeqo.bloons.commands.manager.enums.CommandAccess; +import net.jeqo.bloons.gui.menus.BalloonMenu; +import net.jeqo.bloons.logger.Logger; +import net.jeqo.bloons.utils.ColorManagement; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import static net.jeqo.bloons.commands.utils.ErrorHandling.usage; + +@Getter +public class CommandCore implements CommandExecutor { + private final ArrayList commands; + private final JavaPlugin plugin; + private final MessageTranslations messageTranslations; + + public CommandCore(JavaPlugin providedPlugin) { + this.plugin = providedPlugin; + this.commands = new ArrayList<>(); + this.messageTranslations = new MessageTranslations(this.getPlugin()); + + addCommand(new CommandEquip(this.getPlugin())); + addCommand(new CommandForceEquip(this.getPlugin())); + addCommand(new CommandForceUnequip(this.getPlugin())); + addCommand(new CommandReload(this.getPlugin())); + addCommand(new CommandUnequip(this.getPlugin())); + + registerCommands(); + } + + /** + * Registers all commands in the commands list + */ + public void registerCommands() { + Objects.requireNonNull(this.getPlugin().getCommand("bloons")).setExecutor(this); + } + + /** + * Adds a command to the commands list + * @param command The command to add + */ + public void addCommand(Command command) { + this.getCommands().add(command); + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command command, @NotNull String label, String[] args) { + if (args.length < 1) { + if (!(sender instanceof Player player)) { + Component consoleMessage = Component.text("This command can only be executed by a player.").color(NamedTextColor.RED); + sender.sendMessage(consoleMessage); + return true; + } + + if (!player.hasPermission("bloons.menu")) { + Component noPermission = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("no-permission")); + player.sendMessage(noPermission); + return true; + } + + ArrayList items = new ArrayList<>(); + ConfigurationSection balloonsSection = Bloons.getInstance().getConfig().getConfigurationSection("balloons"); + + if (balloonsSection != null) { + for (String key : balloonsSection.getKeys(false)) { + ConfigurationSection keySection = balloonsSection.getConfigurationSection(key); + if (keySection == null) continue; + + if (shouldAddBalloon(player, key)) { + ItemStack item = createBalloonItem(keySection, key); + items.add(item); + } + } + } + + new BalloonMenu(items, messageTranslations.getString("menu-title"), player); + return true; + } + + + // Define what a subcommand really is + String subcommand = args[0].toLowerCase(); + String[] subcommandArgs = Arrays.copyOfRange(args, 1, args.length); + + for (Command currentCommand : getCommands()) { + if (currentCommand.getCommandAliases().contains(subcommand)) { + if (!meetsRequirements(currentCommand, sender)) { + sender.sendMessage(messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("no-permission"))); + return false; + } + + if (currentCommand.getRequiredAccess() == CommandAccess.DISABLED) { + Component commandDisabledMessage = Component.text("This command is currently disabled.").color(NamedTextColor.RED); + sender.sendMessage(commandDisabledMessage); + return false; + } + + try { + currentCommand.execute(sender, subcommandArgs); + } catch (Exception ignored) { + } + return true; + } + } + + usage(sender); + return false; + } + + /** + * Checks if the player sending the command meets the requirements to execute the command + * @param command The command to check + * @param sender The sender of the command + * @return Whether the user meets the requirements + */ + public boolean meetsRequirements(Command command, CommandSender sender) { + return command.hasRequirement(sender, command.getRequiredPermission()); + } + + /** + * Checks if we should add the balloon to the menu + * @param player The player to check + * @param key The key of the balloon + * @return Whether we should add the balloon to the menu + */ + private boolean shouldAddBalloon(Player player, String key) { + if (messageTranslations.getString("hide-balloons-without-permission").equalsIgnoreCase("true")) { + return player.hasPermission(messageTranslations.getString("balloons." + key + ".permission")); + } + return true; + } + + /** + * Creates an ItemStack for a balloon + * @param keySection The configuration section of the balloon + * @param key The key of the balloon + * @return The ItemStack of the balloon + */ + private ItemStack createBalloonItem(ConfigurationSection keySection, String key) { + Material material = Material.matchMaterial(Objects.requireNonNull(keySection.getString("material"))); + if (material == null) return null; + + ItemStack item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + if (meta == null) return null; + + meta.setLocalizedName(messageTranslations.getString("balloons." + key + ".id")); + setBalloonLore(meta, keySection); + setBalloonDisplayName(meta, keySection); + meta.setCustomModelData(keySection.getInt("custom-model-data")); + setBalloonColor(meta, key, keySection); + + item.setItemMeta(meta); + return item; + } + + /** + * Sets the lore of the balloon + * @param meta The ItemMeta of the balloon + * @param keySection The configuration section of the balloon + */ + private void setBalloonLore(ItemMeta meta, ConfigurationSection keySection) { + if (keySection.contains("lore")) { + List lore = keySection.getStringList("lore"); + lore.replaceAll(ColorManagement::fromHex); + meta.setLore(lore); + } + } + + /** + * Sets the display name of the balloon + * @param meta The ItemMeta of the balloon + * @param keySection The configuration section of the balloon + */ + private void setBalloonDisplayName(ItemMeta meta, ConfigurationSection keySection) { + String name = keySection.getString("name"); + MessageTranslations messageTranslations = new MessageTranslations(this.plugin); + if (name != null) { + meta.displayName(messageTranslations.getSerializedString(name)); + } + } + + /** + * Sets the color of the balloon + * @param meta The ItemMeta of the balloon + * @param key The key of the balloon + * @param keySection The configuration section of the balloon + */ + private void setBalloonColor(ItemMeta meta, String key, ConfigurationSection keySection) { + String color = keySection.getString("color"); + if (color != null && !color.equalsIgnoreCase("potion")) { + if (meta instanceof LeatherArmorMeta) { + ((LeatherArmorMeta) meta).setColor(ColorManagement.hexToColor(color)); + } else { + Logger.logWarning("The color of the balloon " + key + " is set, but the material is not a leather item!"); + } + } + } +} diff --git a/src/main/java/net/jeqo/bloons/commands/manager/CommandManager.java b/src/main/java/net/jeqo/bloons/commands/manager/CommandManager.java deleted file mode 100644 index eb851251..00000000 --- a/src/main/java/net/jeqo/bloons/commands/manager/CommandManager.java +++ /dev/null @@ -1,100 +0,0 @@ -package net.jeqo.bloons.commands.manager; - -import lombok.Getter; -import net.jeqo.bloons.Bloons; -import net.jeqo.bloons.commands.*; -import net.jeqo.bloons.commands.manager.enums.CommandAccess; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.plugin.java.JavaPlugin; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Objects; - -import static net.jeqo.bloons.commands.utils.ErrorHandling.usage; - -public class CommandManager implements CommandExecutor { - @Getter - private final ArrayList commands; - private final JavaPlugin plugin; - - public CommandManager(JavaPlugin providedPlugin) { - plugin = providedPlugin; - commands = new ArrayList<>(); - - addCommand(new CommandEquip(plugin)); - addCommand(new CommandForceEquip(plugin)); - addCommand(new CommandForceUnequip(plugin)); - addCommand(new CommandReload(plugin)); - addCommand(new CommandUnequip(plugin)); - - registerCommands(); - } - - /** - * Registers all commands in the commands list - */ - public void registerCommands() { - Objects.requireNonNull(plugin.getCommand("bloons")).setExecutor(this); - } - - /** - * Adds a command to the commands list - * @param c The command to add - */ - public void addCommand(Command c) { - commands.add(c); - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, org.bukkit.command.@NotNull Command command, @NotNull String label, String[] args) { - if (args.length < 1) { - usage(sender); - return false; - } - - // Define what a subcommand really is - String subcommand = args[0].toLowerCase(); - String[] subcommandArgs = Arrays.copyOfRange(args, 1, args.length); - - boolean commandMatched = false; - for (Command c : getCommands()) { - if (c.getCommandAliases().contains(subcommand)) { - if (!meetsRequirements(c, sender)) { - sender.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("no-permission")); - return false; - } - - if (c.getRequiredAccess() == CommandAccess.DISABLED) { - sender.sendMessage(ChatColor.RED + "This command is currently disabled."); - return false; - } - - try { - c.execute(sender, subcommandArgs); - } catch (Exception ignored) { - } - commandMatched = true; - return true; - } - } - if (!commandMatched) { - usage(sender); - return false; - } - return false; - } - - /** - * Checks if the player sending the command meets the requirements to execute the command - * @param c The command to check - * @param s The sender of the command - * @return Whether the user meets the requirements - */ - public boolean meetsRequirements(Command c, CommandSender s) { - return c.hasRequirement(s, c.getRequiredPermission()); - } -} diff --git a/src/main/java/net/jeqo/bloons/data/BalloonTab.java b/src/main/java/net/jeqo/bloons/commands/manager/CommandTabCompleter.java similarity index 95% rename from src/main/java/net/jeqo/bloons/data/BalloonTab.java rename to src/main/java/net/jeqo/bloons/commands/manager/CommandTabCompleter.java index 1dbd436f..38ff58a3 100644 --- a/src/main/java/net/jeqo/bloons/data/BalloonTab.java +++ b/src/main/java/net/jeqo/bloons/commands/manager/CommandTabCompleter.java @@ -1,15 +1,16 @@ -package net.jeqo.bloons.data; +package net.jeqo.bloons.commands.manager; import net.jeqo.bloons.Bloons; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.jetbrains.annotations.NotNull; + import java.util.Collections; import java.util.List; import java.util.Objects; -public class BalloonTab implements TabCompleter { +public class CommandTabCompleter implements TabCompleter { public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { if (sender.hasPermission("bloons.reload")) { if (args.length == 3) { diff --git a/src/main/java/net/jeqo/bloons/commands/utils/ErrorHandling.java b/src/main/java/net/jeqo/bloons/commands/utils/ErrorHandling.java index e6623e8d..b02cc8af 100644 --- a/src/main/java/net/jeqo/bloons/commands/utils/ErrorHandling.java +++ b/src/main/java/net/jeqo/bloons/commands/utils/ErrorHandling.java @@ -1,6 +1,7 @@ package net.jeqo.bloons.commands.utils; -import net.jeqo.bloons.utils.Utils; +import net.jeqo.bloons.utils.ColorManagement; +import net.kyori.adventure.text.Component; import org.bukkit.command.CommandSender; public class ErrorHandling { @@ -8,23 +9,30 @@ public class ErrorHandling { public static void usage(CommandSender sender) { sender.sendMessage(""); if (sender.hasPermission("bloons.menu")) { - sender.sendMessage(Utils.hex(" #ff00cc/#e30ed5b#c61cddl#aa2be6o#8e39eeo#7147f7n#5555ffs &7- Open the balloon menu")); + Component menuMessage = Component.text(ColorManagement.fromHex("#ff00cc/#e30ed5b#c61cddl#aa2be6o#8e39eeo#7147f7n#5555ffs &7- Open the balloon menu")); + sender.sendMessage(menuMessage); } if (sender.hasPermission("bloons.equip")) { - sender.sendMessage(Utils.hex(" #ff00cc/#f008d1b#e00fd5l#d117dao#c11fdfo#b227e3n#a22ee8s #9336ece#833ef1q#7446f6u#644dfai#5555ffp &7- Equip a balloon")); + Component equipMessage = Component.text(ColorManagement.fromHex("#ff00cc/#e30ed5b#c61cddl#aa2be6o#8e39eeq#7147fui#5555ffp &7- Equip a balloon")); + sender.sendMessage(equipMessage); } if (sender.hasPermission("bloons.unequip")) { - sender.sendMessage(Utils.hex(" #ff00cc/#f207d0b#e50dd4l#d814d8o#cb1adco#be21e0n#b127e4s #a32ee7u#9634ebn#893befe#7c41f3q#6f48f7u#624efbi#5555ffp &7- Unequip a balloon")); + Component unequipMessage = Component.text(ColorManagement.fromHex("#ff00cc/#e30ed5b#c61cddl#aa2be6o#8e39eeu#7147fni#5555ffp &7- Unequip a balloon")); + sender.sendMessage(unequipMessage); } if (sender.hasPermission("bloons.force")) { - sender.sendMessage(Utils.hex(" #ff00cc/#f107d0b#e30ed5l#d515d9o#c61cddo#b823e1n#aa2be6s #9c32eaf#8e39eee#8040f2q#7147f7u#634efbi#5555ffp &7- Equip a balloon to a player")); - sender.sendMessage(Utils.hex(" #ff00cc/#f306d0b#e70cd3l#db12d7o#ce18dbo#c21eden#b624e2s #aa2be6f#9e31e9u#9237edn#863df0e#7943f4q#6d49f8u#614ffbi#5555ffp &7- Unequip a balloon from a player")); + Component forceEquipMessage = Component.text(ColorManagement.fromHex(" #ff00cc/#f107d0b#e30ed5l#d515d9o#c61cddo#b823e1n#aa2be6s #9c32eaf#8e39eee#8040f2q#7147f7u#634efbi#5555ffp &7- Equip a balloon to a player")); + Component forceUnequipMessage = Component.text(ColorManagement.fromHex(" #ff00cc/#f306d0b#e70cd3l#db12d7o#ce18dbo#c21eden#b624e2s #aa2be6f#9e31e9u#9237edn#863df0e#7943f4q#6d49f8u#614ffbi#5555ffp &7- Unequip a balloon from a player")); + sender.sendMessage(forceEquipMessage); + sender.sendMessage(forceUnequipMessage); } if (sender.hasPermission("bloons.reload")) { - sender.sendMessage(Utils.hex(" #ff00cc/#f107d0b#e30ed5l#d515d9o#c61cddo#b823e1n#aa2be6s #9c32ear#8e39eee#8040f2l#7147f7o#634efba#5555ffd &7- Reload the Bloons config")); + Component reloadMessage = Component.text(ColorManagement.fromHex(" #ff00cc/#f107d0b#e30ed5l#d515d9o#c61cddo#b823e1n#aa2be6r #9c32eeo#8e39ee1#8040f2l#7147f7o#634efbi#5555ffd &7- Reload the Bloons config")); + sender.sendMessage(reloadMessage); } - sender.sendMessage(""); - sender.sendMessage(Utils.hex(" #ff00ccB#f406cfl#e80bd3o#dd11d6o#d217dan#c61cdds #bb22e01#b028e4.#a42de70#9933eb.#8e39ee1#823ef5-#7744f5B#6c4af8E#604ffcT#5555ffA &7- &fMade by Jeqo")); - sender.sendMessage(""); + sender.sendMessage(Component.text("")); + Component creditsMessage = Component.text(ColorManagement.fromHex(" #ff00ccB#f406cfl#e80bd3o#dd11d6o#d217dan#c61cdds #bb22e01#b028e4.#a42de70#9933eb.#8e39ee1#823ef5-#7744f5B#6c4af8E#604ffcT#5555ffA &7- &fMade by Jeqo")); + sender.sendMessage(creditsMessage); + sender.sendMessage(Component.text("")); } } diff --git a/src/main/java/net/jeqo/bloons/configuration/BalloonConfiguration.java b/src/main/java/net/jeqo/bloons/configuration/BalloonConfiguration.java new file mode 100644 index 00000000..85d9d893 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/configuration/BalloonConfiguration.java @@ -0,0 +1,6 @@ +package net.jeqo.bloons.configuration; + +public class BalloonConfiguration { + public static final String BALLOON_ARMOR_STAND_ID = "4001147"; // The display name of the armor stand + public static final String BALLOON_CHICKEN_ID = "4001148"; // The display name of the chicken +} diff --git a/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java b/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java index 4fd7835a..d204ff34 100644 --- a/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java +++ b/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java @@ -1,11 +1,6 @@ package net.jeqo.bloons.configuration; -import org.apache.maven.model.Model; -import org.apache.maven.model.io.xpp3.MavenXpp3Reader; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; - -import java.io.FileReader; -import java.io.IOException; +import net.jeqo.bloons.Bloons; /** * A class that contains configurations and information regarding the plugin @@ -17,48 +12,32 @@ public class PluginConfiguration { /** * Get the version of the plugin from the pom.xml file * @return The version of the plugin - * @throws IOException If the file cannot be read - * @throws XmlPullParserException If the file cannot be parsed */ - public static String getVersion() throws IOException, XmlPullParserException { - MavenXpp3Reader reader = new MavenXpp3Reader(); - Model model = reader.read(new FileReader("pom.xml")); - return model.getVersion(); + public static String getVersion() { + return Bloons.getInstance().getDescription().getVersion(); } /** - * Get the name of the plugin from the pom.xml file + * Get the name of the plugin from the plugin.yml file * @return The name of the plugin - * @throws IOException If the file cannot be read - * @throws XmlPullParserException If the file cannot be parsed */ - public static String getName() throws IOException, XmlPullParserException { - MavenXpp3Reader reader = new MavenXpp3Reader(); - Model model = reader.read(new FileReader("pom.xml")); - return model.getName(); + public static String getName() { + return Bloons.getInstance().getDescription().getName(); } /** - * Get the description of the plugin from the pom.xml file + * Get the description of the plugin from the plugin.yml file * @return The description of the plugin - * @throws IOException If the file cannot be read - * @throws XmlPullParserException If the file cannot be parsed */ - public static String getDescription() throws IOException, XmlPullParserException { - MavenXpp3Reader reader = new MavenXpp3Reader(); - Model model = reader.read(new FileReader("pom.xml")); - return model.getDescription(); + public static String getDescription() { + return Bloons.getInstance().getDescription().getDescription(); } /** - * Gets the website URL of the plugin from the pom.xml file + * Gets the website URL of the plugin from the plugin.yml file * @return The website URL of the plugin - * @throws IOException If the file cannot be read - * @throws XmlPullParserException If the file cannot be parsed */ - public static String getURL() throws IOException, XmlPullParserException { - MavenXpp3Reader reader = new MavenXpp3Reader(); - Model model = reader.read(new FileReader("pom.xml")); - return model.getUrl(); + public static String getURL() { + return Bloons.getInstance().getDescription().getWebsite(); } } diff --git a/src/main/java/net/jeqo/bloons/data/BalloonOwner.java b/src/main/java/net/jeqo/bloons/data/BalloonOwner.java deleted file mode 100644 index 621f7ed8..00000000 --- a/src/main/java/net/jeqo/bloons/data/BalloonOwner.java +++ /dev/null @@ -1,146 +0,0 @@ -package net.jeqo.bloons.data; - -import net.jeqo.bloons.Bloons; -import net.jeqo.bloons.utils.Utils; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Particle; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Chicken; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.LeatherArmorMeta; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.EulerAngle; -import org.bukkit.util.Vector; - -import java.util.Objects; -import java.util.concurrent.ThreadLocalRandom; - -public class BalloonOwner extends BukkitRunnable { - private final Player player; - private final ItemStack balloon; - private ArmorStand armorStand; - public Chicken chicken; - private Location playerLocation; - private Location moveLocation; - private int ticks = 0; - private float targetYaw = 0.0F; - - public BalloonOwner(Player player, String balloonId) { - this.player = player; - ConfigurationSection configuration = Bloons.getInstance().getConfig().getConfigurationSection("balloons." + balloonId); - assert configuration != null; - ItemStack item = new ItemStack(Material.valueOf(configuration.getString("material"))); - ItemMeta meta = item.getItemMeta(); - assert meta != null; - meta.setCustomModelData(configuration.getInt("custom-model-data")); - if (Bloons.getString("balloons." + balloonId + ".color") != null) { - if (!Bloons.getString("balloons." + balloonId + ".color").equalsIgnoreCase("potion")) { - LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) meta; - leatherArmorMeta.setColor(Utils.hexToColor(Bloons.getString("balloons." + balloonId + ".color"))); - } else { - Utils.warn("The color of the balloon " + balloonId + " is set, but the material is not a leather item!"); - } - } - item.setItemMeta(meta); - this.balloon = item; - } - - public void run() { - if (this.armorStand == null) { - initBalloon(); - } - Location location = this.player.getLocation(); - location.setYaw(this.playerLocation.getYaw()); - if (this.ticks == 20) { - this.targetYaw = (ThreadLocalRandom.current().nextInt(10) - 5); - this.ticks = 0; - } - if (this.targetYaw > location.getYaw()) { - location.setYaw(location.getYaw() + 0.2F); - } else if (this.targetYaw < location.getYaw()) { - location.setYaw(location.getYaw() - 0.2F); - } - this.moveLocation = this.armorStand.getLocation().subtract(0.0D, 2.0D, 0.0D).clone(); - Vector vector = location.toVector().subtract(this.moveLocation.toVector()); - vector.multiply(0.3D); - this.moveLocation = this.moveLocation.add(vector); - double value1 = vector.getZ() * 50.0D * -1.0D; - double value2 = vector.getX() * 50.0D * -1.0D; - this.armorStand.setHeadPose(new EulerAngle(Math.toRadians(value1), Math.toRadians(location.getYaw()), Math.toRadians(value2))); - teleport(this.moveLocation); - this.playerLocation = this.player.getLocation(); - this.playerLocation.setYaw(location.getYaw()); - this.ticks++; - } - - public synchronized void cancel() throws IllegalStateException { - this.armorStand.remove(); - this.chicken.remove(); - super.cancel(); - } - - public void spawnRemoveParticle() { - this.moveLocation.getWorld().spawnParticle(Particle.CLOUD, this.moveLocation, 5, 0.0D, 0.0D, 0.0D, 0.1D); - } - - private void teleport(Location location) { - this.armorStand.teleport(location.add(0.0D, 2.0D, 0.0D)); - this.chicken.teleport(location.add(0.0D, 1.2D, 0.0D)); - } - - private void initBalloon() { - this.playerLocation = this.player.getLocation(); - this.playerLocation.setYaw(0.0F); - - ItemMeta meta = this.balloon.getItemMeta(); - assert meta != null; - meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); - this.balloon.setItemMeta(meta); - - this.armorStand = Objects.requireNonNull(this.playerLocation.getWorld()).spawn(this.playerLocation, ArmorStand.class); - this.armorStand.setBasePlate(false); - this.armorStand.setVisible(false); - this.armorStand.setInvulnerable(true); - this.armorStand.setCanPickupItems(false); - this.armorStand.setGravity(false); - this.armorStand.setSmall(false); - this.armorStand.setMarker(true); - this.armorStand.setCollidable(false); - this.armorStand.getEquipment().setHelmet(this.balloon); - this.armorStand.setCustomName("4001147"); - - this.chicken = this.playerLocation.getWorld().spawn(this.playerLocation, Chicken.class); - this.chicken.setInvulnerable(true); - this.chicken.setInvisible(true); - this.chicken.setSilent(true); - this.chicken.setBaby(); - this.chicken.setAgeLock(true); - this.chicken.setAware(false); - this.chicken.setCollidable(false); - this.chicken.setLeashHolder(player); - this.chicken.setCustomName("4001148"); - } - - - public static void checkBalloonRemovalOrAdd(final Player player, final String balloonId) { - (new BukkitRunnable() { - public void run() { - BalloonOwner owner = Bloons.playerBalloons.get(player.getUniqueId()); - if (owner != null) { - return; - } - Utils.removeBalloon(player, owner); - BalloonOwner balloonOwner = new BalloonOwner(player, balloonId); - balloonOwner.runTaskTimer(Bloons.getInstance(), 0L, 1L); - Bloons.playerBalloons.put(player.getUniqueId(), balloonOwner); - Bloons.playerBalloonID.put(player.getUniqueId(), balloonId); - - } - }).runTaskLater(Bloons.getInstance(), 1L); - } -} \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/events/BloonsEvent.java b/src/main/java/net/jeqo/bloons/events/BloonsEvent.java new file mode 100644 index 00000000..4b2bd576 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/events/BloonsEvent.java @@ -0,0 +1,62 @@ +package net.jeqo.bloons.events; + +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +public class BloonsEvent extends Event implements Cancellable { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + private boolean cancelled; + + /** + * Gets all listeners that are listening to this event + * @return a list of handlers + */ + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + + /** + * Returns whether the event is cancelled. + * @return true if the event is cancelled, false otherwise + */ + @Override + public boolean isCancelled() { + return this.cancelled; + } + + /** + * Sets whether the event is cancelled. + * @param cancel true if you wish to cancel this event + */ + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + /** + * Cancels the current event + */ + public void cancel() { + this.setCancelled(true); + } + + /** + * Unregisters the listener + * @param plugin the plugin to unregister the event from + */ + public void unregister(Plugin plugin) { + this.getHandlers().unregister(plugin); + } + + /** + * Unregisters all listeners from the event + */ + public void unregisterAll() { + HandlerList.unregisterAll(); + } +} diff --git a/src/main/java/net/jeqo/bloons/gui/GUI.java b/src/main/java/net/jeqo/bloons/gui/GUI.java new file mode 100644 index 00000000..d6398c40 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/GUI.java @@ -0,0 +1,158 @@ +package net.jeqo.bloons.gui; + +import net.jeqo.bloons.events.BloonsEvent; +import net.jeqo.bloons.utils.NBTItem; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; + +public abstract class GUI { + BukkitTask updater; + + /** + * The inventory that is displayed to the player + * @return The inventory as an Inventory object + */ + public abstract Inventory inventory(); + + /** + * The name that is displayed as the GUI title + * @return The name + */ + public abstract Component name(); + + /** + * The number of slots that are present within the GUI + * It should be a multiple of 9. 27 and 54 are common values. + * @return The number of slots contained within the GUI + */ + public abstract int slots(); + + /** + * The filler item that is used to fill empty slots in the GUI + * @return The filler item as a WynncraftItem object + */ + public abstract GUIClickableItem fillerItem(int slot); + + /** + * The border item that is used to create a border around the GUI + * @return The border item as a WynncraftItem object + */ + public abstract GUIClickableItem borderItem(int slot); + + /** + * The item that is displayed in the GUI but can't be picked up + * @param slot The slot that the item is in + * @return The item as a WynncraftItem object + */ + public abstract GUIClickableItem cantPickup(NBTItem item, int slot); + + /** + * The event that is fired when the GUI is opened or triggered + * @return The event as a WynncraftEvent object + */ + public BloonsEvent triggerEvent() { + return null; + } + + /** + * Determines what happens when the GUI is closed + */ + public abstract void onClose(Player player); + + /** + * Determines what happens when the GUI is opened + */ + public abstract void open(Player player); + + /** + * Determines what happens when the GUI is updated (this happens every 20 ticks) + */ + public abstract void update(); + + /** + * Starts the GUI updater to update the GUI every 20 ticks + * This should be executed upon the opening of the GUI + */ + public void startUpdater(JavaPlugin plugin) { + this.updater = Bukkit.getScheduler().runTaskTimer(plugin, this::update, 0, 20); + } + + /** + * Cancels the GUI updater to stop updating the GUI + * This should be executed upon the closing of the GUI + */ + public void stopUpdater() { + this.updater.cancel(); + } + + /** + * Adds an item to the GUI + * @param item The item to add + */ + public void addItem(GUIClickableItem item) { + inventory().setItem(item.getSlot(), item.getFinalizedItem().getItem()); + } + + /** + * Adds an item to the GUI at a specific slot + * @param item The item to add + * @param slot The slot to add the item to + */ + public void addItem(GUIClickableItem item, int slot) { + inventory().setItem(slot, item.getItem()); + } + + /** + * Gets the item in a specific slot + * @param slot The slot to get the item from + */ + public void getItem(int slot) { + inventory().getItem(slot); + } + + /** + * Sets a border around the GUI with a specific item + */ + public void setBorder() { + int size = inventory().getSize(); + if (size < 27) return; + + for (int i = 0; i < 9; i++) { + addItem(borderItem(i), i); + } + + for(int i = 0; i < Math.ceil(size / 10.0); i++) { + addItem(borderItem(i), (8 + (9 * i))); + if(9 + (9 * i) > size - 1) continue; + addItem(borderItem(i), (9 + (9 * i))); + } + + for(int i = size - 9; i < size; i++) { + addItem(borderItem(i), (i)); + } + } + + /** + * Fills all empty slots in the GUI with the filler item + */ + public void fillEmptySlots() { + for (int i = 0; i < slots(); i++) { + if (inventory().getItem(i) == null) { + inventory().setItem(i, fillerItem(i).getItem()); + } + } + } + + /** + * Fills all slots in the GUI with the filler item + */ + public void fillAllSlots() { + for (int i = 0; i < slots(); i++) { + inventory().setItem(i, fillerItem(i).getItem()); + } + } +} \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/gui/GUIClickableItem.java b/src/main/java/net/jeqo/bloons/gui/GUIClickableItem.java new file mode 100644 index 00000000..8e1f34e3 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/GUIClickableItem.java @@ -0,0 +1,60 @@ +package net.jeqo.bloons.gui; + +import net.jeqo.bloons.utils.NBTItem; +import org.bukkit.event.inventory.InventoryClickEvent; + +import java.util.HashMap; +import java.util.UUID; + +/** + * A class that represents a clickable item in a GUI, both interactable and + * non-interactable. + */ +public abstract class GUIClickableItem { + public static HashMap itemData = new HashMap<>(); + private final String uuid; + + /** + * Creates a new clickable item + */ + public GUIClickableItem() { + this.uuid = UUID.randomUUID().toString(); + itemData.put(uuid, this); + } + + /** + * Gets the finalized item with the GUI NBT data attached + * @return The finalized item + */ + public NBTItem getFinalizedItem() { + NBTItem item = getItem(); + item.setStringFlag(GUIHelpers.getClickableItemFlag(), uuid); + return item; + } + + /** + * What runs when the item is clicked + * @param event The event that is fired when the item is clicked + */ + public abstract void run(InventoryClickEvent event); + + /** + * The slot that the item is in + * @return The slot that the item is in as an Integer + */ + public abstract int getSlot(); + + /** + * The item that is displayed in the GUI + * @return The item as a WynncraftItem object + */ + public abstract NBTItem getItem(); + + /** + * Whether the item can be picked up + * @return Whether the item can be picked up + */ + public boolean canPickup() { + return false; + } +} diff --git a/src/main/java/net/jeqo/bloons/gui/GUICore.java b/src/main/java/net/jeqo/bloons/gui/GUICore.java new file mode 100644 index 00000000..e959bb86 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/GUICore.java @@ -0,0 +1,108 @@ +package net.jeqo.bloons.gui; + +import lombok.Getter; +import lombok.Setter; +import net.jeqo.bloons.logger.Logger; +import net.jeqo.bloons.logger.LoggingLevel; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.ArrayList; +import java.util.Arrays; + +@Getter +@Setter +public class GUICore { + private ArrayList guis; + private JavaPlugin plugin; + + /** + * Creates a new instance of the GUI core + */ + public GUICore(JavaPlugin plugin) { + if (plugin == null) { + Logger.log(LoggingLevel.ERROR, "Plugin cannot be null. Please provide a valid instance."); + } + + this.plugin = plugin; + this.guis = new ArrayList<>(); + } + + /** + * Creates a new instance of the GUI core with a list of GUIs + * @param guis The GUIs to register + */ + public GUICore(JavaPlugin plugin, GUI... guis) { + if (plugin == null) { + Logger.log(LoggingLevel.ERROR, "Plugin cannot be null. Please provide a valid instance."); + } + + this.plugin = plugin; + this.guis = new ArrayList<>(); + this.guis.addAll(Arrays.asList(guis)); + } + + /** + * Creates a new instance of the GUI core with a list of GUIs + * @param guis The list of GUIs to register + */ + public GUICore(JavaPlugin plugin, ArrayList guis) { + if (plugin == null) { + Logger.log(LoggingLevel.ERROR, "The Wynncraft plugin cannot be null. Please provide a valid instance."); + } + + this.plugin = plugin; + this.guis = guis; + } + + /** + * Registers a GUI to the GUI core + * @param gui The GUI to register + */ + public void registerGUI(GUI gui) { + this.guis.add(gui); + } + + /** + * Unregisters a GUI from the GUI core + * @param gui The GUI to unregister + */ + public void unregisterGUI(GUI gui) { + this.guis.remove(gui); + } + + /** + * Opens a GUI to the specified player + * @param gui The GUI to open + */ + public void openGUI(GUI gui, Player player) { + if (!this.getGuis().contains(gui)) { + Logger.log(LoggingLevel.ERROR, "The GUI " + gui.name() + " is not registered in the GUI core. Please register it before opening it."); + } else { + // Open the GUI and start a task to update the GUI every 20 ticks + gui.open(player); + player.openInventory(gui.inventory()); + gui.startUpdater(this.getPlugin()); + + // Trigger the event specified in the GUI if it exists + if (gui.triggerEvent() != null) { + gui.triggerEvent().callEvent(); + } + } + } + + /** + * Closes a GUI for the specified player + * @param gui The GUI to close + */ + public void closeGUI(GUI gui, Player player) { + if (!this.getGuis().contains(gui)) { + Logger.log(LoggingLevel.ERROR, "The GUI " + gui.name() + " is not registered in the GUI core. Please register it before closing it."); + } else { + // Close the GUI and stop the task to update the GUI + gui.onClose(player); + player.closeInventory(); + gui.stopUpdater(); + } + } +} diff --git a/src/main/java/net/jeqo/bloons/gui/GUIHelpers.java b/src/main/java/net/jeqo/bloons/gui/GUIHelpers.java new file mode 100644 index 00000000..1c5fab84 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/GUIHelpers.java @@ -0,0 +1,15 @@ +package net.jeqo.bloons.gui; + +/** + * A class with helper methods to assist with GUIs + */ +public class GUIHelpers { + + /** + * Gets the flag that is used to identify clickable item + * @return The flag that is used to identify clickable item + */ + public static String getClickableItemFlag() { + return "GUIClickableItem"; + } +} diff --git a/src/main/java/net/jeqo/bloons/gui/GUIListener.java b/src/main/java/net/jeqo/bloons/gui/GUIListener.java new file mode 100644 index 00000000..f4b53b7b --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/GUIListener.java @@ -0,0 +1,37 @@ +package net.jeqo.bloons.gui; + +import net.jeqo.bloons.utils.NBTItem; +import org.bukkit.Material; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; + +/** + * A listener to handle GUI click events + */ +public class GUIListener implements Listener { + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + if (event.getCurrentItem() == null) { + return; + } + + NBTItem item = (NBTItem) event.getCurrentItem(); + + if (item.getType() != Material.AIR) { + return; + } + + if (!item.hasKey(GUIHelpers.getClickableItemFlag())) { + return; + } + + // Get the clickable item and run it, and/or cancel it if it can't be picked up + GUIClickableItem clickableItem = GUIClickableItem.itemData.get(item.getStringFlag(GUIHelpers.getClickableItemFlag())); + clickableItem.run(event); + if (!clickableItem.canPickup()) { + event.setCancelled(true); + } + } +} diff --git a/src/main/java/net/jeqo/bloons/gui/item/border/BlackGlassPaneBorder.java b/src/main/java/net/jeqo/bloons/gui/item/border/BlackGlassPaneBorder.java new file mode 100644 index 00000000..780874ed --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/item/border/BlackGlassPaneBorder.java @@ -0,0 +1,37 @@ +package net.jeqo.bloons.gui.item.border; + +import net.jeqo.bloons.gui.GUIClickableItem; +import net.jeqo.bloons.utils.NBTItem; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +/** + * An example class to represent how a premade border item can be created + */ +public class BlackGlassPaneBorder { + public static GUIClickableItem getItem(int slot) { + return new GUIClickableItem() { + @Override + public void run(InventoryClickEvent event) { + event.setCancelled(true); + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public NBTItem getItem() { + NBTItem item = new NBTItem(new ItemStack(Material.BLACK_STAINED_GLASS_PANE)); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text(" ")); + item.setItemMeta(meta); + return item; + } + }; + } +} diff --git a/src/main/java/net/jeqo/bloons/gui/item/filler/BlackGlassPaneFillerItem.java b/src/main/java/net/jeqo/bloons/gui/item/filler/BlackGlassPaneFillerItem.java new file mode 100644 index 00000000..d942293f --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/item/filler/BlackGlassPaneFillerItem.java @@ -0,0 +1,37 @@ +package net.jeqo.bloons.gui.item.filler; + +import net.jeqo.bloons.gui.GUIClickableItem; +import net.jeqo.bloons.utils.NBTItem; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +/** + * An example class to represent how a premade filler item can be created + */ +public class BlackGlassPaneFillerItem { + public static GUIClickableItem getItem(int slot) { + return new GUIClickableItem() { + @Override + public void run(InventoryClickEvent event) { + event.setCancelled(true); + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public NBTItem getItem() { + NBTItem item = new NBTItem(new ItemStack(Material.COOKIE)); + ItemMeta meta = item.getItemMeta(); + meta.displayName(Component.text(" ")); + item.setItemMeta(meta); + return item; + } + }; + } +} diff --git a/src/main/java/net/jeqo/bloons/data/BalloonMenu.java b/src/main/java/net/jeqo/bloons/gui/menus/BalloonMenu.java similarity index 63% rename from src/main/java/net/jeqo/bloons/data/BalloonMenu.java rename to src/main/java/net/jeqo/bloons/gui/menus/BalloonMenu.java index c906dd6c..fa5446ae 100644 --- a/src/main/java/net/jeqo/bloons/data/BalloonMenu.java +++ b/src/main/java/net/jeqo/bloons/gui/menus/BalloonMenu.java @@ -1,7 +1,9 @@ -package net.jeqo.bloons.data; +package net.jeqo.bloons.gui.menus; import net.jeqo.bloons.Bloons; -import net.jeqo.bloons.utils.Utils; +import net.jeqo.bloons.logger.Logger; +import net.jeqo.bloons.utils.ColorManagement; +import net.jeqo.bloons.utils.MessageTranslations; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -20,29 +22,30 @@ public class BalloonMenu { public UUID id; public int currpage = 0; public static HashMap users = new HashMap<>(); + MessageTranslations messageTranslations = new MessageTranslations(Bloons.getInstance()); private Inventory getBlankPage(String name){ - int pageSize = Bloons.getInt("menu-size"); - Inventory page = Bukkit.createInventory(null, pageSize, Utils.hex(name)); + int pageSize = messageTranslations.getInt("menu-size"); + Inventory page = Bukkit.createInventory(null, pageSize, ColorManagement.fromHex(name)); - ItemStack nextPage = new ItemStack(Material.valueOf(Bloons.getString("buttons.next-page.material"))); + ItemStack nextPage = new ItemStack(Material.valueOf(messageTranslations.getString("buttons.next-page.material"))); ItemMeta nextMeta = nextPage.getItemMeta(); assert nextMeta != null; - nextMeta.setDisplayName(Utils.hex(Bloons.getString("buttons.next-page.name")));; - nextMeta.setCustomModelData(Bloons.getInt("buttons.next-page.custom-model-data")); + nextMeta.displayName(messageTranslations.getSerializedString(messageTranslations.getString("buttons.next-page.name"))); + nextMeta.setCustomModelData(messageTranslations.getInt("buttons.next-page.custom-model-data")); nextPage.setItemMeta(nextMeta); - ItemStack prevPage = new ItemStack(Material.valueOf(Bloons.getString("buttons.previous-page.material"))); + ItemStack prevPage = new ItemStack(Material.valueOf(messageTranslations.getString("buttons.previous-page.material"))); ItemMeta prevMeta = prevPage.getItemMeta(); assert prevMeta != null; - prevMeta.setDisplayName(Utils.hex(Bloons.getString("buttons.previous-page.name")));; - prevMeta.setCustomModelData(Bloons.getInt("buttons.previous-page.custom-model-data")); + prevMeta.displayName(messageTranslations.getSerializedString(messageTranslations.getString("buttons.previous-page.name")));; + prevMeta.setCustomModelData(messageTranslations.getInt("buttons.previous-page.custom-model-data")); prevPage.setItemMeta(prevMeta); - ItemStack removeBalloon = new ItemStack(Material.valueOf(Bloons.getString("buttons.unequip.material"))); + ItemStack removeBalloon = new ItemStack(Material.valueOf(messageTranslations.getString("buttons.unequip.material"))); ItemMeta removeMeta = removeBalloon.getItemMeta(); assert removeMeta != null; - removeMeta.setDisplayName(Utils.hex(Bloons.getString("buttons.unequip.name")));; - removeMeta.setCustomModelData(Bloons.getInt("buttons.unequip.custom-model-data")); + removeMeta.displayName(messageTranslations.getSerializedString(messageTranslations.getString("buttons.unequip.name")));; + removeMeta.setCustomModelData(messageTranslations.getInt("buttons.unequip.custom-model-data")); removeBalloon.setItemMeta(removeMeta); List previousPageSlots = Bloons.getInstance().getConfig().getStringList("buttons.previous-page.slots"); @@ -50,7 +53,7 @@ private Inventory getBlankPage(String name){ if (Integer.parseInt(previousPageSlot) < pageSize) { page.setItem(Integer.parseInt(previousPageSlot), prevPage); } else { - Utils.warn("Previous page button slot(s) out of bounds!"); + Logger.logWarning("Previous page button slot(s) out of bounds!"); } } @@ -59,7 +62,7 @@ private Inventory getBlankPage(String name){ if (Integer.parseInt(unequipSlot) < pageSize) { page.setItem(Integer.parseInt(unequipSlot), removeBalloon); } else { - Utils.warn("Unequip button slot(s) out of bounds!"); + Logger.logWarning("Unequip button slot(s) out of bounds!"); } } @@ -68,7 +71,7 @@ private Inventory getBlankPage(String name){ if (Integer.parseInt(nextPageSlot) < pageSize) { page.setItem(Integer.parseInt(nextPageSlot), nextPage); } else { - Utils.warn("Next page button slot(s) out of bounds!"); + Logger.logWarning("Next page button slot(s) out of bounds!"); } } return page; @@ -85,7 +88,7 @@ public BalloonMenu(ArrayList items, String name, Player p){ page.setItem(slot, items.get(i)); slot++; } - if (slot == Bloons.getInt("balloon-slots")-1) { + if (slot == messageTranslations.getInt("balloon-slots")-1) { pages.add(page); page = getBlankPage(name); slot = 0; diff --git a/src/main/java/net/jeqo/bloons/gui/menus/ExampleMenu.java b/src/main/java/net/jeqo/bloons/gui/menus/ExampleMenu.java new file mode 100644 index 00000000..bb6dd688 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/gui/menus/ExampleMenu.java @@ -0,0 +1,109 @@ +package net.jeqo.bloons.gui.menus; + +import net.jeqo.bloons.gui.GUI; +import net.jeqo.bloons.gui.GUIClickableItem; +import net.jeqo.bloons.gui.item.border.BlackGlassPaneBorder; +import net.jeqo.bloons.gui.item.filler.BlackGlassPaneFillerItem; +import net.jeqo.bloons.utils.NBTItem; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; + +public class ExampleMenu extends GUI { + Inventory inventory; + + /** + * The inventory that is displayed to the player + * + * @return The inventory as an Inventory object + */ + @Override + public Inventory inventory() { + this.inventory = Bukkit.createInventory(null, slots(), name()); + return this.inventory; + } + + /** + * The name that is displayed as the GUI title + * + * @return The name as a String object + */ + @Override + public Component name() { + return Component.text("Example GUI"); + } + + /** + * The number of slots that are present within the GUI + * It should be a multiple of 9. 27 and 54 are common values. + * + * @return The number of slots contained within the GUI + */ + @Override + public int slots() { + return 27; + } + + /** + * The filler item that is used to fill empty slots in the GUI + * + * @return The filler item as a WynncraftItem object + */ + @Override + public GUIClickableItem fillerItem(int slot) { + return BlackGlassPaneFillerItem.getItem(slot); + } + + @Override + public GUIClickableItem borderItem(int slot) { + return BlackGlassPaneBorder.getItem(slot); + } + + @Override + public GUIClickableItem cantPickup(NBTItem currentItem, int slot) { + return new GUIClickableItem() { + @Override + public void run(InventoryClickEvent event) { + event.setCancelled(true); + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public NBTItem getItem() { + return currentItem; + } + }; + } + + /** + * Determines what happens when the GUI is closed + * + * @param player + */ + @Override + public void onClose(Player player) { + player.sendMessage("You closed the GUI!"); + } + + /** + * Determines what happens when the GUI is opened + * + * @param player + */ + @Override + public void open(Player player) { + fillAllSlots(); + } + + /** + * Determines what happens when the GUI is updated (this happens every 20 ticks) + */ + @Override + public void update() {} +} diff --git a/src/main/java/net/jeqo/bloons/listeners/BalloonUnleashListener.java b/src/main/java/net/jeqo/bloons/listeners/BalloonUnleashListener.java new file mode 100644 index 00000000..e6c42d90 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/listeners/BalloonUnleashListener.java @@ -0,0 +1,19 @@ +package net.jeqo.bloons.listeners; + +import net.jeqo.bloons.configuration.BalloonConfiguration; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerLeashEntityEvent; + +public class BalloonUnleashListener implements Listener { + + /** + * Used to check if player tries to unleash from their balloon, if they do then cancel it + */ + @EventHandler + public void onLeash(PlayerLeashEntityEvent event) { + if (event.getEntity().getCustomName() != null && event.getEntity().getCustomName().contains(BalloonConfiguration.BALLOON_CHICKEN_ID)) { + event.setCancelled(true); + } + } +} diff --git a/src/main/java/net/jeqo/bloons/listeners/LeashHandlers.java b/src/main/java/net/jeqo/bloons/listeners/LeashHandlers.java deleted file mode 100644 index e3eabced..00000000 --- a/src/main/java/net/jeqo/bloons/listeners/LeashHandlers.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.jeqo.bloons.listeners; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityUnleashEvent; -import org.bukkit.event.player.PlayerUnleashEntityEvent; - -public class LeashHandlers implements Listener { - - @EventHandler - /** - * Used to check if player tries to unleash from their balloon, if they do then cancel it - */ - public void onUnleash(PlayerUnleashEntityEvent e) { - if (e.getReason() == EntityUnleashEvent.UnleashReason.PLAYER_UNLEASH) { - if (e.getEntity().getCustomName() != null && e.getEntity().getCustomName().contains("4001148")) { - e.setCancelled(true); - } - } - } -} diff --git a/src/main/java/net/jeqo/bloons/listeners/ListenerCore.java b/src/main/java/net/jeqo/bloons/listeners/ListenerCore.java new file mode 100644 index 00000000..da747676 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/listeners/ListenerCore.java @@ -0,0 +1,49 @@ +package net.jeqo.bloons.listeners; + +import lombok.Getter; +import lombok.Setter; +import net.jeqo.bloons.Bloons; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; + +import java.util.ArrayList; + +/** + * Core class for handling listeners + */ +@Setter @Getter +public class ListenerCore { + private final Bloons plugin; + private ArrayList listeners; + + public ListenerCore(Bloons plugin) { + this.plugin = plugin; + + this.setListeners(new ArrayList<>()); + } + + /** + * Adds a listener to the list of listeners + * @param listener The listener to add + */ + public void stageListener(Listener listener) { + this.getListeners().add(listener); + } + + /** + * Registers all listeners in the listeners list + */ + public void registerListeners() { + for (Listener listener : this.getListeners()) { + this.getPlugin().getServer().getPluginManager().registerEvents(listener, this.getPlugin()); + } + } + + /** + * Unregisters all listeners and clear staged listeners + */ + public void unregisterListeners() { + this.setListeners(new ArrayList<>()); + HandlerList.unregisterAll(this.getPlugin()); + } +} diff --git a/src/main/java/net/jeqo/bloons/listeners/MenuClickListener.java b/src/main/java/net/jeqo/bloons/listeners/MenuClickListener.java new file mode 100644 index 00000000..2246da63 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/listeners/MenuClickListener.java @@ -0,0 +1,126 @@ +package net.jeqo.bloons.listeners; + +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.SingleBalloon; +import net.jeqo.bloons.gui.menus.BalloonMenu; +import net.jeqo.bloons.utils.BalloonManagement; +import net.jeqo.bloons.utils.ColorCodeConverter; +import net.jeqo.bloons.utils.ColorManagement; +import net.jeqo.bloons.utils.MessageTranslations; +import net.kyori.adventure.text.Component; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; + +public class MenuClickListener implements Listener { + + /** + * When a player interacts with the GUI menu, do the action required accordingly + */ + @EventHandler + public void onClick(InventoryClickEvent event){ + MessageTranslations messageTranslations = new MessageTranslations(Bloons.getInstance()); + + if (!event.getView().getTitle().equals(ColorManagement.fromHex(messageTranslations.getString("menu-title")))) return; + if(!(event.getWhoClicked() instanceof Player player)) return; + if(!BalloonMenu.users.containsKey(player.getUniqueId())) return; + + // The users inside the GUI + BalloonMenu inventory = BalloonMenu.users.get(player.getUniqueId()); + + // If the current item is null and has no meta, return + if(event.getCurrentItem() == null) return; + if(event.getCurrentItem().getItemMeta() == null) return; + + int pageSize = messageTranslations.getInt("balloon-slots"); + + // Get the display name of the item clicked and the converted balloon name + String displayName = event.getCurrentItem().getItemMeta().getDisplayName(); + String localizedName = event.getCurrentItem().getItemMeta().getLocalizedName(); + String convertedColourBalloonName = ColorCodeConverter.colorCodeToAdventure(displayName); // Weird parsing is needed for this because of the usage of minimessage + + // Always check for shift clicks + if (event.isShiftClick()) event.setCancelled(true); + + if (event.getRawSlot() <= pageSize) { + // Do checks on if they're using the other buttons + if (displayName.equals(ColorCodeConverter.adventureToColorCode(messageTranslations.getString("buttons.previous-page.name")))) event.setCancelled(true); + if (displayName.equals(ColorCodeConverter.adventureToColorCode(messageTranslations.getString("buttons.next-page.name")))) event.setCancelled(true); + if (displayName.equals(ColorCodeConverter.adventureToColorCode(messageTranslations.getString("buttons.unequip.name")))) event.setCancelled(true); + + // Check if a balloon needs to be added or removed + BalloonManagement.removeBalloon(player, Bloons.playerBalloons.get(player.getUniqueId())); + SingleBalloon.checkBalloonRemovalOrAdd(player, localizedName); + + // Send equipped message and play sound + player.playSound(player.getLocation(), Sound.ENTITY_CHICKEN_EGG, 1, 1); + Component equippedMessage = messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("equipped", convertedColourBalloonName)); + player.sendMessage(equippedMessage); + + // Close inventory if the config is set to true + if (messageTranslations.getString("close-on-equip").equals("true")) player.closeInventory(); + } else { + event.setCancelled(true); + } + + /* Next page functionality **/ + if(displayName.equals(ColorCodeConverter.adventureToColorCode(messageTranslations.getString("buttons.next-page.name")))) { + event.setCancelled(true); + + if (inventory.currpage >= inventory.pages.size()-1) { + // If they're at the last page, play error sound + ((Player) event.getWhoClicked()).playSound(event.getWhoClicked().getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); + } else { + // If they're within page bounds that can change, go to the next page + player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BIT, 1, 1); + inventory.currpage += 1; + player.openInventory(inventory.pages.get(inventory.currpage)); + } + } + + /* Previous page functionality **/ + else if(displayName.equals(ColorCodeConverter.adventureToColorCode(messageTranslations.getString("buttons.previous-page.name")))) { + event.setCancelled(true); + + if (inventory.currpage > 0) { + // If they're within page bounds that can change, go to the previous page + player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BIT, 1, 1); + inventory.currpage -= 1; + player.openInventory(inventory.pages.get(inventory.currpage)); + } else { + // If there's no pages to go to, play error sound + ((Player) event.getWhoClicked()).playSound(event.getWhoClicked().getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); + } + + } + + /* Unequip button functionality **/ + else if(displayName.equals(ColorCodeConverter.adventureToColorCode(messageTranslations.getString("buttons.unequip.name")))) { + event.setCancelled(true); + + if (!event.isShiftClick()) { + SingleBalloon balloon = Bloons.playerBalloons.get(player.getUniqueId()); + + if (balloon == null) { + // If no balloon equipped, play sound and send message notifying them + player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); + player.sendMessage(messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("not-equipped"))); + } else { + if (messageTranslations.getString("close-on-unequip").equals("true")) player.closeInventory(); + + // Play sound and send message saying the balloon is unequipped + player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_HURT_SWEET_BERRY_BUSH, 1, 1); + player.sendMessage(messageTranslations.getSerializedString(messageTranslations.getMessage("prefix"), messageTranslations.getMessage("unequipped"))); + } + + // Remove the balloon + BalloonManagement.removeBalloon(player, balloon); + } + + } else { + event.setCancelled(true); + } + } +} \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/listeners/MenuHandlers.java b/src/main/java/net/jeqo/bloons/listeners/MenuHandlers.java deleted file mode 100644 index 0cf97503..00000000 --- a/src/main/java/net/jeqo/bloons/listeners/MenuHandlers.java +++ /dev/null @@ -1,102 +0,0 @@ -package net.jeqo.bloons.listeners; - -import net.jeqo.bloons.Bloons; -import net.jeqo.bloons.data.BalloonMenu; -import net.jeqo.bloons.data.BalloonOwner; -import net.jeqo.bloons.utils.Utils; -import org.bukkit.Sound; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryClickEvent; - -public class MenuHandlers implements Listener { - - @EventHandler - /** - * When a player interacts with the GUI menu, do the action required accordingly - */ - public void onClick(InventoryClickEvent e){ - if (!e.getView().getTitle().equals(Utils.hex(Bloons.getString("menu-title")))) return; - if(!(e.getWhoClicked() instanceof Player)) return; - Player p = (Player) e.getWhoClicked(); - if(!BalloonMenu.users.containsKey(p.getUniqueId())) return; - BalloonMenu inv = BalloonMenu.users.get(p.getUniqueId()); - if(e.getCurrentItem() == null) return; - if(e.getCurrentItem().getItemMeta() == null) return; - - int pageSize = Bloons.getInt("balloon-slots"); - - if (e.getRawSlot() <= pageSize) { - if (e.getCurrentItem().getItemMeta().getDisplayName().equals(Utils.hex(Bloons.getString("buttons.previous-page.name"))) || e.getCurrentItem().getItemMeta().getDisplayName().equals(Utils.hex(Bloons.getString("buttons.next-page.name"))) || e.getCurrentItem().getItemMeta().getDisplayName().equals(Utils.hex(Bloons.getString("buttons.unequip.name"))) ) { - e.setCancelled(true); - } else { - if (e.isShiftClick()) { - e.setCancelled(true); - } else { - Utils.removeBalloon(p, Bloons.playerBalloons.get(p.getUniqueId())); - Player player = (Player) e.getWhoClicked(); - String balloon = e.getCurrentItem().getItemMeta().getLocalizedName(); - BalloonOwner.checkBalloonRemovalOrAdd(player, balloon); - player.playSound(player.getLocation(), Sound.ENTITY_CHICKEN_EGG, 1, 1); - String balloonName = e.getCurrentItem().getItemMeta().getDisplayName(); - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("equipped", balloonName)); - if (Bloons.getString("close-on-equip").equals("true")) { - player.closeInventory(); - } - } - } - } else { - if (e.isShiftClick()) { - e.setCancelled(true); - } - e.setCancelled(true); - } - - if(e.getCurrentItem().getItemMeta().getDisplayName().equals(Utils.hex(Bloons.getString("buttons.next-page.name")))) { - e.setCancelled(true); - if (inv.currpage >= inv.pages.size()-1) { - ((Player) e.getWhoClicked()).playSound(e.getWhoClicked().getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); - } else { - p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BIT, 1, 1); - inv.currpage += 1; - p.openInventory(inv.pages.get(inv.currpage)); - } - - - } else if(e.getCurrentItem().getItemMeta().getDisplayName().equals(Utils.hex(Bloons.getString("buttons.previous-page.name")))) { - e.setCancelled(true); - if (inv.currpage > 0) { - p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_BIT, 1, 1); - inv.currpage -= 1; - p.openInventory(inv.pages.get(inv.currpage)); - } else { - ((Player) e.getWhoClicked()).playSound(e.getWhoClicked().getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); - } - - } else if(e.getCurrentItem().getItemMeta().getDisplayName().equals(Utils.hex(Bloons.getString("buttons.unequip.name")))) { - e.setCancelled(true); - Player player = (Player) e.getWhoClicked(); - - - if (e.isShiftClick()) { - e.setCancelled(true); - } else { - BalloonOwner balloonOwner1 = Bloons.playerBalloons.get(player.getUniqueId()); - if (balloonOwner1 == null) { - player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_DIDGERIDOO, 1, 1); - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("not-equipped")); - } else { - if (Bloons.getString("close-on-unequip").equals("true")) { - player.closeInventory(); - } - player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_HURT_SWEET_BERRY_BUSH, 1, 1); - player.sendMessage(Bloons.getMessage("prefix") + Bloons.getMessage("unequipped")); - } - Utils.removeBalloon(player, balloonOwner1); - } - } else { - e.setCancelled(true); - } - } -} \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/listeners/PlayerHandlers.java b/src/main/java/net/jeqo/bloons/listeners/PlayerHandlers.java deleted file mode 100644 index 6307eb7d..00000000 --- a/src/main/java/net/jeqo/bloons/listeners/PlayerHandlers.java +++ /dev/null @@ -1,87 +0,0 @@ -package net.jeqo.bloons.listeners; - -import net.jeqo.bloons.Bloons; -import net.jeqo.bloons.data.BalloonOwner; -import net.jeqo.bloons.data.UpdateChecker; -import net.jeqo.bloons.utils.Utils; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerRespawnEvent; - -import java.util.Objects; - -public class PlayerHandlers implements Listener { - - @EventHandler - /** - * When a player quits, make sure to despawn and store their balloon in storage - */ - public void onQuit(PlayerQuitEvent e) { - BalloonOwner owner = Bloons.playerBalloons.get(e.getPlayer().getUniqueId()); - Utils.storeBalloon(e.getPlayer(), owner); - } - - @EventHandler - /** - * When a player joins, add the balloon back if they left with one, or just don't add anything - */ - public void onJoin(PlayerJoinEvent e) { - String id = Bloons.playerBalloonID.get(e.getPlayer().getUniqueId()); - if (id != null) { - Utils.removeBalloon(e.getPlayer(), (BalloonOwner) Bloons.playerBalloons.get(e.getPlayer().getUniqueId())); - BalloonOwner.checkBalloonRemovalOrAdd(e.getPlayer(), id); - } - - if (e.getPlayer().isOp()) { - Player p = e.getPlayer(); - new UpdateChecker(Bloons.getInstance(), 106243).getVersion(version -> { - if (!Bloons.getInstance().getDescription().getVersion().equals(version)) { - p.sendMessage(""); - p.sendMessage(Utils.hex(Bloons.getMessage("prefix") + "&eNew update! " + version + " is now available.")); - p.sendMessage(Utils.hex(Bloons.getMessage("prefix") + "&eDownload it here: &nhttps://jeqo.net/spigot/bloons")); - p.sendMessage(""); - } - }); - } - } - - @EventHandler - /** - * When they die, remove their balloon - */ - public void onDeath(PlayerDeathEvent e) { - BalloonOwner owner = Bloons.playerBalloons.get(Objects.requireNonNull(e.getEntity().getPlayer()).getUniqueId()); - Utils.removeBalloon(e.getEntity().getPlayer(), owner); - } - - @EventHandler - /** - * When they respawn, add the balloon they back that they died with - */ - public void onRespawn(PlayerRespawnEvent e) { - String id = Bloons.playerBalloonID.get(e.getPlayer().getUniqueId()); - if (id != null) { - BalloonOwner.checkBalloonRemovalOrAdd(e.getPlayer(), id); - } - } - - @EventHandler - /** - * When they change worlds, store their balloon and move the balloon armor stand over - */ - public void onWorldChange(PlayerChangedWorldEvent e) { - BalloonOwner owner = Bloons.playerBalloons.get(e.getPlayer().getUniqueId()); - Utils.storeBalloon(e.getPlayer(), owner); - - String id = Bloons.playerBalloonID.get(e.getPlayer().getUniqueId()); - if (id != null) { - Utils.removeBalloon(e.getPlayer(), Bloons.playerBalloons.get(e.getPlayer().getUniqueId())); - BalloonOwner.checkBalloonRemovalOrAdd(e.getPlayer(), id); - } - } -} \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/listeners/PlayerListener.java b/src/main/java/net/jeqo/bloons/listeners/PlayerListener.java new file mode 100644 index 00000000..d2fab73c --- /dev/null +++ b/src/main/java/net/jeqo/bloons/listeners/PlayerListener.java @@ -0,0 +1,89 @@ +package net.jeqo.bloons.listeners; + +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.SingleBalloon; +import net.jeqo.bloons.utils.UpdateChecker; +import net.jeqo.bloons.logger.Logger; +import net.jeqo.bloons.utils.BalloonManagement; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; + +import java.util.Objects; + +public class PlayerListener implements Listener { + + /** + * When a player quits, make sure to despawn and store their balloon in storage + */ + @EventHandler + public void onQuit(PlayerQuitEvent e) { + SingleBalloon owner = Bloons.playerBalloons.get(e.getPlayer().getUniqueId()); + BalloonManagement.storeBalloon(owner); + } + + /** + * When a player joins, add the balloon back if they left with one, or just don't add anything + */ + @EventHandler + public void onJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + String balloonID = Bloons.playerBalloonID.get(event.getPlayer().getUniqueId()); + + // If they have a balloon active, remove it and add it back to reduce issues + if (balloonID != null) { + BalloonManagement.removeBalloon(event.getPlayer(), Bloons.playerBalloons.get(event.getPlayer().getUniqueId())); + SingleBalloon.checkBalloonRemovalOrAdd(event.getPlayer(), balloonID); + } + + if (event.getPlayer().isOp()) { + // Check for an update if the player is an operator on the server + new UpdateChecker(Bloons.getInstance(), 106243).getVersion(version -> { + if (!Bloons.getInstance().getDescription().getVersion().equals(version)) { + Logger.logUpdateNotificationPlayer(player); + } + }); + } + } + + /** + * When they die, remove their balloon + */ + @EventHandler + public void onDeath(PlayerDeathEvent event) { + SingleBalloon balloonOwner = Bloons.playerBalloons.get(Objects.requireNonNull(event.getEntity().getPlayer()).getUniqueId()); + BalloonManagement.removeBalloon(event.getEntity().getPlayer(), balloonOwner); + } + + /** + * When they respawn, add the balloon they back that they died with + */ + @EventHandler + public void onRespawn(PlayerRespawnEvent event) { + String balloonID = Bloons.playerBalloonID.get(event.getPlayer().getUniqueId()); + + if (balloonID != null) { + SingleBalloon.checkBalloonRemovalOrAdd(event.getPlayer(), balloonID); + } + } + + /** + * When they change worlds, store their balloon and move the balloon armor stand over + */ + @EventHandler + public void onWorldChange(PlayerChangedWorldEvent event) { + SingleBalloon balloonOwner = Bloons.playerBalloons.get(event.getPlayer().getUniqueId()); + String balloonID = Bloons.playerBalloonID.get(event.getPlayer().getUniqueId()); + BalloonManagement.storeBalloon(balloonOwner); + + if (balloonID != null) { + BalloonManagement.removeBalloon(event.getPlayer(), Bloons.playerBalloons.get(event.getPlayer().getUniqueId())); + SingleBalloon.checkBalloonRemovalOrAdd(event.getPlayer(), balloonID); + } + } +} \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/logger/Logger.java b/src/main/java/net/jeqo/bloons/logger/Logger.java index f17eb9f1..2b656b0a 100644 --- a/src/main/java/net/jeqo/bloons/logger/Logger.java +++ b/src/main/java/net/jeqo/bloons/logger/Logger.java @@ -1,12 +1,11 @@ package net.jeqo.bloons.logger; +import net.jeqo.bloons.Bloons; import net.jeqo.bloons.configuration.PluginConfiguration; +import net.jeqo.bloons.utils.MessageTranslations; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; - -import java.io.IOException; /** * A utility class intended to log messages easily to the Bukkit console @@ -31,13 +30,19 @@ public static void logToPlayer(LoggingLevel level, Player player, String message player.sendMessage(component); } + public static void logToPlayer(Player player, String message) { + MessageTranslations messageTranslations = new MessageTranslations(Bloons.getInstance()); + Component component = Component.text(messageTranslations.getMessage("prefix") + " " + message); + player.sendMessage(component); + } + /** * Log a message to the console * @param level The logging level * @param message The message to log */ public static void log(LoggingLevel level, String message) { - Component component = Component.text(level.getColor() + "[" + level.getName() + "] " + message); + Component component = Component.text("[" + level.getName() + "] " + message).color(level.getColor()); Bukkit.getServer().getConsoleSender().sendMessage(component); } @@ -76,23 +81,40 @@ public static void logDebug(String message) { /** * Logs an initialization message to the Bukkit console */ - public static void logInitialization() throws XmlPullParserException, IOException { - log(LoggingLevel.INFO, "Initializing" + PluginConfiguration.getName() + " plugin..."); + public static void logInitialization() { + log(LoggingLevel.INFO, "Initializing " + PluginConfiguration.getName() + " plugin..."); } /** * Logs a startup message to the Bukkit console containing plugin information */ - public static void logStartup() throws XmlPullParserException, IOException { - log(LoggingLevel.INFO, PluginConfiguration.getName() + "plugin has initialized"); + public static void logStartup() { + log(LoggingLevel.INFO, PluginConfiguration.getName() + " plugin has initialized"); log(LoggingLevel.INFO, "Version: " + PluginConfiguration.getVersion()); log(LoggingLevel.INFO, "Developers: " + PluginConfiguration.DEVELOPER_CREDITS); } + /** + * Logs an update notification to the Bukkit console + */ + public static void logUpdateNotificationConsole() { + logInfo("A new update is available for " + PluginConfiguration.getName() + " plugin"); + logInfo("You can find the update at: https://jeqo.net/spigot/bloons"); + } + + /** + * Logs an update notification to a player + */ + public static void logUpdateNotificationPlayer(Player player) { + logToPlayer(player, "A new update is available for " + PluginConfiguration.getName() + " plugin"); + logToPlayer(player, "You can find the update at: https://jeqo.net/spigot/bloons"); + } + + /** * Logs a shutdown message to the Bukkit console */ - public static void logShutdown() throws XmlPullParserException, IOException { - log(LoggingLevel.INFO, PluginConfiguration.getName() + "plugin has been shutdown gracefully"); + public static void logShutdown() { + log(LoggingLevel.INFO, PluginConfiguration.getName() + " plugin has been shutdown gracefully"); } } diff --git a/src/main/java/net/jeqo/bloons/utils/BalloonManagement.java b/src/main/java/net/jeqo/bloons/utils/BalloonManagement.java new file mode 100644 index 00000000..dee534de --- /dev/null +++ b/src/main/java/net/jeqo/bloons/utils/BalloonManagement.java @@ -0,0 +1,45 @@ +package net.jeqo.bloons.utils; + +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.SingleBalloon; +import org.bukkit.entity.Player; + +public class BalloonManagement { + + /** + * Remove the balloon from the player + * @param player The player to remove the balloon from + * @param owner The balloon + */ + public static void removeBalloon(Player player, SingleBalloon owner) { + if (owner != null) { + owner.spawnRemoveParticle(); + owner.cancel(); + Bloons.playerBalloons.remove(player.getUniqueId()); + Bloons.playerBalloonID.remove(player.getUniqueId()); + } + } + + /** + * Remove the balloon from the player quickly + * @param player The player to remove the balloon from + * @param owner The balloon + */ + public static void quickRemoveBalloon(Player player, SingleBalloon owner) { + if (owner != null) { + owner.cancel(); + Bloons.playerBalloons.remove(player.getUniqueId()); + Bloons.playerBalloonID.remove(player.getUniqueId()); + } + } + + /** + * Store the balloon in storage and just cancel the runnable + * @param owner The balloon + */ + public static void storeBalloon(SingleBalloon owner) { + if (owner != null) { + owner.cancel(); + } + } +} diff --git a/src/main/java/net/jeqo/bloons/utils/ColorCodeConverter.java b/src/main/java/net/jeqo/bloons/utils/ColorCodeConverter.java new file mode 100644 index 00000000..e3a22502 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/utils/ColorCodeConverter.java @@ -0,0 +1,56 @@ +package net.jeqo.bloons.utils; + +import java.util.HashMap; +import java.util.Map; + +/** + * A class used to convert color codes between Adventure and Minecraft + */ +public class ColorCodeConverter { + + private static final Map colorCodes = new HashMap<>(); + + static { + colorCodes.put("", "§0"); + colorCodes.put("", "§1"); + colorCodes.put("", "§2"); + colorCodes.put("", "§3"); + colorCodes.put("", "§4"); + colorCodes.put("", "§5"); + colorCodes.put("", "§6"); + colorCodes.put("", "§7"); + colorCodes.put("", "§8"); + colorCodes.put("", "§9"); + colorCodes.put("", "§a"); + colorCodes.put("", "§b"); + colorCodes.put("", "§c"); + colorCodes.put("", "§d"); + colorCodes.put("", "§e"); + colorCodes.put("", "§f"); + } + + /** + * Converts all basic adventure color codes to Minecraft color codes + * @param message The message to convert + * @return The converted message + */ + public static String adventureToColorCode(String message) { + for (Map.Entry entry : colorCodes.entrySet()) { + message = message.replace(entry.getKey(), entry.getValue()); + } + return message; + } + + /** + * Converts all Minecraft color codes to Adventure color codes + * @param message The message to convert + * @return The converted message + */ + public static String colorCodeToAdventure(String message) { + for (Map.Entry entry : colorCodes.entrySet()) { + message = message.replace(entry.getValue(), entry.getKey()); + } + return message; + } +} + diff --git a/src/main/java/net/jeqo/bloons/utils/ColorManagement.java b/src/main/java/net/jeqo/bloons/utils/ColorManagement.java new file mode 100644 index 00000000..91c0d189 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/utils/ColorManagement.java @@ -0,0 +1,45 @@ +package net.jeqo.bloons.utils; + +import org.bukkit.ChatColor; +import org.bukkit.Color; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A class to convert messages with hex codes, and hex strings to Bukkit colors + */ +public class ColorManagement { + + /** + * Converts a message with hex codes to a Bukkit color + * @param message The message to convert + * @return The Bukkit color + */ + public static String fromHex(String message) { + Pattern pattern = Pattern.compile("#[a-fA-F0-9]{6}"); + Matcher matcher = pattern.matcher(message); + + while (matcher.find()) { + String hexCode = message.substring(matcher.start(), matcher.end()); + String replaceSharp = hexCode.replace('#', 'x'); + char[] ch = replaceSharp.toCharArray(); + StringBuilder builder = new StringBuilder(); + for (char c : ch) { + builder.append("&").append(c); + } + message = message.replace(hexCode, builder.toString()); + matcher = pattern.matcher(message); + } + return ChatColor.translateAlternateColorCodes('&', message); + } + + /** + * Converts a hex string to a Bukkit color + * @param string The hex string to convert + * @return The Bukkit color + */ + public static Color hexToColor(String string) { + return Color.fromRGB(Integer.parseInt(string.substring(1), 16)); + } +} diff --git a/src/main/java/net/jeqo/bloons/utils/MessageTranslations.java b/src/main/java/net/jeqo/bloons/utils/MessageTranslations.java new file mode 100644 index 00000000..cd08e819 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/utils/MessageTranslations.java @@ -0,0 +1,34 @@ +package net.jeqo.bloons.utils; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.plugin.java.JavaPlugin; + +public record MessageTranslations(JavaPlugin instance) { + + public String getMessage(String id, String arg) { + return String.format(this.instance.getConfig().getString("messages." + id, ""), arg); + } + + public String getMessage(String id) { + return this.instance.getConfig().getString("messages." + id, ""); + } + + public Component getSerializedString(String messagePrefix, String messageSuffix) { + MiniMessage mm = MiniMessage.miniMessage(); + return mm.deserialize(messagePrefix + messageSuffix); + } + + public Component getSerializedString(String message) { + MiniMessage mm = MiniMessage.miniMessage(); + return mm.deserialize(message); + } + + public String getString(String path) { + return this.instance.getConfig().getString(path); + } + + public Integer getInt(String path) { + return this.instance.getConfig().getInt(path); + } +} diff --git a/src/main/java/net/jeqo/bloons/utils/NBTItem.java b/src/main/java/net/jeqo/bloons/utils/NBTItem.java new file mode 100644 index 00000000..0738731a --- /dev/null +++ b/src/main/java/net/jeqo/bloons/utils/NBTItem.java @@ -0,0 +1,152 @@ +package net.jeqo.bloons.utils; + +import lombok.Getter; +import lombok.Setter; +import net.jeqo.bloons.Bloons; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; + +/** + * An extension of an Item with the utilities to manage NBT + * data easier and more efficiently + */ +@Getter +@Setter +public class NBTItem extends ItemStack { + private ItemStack item; + + /** + * Creates a new NBTItem with NBT data from an existing ItemStack + * @param item The item to create the NBTItem from + */ + public NBTItem(ItemStack item) { + this.item = item; + } + + /** + * Checks if the item has a key in its NBT data + * @param key The key to check for + * @return Whether the key exists in the NBT data + */ + public boolean hasKey(String key) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + + return container.getKeys().contains(nbtKey); + } + + /** + * Sets a string flag in the NBT data of the item + * @param key The key to set + * @param value The value to set the key to + */ + public void setStringFlag(String key, String value) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + + ItemMeta meta = item.getItemMeta(); + meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.STRING, value); + + this.item.setItemMeta(meta); + } + + /** + * Gets a string flag from the NBT data of the item + * @param key The key to get + * @return The value of the key + */ + public String getStringFlag(String key) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + + if (!container.has(nbtKey, PersistentDataType.STRING)) return null; + + return container.get(nbtKey, PersistentDataType.STRING); + } + + /** + * Sets an integer flag in the NBT data of the item + * @param key The key to set + * @param value The value to set the key to + */ + public void setIntegerFlag(String key, int value) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + + ItemMeta meta = item.getItemMeta(); + meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.INTEGER, value); + + this.item.setItemMeta(meta); + } + + /** + * Gets an integer flag from the NBT data of the item + * @param key The key to get + * @return The value of the key + */ + public int getIntegerFlag(String key) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + + if (!container.has(nbtKey, PersistentDataType.INTEGER)) return 0; + + return container.get(nbtKey, PersistentDataType.INTEGER); + } + + /** + * Sets a double flag in the NBT data of the item + * @param key The key to set + * @param value The value to set the key to + */ + public void setDoubleFlag(String key, double value) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + + ItemMeta meta = item.getItemMeta(); + meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.DOUBLE, value); + + this.item.setItemMeta(meta); + } + + /** + * Gets a double flag from the NBT data of the item + * @param key The key to get + * @return The value of the key + */ + public double getDoubleFlag(String key) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + + if (!container.has(nbtKey, PersistentDataType.DOUBLE)) return 0.0; + + return container.get(nbtKey, PersistentDataType.DOUBLE); + } + + /** + * Sets a boolean flag in the NBT data of the item + * @param key The key to set + * @param value The value to set the key to + */ + public void setBooleanFlag(String key, boolean value) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + + ItemMeta meta = item.getItemMeta(); + meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.BOOLEAN, value); + + this.item.setItemMeta(meta); + } + + /** + * Gets a boolean flag from the NBT data of the item + * @param key The key to get + * @return The value of the key + */ + public boolean getBooleanFlag(String key) { + NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer(); + + if (!container.has(nbtKey, PersistentDataType.BOOLEAN)) return false; + + return Boolean.TRUE.equals(container.get(nbtKey, PersistentDataType.BOOLEAN)); + } +} diff --git a/src/main/java/net/jeqo/bloons/data/UpdateChecker.java b/src/main/java/net/jeqo/bloons/utils/UpdateChecker.java similarity index 80% rename from src/main/java/net/jeqo/bloons/data/UpdateChecker.java rename to src/main/java/net/jeqo/bloons/utils/UpdateChecker.java index cf26e988..a5d93558 100644 --- a/src/main/java/net/jeqo/bloons/data/UpdateChecker.java +++ b/src/main/java/net/jeqo/bloons/utils/UpdateChecker.java @@ -1,4 +1,4 @@ -package net.jeqo.bloons.data; +package net.jeqo.bloons.utils; import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; @@ -8,6 +8,9 @@ import java.util.Scanner; import java.util.function.Consumer; +/** + * A utility class intended to check for updates on the SpigotMC website + */ public class UpdateChecker { private final JavaPlugin plugin; private final int resourceId; @@ -17,6 +20,10 @@ public UpdateChecker(JavaPlugin plugin, int resourceId) { this.resourceId = resourceId; } + /** + * Gets the latest version of the plugin available on SpigotMC + * @param consumer The consumer to accept the version + */ public void getVersion(final Consumer consumer) { Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + this.resourceId).openStream(); Scanner scanner = new Scanner(inputStream)) { diff --git a/src/main/java/net/jeqo/bloons/utils/Utils.java b/src/main/java/net/jeqo/bloons/utils/Utils.java deleted file mode 100644 index f9844d3f..00000000 --- a/src/main/java/net/jeqo/bloons/utils/Utils.java +++ /dev/null @@ -1,52 +0,0 @@ -package net.jeqo.bloons.utils; - -import net.jeqo.bloons.Bloons; -import net.jeqo.bloons.data.BalloonOwner; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Color; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import java.util.logging.Level; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class Utils { - - public static void removeBalloon(Player player, BalloonOwner owner) { - if (owner != null) { - owner.spawnRemoveParticle(); - owner.cancel(); - Bloons.playerBalloons.remove(player.getUniqueId()); - Bloons.playerBalloonID.remove(player.getUniqueId()); - } - } - - public static void quickRemoveBalloon(Player player, BalloonOwner owner) { - if (owner != null) { - owner.cancel(); - Bloons.playerBalloons.remove(player.getUniqueId()); - Bloons.playerBalloonID.remove(player.getUniqueId()); - } - } - - public static void storeBalloon(Player player, BalloonOwner owner) { - if (owner != null) { - owner.cancel(); - } - } - - public static String hex(String message) { Pattern pattern = Pattern.compile("#[a-fA-F0-9]{6}"); Matcher matcher = pattern.matcher(message); while (matcher.find()) { String hexCode = message.substring(matcher.start(), matcher.end()); String replaceSharp = hexCode.replace('#', 'x'); char[] ch = replaceSharp.toCharArray(); StringBuilder builder = new StringBuilder(""); for (char c : ch) { builder.append("&" + c);} message = message.replace(hexCode, builder.toString()); matcher = pattern.matcher(message);} return ChatColor.translateAlternateColorCodes('&', message); } - - public static void log(@NotNull String text) { - Bukkit.getLogger().log(Level.INFO, "[Bloons] " + text); - } - - public static void warn(@NotNull String text) { - Bukkit.getLogger().log(Level.WARNING, "[Bloons] " + text); - } - - public static Color hexToColor(String string) { - return Color.fromRGB(Integer.parseInt(string.substring(1), 16)); - } -} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index dd1739b0..fcc7874d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,6 +1,6 @@ # --------------------------------------------------# # -# Bloons 1.0.5-BETA +# Bloons 1.1.0-BETA # Made by Jeqo # # Wiki: https://jeqo.net/wiki/bloons @@ -23,7 +23,7 @@ close-on-unequip: true # Do you want to hide balloons that the player does not have permission for? hide-balloons-without-permission: true # Title for the balloons menu. -menu-title: "&f" +menu-title: "" # Amount of slots per page. Valid values: 27, 36, 45, and 54. 9 of these slots will be used for the menu buttons. menu-size: 54 # Amount of slots from the top that you want the balloons to appear in. Valid values: 9, 18, 27, 36, and 45. @@ -35,19 +35,19 @@ buttons: previous-page: material: FLINT custom-model-data: 2 - name: '&7← ᴘʀᴇᴠɪᴏᴜs ᴘᴀɢᴇ' + name: '← ᴘʀᴇᴠɪᴏᴜs ᴘᴀɢᴇ' slots: - 48 unequip: material: FLINT custom-model-data: 3 - name: '&7ᴜɴᴇǫᴜɪᴘ ʙᴀʟʟᴏᴏɴ' + name: 'ᴜɴᴇǫᴜɪᴘ ʙᴀʟʟᴏᴏɴ' slots: - 49 next-page: material: FLINT custom-model-data: 4 - name: '&7ɴᴇxᴛ ᴘᴀɢᴇ →' + name: 'ɴᴇxᴛ ᴘᴀɢᴇ →' slots: - 50 # @@ -56,15 +56,15 @@ buttons: # --------------------------------------------------# # messages: - prefix: '#ff00cc[#e70cd3B#ce18dbl#b624e2o#9e31e9o#863df0n#6d49f8s#5555ff] &r' - no-permission: '#fc1c1cAccess denied.' - player-not-found: '#fc1c1cPlayer not found.' - config-reloaded: '&aConfig reloaded!' + prefix: '[Bloons] ' + no-permission: '<#fc1c1c>Access denied.' + player-not-found: '<#fc1c1c>Player not found.' + config-reloaded: 'Config reloaded.' # Balloon related messages. - equipped: '%s &aequipped!' - unequipped: '&aYour balloon has been stored safely.' - balloon-not-found: '#fc1c1cBalloon not found.' - not-equipped: '#fc1c1cYou do not currently have a balloon equipped.' + equipped: '%s equipped!' + unequipped: 'Your balloon has been stored safely.' + balloon-not-found: '<#fc1c1c>Balloon not found.' + not-equipped: '<#fc1c1c>You do not currently have a balloon equipped.' # # --------------------------------------------------# # BALLOONS # @@ -78,7 +78,7 @@ balloons: permission: balloon.blue material: FLINT custom-model-data: 5 - name: '&bBlue &fBalloon' + name: 'Blue Balloon' lore: - '&8Bloons Default Balloon' - '' @@ -88,7 +88,7 @@ balloons: permission: balloon.green material: FLINT custom-model-data: 6 - name: '&aGreen &fBalloon' + name: 'Green Balloon' lore: - '&8Bloons Default Balloon' - '' @@ -98,7 +98,7 @@ balloons: permission: balloon.pink material: FLINT custom-model-data: 7 - name: '&dPink &fBalloon' + name: 'Pink Balloon' lore: - '&8Bloons Default Balloon' - '' @@ -108,7 +108,7 @@ balloons: permission: balloon.yellow material: FLINT custom-model-data: 8 - name: '&eYellow &fBalloon' + name: 'Yellow Balloon' lore: - '&8Bloons Default Balloon' - '' @@ -119,7 +119,7 @@ balloons: material: LEATHER_HORSE_ARMOR color: '#ffffff' custom-model-data: 1 - name: '#ffffffDyeable Balloon' + name: 'Dyeable Balloon' lore: - '&8Bloons Example Balloon' - ''