From d1fe2936f02dce1df956a1f221cbb692b7697c9b Mon Sep 17 00:00:00 2001 From: Jerzean Date: Mon, 22 Sep 2025 23:51:40 -0400 Subject: [PATCH 1/4] crafter fix/support bump spigot version(its required until we can find away to add sub 1.21.3 back) --- pom.xml | 4 ++-- .../espi/protectionstones/ListenerClass.java | 22 +++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 37940957..b6e32230 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 dev.espi protectionstones - 2.10.5 + 2.10.6 ProtectionStones A grief prevention plugin for Spigot Minecraft servers. https://github.com/espidev/ProtectionStones @@ -207,7 +207,7 @@ org.spigotmc spigot-api - 1.20.6-R0.1-SNAPSHOT + 1.21.3-R0.1-SNAPSHOT provided diff --git a/src/main/java/dev/espi/protectionstones/ListenerClass.java b/src/main/java/dev/espi/protectionstones/ListenerClass.java index 783de998..3738b688 100644 --- a/src/main/java/dev/espi/protectionstones/ListenerClass.java +++ b/src/main/java/dev/espi/protectionstones/ListenerClass.java @@ -33,10 +33,7 @@ import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.Furnace; +import org.bukkit.block.*; import org.bukkit.command.CommandSender; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; @@ -53,6 +50,7 @@ import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import java.util.List; @@ -307,6 +305,22 @@ public void onPrepareItemCraft(PrepareItemCraftEvent e) { } } + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onCrafter(CrafterCraftEvent e) { + Block block = e.getBlock(); + BlockState state = block.getState(); + if (block.getType() != Material.CRAFTER) return; + if (!(state instanceof Container container)) return; + Inventory inv = container.getInventory(); + for (ItemStack item : inv.getContents()) { + if (item == null) continue; + PSProtectBlock options = ProtectionStones.getBlockOptions(item); + if (options != null && !options.allowUseInCrafting) { + e.setCancelled(true); + e.setResult(new ItemStack(Material.AIR)); + } + } + } // -=-=-=- disable grindstone inventory to prevent infinite exp exploit with enchanted_effect option -=-=-=- // see https://github.com/espidev/ProtectionStones/issues/324 From 46dd6bf702bc4658e2eed1ebc0d8c83d81079500 Mon Sep 17 00:00:00 2001 From: Jerzean Date: Thu, 29 Jan 2026 12:43:48 -0500 Subject: [PATCH 2/4] update ps view to be more vis, Fix player head issues --- .../commands/ArgAdminHelp.java | 157 +++++++++++++++--- .../protectionstones/commands/ArgFlag.java | 30 ++-- .../protectionstones/utils/BlockUtil.java | 28 ++-- .../protectionstones/utils/ParticlesUtil.java | 19 ++- src/main/resources/config.toml | 4 + 5 files changed, 184 insertions(+), 54 deletions(-) diff --git a/src/main/java/dev/espi/protectionstones/commands/ArgAdminHelp.java b/src/main/java/dev/espi/protectionstones/commands/ArgAdminHelp.java index c224df2b..01856f96 100644 --- a/src/main/java/dev/espi/protectionstones/commands/ArgAdminHelp.java +++ b/src/main/java/dev/espi/protectionstones/commands/ArgAdminHelp.java @@ -16,7 +16,8 @@ package dev.espi.protectionstones.commands; import dev.espi.protectionstones.ProtectionStones; -import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; @@ -24,32 +25,140 @@ public class ArgAdminHelp { - private static void send(CommandSender p, String text, String info) { - TextComponent tc = new TextComponent(text); - tc.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(info).create())); - p.spigot().sendMessage(tc); + private static void send(CommandSender p, String text, String info, String clickCommand, boolean run) { + // Create the main text component from legacy text. + BaseComponent[] mainComponents = TextComponent.fromLegacyText(text); + TextComponent mainText = new TextComponent(""); + for (BaseComponent component : mainComponents) { + mainText.addExtra(component); + } + + // Create the hover event from the info text, add click event after + BaseComponent[] hoverComponents = TextComponent.fromLegacyText(info); + mainText.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverComponents)); + //toggle for running on mouse click, currently disabled + if (run) { + mainText.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, ChatColor.stripColor(clickCommand))); + } else { + mainText.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, ChatColor.stripColor(clickCommand))); + } + + // Send the assembled message. + p.spigot().sendMessage(mainText); } static boolean argumentAdminHelp(CommandSender p, String[] args) { - String bc = "/" + ProtectionStones.getInstance().getConfigOptions().base_command; - - p.sendMessage(ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "=====" + ChatColor.RESET + " PS Admin Help " + ChatColor.DARK_GRAY + ChatColor.STRIKETHROUGH + "=====\n" + ChatColor.AQUA + "> " + ChatColor.GRAY + "/ps admin help"); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin version", "Show the version number of the plugin."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin hide", "Hide all of the protection stone blocks in the world you are in."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin unhide", "Unhide all of the protection stone blocks in the world you are in."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin cleanup remove [days] [-t typealias (optional)] [world (console)]", "Remove inactive players that haven't joined within the last [days] days from protected regions in the world you are in (or specified). Then, remove any regions with no owners left."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin cleanup disown [days] [-t typealias (optional)] [world (console)]", "Remove inactive players that haven't joined within the last [days] days from protected regions in the world you are in (or specified)."); - send(p, ArgAdmin.getFlagHelp(), "Set a flag for all protection stone regions in a world."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin lastlogon [player]", "Get the last time a player logged on."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin lastlogons", "List all of the last logons of each player."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin stats [player (optional)]", "Show some statistics of the plugin."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin recreate", "Recreate all PS regions using radius set in config."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin debug", "Toggles debug mode."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin settaxautopayers", "Add a tax autopayer for every region on the server that does not have one."); - send(p, ArgAdmin.getForceMergeHelp(), "Merge overlapping PS regions together if they have the same owners, members and flags."); - send(p, ArgAdmin.getChangeBlockHelp(), "Change all of the PS blocks and regions in a world to a different block. Both blocks must be configured in config."); - send(p, ArgAdmin.getChangeRegionTypeHelp(), "Change the internal type of all PS regions of a certain type. Useful for error correction."); - send(p, ChatColor.AQUA + "> " + ChatColor.GRAY + bc + " admin fixregions", "Use this command to recalculate block types for PS regions in a world."); + String baseCommand = ProtectionStones.getInstance().getConfigOptions().base_command; + String bc = "/" + baseCommand; + String tx = ChatColor.AQUA + "> " + ChatColor.GRAY + "/" + bc; + + p.sendMessage(ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "===============" + + ChatColor.RESET + " PS Admin Help " + + ChatColor.DARK_GRAY + ChatColor.STRIKETHROUGH + "===============\n"); + + send(p, + tx + " admin version", + "Show the version number of the plugin.\n\n" + bc + " admin version", + baseCommand + " admin version", + false); + + send(p, + tx + " admin hide", + "Hide all of the protection stone blocks in the world you are in.\n\n" + bc + " admin hide", + bc + " admin hide", + false); + + send(p, + tx + " admin unhide", + "Unhide all of the protection stone blocks in the world you are in.\n\n" + bc + " admin unhide", + bc + " admin unhide", + false); + + send(p, + tx + " admin cleanup remove", + "Remove inactive players that haven't joined within the last [days] days from protected regions in the world you are in (or specified). Then, remove any regions with no owners left.\n\n" + + bc + " admin cleanup remove [days] [-t typealias (optional)] [world (console)]", + bc + " admin cleanup remove", + false); + + send(p, + tx + " admin cleanup disown", + "Remove inactive players that haven't joined within the last [days] days from protected regions in the world you are in (or specified).\n\n" + + bc + " admin cleanup disown", + bc + " admin cleanup disown", + false); + + send(p, + tx + " admin flag", + "Set a flag for all protection stone regions in a world.\n\n" + + bc + " admin flag [world] [flagname] [value|null|default]", + bc + " admin flag [world] [flagname] [value|null|default]", + false); + + send(p, + tx + " admin lastlogon", + "Get the last time a player logged on.\n\n" + bc + " admin lastlogon [player]", + bc + " admin lastlogon", + false); + + send(p, + tx + " admin lastlogons", + "List all of the last logons of each player.\n\n" + bc + " admin lastlogons", + bc + " admin lastlogons", + false); + + send(p, + tx + " admin stats", + "Show some statistics of the plugin.\n\n" + bc + " admin stats [player (optional)]", + bc + " admin stats", + false); + + send(p, + tx + " admin recreate", + "Recreate all PS regions using radius set in config.\n\n" + bc + " admin recreate", + bc + " admin recreate", + false); + + send(p, + tx + " admin debug", + "Toggle debug mode.\n\n" + bc + " admin debug", + bc + " admin debug", + false); + + send(p, + tx + " admin settaxautopayers", + "Add a tax autopayer for every region on the server that does not have one.\n\n" + bc + " admin settaxautopayers", + bc + " admin settaxautopayers", + false); + + send(p, + tx + " admin forcemerge", + "Merge overlapping PS regions together if they have the same owners, members and flags.\n\n" + + bc + " admin forcemerge [world]", + bc + " admin forcemerge [world]", + false); + + send(p, + tx + " admin changeblock", + "Change all of the PS blocks and regions in a world to a different block. Both blocks must be configured in config.\n\n" + + bc + " admin changeblock [world] [oldtypealias] [newtypealias]", + bc + " admin changeblock [world] [oldtypealias] [newtypealias]", + false); + + send(p, + tx + " admin changeregiontype", + "Change the internal type of all PS regions of a certain type. Useful for error correction.\n\n" + + bc + " admin changeregiontype [world] [oldtype] [newtype]", + bc + " admin changeregiontype [world] [oldtype] [newtype]", + false); + + send(p, + tx + " admin fixregions", + "Use this command to recalculate block types for PS regions in a world.\n\n" + bc + " admin fixregions", + bc + " admin fixregions", + false); + //add footer since it was missing + p.sendMessage(ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "============================================="); return true; } diff --git a/src/main/java/dev/espi/protectionstones/commands/ArgFlag.java b/src/main/java/dev/espi/protectionstones/commands/ArgFlag.java index 829bdad2..2b95301d 100644 --- a/src/main/java/dev/espi/protectionstones/commands/ArgFlag.java +++ b/src/main/java/dev/espi/protectionstones/commands/ArgFlag.java @@ -118,8 +118,8 @@ private boolean openFlagGUI(Player p, PSRegion r, int page) { } // add line based on flag type + boolean isGroupValueAll = groupfValue.equalsIgnoreCase("all") || groupfValue.isEmpty();; if (f instanceof StateFlag) { // allow/deny - boolean isGroupValueAll = groupfValue.equalsIgnoreCase("all") || groupfValue.isEmpty(); TextComponent allow = new TextComponent((fValue == StateFlag.State.ALLOW ? ChatColor.WHITE : ChatColor.DARK_GRAY) + "Allow"), deny = new TextComponent((fValue == StateFlag.State.DENY ? ChatColor.WHITE : ChatColor.DARK_GRAY) + "Deny"); @@ -138,14 +138,6 @@ private boolean openFlagGUI(Player p, PSRegion r, int page) { deny.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, suggestedCommand + flagGroup + page + ":" + flag + " deny")); } - // HACK: Prevent pvp flag value from being changed to none/null, if it is set to a value with the group flag set to all - if (flag.equalsIgnoreCase("pvp") && isGroupValueAll) { - if (fValue == StateFlag.State.DENY) { - deny.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(PSL.FLAG_PREVENT_EXPLOIT_HOVER.msg()).create())); - } else if (fValue == StateFlag.State.ALLOW) { - allow.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(PSL.FLAG_PREVENT_EXPLOIT_HOVER.msg()).create())); - } - } flagLine.addExtra(allow); flagLine.addExtra(" "); @@ -193,15 +185,27 @@ private boolean openFlagGUI(Player p, PSRegion r, int page) { // set hover and click task for flag group BaseComponent[] hover; - if (fValue == null) { + // HACK: Prevent pvp flag value from being changed to none/null + // Special handling for "pvp" flag with "all" group, disabling interaction. + if (flag.equalsIgnoreCase("pvp") && isGroupValueAll) { + hover = new ComponentBuilder(PSL.FLAG_PREVENT_EXPLOIT_HOVER.msg()).create(); + // Remove click action to fully disable changing this group. + groupChange.setClickEvent(null); + } else if (fValue == null) { hover = new ComponentBuilder(PSL.FLAG_GUI_HOVER_CHANGE_GROUP_NULL.msg()).create(); } else { hover = new ComponentBuilder(PSL.FLAG_GUI_HOVER_CHANGE_GROUP.msg().replace("%group%", nextGroup)).create(); } - if (!nextGroup.equals(groupfValue)) { // only display hover message if the group is not the same + + // Always set hover if the flag is pvp and group is "all" + if (flag.equalsIgnoreCase("pvp") && groupfValue.equalsIgnoreCase("all")) { + hover = new ComponentBuilder(PSL.FLAG_PREVENT_EXPLOIT_HOVER.msg()).create(); groupChange.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hover)); + groupChange.setClickEvent(null); // Disable click event explicitly + } else if (!nextGroup.equals(groupfValue)) { + groupChange.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hover)); + groupChange.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, suggestedCommand + "-g " + nextGroup + " " + page + ":" + flag + " " + fValue)); } - groupChange.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, suggestedCommand + "-g " + nextGroup + " " + page + ":" + flag + " " + fValue)); flagLine.addExtra(groupChange); // send message @@ -251,7 +255,7 @@ public boolean executeArgument(CommandSender s, String[] args, HashMap { - if (p.isOnline()) p.spawnParticle(Particle.DUST, l, 1, d); - }, i*20); + if (!p.isOnline()) return; + + // Stronger "glow marker" burst + p.spawnParticle(Particle.DUST, l, + 2, // count (was 1) + 0.10, 0.15, 0.10, // offset/spread (x,y,z) + 0.0, + d + ); + + p.spawnParticle(Particle.GLOW, l, + 2, + 0.05, 0.08, 0.05, + 0.0 + ); + + }, i * 20L); } } } diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index 539f62a7..416fe8b8 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -36,6 +36,10 @@ aliases = [ "protectionstones" ] +# PS View Particle type +# there are three options ( Redstone, Glow, EndRod ) +ps_view_particle = "Redstone" + # Whether or not to drop items on the ground if the inventory is full (ex. during /ps unclaim) # If set to false, the event will be prevented from happening, and say that inventory is full drop_item_when_inventory_full = true From caf0fffa398727190257760bac56f1e5c594790e Mon Sep 17 00:00:00 2001 From: Jerzean Date: Thu, 29 Jan 2026 12:44:06 -0500 Subject: [PATCH 3/4] update ps view to be more vis, Fix player head issues --- src/main/resources/config.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/resources/config.toml b/src/main/resources/config.toml index 416fe8b8..81481800 100644 --- a/src/main/resources/config.toml +++ b/src/main/resources/config.toml @@ -36,9 +36,6 @@ aliases = [ "protectionstones" ] -# PS View Particle type -# there are three options ( Redstone, Glow, EndRod ) -ps_view_particle = "Redstone" # Whether or not to drop items on the ground if the inventory is full (ex. during /ps unclaim) # If set to false, the event will be prevented from happening, and say that inventory is full From 82c9a696161c9a28d8818f2d054dfad1cc421126 Mon Sep 17 00:00:00 2001 From: Jerzean Date: Thu, 29 Jan 2026 12:56:54 -0500 Subject: [PATCH 4/4] update ps view to be more vis, Fix player head issues --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b6e32230..e0de888d 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 dev.espi protectionstones - 2.10.6 + 2.10.7 ProtectionStones A grief prevention plugin for Spigot Minecraft servers. https://github.com/espidev/ProtectionStones @@ -207,7 +207,7 @@ org.spigotmc spigot-api - 1.21.3-R0.1-SNAPSHOT + 1.21.10-R0.1-SNAPSHOT provided