diff --git a/pom.xml b/pom.xml
index 37940957..e0de888d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
4.0.0
dev.espi
protectionstones
- 2.10.5
+ 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.20.6-R0.1-SNAPSHOT
+ 1.21.10-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
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..81481800 100644
--- a/src/main/resources/config.toml
+++ b/src/main/resources/config.toml
@@ -36,6 +36,7 @@ aliases = [
"protectionstones"
]
+
# 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