Mirror von
https://github.com/St3venAU/ArmorStandTools.git
synchronisiert 2024-12-28 04:20:08 +01:00
Prevent configured armor stand items and shulker boxes getting into a new configured armor stand item causing something like a book ban, properly escape armor stand name to prevent NBT tag injection
Dieser Commit ist enthalten in:
Ursprung
6acd7b52d0
Commit
0651dfdc18
@ -10,10 +10,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.*;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@ -263,6 +260,11 @@ class ArmorStandGUI implements Listener {
|
||||
break;
|
||||
case ITEM:
|
||||
ItemStack stack = Utils.createArmorStandItem(as);
|
||||
if(stack == null){
|
||||
p.sendMessage(ChatColor.RED + Config.armorStandItemFail);
|
||||
p.closeInventory();
|
||||
break;
|
||||
}
|
||||
HashMap<Integer, ItemStack> leftover = p.getInventory().addItem(stack);
|
||||
if(leftover.containsKey(0)){ // if inventory full, drop item on ground and tell the player
|
||||
p.getWorld().dropItem(as.getLocation(), leftover.get(0)).setVelocity(new Vector(0, 0.2d, 0));
|
||||
|
@ -74,7 +74,8 @@ class Config {
|
||||
listAssignedCmds, addACmd, removeACmd, cmdHelp,
|
||||
enterName, enterName2, enterSkull, inputTimeout,
|
||||
nameSet, nameRemoved, skullSet, enterNameC,
|
||||
enterNameC2, enterSkullC, invFullForArmorStandItem;
|
||||
enterNameC2, enterSkullC, invFullForArmorStandItem,
|
||||
armorStandItemFail;
|
||||
|
||||
static void reload() {
|
||||
reloadMainConfig();
|
||||
@ -262,6 +263,7 @@ class Config {
|
||||
enterNameC2 = languageConfig.getString("enterNameC2");
|
||||
enterSkullC = languageConfig.getString("enterSkullC");
|
||||
invFullForArmorStandItem = languageConfig.getString("invFullForArmorStandItem");
|
||||
armorStandItemFail = languageConfig.getString("armorStandItemFail");
|
||||
}
|
||||
|
||||
private static ItemStack getItemStack(String configPath) {
|
||||
|
@ -5,11 +5,14 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ItemStackReflections {
|
||||
private final static Method AS_NMS_COPY;
|
||||
private final static Method GET_TAG;
|
||||
private final static Method MODIFY_ITEM_STACK;
|
||||
private final static Method CONTAINS;
|
||||
private final static Object CRAFT_MAGIC_NUMBERS;
|
||||
private static final String SERVER_VERSION;
|
||||
|
||||
@ -23,33 +26,45 @@ public class ItemStackReflections {
|
||||
Class<?> mcItemStack = Class.forName("net.minecraft.world.item.ItemStack");
|
||||
Class<?> bukkitItemStack = Class.forName("org.bukkit.craftbukkit." + SERVER_VERSION + ".inventory.CraftItemStack");
|
||||
Class<?> craftMagicNumbers = Class.forName("org.bukkit.craftbukkit." + SERVER_VERSION + ".util.CraftMagicNumbers");
|
||||
Class<?> nbtTagCompound = Class.forName("net.minecraft.nbt.NBTTagCompound");
|
||||
AS_NMS_COPY = bukkitItemStack.getMethod("asNMSCopy", ItemStack.class);
|
||||
GET_TAG = mcItemStack.getDeclaredMethod("getTagClone");
|
||||
GET_TAG.setAccessible(true);
|
||||
MODIFY_ITEM_STACK = craftMagicNumbers.getDeclaredMethod("modifyItemStack", ItemStack.class, String.class);
|
||||
CRAFT_MAGIC_NUMBERS = craftMagicNumbers.getField("INSTANCE").get(null);
|
||||
Class<?>[] parameters = new Class[]{String.class, int.class};
|
||||
CONTAINS = Arrays.stream(nbtTagCompound.getDeclaredMethods()).filter(m ->
|
||||
m.getReturnType() == boolean.class && Arrays.equals(m.getParameterTypes(), parameters)).findAny().orElseThrow();
|
||||
} catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// CREDIT: This function is based on the MiniNBT library: https://github.com/I-Al-Istannen/MiniNBT
|
||||
public static String itemNBTToString(ItemStack item){
|
||||
Object nmsItem;
|
||||
try {
|
||||
nmsItem = AS_NMS_COPY.invoke(null, item);
|
||||
Object tag = getItemNBT(item);
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
return tag.toString();
|
||||
}
|
||||
|
||||
public static Object getItemNBT(ItemStack item){
|
||||
try {
|
||||
Object nmsItem = AS_NMS_COPY.invoke(null, item);
|
||||
if (nmsItem == null) {
|
||||
throw new NullPointerException("Unable to find a nms item clone for " + item);
|
||||
}
|
||||
return GET_TAG.invoke(nmsItem);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
Object tag = GET_TAG.invoke(nmsItem);
|
||||
|
||||
if (tag == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return tag.toString();
|
||||
public static boolean containsEntityTag(ItemStack itemStack){
|
||||
Object tag = getItemNBT(itemStack);
|
||||
if (tag == null) return false;
|
||||
try {
|
||||
return (Boolean) CONTAINS.invoke(tag, "EntityTag", 10/*CompoundTag*/);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -4,15 +4,14 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.CommandBlock;
|
||||
import org.bukkit.block.ShulkerBox;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
@ -200,17 +199,26 @@ class Utils {
|
||||
}
|
||||
|
||||
static String quote(String s) {
|
||||
return "\"\\\"" + s + "\\\"\"";
|
||||
return "\"\\\"" +
|
||||
s.replace("\\", "\\\\\\\\").replace("\"", "\\\\\\\"") // escape " and \
|
||||
+ "\\\"\"";
|
||||
}
|
||||
|
||||
static ItemStack createArmorStandItem(ArmorStand as) {
|
||||
EntityEquipment equipment = as.getEquipment();
|
||||
if(equipment != null){
|
||||
for(EquipmentSlot slot : EquipmentSlot.values()){
|
||||
if(canArmorStandItemContain(equipment.getItem(slot))) return null;
|
||||
}
|
||||
}
|
||||
ItemStack armorStand = new ItemStack(Material.ARMOR_STAND);
|
||||
ItemStackReflections.setItemNBTFromString(armorStand, "{HideFlags:1,EntityTag:" + createEntityTag(as) + "}");
|
||||
ItemStackReflections.setItemNBTFromString(armorStand, "{EntityTag:" + createEntityTag(as) + "}");
|
||||
ItemMeta meta = armorStand.getItemMeta();
|
||||
if(meta != null){
|
||||
meta.setLore(createItemLore(as));
|
||||
meta.setDisplayName(Config.configuredArmorStand);
|
||||
meta.addEnchant(Enchantment.DURABILITY, 1, true);
|
||||
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||
}
|
||||
armorStand.setItemMeta(meta);
|
||||
return armorStand;
|
||||
@ -386,4 +394,13 @@ class Utils {
|
||||
clone.setMetadata("clone", new FixedMetadataValue(AST.plugin, true));
|
||||
return clone;
|
||||
}
|
||||
|
||||
static boolean isConfiguredArmorStandItem(ItemStack item){
|
||||
return item.getType() == Material.ARMOR_STAND && ItemStackReflections.containsEntityTag(item);
|
||||
}
|
||||
|
||||
static boolean canArmorStandItemContain(ItemStack item){
|
||||
return !isConfiguredArmorStandItem (item) &&
|
||||
!(item.getItemMeta() instanceof BlockStateMeta meta && meta.getBlockState() instanceof ShulkerBox);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ wgNoPerm: 'No permission to alter an armor stand in this region'
|
||||
noCommandPerm: 'You do not have permission to use this command'
|
||||
armorStand: 'Armor Stand'
|
||||
none: 'None'
|
||||
guiInUse: 'This armor stands GUI is in use'
|
||||
guiInUse: "This armor stand's GUI is in use"
|
||||
# New since v2.4.0:
|
||||
noASNearBy: 'No armor stand found near by'
|
||||
closestAS: 'Closest armor stand'
|
||||
@ -115,7 +115,8 @@ enterNameC: 'To set armor stand name'
|
||||
enterNameC2: 'Or to remove the name'
|
||||
enterSkullC: 'To set MC username for skull'
|
||||
#New since v4.4.4
|
||||
invFullForArmorStandItem: 'Your inventory is full! The item was dropped at the armor stand.'
|
||||
invFullForArmorStandItem: 'Your inventory is full! The item was dropped at the armor stand'
|
||||
armorStandItemFail: "Armor stand can't be turned into an item because it contains disallowed items"
|
||||
#############################
|
||||
# Tool names & descriptions #
|
||||
#############################
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren