From 1f185b7c2b5763804ee0e054ff4d69d3885449b5 Mon Sep 17 00:00:00 2001 From: Alexander Noyle Date: Mon, 9 Mar 2026 10:36:26 -0400 Subject: [PATCH] Add bounty increase flow and update head messaging --- .../playerbountiesplus/PlayerBountiesOG.java | 12 + .../command/BountyCommand.java | 13 +- .../command/bounty/BountyAddCmd.java | 371 ++++++++++++++++++ .../command/bounty/BountySetCmd.java | 6 +- .../command/bounty/BountyTopCmd.java | 2 +- .../playerbountiesplus/gui/MainBountyGui.java | 59 +++ .../listener/BountyHeadListener.java | 42 +- .../BountyIncreasePromptListener.java | 97 +++++ .../listener/DeathListener.java | 6 +- src/main/resources/lang/en_us.yml | 10 +- src/main/resources/plugin.yml | 2 + 11 files changed, 608 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyAddCmd.java create mode 100644 src/main/java/com/tcoded/playerbountiesplus/listener/BountyIncreasePromptListener.java diff --git a/src/main/java/com/tcoded/playerbountiesplus/PlayerBountiesOG.java b/src/main/java/com/tcoded/playerbountiesplus/PlayerBountiesOG.java index 61ee343..89f00c0 100644 --- a/src/main/java/com/tcoded/playerbountiesplus/PlayerBountiesOG.java +++ b/src/main/java/com/tcoded/playerbountiesplus/PlayerBountiesOG.java @@ -20,6 +20,7 @@ import com.tcoded.playerbountiesplus.hook.logging.CoreProtectHook; import com.tcoded.playerbountiesplus.hook.currency.EconomyHook; import com.tcoded.playerbountiesplus.hook.team.TeamHook; import com.tcoded.playerbountiesplus.listener.BountyHeadListener; +import com.tcoded.playerbountiesplus.listener.BountyIncreasePromptListener; import com.tcoded.playerbountiesplus.listener.DeathListener; import com.tcoded.playerbountiesplus.listener.GuiProtectionListener; import com.tcoded.playerbountiesplus.manager.BountyDataManager; @@ -65,6 +66,8 @@ public final class PlayerBountiesOG extends JavaPlugin { // CoreProtect API hook. private CoreProtectHook coreProtectHook; + private BountyIncreasePromptListener bountyIncreasePromptListener; + public PlayerBountiesOG() { instance = this; @@ -157,8 +160,11 @@ public final class PlayerBountiesOG extends JavaPlugin { // Listeners. this.getServer().getPluginManager().registerEvents(new DeathListener(this, this.diamondBankAPI, this.luckPerms), this); + this.bountyIncreasePromptListener = new BountyIncreasePromptListener(this); + this.getServer().getPluginManager().registerEvents( new BountyHeadListener(this, this.diamondBankAPI, this.luckPerms, this.coreProtectHook), this); + this.getServer().getPluginManager().registerEvents(this.bountyIncreasePromptListener, this); this.getServer().getPluginManager().registerEvents(new GuiProtectionListener(this), this); final List plugins = ImmutableList.copyOf(this.getServer().getPluginManager().getPlugins()); @@ -230,6 +236,12 @@ public final class PlayerBountiesOG extends JavaPlugin { } + public BountyIncreasePromptListener getBountyIncreasePromptListener() { + + return this.bountyIncreasePromptListener; + + } + // Utilities. private static void findPluginWithQuery(List plugins, String pluginNameQuery, String... excludeStrings) { diff --git a/src/main/java/com/tcoded/playerbountiesplus/command/BountyCommand.java b/src/main/java/com/tcoded/playerbountiesplus/command/BountyCommand.java index 7db7dbb..72d8907 100644 --- a/src/main/java/com/tcoded/playerbountiesplus/command/BountyCommand.java +++ b/src/main/java/com/tcoded/playerbountiesplus/command/BountyCommand.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.Nullable; import com.google.common.collect.Lists; import com.tcoded.playerbountiesplus.PlayerBountiesOG; import com.tcoded.playerbountiesplus.command.bounty.BountyCheckCmd; +import com.tcoded.playerbountiesplus.command.bounty.BountyAddCmd; import com.tcoded.playerbountiesplus.command.bounty.BountySetCmd; import com.tcoded.playerbountiesplus.command.bounty.BountyTopCmd; @@ -69,6 +70,12 @@ public class BountyCommand implements CommandExecutor, TabCompleter { } + case "add" -> { + + return BountyAddCmd.handleCmd(plugin, sender, cmd, cmdName, args); + + } + case "top" -> { return BountyTopCmd.handleCmd(plugin, diamondBankAPI, sender, cmd, cmdName, args); @@ -99,7 +106,7 @@ public class BountyCommand implements CommandExecutor, TabCompleter { if (args.length == 1) { - return Lists.newArrayList("set", "top", "check").stream() + return Lists.newArrayList("set", "add", "top", "check").stream() .filter(action -> StringUtils.startsWith(action, StringUtils.lowerCase(args[0]))) .collect(Collectors.toList()); @@ -112,6 +119,10 @@ public class BountyCommand implements CommandExecutor, TabCompleter { .onTabComplete(sender, args).stream().filter(suggestion -> StringUtils .startsWith(StringUtils.lowerCase(suggestion), StringUtils.lowerCase(args[1]))) .collect(Collectors.toList()); + case "add" -> BountyAddCmd + .onTabComplete(sender, args).stream().filter(suggestion -> StringUtils + .startsWith(StringUtils.lowerCase(suggestion), StringUtils.lowerCase(args[1]))) + .collect(Collectors.toList()); case "check" -> BountyCheckCmd .onTabComplete(sender, args).stream().filter(suggestion -> StringUtils .startsWith(StringUtils.lowerCase(suggestion), StringUtils.lowerCase(args[1]))) diff --git a/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyAddCmd.java b/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyAddCmd.java new file mode 100644 index 0000000..0141c43 --- /dev/null +++ b/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyAddCmd.java @@ -0,0 +1,371 @@ +package com.tcoded.playerbountiesplus.command.bounty; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import com.tcoded.playerbountiesplus.PlayerBountiesOG; +import com.tcoded.playerbountiesplus.manager.BountyDataManager; + +import net.luckperms.api.LuckPerms; +import net.luckperms.api.cacheddata.CachedMetaData; +import net.luckperms.api.model.user.User; +import net.trueog.diamondbankog.DiamondBankException.EconomyDisabledException; +import net.trueog.diamondbankog.DiamondBankException.InsufficientFundsException; +import net.trueog.diamondbankog.DiamondBankException.InvalidPlayerException; +import net.trueog.diamondbankog.DiamondBankException.PlayerNotOnlineException; +import net.trueog.diamondbankog.api.DiamondBankAPIJava; +import net.trueog.utilitiesog.UtilitiesOG; + +public class BountyAddCmd { + + public static boolean handleCmd(PlayerBountiesOG plugin, CommandSender sender, Command cmd, String cmdName, + String[] args) + { + + if (!(sender instanceof Player player)) { + + UtilitiesOG.logToConsole(PlayerBountiesOG.getPrefix(), "&cERROR: Only players can use this command."); + return true; + + } + + if (!sender.hasPermission("playerbountiesplus.command.bounty.add")) { + + final String noPerm = plugin.getLang().getColored("command.no-permission"); + final String noPermDetailed = plugin.getLang().getColored("command.no-permission-detailed") + .replace("{no-permission-msg}", noPerm) + .replace("{permission}", "playerbountiesplus.command.bounty.add"); + UtilitiesOG.trueogMessage(player, noPermDetailed); + + return true; + + } + + if (args.length < 3) { + + UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.missing-args")); + return true; + + } + + final String targetNameArg = args[1]; + final double amount; + try { + + amount = parseAmount(args[2]); + + } catch (NumberFormatException numberFormatException) { + + UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.amount-nan")); + return true; + + } + + final OfflinePlayer target = Bukkit.getOfflinePlayer(targetNameArg); + if (target.getUniqueId() == null) { + + UtilitiesOG.trueogMessage(player, plugin.getLang().getColored("command.bounty.add.player-not-found")); + return true; + + } + + return addBounty(plugin, player, target.getUniqueId(), target.getName(), amount, true); + + } + + public static boolean addBounty(PlayerBountiesOG plugin, Player setter, UUID targetUuid, String targetName, + double parsedAmount, boolean saveData) + { + + final String safeTargetName = StringUtils.defaultIfBlank(targetName, + Bukkit.getOfflinePlayer(targetUuid).getName()); + if (safeTargetName == null || safeTargetName.isBlank()) { + + UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.add.player-not-found")); + return true; + + } + + final DiamondBankAPIJava diamondBankAPI = resolveDiamondBankApi(plugin); + + final double minimum = plugin.getConfig().getDouble("bounty-minimum", 1.0); + if (parsedAmount < minimum) { + + UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.set.under-minimum") + .replace("{minimum}", String.valueOf(minimum))); + return true; + + } + + final double maximum = plugin.getConfig().getDouble("bounty-maximum", 1000000.0); + if (parsedAmount > maximum) { + + UtilitiesOG.trueogMessage(setter, + plugin.getLang().getColored("command.bounty.set.over-maximum").replace("{maximum}", + String.valueOf(maximum))); + return true; + + } + + final long addedShards = diamondBankAPI.diamondsToShards((float) parsedAmount); + if (addedShards <= 0L) { + + UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.set.internal-invalid-value")); + return true; + + } + + if (!chargeSetter(plugin, setter, diamondBankAPI, safeTargetName, addedShards)) { + + return true; + + } + + final BountyDataManager bountyDataManager = plugin.getBountyDataManager(); + final long existingShards = diamondBankAPI.diamondsToShards((float) bountyDataManager.getBounty(targetUuid)); + final long totalShards = existingShards + addedShards; + final double totalBounty = Double.parseDouble(diamondBankAPI.shardsToDiamonds(totalShards)); + + bountyDataManager.setBounty(targetUuid, totalBounty); + + final LuckPerms luckPerms = resolveLuckPerms(plugin); + final String setterDisplay = formatLuckPermsDisplay(luckPerms, setter); + final String targetDisplay = resolveLuckPermsDisplayName(luckPerms, targetUuid, safeTargetName); + final String addedDisplay = diamondBankAPI.shardsToDiamonds(addedShards); + final String totalDisplay = diamondBankAPI.shardsToDiamonds(totalShards); + + UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.add.success") + .replace("{amount}", addedDisplay).replace("{target}", targetDisplay).replace("{total}", totalDisplay)); + + if (plugin.getConfig().getBoolean("bounty-placed-announce", true)) { + + final String announce = plugin.getLang().getColored("command.bounty.add.announce").replace("{amount}", + addedDisplay).replace("{target}", targetDisplay).replace("{total}", totalDisplay) + .replace("{player}", setterDisplay); + + Bukkit.getOnlinePlayers().forEach(player -> UtilitiesOG.trueogMessage(player, PlayerBountiesOG.getPrefix() + + "&a" + announce)); + + } + + if (saveData) { + + bountyDataManager.saveBountiesAsync(); + + } + + return true; + + } + + private static boolean chargeSetter(PlayerBountiesOG plugin, Player setter, DiamondBankAPIJava diamondBankAPI, + String targetName, long addedShards) + { + + try { + + diamondBankAPI.consumeFromPlayer(setter.getUniqueId(), addedShards, + "Player " + setter.getName() + " contributed " + diamondBankAPI.shardsToDiamonds(addedShards) + + " Diamonds toward a bounty on " + targetName + ".", + "Plugin: PlayerBounties-OG"); + + return true; + + } catch (EconomyDisabledException economyDisabledException) { + + PlayerBountiesOG.disableSelf( + "[PlayerBounties-OG] DiamondBank-OG economy disabled: " + economyDisabledException.getMessage()); + return false; + + } catch (InvalidPlayerException invalidPlayerException) { + + plugin.getLogger().warning("Invalid player for consumeFromPlayer: " + setter.getName()); + UtilitiesOG.trueogMessage(setter, + "&cERROR: your player account could not be found by DiamondBank-OG. Contact an administrator!"); + return false; + + } catch (InsufficientFundsException insufficientFundsException) { + + UtilitiesOG.trueogMessage(setter, plugin.getLang().getColored("command.bounty.set.not-enough-money")); + return false; + + } + // TODO: Remove PlayerNotOnlineException catch block after next DiamondBank-OG update. + catch (PlayerNotOnlineException temporaryPlayerNotOnlineError) { + + plugin.getLogger().warning("Player " + setter.getName() + + " not online when attempting to consumeFromPlayer. This error is expected to be removed in the next DiamondBank-OG update."); + temporaryPlayerNotOnlineError.printStackTrace(); + return false; + + } + + } + + private static double parseAmount(String amountInput) { + + if (!amountInput.matches("^\\d+(?:\\.\\d)?$")) { + + throw new NumberFormatException("Invalid amount format"); + + } + + return Double.parseDouble(amountInput); + + } + + private static DiamondBankAPIJava resolveDiamondBankApi(PlayerBountiesOG plugin) { + + final RegisteredServiceProvider provider = plugin.getServer().getServicesManager() + .getRegistration(DiamondBankAPIJava.class); + + if (provider == null) { + + throw new IllegalStateException("DiamondBank-OG API is null"); + + } + + return provider.getProvider(); + + } + + private static LuckPerms resolveLuckPerms(PlayerBountiesOG plugin) { + + final RegisteredServiceProvider provider = plugin.getServer().getServicesManager() + .getRegistration(LuckPerms.class); + + if (provider == null) { + + return null; + + } + + return provider.getProvider(); + + } + + private static String resolveLuckPermsDisplayName(LuckPerms luckPerms, UUID playerId, String playerName) { + + final String safeName = StringUtils.defaultIfBlank(playerName, "Unknown Player"); + if (luckPerms == null) { + + return "&f" + safeName; + + } + + final User user = luckPerms.getUserManager().getUser(playerId); + if (user == null) { + + return "&f" + safeName; + + } + + final CachedMetaData meta = user.getCachedData().getMetaData(); + final String prefix = StringUtils.trim(StringUtils.defaultString(meta.getPrefix()).replace('§', '&')); + final String suffix = StringUtils.trim(StringUtils.defaultString(meta.getSuffix()).replace('§', '&')); + final boolean metaContainsName = containsVisibleName(prefix, safeName) || containsVisibleName(suffix, safeName); + + final StringBuilder out = new StringBuilder(); + if (!prefix.isBlank()) { + + out.append(prefix).append(' '); + + } + + if (!metaContainsName) { + + out.append(safeName); + + } + + if (!suffix.isBlank()) { + + out.append(' ').append(suffix); + + } + + return sanitizeDisplay(out.toString(), safeName); + + } + + private static String formatLuckPermsDisplay(LuckPerms luckPerms, Player player) { + + return resolveLuckPermsDisplayName(luckPerms, player.getUniqueId(), player.getName()); + + } + + private static String sanitizeDisplay(String formatted, String fallbackName) { + + final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:|[&§]r))+$", "") + .replaceAll("\\s*>$", ""); + + if (cleaned.isBlank()) { + + return fallbackName; + + } + + return cleaned; + + } + + private static boolean containsVisibleName(String text, String playerName) { + + if (text == null || playerName == null || playerName.isBlank()) { + + return false; + + } + + final String normalizedText = stripFormatting(text).toLowerCase(Locale.ROOT); + final String normalizedName = playerName.toLowerCase(Locale.ROOT); + + return normalizedText.contains(normalizedName); + + } + + private static String stripFormatting(String input) { + + if (input == null || input.isBlank()) { + + return ""; + + } + + return input.replaceAll("(?i)[&§][0-9A-FK-ORX]", "").replaceAll("<[^>]+>", "").trim(); + + } + + @Nullable + public static List onTabComplete(@NotNull CommandSender sender, @NotNull String[] args) { + + if (args.length == 2) { + + return sender.getServer().getOnlinePlayers().stream().map(Player::getName) + .filter(name -> StringUtils.startsWith(StringUtils.lowerCase(name), StringUtils.lowerCase(args[1]))) + .collect(Collectors.toList()); + + } else if (args.length == 3) { + + return Collections.singletonList(""); + + } + + return Collections.emptyList(); + + } + +} diff --git a/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountySetCmd.java b/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountySetCmd.java index 581712b..4673ba8 100644 --- a/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountySetCmd.java +++ b/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountySetCmd.java @@ -314,17 +314,17 @@ public class BountySetCmd { if (prefix.isBlank()) { - return player.getName(); + return player.getName().replaceAll("\\s*>$", ""); } if (leadingColorCodes.isBlank()) { - return prefix + " " + player.getName(); + return (prefix + " " + player.getName()).replaceAll("\\s*>$", ""); } - return prefix + " " + leadingColorCodes + player.getName(); + return (prefix + " " + leadingColorCodes + player.getName()).replaceAll("\\s*>$", ""); } diff --git a/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyTopCmd.java b/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyTopCmd.java index 92ab4bf..c928271 100644 --- a/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyTopCmd.java +++ b/src/main/java/com/tcoded/playerbountiesplus/command/bounty/BountyTopCmd.java @@ -125,7 +125,7 @@ public class BountyTopCmd { private static String sanitizeDisplay(String formatted, String fallbackName) { final String cleaned = StringUtils.trimToEmpty(formatted).replaceAll("(?i)(?:\\s*(?:|[&§]r))+$", "") - .replaceAll("\\s+>", " >").replaceAll("\\s*>$", ""); + .replaceAll("\\s*>$", ""); if (cleaned.isBlank()) { diff --git a/src/main/java/com/tcoded/playerbountiesplus/gui/MainBountyGui.java b/src/main/java/com/tcoded/playerbountiesplus/gui/MainBountyGui.java index 2b4ef43..1969002 100644 --- a/src/main/java/com/tcoded/playerbountiesplus/gui/MainBountyGui.java +++ b/src/main/java/com/tcoded/playerbountiesplus/gui/MainBountyGui.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.UUID; import java.util.function.Supplier; +import org.apache.commons.lang3.StringUtils; + import org.bukkit.Material; import org.bukkit.entity.Player; @@ -16,6 +18,7 @@ import net.trueog.diamondbankog.api.DiamondBankAPIJava; import net.trueog.gxui.GUIBase; import net.trueog.gxui.GUIButton; import net.trueog.gxui.GUIItem; +import net.trueog.utilitiesog.UtilitiesOG; public class MainBountyGui extends GUIBase { @@ -246,6 +249,8 @@ public class MainBountyGui extends GUIBase { final ArrayList lore = new ArrayList<>(); lore.add("&eBounty: &b" + formatBounty(entry.bountyDiamonds())); + lore.add("&7Click to increase this player's bounty."); + lore.add("&8You will be prompted in chat for the amount."); lore.add(""); lore.add("&6Claiming the bounty will give you a 50% chance of beheading your victim!"); @@ -261,12 +266,66 @@ public class MainBountyGui extends GUIBase { } item.lore(lore); + item.setButton(new GUIButton() + { + + @Override + public boolean leftClick() { + + return promptIncrease(entry); + + } + + @Override + public boolean leftClickShift() { + + return promptIncrease(entry); + + } + + @Override + public boolean rightClick() { + + return promptIncrease(entry); + + } + + @Override + public boolean rightClickShift() { + + return promptIncrease(entry); + + } + + }); item.setPlayErrorSound(false); return item; } + private boolean promptIncrease(BountyGuiEntry entry) { + + if (entry.targetUuid() == null) { + + UtilitiesOG.trueogMessage(viewer, plugin.getLang().getColored("command.bounty.add.player-not-found")); + return true; + + } + + final String targetName = StringUtils.defaultIfBlank(entry.targetName(), "Unknown Player"); + plugin.getBountyIncreasePromptListener().prompt(viewer.getUniqueId(), entry.targetUuid(), targetName); + + final String promptMessage = plugin.getLang().getColored("command.bounty.add.prompt") + .replace("{target}", safeDisplayName(entry.displayName())); + UtilitiesOG.trueogMessage(viewer, promptMessage); + + viewer.closeInventory(); + + return true; + + } + private String formatBounty(double bountyDiamonds) { final long shards = diamondBankAPI.diamondsToShards(bountyDiamonds); diff --git a/src/main/java/com/tcoded/playerbountiesplus/listener/BountyHeadListener.java b/src/main/java/com/tcoded/playerbountiesplus/listener/BountyHeadListener.java index b1ea1dd..fa90e85 100644 --- a/src/main/java/com/tcoded/playerbountiesplus/listener/BountyHeadListener.java +++ b/src/main/java/com/tcoded/playerbountiesplus/listener/BountyHeadListener.java @@ -17,7 +17,9 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemHeldEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.SkullMeta; @@ -184,6 +186,40 @@ public class BountyHeadListener implements Listener { } + @EventHandler(ignoreCancelled = true) + public void onInventoryHover(InventoryClickEvent event) { + + if (!(event.getWhoClicked() instanceof Player player)) { + + return; + + } + + final ItemStack currentItem = event.getCurrentItem(); + if (currentItem == null || !isHeadMaterial(currentItem.getType())) { + + return; + + } + + sendBountyHeadActionbar(player, currentItem.getItemMeta()); + + } + + @EventHandler(ignoreCancelled = true) + public void onHotbarScroll(PlayerItemHeldEvent event) { + + final ItemStack newSlotItem = event.getPlayer().getInventory().getItem(event.getNewSlot()); + if (newSlotItem == null || !isHeadMaterial(newSlotItem.getType())) { + + return; + + } + + sendBountyHeadActionbar(event.getPlayer(), newSlotItem.getItemMeta()); + + } + private void sendBountyHeadActionbar(Player player, ItemMeta itemMeta) { if (itemMeta == null) { @@ -211,14 +247,14 @@ public class BountyHeadListener implements Listener { final UUID uuid = parseUuid(targetUuid); final String playerDisplay = formatLuckPermsDisplay(uuid, targetName); final String diamonds = formatDiamonds(bountyAmount); - player.sendActionBar( - UtilitiesOG.trueogColorize("&cBounty Head: " + playerDisplay + " &7- &b" + diamonds + " &bDiamonds")); + player.sendActionBar(UtilitiesOG.trueogColorize("&c" + playerDisplay + "'s Head &7- &b" + diamonds + + " &bDiamonds")); } private void applyBountyData(SkullMeta meta, String targetName, String targetUuid, double bountyAmount) { - meta.displayName(UtilitiesOG.trueogColorize("&c" + targetName + "'s Bounty Head")); + meta.displayName(UtilitiesOG.trueogColorize("&c" + targetName + "'s Head")); final UUID uuid = parseUuid(targetUuid); final String playerDisplay = formatLuckPermsDisplay(uuid, targetName); diff --git a/src/main/java/com/tcoded/playerbountiesplus/listener/BountyIncreasePromptListener.java b/src/main/java/com/tcoded/playerbountiesplus/listener/BountyIncreasePromptListener.java new file mode 100644 index 0000000..6df9bc2 --- /dev/null +++ b/src/main/java/com/tcoded/playerbountiesplus/listener/BountyIncreasePromptListener.java @@ -0,0 +1,97 @@ +package com.tcoded.playerbountiesplus.listener; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.commons.lang3.StringUtils; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import com.tcoded.playerbountiesplus.PlayerBountiesOG; +import com.tcoded.playerbountiesplus.command.bounty.BountyAddCmd; + +import net.trueog.utilitiesog.UtilitiesOG; + +public class BountyIncreasePromptListener implements Listener { + + private final PlayerBountiesOG plugin; + private final Map pendingPrompts = new ConcurrentHashMap<>(); + + public BountyIncreasePromptListener(PlayerBountiesOG plugin) { + + this.plugin = plugin; + + } + + public void prompt(UUID setterUuid, UUID targetUuid, String targetName) { + + pendingPrompts.put(setterUuid, new PendingIncreasePrompt(targetUuid, targetName)); + + } + + public boolean hasPrompt(UUID setterUuid) { + + return pendingPrompts.containsKey(setterUuid); + + } + + @EventHandler(ignoreCancelled = true) + public void onChat(AsyncPlayerChatEvent event) { + + final PendingIncreasePrompt prompt = pendingPrompts.get(event.getPlayer().getUniqueId()); + if (prompt == null) { + + return; + + } + + event.setCancelled(true); + + final String input = StringUtils.trimToEmpty(event.getMessage()); + if (input.equalsIgnoreCase("cancel")) { + + pendingPrompts.remove(event.getPlayer().getUniqueId()); + UtilitiesOG.trueogMessage(event.getPlayer(), plugin.getLang().getColored("command.bounty.add.cancelled")); + return; + + } + + final double amount; + try { + + if (!input.matches("^\\d+(?:\\.\\d)?$")) { + + throw new NumberFormatException("Invalid amount format"); + + } + + amount = Double.parseDouble(input); + + } catch (NumberFormatException numberFormatException) { + + UtilitiesOG.trueogMessage(event.getPlayer(), plugin.getLang().getColored("command.bounty.add.amount-nan")); + return; + + } + + pendingPrompts.remove(event.getPlayer().getUniqueId()); + plugin.getServer().getScheduler().runTask(plugin, + () -> BountyAddCmd.addBounty(plugin, event.getPlayer(), prompt.targetUuid(), prompt.targetName(), amount, + true)); + + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + + pendingPrompts.remove(event.getPlayer().getUniqueId()); + + } + + private static record PendingIncreasePrompt(UUID targetUuid, String targetName) { + } + +} diff --git a/src/main/java/com/tcoded/playerbountiesplus/listener/DeathListener.java b/src/main/java/com/tcoded/playerbountiesplus/listener/DeathListener.java index 59340c6..0570ae3 100644 --- a/src/main/java/com/tcoded/playerbountiesplus/listener/DeathListener.java +++ b/src/main/java/com/tcoded/playerbountiesplus/listener/DeathListener.java @@ -256,7 +256,7 @@ public class DeathListener implements Listener { } - return out.toString(); + return StringUtils.trim(out.toString()).replaceAll("\\s*>$", ""); } @@ -275,7 +275,7 @@ public class DeathListener implements Listener { final PlayerProfile profile = Bukkit.createProfile(victim.getUniqueId()); headMeta.setPlayerProfile(profile); - headMeta.displayName(UtilitiesOG.trueogColorize("&c" + victim.getName() + "'s Bounty Head")); + headMeta.displayName(UtilitiesOG.trueogColorize("&c" + victim.getName() + "'s Head")); final String bountyDisplay = formatDiamonds(bounty); headMeta.lore(java.util.List.of( Component.text("Target: ", NamedTextColor.GRAY) @@ -400,7 +400,7 @@ public class DeathListener implements Listener { } - return out.toString(); + return StringUtils.trim(out.toString()).replaceAll("\\s*>$", ""); } diff --git a/src/main/resources/lang/en_us.yml b/src/main/resources/lang/en_us.yml index 1f64021..681ef57 100644 --- a/src/main/resources/lang/en_us.yml +++ b/src/main/resources/lang/en_us.yml @@ -36,7 +36,7 @@ command: player-not-found: "&cThat player is not online or doesn't exist!" success: "&a{target} currently has a bounty of {bounty}." bounty: - no-action: "&cYou need to specify an action! /bounty " + no-action: "&cYou need to specify an action! /bounty " invalid-action: "&cThat's not a valid action!" set: missing-args: "&cYou need to specify a player and an amount! /bounty set " @@ -49,6 +49,14 @@ command: success: "&cYou placed a bounty of {bounty} on {target}'s head!" announce: "\nA bounty of {bounty} was placed on {target}'s &ahead by&r {player}!{extra}\n" announce-extra: " (Total: {total})" + add: + missing-args: "&cYou need to specify a player and an amount! /bounty add " + amount-nan: "&cThat's not a valid number!" + player-not-found: "&cThat player could not be found!" + success: "&aYou increased {target}'s bounty by {amount}. Total: {total}." + announce: "\n{player} increased {target}'s bounty by {amount}&a! &7(Total: &b{total}&7)\n" + prompt: "&eType how many diamonds to add to {target}'s bounty in chat. Type &ccancel &eto abort." + cancelled: "&cBounty increase cancelled." check: no-player-specified: "&cYou need to specify a player! /bounty check " player-not-found: "&cThat player is not online or doesn't exist!" diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 2a12541..ac1c69f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -36,5 +36,7 @@ permissions: playerbountiesplus.command.admin.bounty.delete: {} playerbountiesplus.command.bounty.set: default: true + playerbountiesplus.command.bounty.add: + default: true playerbountiesplus.event.claim: default: true -- 2.47.3