From 3785c9404ed207d6d12a2a4de4ed0503368f2758 Mon Sep 17 00:00:00 2001 From: darbyjack Date: Fri, 26 Jun 2026 13:24:40 -0500 Subject: [PATCH] fix(misc): harden guild damage, config parsing, and claims --- .../java/me/glaremasters/guilds/Guilds.java | 30 +++++++++++++- .../me/glaremasters/guilds/guild/Guild.java | 11 ----- .../guilds/guild/GuildHandler.java | 28 ++++++++++++- .../guilds/listeners/ClaimSignListener.java | 41 ++++++++++++++++--- .../guilds/listeners/EntityListener.java | 5 +++ .../me/glaremasters/guilds/guis/BuffGUI.kt | 31 ++++++++++---- .../guilds/listeners/WorldGuardListener.kt | 4 +- 7 files changed, 119 insertions(+), 31 deletions(-) diff --git a/src/main/java/me/glaremasters/guilds/Guilds.java b/src/main/java/me/glaremasters/guilds/Guilds.java index accfd88a5..8d9682c50 100644 --- a/src/main/java/me/glaremasters/guilds/Guilds.java +++ b/src/main/java/me/glaremasters/guilds/Guilds.java @@ -66,6 +66,7 @@ import org.bukkit.Bukkit; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; +import org.codemc.worldguardwrapper.WorldGuardWrapper; import org.bxteam.quark.bukkit.BukkitLibraryManager; import java.io.IOException; @@ -321,11 +322,36 @@ private void optionalListeners() { } if (settingsHandler.getMainConf().getProperty(HooksSettings.WORLDGUARD)) { - getServer().getPluginManager().registerEvents(new WorldGuardListener(guildHandler), this); - getServer().getPluginManager().registerEvents(new ClaimSignListener(this, settingsHandler.getMainConf(), guildHandler), this); + registerWorldGuardListeners(); } } + /** + * Register WorldGuard-backed listeners only when the optional hook is available. + */ + private void registerWorldGuardListeners() { + if (!Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) { + LoggingUtils.warn("WorldGuard hook is enabled in config, but WorldGuard is not installed or enabled. Skipping WorldGuard claim listeners."); + return; + } + + final WorldGuardWrapper wrapper; + try { + wrapper = WorldGuardWrapper.getInstance(); + } catch (RuntimeException | LinkageError e) { + LoggingUtils.warn("WorldGuard hook is enabled, but WorldGuardWrapper could not initialize. Skipping WorldGuard claim listeners.", e); + return; + } + + if (wrapper == null) { + LoggingUtils.warn("WorldGuard hook is enabled, but WorldGuardWrapper returned no instance. Skipping WorldGuard claim listeners."); + return; + } + + getServer().getPluginManager().registerEvents(new WorldGuardListener(guildHandler, wrapper), this); + getServer().getPluginManager().registerEvents(new ClaimSignListener(this, settingsHandler.getMainConf(), guildHandler, wrapper), this); + } + /** * Used to create a new chain of commands * diff --git a/src/main/java/me/glaremasters/guilds/guild/Guild.java b/src/main/java/me/glaremasters/guilds/guild/Guild.java index 3d4b45978..9d6a88953 100644 --- a/src/main/java/me/glaremasters/guilds/guild/Guild.java +++ b/src/main/java/me/glaremasters/guilds/guild/Guild.java @@ -35,7 +35,6 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import java.util.ArrayList; import java.util.List; @@ -565,16 +564,6 @@ public void transferGuildAdmin(final OfflinePlayer master, final GuildHandler ha setGuildMaster(newGuildMaster); } - /** - * Simple method to add a buff to all online members - * @param type the potion type - * @param length the length of the potion - * @param amplifier the strength of the potion - */ - public void addPotion(String type, int length, int amplifier) { - getOnlineAsPlayers().forEach(p -> p.addPotionEffect(new PotionEffect(PotionEffectType.getByName(type), length, amplifier))); - } - /** * Determine if a player has role permission * @param player the player to check diff --git a/src/main/java/me/glaremasters/guilds/guild/GuildHandler.java b/src/main/java/me/glaremasters/guilds/guild/GuildHandler.java index 652e55468..f17476214 100644 --- a/src/main/java/me/glaremasters/guilds/guild/GuildHandler.java +++ b/src/main/java/me/glaremasters/guilds/guild/GuildHandler.java @@ -24,6 +24,7 @@ package me.glaremasters.guilds.guild; import ch.jalu.configme.SettingsManager; +import com.cryptomorin.xseries.XMaterial; import co.aikar.commands.ACFBukkitUtil; import co.aikar.commands.ACFUtil; import co.aikar.commands.PaperCommandManager; @@ -61,6 +62,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -747,7 +749,7 @@ public void pingOnlineInviters(Guild guild, PaperCommandManager commandManager, * @return the guild upgrade ticket */ public ItemStack getUpgradeTicket(SettingsManager settingsManager, int amount) { - ItemBuilder builder = new ItemBuilder(Material.valueOf(settingsManager.getProperty(TicketSettings.TICKET_MATERIAL))); + ItemBuilder builder = new ItemBuilder(resolveTicketMaterial(settingsManager)); builder.setAmount(amount); builder.setName(StringUtils.color(settingsManager.getProperty(TicketSettings.TICKET_NAME))); builder.setLore(settingsManager.getProperty(TicketSettings.TICKET_LORE).stream().map(StringUtils::color).collect(Collectors.toList())); @@ -761,13 +763,35 @@ public ItemStack getUpgradeTicket(SettingsManager settingsManager, int amount) { * @return the itemstack */ public ItemStack matchTicket(SettingsManager settingsManager) { - ItemBuilder builder = new ItemBuilder(Material.valueOf(settingsManager.getProperty(TicketSettings.TICKET_MATERIAL))); + ItemBuilder builder = new ItemBuilder(resolveTicketMaterial(settingsManager)); builder.setAmount(1); builder.setName(StringUtils.color(settingsManager.getProperty(TicketSettings.TICKET_NAME))); builder.setLore(settingsManager.getProperty(TicketSettings.TICKET_LORE).stream().map(StringUtils::color).collect(Collectors.toList())); return builder.build(); } + /** + * Resolve the configured ticket material safely across Bukkit versions. + * + * @param settingsManager settings manager + * @return configured material or PAPER if invalid + */ + private Material resolveTicketMaterial(SettingsManager settingsManager) { + final String rawMaterial = settingsManager.getProperty(TicketSettings.TICKET_MATERIAL); + if (rawMaterial != null && !rawMaterial.trim().isEmpty()) { + final Optional matchedMaterial = XMaterial.matchXMaterial(rawMaterial.trim()); + + if (matchedMaterial.isPresent()) { + final Material material = matchedMaterial.get().get(); + if (material != null && new ItemStack(material).getItemMeta() != null) { + return material; + } + } + } + + LoggingUtils.warn("Invalid or non-item ticket material configured at tickets.material: '" + rawMaterial + "'. Falling back to PAPER."); + return Material.PAPER; + } /** * Simple method to check if a guild is full or not diff --git a/src/main/java/me/glaremasters/guilds/listeners/ClaimSignListener.java b/src/main/java/me/glaremasters/guilds/listeners/ClaimSignListener.java index 1c93ce69d..689e6214a 100644 --- a/src/main/java/me/glaremasters/guilds/listeners/ClaimSignListener.java +++ b/src/main/java/me/glaremasters/guilds/listeners/ClaimSignListener.java @@ -42,6 +42,8 @@ import org.codemc.worldguardwrapper.WorldGuardWrapper; import org.codemc.worldguardwrapper.selection.ICuboidSelection; +import java.util.OptionalDouble; + /** * Created by Glare * Date: 5/29/2019 @@ -52,12 +54,13 @@ public class ClaimSignListener implements Listener { private final Guilds guilds; private final SettingsManager settingsManager; private final GuildHandler guildHandler; - private final WorldGuardWrapper wrapper = WorldGuardWrapper.getInstance(); + private final WorldGuardWrapper wrapper; - public ClaimSignListener(Guilds guilds, SettingsManager settingsManager, GuildHandler guildHandler) { + public ClaimSignListener(Guilds guilds, SettingsManager settingsManager, GuildHandler guildHandler, WorldGuardWrapper wrapper) { this.guilds = guilds; this.settingsManager = settingsManager; this.guildHandler = guildHandler; + this.wrapper = wrapper; } @EventHandler @@ -79,7 +82,7 @@ public void onSignChange(SignChangeEvent event) { return; } - if (event.getLine(1).isEmpty() || event.getLine(2).isEmpty()) { + if (event.getLine(1).isEmpty() || !parseClaimPrice(event.getLine(2)).isPresent()) { guilds.getCommandManager().getCommandIssuer(player).sendInfo(Messages.CLAIM__SIGN_INVALID_FORMAT); event.setCancelled(true); return; @@ -136,7 +139,14 @@ public void onSignInteract(PlayerInteractEvent event) { return; } - if (guild.getBalance() < Double.valueOf(sign.getLine(2))) { + OptionalDouble parsedPrice = parseClaimPrice(sign.getLine(2)); + if (!parsedPrice.isPresent()) { + guilds.getCommandManager().getCommandIssuer(player).sendInfo(Messages.CLAIM__SIGN_INVALID_FORMAT); + return; + } + + double claimPrice = parsedPrice.getAsDouble(); + if (guild.getBalance() < claimPrice) { guilds.getCommandManager().getCommandIssuer(player).sendInfo(Messages.CLAIM__SIGN_NOT_ENOUGH); return; } @@ -156,9 +166,30 @@ public void onSignInteract(PlayerInteractEvent event) { player.getWorld().getBlockAt(block.getLocation()).breakNaturally(); - guild.setBalance(guild.getBalance() - Double.valueOf(sign.getLine(2))); + guild.setBalance(guild.getBalance() - claimPrice); guilds.getCommandManager().getCommandIssuer(player).sendInfo(Messages.CLAIM__SIGN_BUY_SUCCESS); } + private OptionalDouble parseClaimPrice(String raw) { + if (raw == null) { + return OptionalDouble.empty(); + } + + String trimmed = raw.trim(); + if (trimmed.isEmpty()) { + return OptionalDouble.empty(); + } + + try { + double price = Double.parseDouble(trimmed); + if (Double.isNaN(price) || Double.isInfinite(price) || price < 0) { + return OptionalDouble.empty(); + } + return OptionalDouble.of(price); + } catch (NumberFormatException ignored) { + return OptionalDouble.empty(); + } + } + } diff --git a/src/main/java/me/glaremasters/guilds/listeners/EntityListener.java b/src/main/java/me/glaremasters/guilds/listeners/EntityListener.java index 74aaae897..3d248ea35 100644 --- a/src/main/java/me/glaremasters/guilds/listeners/EntityListener.java +++ b/src/main/java/me/glaremasters/guilds/listeners/EntityListener.java @@ -73,6 +73,10 @@ public void onMobDamage(EntityDamageByEntityEvent event) { return; } + if (!(event.getEntity() instanceof Monster)) { + return; + } + final Entity damager = event.getDamager(); if (!(damager instanceof Player)) { return; @@ -94,6 +98,7 @@ public void onMobDamage(EntityDamageByEntityEvent event) { * * @param event The EntityDeathEvent that triggered the method. */ + @EventHandler public void onMobDeath(EntityDeathEvent event) { if (!(event.getEntity() instanceof Monster)) { return; diff --git a/src/main/kotlin/me/glaremasters/guilds/guis/BuffGUI.kt b/src/main/kotlin/me/glaremasters/guilds/guis/BuffGUI.kt index b77f3ca8e..b5f567824 100644 --- a/src/main/kotlin/me/glaremasters/guilds/guis/BuffGUI.kt +++ b/src/main/kotlin/me/glaremasters/guilds/guis/BuffGUI.kt @@ -38,11 +38,11 @@ import me.glaremasters.guilds.guild.Guild import me.glaremasters.guilds.messages.Messages import me.glaremasters.guilds.utils.EconomyUtils import me.glaremasters.guilds.utils.GuiUtils +import me.glaremasters.guilds.utils.LoggingUtils import me.glaremasters.guilds.utils.StringUtils import org.bukkit.Bukkit import org.bukkit.entity.Player import org.bukkit.potion.PotionEffect -import org.bukkit.potion.PotionEffectType import java.util.concurrent.TimeUnit class BuffGUI(private val buffConfig: SettingsManager, private val cooldownHandler: CooldownHandler) { @@ -113,7 +113,7 @@ class BuffGUI(private val buffConfig: SettingsManager, private val cooldownHandl if (!buffConfig.getProperty(GuildBuffSettings.BUFF_STACKING) && !player.activePotionEffects.isEmpty()) { return@setAction } - guild.balance = guild.balance - cost + guild.balance -= cost getBuffEffects(buff.effects).forEach { effect -> guild.addPotion(effect) } @@ -127,12 +127,27 @@ class BuffGUI(private val buffConfig: SettingsManager, private val cooldownHandl private fun getBuffEffects(effects: List): Set { val potions = mutableSetOf() - effects.forEach { - val split = it.split(";") - val type = XPotion.matchXPotion(split[0]).get().potionEffectType ?: PotionEffectType.WATER_BREATHING - val amp = Integer.parseInt(split[1]) - val length = Integer.parseInt(split[2]) - potions.add(PotionEffect(type, (length * 20), amp)) + effects.forEach { rawEffect -> + val split = rawEffect.split(";").map { it.trim() } + if (split.size != 3 || split[0].isEmpty() || split[1].isEmpty() || split[2].isEmpty()) { + LoggingUtils.warn("Invalid guild buff effect configured at guild-buffs.buffs.effects: '$rawEffect'. Expected EFFECT_TYPE;AMPLIFICATION;LENGTH. Skipping effect.") + return@forEach + } + + val type = XPotion.of(split[0]).orElse(null)?.potionEffectType + if (type == null) { + LoggingUtils.warn("Invalid guild buff potion effect configured at guild-buffs.buffs.effects: '${split[0]}'. Skipping effect.") + return@forEach + } + + val amp = split[1].toIntOrNull() + val length = split[2].toIntOrNull() + if (amp == null || amp < 0 || length == null || length <= 0 || length > Int.MAX_VALUE / 20) { + LoggingUtils.warn("Invalid guild buff duration/amplifier configured at guild-buffs.buffs.effects: '$rawEffect'. Skipping effect.") + return@forEach + } + + potions.add(PotionEffect(type, length * 20, amp)) } return potions } diff --git a/src/main/kotlin/me/glaremasters/guilds/listeners/WorldGuardListener.kt b/src/main/kotlin/me/glaremasters/guilds/listeners/WorldGuardListener.kt index 186eb8572..8db1e5c4b 100644 --- a/src/main/kotlin/me/glaremasters/guilds/listeners/WorldGuardListener.kt +++ b/src/main/kotlin/me/glaremasters/guilds/listeners/WorldGuardListener.kt @@ -34,9 +34,7 @@ import org.bukkit.event.player.PlayerInteractEvent import org.codemc.worldguardwrapper.WorldGuardWrapper import org.codemc.worldguardwrapper.flag.WrappedState -class WorldGuardListener(private val guildHandler: GuildHandler) : Listener { - - private val wrapper = WorldGuardWrapper.getInstance() +class WorldGuardListener(private val guildHandler: GuildHandler, private val wrapper: WorldGuardWrapper) : Listener { @EventHandler fun BlockPlaceEvent.onPlace() {