Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>dev.espi</groupId>
<artifactId>protectionstones</artifactId>
<version>2.10.5</version>
<version>2.10.7</version>
<name>ProtectionStones</name>
<description>A grief prevention plugin for Spigot Minecraft servers.</description>
<url>https://github.com/espidev/ProtectionStones</url>
Expand Down Expand Up @@ -207,7 +207,7 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.6-R0.1-SNAPSHOT</version>
<version>1.21.10-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down
22 changes: 18 additions & 4 deletions src/main/java/dev/espi/protectionstones/ListenerClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
157 changes: 133 additions & 24 deletions src/main/java/dev/espi/protectionstones/commands/ArgAdminHelp.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,40 +16,149 @@
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;
import org.bukkit.command.CommandSender;

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;
}
Expand Down
30 changes: 17 additions & 13 deletions src/main/java/dev/espi/protectionstones/commands/ArgFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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(" ");
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -251,7 +255,7 @@ public boolean executeArgument(CommandSender s, String[] args, HashMap<String, S

// /ps flag GUI
if (args.length == 1) return openFlagGUI(p, r, 0);

// go to GUI page
if (args.length == 2) {
if (MiscUtil.isValidInteger(args[1])) {
Expand Down
28 changes: 13 additions & 15 deletions src/main/java/dev/espi/protectionstones/utils/BlockUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,23 @@
import dev.espi.protectionstones.PSProtectBlock;
import dev.espi.protectionstones.ProtectionStones;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Block;
import org.bukkit.block.Skull;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.profile.PlayerProfile;
import org.bukkit.profile.PlayerTextures;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Base64;
import java.util.HashMap;
import java.util.UUID;
import java.util.Base64;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class BlockUtil {
static final int MAX_USERNAME_LENGTH = 16;
Expand Down Expand Up @@ -71,12 +68,13 @@ public static String getProtectBlockType(ItemStack i) {
}

// PLAYER_HEAD:base64
if (ProtectionStones.getBlockOptions("PLAYER_HEAD:" + sm.getOwningPlayer().getUniqueId()) != null) {
return Material.PLAYER_HEAD + ":" + sm.getOwningPlayer().getUniqueId();
PlayerProfile offlineProfile = sm.getOwnerProfile();
if (ProtectionStones.getBlockOptions("PLAYER_HEAD:" +offlineProfile.getUniqueId()) != null) {
return Material.PLAYER_HEAD + ":" +offlineProfile.getUniqueId();
}

// PLAYER_HEAD:name
return Material.PLAYER_HEAD + ":" + sm.getOwningPlayer().getName(); // return name if it doesn't exist
return Material.PLAYER_HEAD + ":" + offlineProfile.getName(); // return name if it doesn't exist
}
return i.getType().toString();
}
Expand All @@ -86,13 +84,13 @@ public static String getProtectBlockType(Block block) {

Skull s = (Skull) block.getState();
if (s.hasOwner() && isOwnedSkullTypeConfigured()) {
OfflinePlayer op = s.getOwningPlayer();
if (ProtectionStones.getBlockOptions("PLAYER_HEAD:" + op.getUniqueId()) != null) {
PlayerProfile offlineProfile = s.getOwnerProfile();
if (ProtectionStones.getBlockOptions("PLAYER_HEAD:" + offlineProfile.getUniqueId()) != null) {
// PLAYER_HEAD:base64
return Material.PLAYER_HEAD + ":" + op.getUniqueId();
return Material.PLAYER_HEAD + ":" + offlineProfile.getUniqueId();
} else {
// PLAYER_HEAD:name
return Material.PLAYER_HEAD + ":" + op.getName(); // return name if doesn't exist
return Material.PLAYER_HEAD + ":" + offlineProfile.getName(); // return name if doesn't exist
}
} else { // PLAYER_HEAD
return Material.PLAYER_HEAD.toString();
Expand Down Expand Up @@ -203,4 +201,4 @@ public static String getUUIDFromBase64PS(PSProtectBlock b) {
// see github issue #126
return new UUID(base64.hashCode(), base64.hashCode()).toString();
}
}
}
Loading