From d48887eb42092dfb716e4eb349aeacc48a8d1b05 Mon Sep 17 00:00:00 2001 From: Ian Tapply Date: Fri, 31 Jan 2025 14:29:06 -0500 Subject: [PATCH] feat: Version 2.1.1 - Organization Cleanup (#49) --- pom.xml | 2 +- src/main/java/net/jeqo/bloons/Bloons.java | 44 +++-------------- .../multipart/MultipartBalloonModel.java | 2 +- .../bloons/balloon/single/SingleBalloon.java | 34 +++++++++++-- .../jeqo/bloons/commands/CommandEquip.java | 13 +++-- .../bloons/commands/CommandForceEquip.java | 2 - .../bloons/commands/CommandForceUnequip.java | 2 - .../jeqo/bloons/commands/CommandReload.java | 3 -- .../jeqo/bloons/commands/CommandUnequip.java | 1 - .../bloons/commands/manager/CommandCore.java | 2 +- .../bloons/commands/utils/ErrorHandling.java | 4 -- .../configuration/ConfigConfiguration.java | 1 - .../configuration/PluginConfiguration.java | 3 ++ .../java/net/jeqo/bloons/item/NBTItem.java | 18 +++++-- ...java => BalloonChickenEntityListener.java} | 2 +- ....java => BalloonChickenLeashListener.java} | 3 +- .../PlayerUpdateNotificationListener.java | 30 ++++++++++++ .../SingleBalloonPlayerJoinListener.java | 27 +++++++++++ .../SingleBalloonPlayerLeaveListener.java | 22 +++++++++ .../single/SingleBalloonPlayerListener.java | 48 ------------------- .../java/net/jeqo/bloons/logger/Logger.java | 2 - .../management/SingleBalloonManagement.java | 13 ----- .../net/jeqo/bloons/utils/VersionChecker.java | 34 +++++++++++++ 23 files changed, 181 insertions(+), 131 deletions(-) rename src/main/java/net/jeqo/bloons/listeners/{BalloonEntityListener.java => BalloonChickenEntityListener.java} (92%) rename src/main/java/net/jeqo/bloons/listeners/{BalloonUnleashListener.java => BalloonChickenLeashListener.java} (92%) create mode 100644 src/main/java/net/jeqo/bloons/listeners/PlayerUpdateNotificationListener.java create mode 100644 src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerJoinListener.java create mode 100644 src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerLeaveListener.java create mode 100644 src/main/java/net/jeqo/bloons/utils/VersionChecker.java diff --git a/pom.xml b/pom.xml index 3f6b262a..71221d29 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.jeqo bloons - 2.1.0 + 2.1.1 jar Bloons diff --git a/src/main/java/net/jeqo/bloons/Bloons.java b/src/main/java/net/jeqo/bloons/Bloons.java index 60766065..17a47276 100644 --- a/src/main/java/net/jeqo/bloons/Bloons.java +++ b/src/main/java/net/jeqo/bloons/Bloons.java @@ -6,6 +6,7 @@ import net.jeqo.bloons.balloon.multipart.balloon.MultipartBalloon; import net.jeqo.bloons.balloon.single.SingleBalloon; import net.jeqo.bloons.commands.manager.CommandCore; +import net.jeqo.bloons.configuration.PluginConfiguration; import net.jeqo.bloons.listeners.*; import net.jeqo.bloons.listeners.multipart.MultipartBalloonPlayerJoinListener; import net.jeqo.bloons.listeners.multipart.MultipartBalloonPlayerLeaveListener; @@ -14,6 +15,7 @@ import net.jeqo.bloons.health.UpdateChecker; import net.jeqo.bloons.logger.Logger; import net.jeqo.bloons.health.Metrics; +import net.jeqo.bloons.utils.VersionChecker; import org.bukkit.plugin.java.JavaPlugin; import java.util.HashMap; @@ -77,9 +79,9 @@ public void onEnable() { // Stage listeners getListenerCore().stageListener(new SingleBalloonPlayerListener()); - getListenerCore().stageListener(new BalloonUnleashListener()); + getListenerCore().stageListener(new BalloonChickenLeashListener()); getListenerCore().stageListener(new BalloonMenuListener()); - getListenerCore().stageListener(new BalloonEntityListener()); + getListenerCore().stageListener(new BalloonChickenEntityListener()); getListenerCore().stageListener(new MultipartBalloonPlayerJoinListener()); getListenerCore().stageListener(new MultipartBalloonPlayerLeaveListener()); @@ -88,9 +90,7 @@ public void onEnable() { getListenerCore().registerListeners(); // Startup the metrics and update checker - // This is the ID of the plugin on bStats, this should be kept as a constant - int pluginId = 16872; - new Metrics(this, pluginId); + new Metrics(this, PluginConfiguration.BSTATS_PLUGIN_ID); updateChecker(); // Copy over example balloons folder @@ -143,41 +143,11 @@ public void updateChecker() { new UpdateChecker(this, resourceId).getVersion(version -> { String currentVersion = this.getDescription().getVersion(); - if (isVersionLower(currentVersion, version)) { + if (VersionChecker.isVersionLower(currentVersion, version)) { Logger.logUpdateNotificationConsole(); - } else if (isVersionHigher(currentVersion, version)) { + } else if (VersionChecker.isVersionHigher(currentVersion, version)) { Logger.logUnreleasedVersionNotification(); } }); } - - public boolean isVersionLower(String current, String latest) { - return compareVersions(current, latest) < 0; - } - - public boolean isVersionHigher(String current, String latest) { - return compareVersions(current, latest) > 0; - } - - /** - * Compares two version strings (e.g., "1.2.3" vs. "1.2.4"). - * Returns: - * - A negative value if v1 < v2 - * - Zero if v1 == v2 - * - A positive value if v1 > v2 - */ - public int compareVersions(String v1, String v2) { - String[] v1Parts = v1.split("\\."); - String[] v2Parts = v2.split("\\."); - - int length = Math.max(v1Parts.length, v2Parts.length); - for (int i = 0; i < length; i++) { - int part1 = i < v1Parts.length ? Integer.parseInt(v1Parts[i]) : 0; - int part2 = i < v2Parts.length ? Integer.parseInt(v2Parts[i]) : 0; - if (part1 != part2) { - return Integer.compare(part1, part2); - } - } - return 0; - } } \ No newline at end of file diff --git a/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java b/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java index 4717dc45..771f867e 100644 --- a/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java +++ b/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java @@ -43,7 +43,7 @@ public class MultipartBalloonModel { public MultipartBalloonModel(BalloonSegmentType segmentType, String material, String color, int customModelData) { this.setSegmentType(segmentType); this.setMaterial(material); - if (!color.equals(this.getColor()) && color != null && !color.isEmpty()) this.setColor(color); + if (!color.equals(this.getColor()) && !color.isEmpty()) this.setColor(color); this.setCustomModelData(customModelData); } diff --git a/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java b/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java index 465414c6..b759fa88 100644 --- a/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java +++ b/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java @@ -82,7 +82,11 @@ private void initializeBalloon() { if (this.getType().getMegModelID() == null) { // Create and set the balloons visual appearance/model ItemMeta meta = this.getVisual().getItemMeta(); - meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + + if (meta != null) { + meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + } + this.getVisual().setItemMeta(meta); } @@ -95,6 +99,13 @@ private void initializeBalloon() { * Initializes the balloon's armor stand entity with the proper configurations */ public void initializeBalloonArmorStand() { + if (this.getPlayerLocation().getWorld() == null) { + Logger.logError("Player world is not currently set. Could not initialize balloon, removing from player."); + // Remove the balloon from the player + SingleBalloonManagement.removeBalloon(player, null); + return; + } + this.setArmorStand(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), ArmorStand.class)); this.getArmorStand().setBasePlate(false); this.getArmorStand().setVisible(false); @@ -105,7 +116,9 @@ public void initializeBalloonArmorStand() { this.getArmorStand().setMarker(true); this.getArmorStand().setCollidable(false); if (this.getType().getMegModelID() == null) { - this.getArmorStand().getEquipment().setHelmet(this.getVisual()); + if (this.getArmorStand().getEquipment() != null) { + this.getArmorStand().getEquipment().setHelmet(this.getVisual()); + } } else { try { // Create the entity and tag it onto the armor stand @@ -120,8 +133,7 @@ public void initializeBalloonArmorStand() { // If an idle animation exists, play it initially this.getAnimationHandler().playAnimation(this.getDefaultIdleAnimationID(), 0.3, 0.3, 1,true); } catch (Exception e) { - Logger.logError("An error occurred while creating the MEG model for the balloon " + this.getType().getId() + "! This is because a MEG model error occurred."); - e.printStackTrace(); + Logger.logError("An error occurred while creating the MEG model for the balloon " + this.getType().getId() + "! This is because a MEG model error occurred: " + e.getMessage()); } } this.getArmorStand().setCustomName(BalloonConfiguration.BALLOON_ARMOR_STAND_ID); @@ -131,6 +143,13 @@ public void initializeBalloonArmorStand() { * Initializes the balloon's lead to the player (chicken entity) */ public void initializeBalloonLead() { + if (this.getPlayerLocation().getWorld() == null) { + Logger.logError("Player world is not currently set. Could not initialize balloon, removing from player."); + // Remove the balloon from the player + SingleBalloonManagement.removeBalloon(player, null); + return; + } + this.setChicken(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), Chicken.class)); this.getChicken().setInvulnerable(true); this.getChicken().setInvisible(true); @@ -237,6 +256,8 @@ public synchronized void cancel() throws IllegalStateException { * Spawns the particle effect when the balloon is removed */ public void spawnRemoveParticle() { + if (this.getMoveLocation().getWorld() == null) return; + this.getMoveLocation().getWorld().spawnParticle(Particle.CLOUD, this.getMoveLocation(), 5, 0.0D, 0.0D, 0.0D, 0.1D); } @@ -280,7 +301,10 @@ public ItemStack getConfiguredBalloonVisual(String balloonID) { // Generate the item and set the custom model data meta ItemStack item = new ItemStack(material); ItemMeta meta = item.getItemMeta(); - meta.setCustomModelData(singleBalloonType.getCustomModelData()); + + if (meta != null) { + meta.setCustomModelData(singleBalloonType.getCustomModelData()); + } // If the color of the balloon is not set, log an error and return null if (singleBalloonType.getColor() != null && singleBalloonType.getMaterial().startsWith(LEATHER_MATERIAL_PREFIX)) { diff --git a/src/main/java/net/jeqo/bloons/commands/CommandEquip.java b/src/main/java/net/jeqo/bloons/commands/CommandEquip.java index e28c67bb..19b7fe63 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandEquip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandEquip.java @@ -8,9 +8,10 @@ import net.jeqo.bloons.balloon.single.SingleBalloonType; import net.jeqo.bloons.commands.manager.Command; import net.jeqo.bloons.commands.manager.types.CommandPermission; +import net.jeqo.bloons.logger.Logger; +import net.jeqo.bloons.logger.LoggingLevel; import net.jeqo.bloons.message.Languages; import net.jeqo.bloons.management.SingleBalloonManagement; -import net.jeqo.bloons.message.MessageTranslations; import net.jeqo.bloons.management.MultipartBalloonManagement; import org.bukkit.ChatColor; import org.bukkit.Sound; @@ -45,7 +46,6 @@ public boolean execute(CommandSender sender, String[] args) { if (args.length < 1) usage(player); String balloonID = args[0]; - MessageTranslations messageTranslations = new MessageTranslations(this.getPlugin()); // If the balloon ID isn't found in both balloon types, send a message to the player if (Bloons.getBalloonCore().containsSingleBalloon(balloonID) && Bloons.getBalloonCore().containsMultipartBalloon(balloonID)) { @@ -101,8 +101,13 @@ public boolean execute(CommandSender sender, String[] args) { SingleBalloonManagement.removeBalloon(player, Bloons.getPlayerSingleBalloons().get(player.getUniqueId())); SingleBalloon.checkBalloonRemovalOrAdd(player, balloonID); - String equippedMessage = Languages.getMessage("prefix") + String.format(Languages.getMessage("equipped"), singleBalloonType.getName()); - player.sendMessage(ChatColor.translateAlternateColorCodes('&', equippedMessage)); + if (singleBalloonType == null) { + Logger.logToPlayer(LoggingLevel.ERROR, player, "The current balloon type is null! Please correct this in the config."); + return false; + } else { + String equippedMessage = Languages.getMessage("prefix") + String.format(Languages.getMessage("equipped"), singleBalloonType.getName()); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', equippedMessage)); + } } // Play a sound regardless of the balloon type and when it executes successfully diff --git a/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java b/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java index 16bfff3e..e89d6ed9 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandForceEquip.java @@ -10,7 +10,6 @@ import net.jeqo.bloons.commands.manager.types.CommandPermission; import net.jeqo.bloons.message.Languages; import net.jeqo.bloons.management.SingleBalloonManagement; -import net.jeqo.bloons.message.MessageTranslations; import net.jeqo.bloons.management.MultipartBalloonManagement; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -43,7 +42,6 @@ public boolean execute(CommandSender sender, String[] args) { if (args.length < 1) usage(sender); Player player = Bukkit.getPlayer(args[0]); - MessageTranslations messageTranslations = new MessageTranslations(this.getPlugin()); // If the player isn't found, send a message to the sender if (player == null) { diff --git a/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java b/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java index 520331c5..f5c74f05 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandForceUnequip.java @@ -7,7 +7,6 @@ import net.jeqo.bloons.commands.manager.types.CommandPermission; import net.jeqo.bloons.message.Languages; import net.jeqo.bloons.management.SingleBalloonManagement; -import net.jeqo.bloons.message.MessageTranslations; import net.jeqo.bloons.management.MultipartBalloonManagement; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -27,7 +26,6 @@ public CommandForceUnequip(JavaPlugin plugin) { @Override public boolean execute(CommandSender sender, String[] args) { - MessageTranslations messageTranslations = new MessageTranslations(this.getPlugin()); Player player = Bukkit.getPlayer(args[0]); // If the specified player doesn't exist, send a message to the sender diff --git a/src/main/java/net/jeqo/bloons/commands/CommandReload.java b/src/main/java/net/jeqo/bloons/commands/CommandReload.java index 3204f4f1..655cb25b 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandReload.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandReload.java @@ -4,7 +4,6 @@ import net.jeqo.bloons.commands.manager.Command; import net.jeqo.bloons.commands.manager.types.CommandPermission; import net.jeqo.bloons.message.Languages; -import net.jeqo.bloons.message.MessageTranslations; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.plugin.java.JavaPlugin; @@ -29,8 +28,6 @@ public CommandReload(JavaPlugin plugin) { @Override public boolean execute(CommandSender sender, String[] args) { - MessageTranslations messageTranslations = new MessageTranslations(this.getPlugin()); - // Reload the main config.yml and its defaults Bloons.getInstance().reloadConfig(); Bloons.getInstance().getConfig().options().copyDefaults(); diff --git a/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java b/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java index 7fd8e4d1..1af0d76b 100644 --- a/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java +++ b/src/main/java/net/jeqo/bloons/commands/CommandUnequip.java @@ -7,7 +7,6 @@ import net.jeqo.bloons.commands.manager.types.CommandPermission; import net.jeqo.bloons.message.Languages; import net.jeqo.bloons.management.SingleBalloonManagement; -import net.jeqo.bloons.message.MessageTranslations; import net.jeqo.bloons.management.MultipartBalloonManagement; import org.bukkit.ChatColor; import org.bukkit.Sound; diff --git a/src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java b/src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java index bc06e19d..4803d0bb 100644 --- a/src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java +++ b/src/main/java/net/jeqo/bloons/commands/manager/CommandCore.java @@ -113,7 +113,7 @@ public boolean onCommand(@NotNull CommandSender sender, org.bukkit.command.@NotN ArrayList singleBalloonTypes = Bloons.getBalloonCore().getSingleBalloonTypes(); ArrayList multipartBalloonTypes = Bloons.getBalloonCore().getMultipartBalloonTypes(); - // + // Check if none are registered if (singleBalloonTypes == null && multipartBalloonTypes == null) { Logger.logError(ChatColor.translateAlternateColorCodes('&', Languages.getMessage("no-balloons-registered"))); return false; 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 568b327e..5822af34 100644 --- a/src/main/java/net/jeqo/bloons/commands/utils/ErrorHandling.java +++ b/src/main/java/net/jeqo/bloons/commands/utils/ErrorHandling.java @@ -2,7 +2,6 @@ import net.jeqo.bloons.Bloons; import net.jeqo.bloons.configuration.PluginConfiguration; -import net.jeqo.bloons.message.MessageTranslations; import org.bukkit.command.CommandSender; /** @@ -16,9 +15,6 @@ public class ErrorHandling { * @param sender The sender of the command, type org.bukkit.command.CommandSender */ public static void usage(CommandSender sender) { - // MessageTranslations will need to adapt for plain text - MessageTranslations messageTranslations = new MessageTranslations(Bloons.getInstance()); - sender.sendMessage(""); // Blank line for spacing if (sender.hasPermission("bloons.menu")) { String menuMessage = " §d/bloons §7- Open the balloon menu"; diff --git a/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java b/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java index defdcbec..61e150fc 100644 --- a/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java +++ b/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java @@ -13,7 +13,6 @@ import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; diff --git a/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java b/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java index 9362a022..fcb9f2fe 100644 --- a/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java +++ b/src/main/java/net/jeqo/bloons/configuration/PluginConfiguration.java @@ -13,6 +13,9 @@ public class PluginConfiguration { // The base prefix to all commands within the plugin public static final String COMMAND_BASE = "bloons"; + // The bStats plugin resource ID used for metrics + public static final int BSTATS_PLUGIN_ID = 16872; + /** * Get the version of the plugin from the pom.xml file * @return The version of the plugin, type java.lang.String diff --git a/src/main/java/net/jeqo/bloons/item/NBTItem.java b/src/main/java/net/jeqo/bloons/item/NBTItem.java index 4596f8c6..0824eeb3 100644 --- a/src/main/java/net/jeqo/bloons/item/NBTItem.java +++ b/src/main/java/net/jeqo/bloons/item/NBTItem.java @@ -9,6 +9,8 @@ import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; +import java.util.Optional; + /** * An extension of an Item with the utilities to manage NBT * data easier and more efficiently @@ -32,6 +34,8 @@ public NBTItem(ItemStack item) { */ public boolean hasKey(String key) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + + if (this.getItem().getItemMeta() == null) return false; PersistentDataContainer container = this.getItem().getItemMeta().getPersistentDataContainer(); return container.getKeys().contains(nbtKey); @@ -45,7 +49,8 @@ public boolean hasKey(String key) { public void setStringFlag(String key, String value) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); - ItemMeta meta = getItem().getItemMeta(); + ItemMeta meta = this.getItem().getItemMeta(); + if (meta == null) return; meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.STRING, value); this.getItem().setItemMeta(meta); @@ -58,6 +63,7 @@ public void setStringFlag(String key, String value) { */ public String getStringFlag(String key) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + if (this.getItem().getItemMeta() == null) return ""; PersistentDataContainer container = this.getItem().getItemMeta().getPersistentDataContainer(); if (!container.has(nbtKey, PersistentDataType.STRING)) return null; @@ -74,6 +80,7 @@ public void setIntegerFlag(String key, int value) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); ItemMeta meta = this.getItem().getItemMeta(); + if (meta == null) return; meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.INTEGER, value); this.getItem().setItemMeta(meta); @@ -86,11 +93,12 @@ public void setIntegerFlag(String key, int value) { */ public int getIntegerFlag(String key) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + if (this.getItem().getItemMeta() == null) return 0; PersistentDataContainer container = this.getItem().getItemMeta().getPersistentDataContainer(); if (!container.has(nbtKey, PersistentDataType.INTEGER)) return 0; - return container.get(nbtKey, PersistentDataType.INTEGER); + return Optional.ofNullable(container.get(nbtKey, PersistentDataType.INTEGER)).orElse(0); } /** @@ -102,6 +110,7 @@ public void setDoubleFlag(String key, double value) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); ItemMeta meta = this.getItem().getItemMeta(); + if (meta == null) return; meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.DOUBLE, value); this.getItem().setItemMeta(meta); @@ -114,11 +123,12 @@ public void setDoubleFlag(String key, double value) { */ public double getDoubleFlag(String key) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + if (this.getItem().getItemMeta() == null) return 0.0; PersistentDataContainer container = this.getItem().getItemMeta().getPersistentDataContainer(); if (!container.has(nbtKey, PersistentDataType.DOUBLE)) return 0.0; - return container.get(nbtKey, PersistentDataType.DOUBLE); + return Optional.ofNullable(container.get(nbtKey, PersistentDataType.DOUBLE)).orElse(0.0); } /** @@ -130,6 +140,7 @@ public void setBooleanFlag(String key, boolean value) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); ItemMeta meta = this.getItem().getItemMeta(); + if (meta == null) return; meta.getPersistentDataContainer().set(nbtKey, PersistentDataType.BOOLEAN, value); this.getItem().setItemMeta(meta); @@ -142,6 +153,7 @@ public void setBooleanFlag(String key, boolean value) { */ public boolean getBooleanFlag(String key) { NamespacedKey nbtKey = new NamespacedKey(Bloons.getInstance(), key); + if (this.getItem().getItemMeta() == null) return false; PersistentDataContainer container = this.getItem().getItemMeta().getPersistentDataContainer(); if (!container.has(nbtKey, PersistentDataType.BOOLEAN)) return false; diff --git a/src/main/java/net/jeqo/bloons/listeners/BalloonEntityListener.java b/src/main/java/net/jeqo/bloons/listeners/BalloonChickenEntityListener.java similarity index 92% rename from src/main/java/net/jeqo/bloons/listeners/BalloonEntityListener.java rename to src/main/java/net/jeqo/bloons/listeners/BalloonChickenEntityListener.java index 618e8ad6..6cb0888f 100644 --- a/src/main/java/net/jeqo/bloons/listeners/BalloonEntityListener.java +++ b/src/main/java/net/jeqo/bloons/listeners/BalloonChickenEntityListener.java @@ -8,7 +8,7 @@ /** * A class that listens for events related to balloon entities */ -public class BalloonEntityListener implements Listener { +public class BalloonChickenEntityListener implements Listener { /** * Stop the chicken from going through the portal to prevent unleashing from player to balloon diff --git a/src/main/java/net/jeqo/bloons/listeners/BalloonUnleashListener.java b/src/main/java/net/jeqo/bloons/listeners/BalloonChickenLeashListener.java similarity index 92% rename from src/main/java/net/jeqo/bloons/listeners/BalloonUnleashListener.java rename to src/main/java/net/jeqo/bloons/listeners/BalloonChickenLeashListener.java index cd903acd..57e71ca2 100644 --- a/src/main/java/net/jeqo/bloons/listeners/BalloonUnleashListener.java +++ b/src/main/java/net/jeqo/bloons/listeners/BalloonChickenLeashListener.java @@ -3,14 +3,13 @@ import net.jeqo.bloons.configuration.BalloonConfiguration; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityUnleashEvent; import org.bukkit.event.entity.PlayerLeashEntityEvent; import org.bukkit.event.player.PlayerUnleashEntityEvent; /** * A class that listens for events related to balloon unleashing and leashing */ -public class BalloonUnleashListener implements Listener { +public class BalloonChickenLeashListener implements Listener { /** * Used to check if player tries to unleash from their balloon, if they do then cancel it diff --git a/src/main/java/net/jeqo/bloons/listeners/PlayerUpdateNotificationListener.java b/src/main/java/net/jeqo/bloons/listeners/PlayerUpdateNotificationListener.java new file mode 100644 index 00000000..c834ba5a --- /dev/null +++ b/src/main/java/net/jeqo/bloons/listeners/PlayerUpdateNotificationListener.java @@ -0,0 +1,30 @@ +package net.jeqo.bloons.listeners; + +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.health.UpdateChecker; +import net.jeqo.bloons.logger.Logger; +import net.jeqo.bloons.utils.VersionChecker; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerUpdateNotificationListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + if (event.getPlayer().isOp()) { + if (Bloons.getInstance().getConfig().getBoolean("check-for-updates")) { + // Check for an update if the player is an operator on the server + new UpdateChecker(Bloons.getInstance(), 106243).getVersion(version -> { + String currentVersion = Bloons.getInstance().getDescription().getVersion(); + + if (VersionChecker.isVersionLower(currentVersion, version)) { + Logger.logUpdateNotificationPlayer(event.getPlayer()); + } else if (VersionChecker.isVersionHigher(currentVersion, version)) { + Logger.logUnreleasedVersionNotificationPlayer(event.getPlayer()); + } + }); + } + } + } +} diff --git a/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerJoinListener.java b/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerJoinListener.java new file mode 100644 index 00000000..50e40851 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerJoinListener.java @@ -0,0 +1,27 @@ +package net.jeqo.bloons.listeners.single; + +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.single.SingleBalloon; +import net.jeqo.bloons.management.SingleBalloonManagement; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class SingleBalloonPlayerJoinListener implements Listener { + + /** + * When a player joins, add the balloon back if they left with one, or just don't add anything + * @param event The event that is called when a player joins the server, type org.bukkit.event.player.PlayerJoinEvent + */ + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + String balloonID = Bloons.getPlayerSingleBalloonID().get(event.getPlayer().getUniqueId()); + + // If they have a balloon active, remove it and add it back to reduce issues + if (balloonID != null) { + SingleBalloonManagement.removeBalloon(event.getPlayer(), Bloons.getPlayerSingleBalloons().get(event.getPlayer().getUniqueId())); + + SingleBalloon.checkBalloonRemovalOrAdd(event.getPlayer(), balloonID); + } + } +} diff --git a/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerLeaveListener.java b/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerLeaveListener.java new file mode 100644 index 00000000..4c39aae0 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerLeaveListener.java @@ -0,0 +1,22 @@ +package net.jeqo.bloons.listeners.single; + +import net.jeqo.bloons.Bloons; +import net.jeqo.bloons.balloon.single.SingleBalloon; +import net.jeqo.bloons.management.SingleBalloonManagement; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +public class SingleBalloonPlayerLeaveListener implements Listener { + + /** + * When a player quits, make sure to despawn and store their balloon in storage + * @param event The event that is called when a player quits the server, type org.bukkit.event.player.PlayerQuitEvent + */ + @EventHandler + public void onPlayerLeave(PlayerQuitEvent event) { + SingleBalloon owner = Bloons.getPlayerSingleBalloons().get(event.getPlayer().getUniqueId()); + + SingleBalloonManagement.storeBalloon(owner); + } +} diff --git a/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerListener.java b/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerListener.java index 76ab2e64..faff55a9 100644 --- a/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerListener.java +++ b/src/main/java/net/jeqo/bloons/listeners/single/SingleBalloonPlayerListener.java @@ -2,65 +2,17 @@ import net.jeqo.bloons.Bloons; import net.jeqo.bloons.balloon.single.SingleBalloon; -import net.jeqo.bloons.health.UpdateChecker; -import net.jeqo.bloons.logger.Logger; import net.jeqo.bloons.management.SingleBalloonManagement; -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 SingleBalloonPlayerListener implements Listener { - /** - * When a player quits, make sure to despawn and store their balloon in storage - * @param event The event that is called when a player quits the server, type org.bukkit.event.player.PlayerQuitEvent - */ - @EventHandler - public void onQuit(PlayerQuitEvent event) { - SingleBalloon owner = Bloons.getPlayerSingleBalloons().get(event.getPlayer().getUniqueId()); - - SingleBalloonManagement.storeBalloon(owner); - } - - /** - * When a player joins, add the balloon back if they left with one, or just don't add anything - * @param event The event that is called when a player joins the server, type org.bukkit.event.player.PlayerJoinEvent - */ - @EventHandler - public void onJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - String balloonID = Bloons.getPlayerSingleBalloonID().get(event.getPlayer().getUniqueId()); - - // If they have a balloon active, remove it and add it back to reduce issues - if (balloonID != null) { - SingleBalloonManagement.removeBalloon(event.getPlayer(), Bloons.getPlayerSingleBalloons().get(event.getPlayer().getUniqueId())); - - SingleBalloon.checkBalloonRemovalOrAdd(event.getPlayer(), balloonID); - } - - if (event.getPlayer().isOp()) { - if (Bloons.getInstance().getConfig().getBoolean("check-for-updates")) { - // Check for an update if the player is an operator on the server - new UpdateChecker(Bloons.getInstance(), 106243).getVersion(version -> { - String currentVersion = Bloons.getInstance().getDescription().getVersion(); - - if (Bloons.getInstance().isVersionLower(currentVersion, version)) { - Logger.logUpdateNotificationPlayer(event.getPlayer()); - } else if (Bloons.getInstance().isVersionHigher(currentVersion, version)) { - Logger.logUnreleasedVersionNotificationPlayer(event.getPlayer()); - } - }); - } - } - } - /** * When they die, remove their balloon * @param event The event that is called when a player dies, type org.bukkit.event.entity.PlayerDeathEvent diff --git a/src/main/java/net/jeqo/bloons/logger/Logger.java b/src/main/java/net/jeqo/bloons/logger/Logger.java index a12d3812..47b2e629 100644 --- a/src/main/java/net/jeqo/bloons/logger/Logger.java +++ b/src/main/java/net/jeqo/bloons/logger/Logger.java @@ -3,8 +3,6 @@ import net.jeqo.bloons.Bloons; import net.jeqo.bloons.configuration.ConfigConfiguration; import net.jeqo.bloons.configuration.PluginConfiguration; -import net.jeqo.bloons.message.Languages; -import net.jeqo.bloons.message.MessageTranslations; import org.bukkit.Bukkit; import org.bukkit.entity.Player; diff --git a/src/main/java/net/jeqo/bloons/management/SingleBalloonManagement.java b/src/main/java/net/jeqo/bloons/management/SingleBalloonManagement.java index 1d617067..58d130a5 100644 --- a/src/main/java/net/jeqo/bloons/management/SingleBalloonManagement.java +++ b/src/main/java/net/jeqo/bloons/management/SingleBalloonManagement.java @@ -23,19 +23,6 @@ public static void removeBalloon(Player player, SingleBalloon owner) { Bloons.getPlayerSingleBalloonID().remove(player.getUniqueId()); } - /** - * Remove the balloon from the player quickly - * @param player The player to remove the balloon from, type org.bukkit.entity.Player - * @param owner The balloon, type net.jeqo.bloons.balloon.single.SingleBalloon - */ - public static void quickRemoveBalloon(Player player, SingleBalloon owner) { - if (owner == null) return; - - owner.cancel(); - Bloons.getPlayerSingleBalloons().remove(player.getUniqueId()); - Bloons.getPlayerSingleBalloonID().remove(player.getUniqueId()); - } - /** * Store the balloon in storage and just cancel the runnable * @param balloon The balloon, type net.jeqo.bloons.balloon.single.SingleBalloon diff --git a/src/main/java/net/jeqo/bloons/utils/VersionChecker.java b/src/main/java/net/jeqo/bloons/utils/VersionChecker.java new file mode 100644 index 00000000..57247604 --- /dev/null +++ b/src/main/java/net/jeqo/bloons/utils/VersionChecker.java @@ -0,0 +1,34 @@ +package net.jeqo.bloons.utils; + +public class VersionChecker { + + public static boolean isVersionLower(String current, String latest) { + return compareVersions(current, latest) < 0; + } + + public static boolean isVersionHigher(String current, String latest) { + return compareVersions(current, latest) > 0; + } + + /** + * Compares two version strings (e.g., "1.2.3" vs. "1.2.4"). + * Returns: + * - A negative value if v1 < v2 + * - Zero if v1 == v2 + * - A positive value if v1 > v2 + */ + public static int compareVersions(String v1, String v2) { + String[] v1Parts = v1.split("\\."); + String[] v2Parts = v2.split("\\."); + + int length = Math.max(v1Parts.length, v2Parts.length); + for (int i = 0; i < length; i++) { + int part1 = i < v1Parts.length ? Integer.parseInt(v1Parts[i]) : 0; + int part2 = i < v2Parts.length ? Integer.parseInt(v2Parts[i]) : 0; + if (part1 != part2) { + return Integer.compare(part1, part2); + } + } + return 0; + } +}