From 9ec827f55fa13a1a3110b6fe1c5a5f81d142144e Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sat, 6 Jan 2024 15:07:59 +0100 Subject: [PATCH] Fixup NamespacedKey parsing --- ...empty-String-in-NamespacedKey.fromSt.patch | 40 ++++++ ...Fix-Bukkit-NamespacedKey-shenanigans.patch | 45 ------- .../Fixup-ResourceLocation-handling.patch | 124 ++++++++++++++++++ ...definitions-of-trim-material-pattern.patch | 19 --- ...Suppress-Item-Meta-Validation-Checks.patch | 86 ------------ 5 files changed, 164 insertions(+), 150 deletions(-) create mode 100644 patches/api/Return-null-for-empty-String-in-NamespacedKey.fromSt.patch delete mode 100644 patches/server/Fix-Bukkit-NamespacedKey-shenanigans.patch create mode 100644 patches/server/Fixup-ResourceLocation-handling.patch delete mode 100644 patches/server/Ignore-inline-definitions-of-trim-material-pattern.patch delete mode 100644 patches/server/Suppress-Item-Meta-Validation-Checks.patch diff --git a/patches/api/Return-null-for-empty-String-in-NamespacedKey.fromSt.patch b/patches/api/Return-null-for-empty-String-in-NamespacedKey.fromSt.patch new file mode 100644 index 0000000000..4c8daeb08c --- /dev/null +++ b/patches/api/Return-null-for-empty-String-in-NamespacedKey.fromSt.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sat, 6 Jan 2024 14:18:58 +0100 +Subject: [PATCH] Return null for empty String in NamespacedKey.fromString + + +diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/NamespacedKey.java ++++ b/src/main/java/org/bukkit/NamespacedKey.java +@@ -0,0 +0,0 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key, com.des + this.namespace = namespace; + this.key = key; + +- String string = toString(); +- Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters", string); + } + + /** +@@ -0,0 +0,0 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key, com.des + Preconditions.checkArgument(isValidNamespace(this.namespace), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace); + Preconditions.checkArgument(isValidKey(this.key), "Invalid key. Must be [a-z0-9/._-]: %s", this.key); + +- String string = toString(); +- Preconditions.checkArgument(string.length() < 256, "NamespacedKey must be less than 256 characters (%s)", string); + } + + @NotNull +@@ -0,0 +0,0 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key, com.des + */ + @Nullable + public static NamespacedKey fromString(@NotNull String string, @Nullable Plugin defaultNamespace) { +- Preconditions.checkArgument(string != null && !string.isEmpty(), "Input string must not be empty or null"); ++ // Paper - Return null for empty string ++ Preconditions.checkArgument(string != null, "Input string must not be null"); ++ if (string.isEmpty()) return null; ++ // Paper end - Return null for empty string + + String[] components = string.split(":", 3); + if (components.length > 2) { diff --git a/patches/server/Fix-Bukkit-NamespacedKey-shenanigans.patch b/patches/server/Fix-Bukkit-NamespacedKey-shenanigans.patch deleted file mode 100644 index 6e29047208..0000000000 --- a/patches/server/Fix-Bukkit-NamespacedKey-shenanigans.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Nassim Jahnke -Date: Sun, 24 Oct 2021 15:49:35 +0200 -Subject: [PATCH] Fix Bukkit NamespacedKey shenanigans - - -diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java -+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java -@@ -0,0 +0,0 @@ public class PaperContainerEntityLootableInventory implements PaperLootableEntit - - @Override - public org.bukkit.loot.LootTable getLootTable() { -- return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null; -+ return entity.getLootTable() != null && !entity.getLootTable().getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null; - } - - @Override -diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java -+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java -@@ -0,0 +0,0 @@ public class PaperTileEntityLootableInventory implements PaperLootableBlockInven - - @Override - public org.bukkit.loot.LootTable getLootTable() { -- return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null; -+ return tileEntityLootable.lootTable != null && !tileEntityLootable.lootTable.getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null; - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java -@@ -0,0 +0,0 @@ public final class CraftNamespacedKey { - return null; - } - ResourceLocation minecraft = ResourceLocation.tryParse(string); -- return (minecraft == null) ? null : CraftNamespacedKey.fromMinecraft(minecraft); -+ return (minecraft == null || minecraft.getPath().isEmpty()) ? null : CraftNamespacedKey.fromMinecraft(minecraft); // Paper - Bukkit's parser does not match Vanilla for empty paths - } - - public static NamespacedKey fromString(String string) { diff --git a/patches/server/Fixup-ResourceLocation-handling.patch b/patches/server/Fixup-ResourceLocation-handling.patch new file mode 100644 index 0000000000..0b7eb912e0 --- /dev/null +++ b/patches/server/Fixup-ResourceLocation-handling.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nassim Jahnke +Date: Sat, 6 Jan 2024 14:31:00 +0100 +Subject: [PATCH] Fixup ResourceLocation handling + + +diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java ++++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java +@@ -0,0 +0,0 @@ public class PaperContainerEntityLootableInventory implements PaperLootableEntit + + @Override + public org.bukkit.loot.LootTable getLootTable() { +- return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null; ++ return entity.getLootTable() != null && !entity.getLootTable().getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null; + } + + @Override +diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java ++++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java +@@ -0,0 +0,0 @@ public class PaperTileEntityLootableInventory implements PaperLootableBlockInven + + @Override + public org.bukkit.loot.LootTable getLootTable() { +- return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null; ++ return tileEntityLootable.lootTable != null && !tileEntityLootable.lootTable.getPath().isEmpty() ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null; + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java ++++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttribute.java +@@ -0,0 +0,0 @@ public class CraftAttribute { + public static Attribute stringToBukkit(String bukkit) { + Preconditions.checkArgument(bukkit != null); + +- return Registry.ATTRIBUTE.get(NamespacedKey.fromString(bukkit)); ++ // Paper start - Fixup NamespacedKey handling ++ final NamespacedKey key = NamespacedKey.fromString(bukkit); ++ return key != null ? Registry.ATTRIBUTE.get(key) : null; ++ // Paper end - Fixup NamespacedKey handling + } + + public static net.minecraft.world.entity.ai.attributes.Attribute bukkitToMinecraft(Attribute bukkit) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +@@ -0,0 +0,0 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { + if (tag.contains(CraftMetaArmor.TRIM.NBT)) { + CompoundTag trimCompound = tag.getCompound(CraftMetaArmor.TRIM.NBT); + +- if (trimCompound.contains(CraftMetaArmor.TRIM_MATERIAL.NBT) && trimCompound.contains(CraftMetaArmor.TRIM_PATTERN.NBT)) { +- TrimMaterial trimMaterial = Registry.TRIM_MATERIAL.get(NamespacedKey.fromString(trimCompound.getString(CraftMetaArmor.TRIM_MATERIAL.NBT))); +- TrimPattern trimPattern = Registry.TRIM_PATTERN.get(NamespacedKey.fromString(trimCompound.getString(CraftMetaArmor.TRIM_PATTERN.NBT))); ++ // Paper start - Fixup NamedspacedKey handling ++ if (trimCompound.contains(CraftMetaArmor.TRIM_MATERIAL.NBT, net.minecraft.nbt.Tag.TAG_STRING) && trimCompound.contains(CraftMetaArmor.TRIM_PATTERN.NBT, net.minecraft.nbt.Tag.TAG_STRING)) { // TODO Can also be inlined in a compound tag ++ TrimMaterial trimMaterial = registryEntry(Registry.TRIM_MATERIAL, trimCompound.getString(TRIM_MATERIAL.NBT)); ++ TrimPattern trimPattern = registryEntry(Registry.TRIM_PATTERN, trimCompound.getString(TRIM_PATTERN.NBT)); + +- this.trim = new ArmorTrim(trimMaterial, trimPattern); ++ this.trim = trimMaterial != null && trimPattern != null ? new ArmorTrim(trimMaterial, trimPattern) : null; ++ // Paper end - Fixup NamedspacedKey handling + } + } + } ++ // Paper start - Fixup NamedspacedKey handling ++ private T registryEntry(final Registry registry, final String value) { ++ final NamespacedKey key = NamespacedKey.fromString(value); ++ return key != null ? registry.get(key) : null; ++ } ++ // Paper end - Fixup NamedspacedKey handling + + CraftMetaArmor(Map map) { + super(map); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +@@ -0,0 +0,0 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst + + if (tag.contains(CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.NBT)) { + String string = tag.getString(CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.NBT); +- this.instrument = Registry.INSTRUMENT.get(NamespacedKey.fromString(string)); ++ // Paper start - Fixup NamespacedKey handling ++ final NamespacedKey key = NamespacedKey.fromString(string); ++ this.instrument = key != null ? Registry.INSTRUMENT.get(key) : null; ++ // Paper end - Fixup NamespacedKey handling + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java ++++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionType.java +@@ -0,0 +0,0 @@ public class CraftPotionType implements PotionType.InternalPotionData { + public static PotionType stringToBukkit(String string) { + Preconditions.checkArgument(string != null); + +- return Registry.POTION.get(NamespacedKey.fromString(string)); ++ // Paper start - Fixup NamespacedKey handling ++ final NamespacedKey key = NamespacedKey.fromString(string); ++ return key != null ? Registry.POTION.get(key) : null; ++ // Paper end - Fixup NamespacedKey handling + } + + private final NamespacedKey key; +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftNamespacedKey.java +@@ -0,0 +0,0 @@ public final class CraftNamespacedKey { + return null; + } + ResourceLocation minecraft = ResourceLocation.tryParse(string); +- return (minecraft == null) ? null : CraftNamespacedKey.fromMinecraft(minecraft); ++ return (minecraft == null || minecraft.getPath().isEmpty()) ? null : CraftNamespacedKey.fromMinecraft(minecraft); // Paper - Bukkit's parser does not match Vanilla for empty paths + } + + public static NamespacedKey fromString(String string) { diff --git a/patches/server/Ignore-inline-definitions-of-trim-material-pattern.patch b/patches/server/Ignore-inline-definitions-of-trim-material-pattern.patch deleted file mode 100644 index 151a7edc84..0000000000 --- a/patches/server/Ignore-inline-definitions-of-trim-material-pattern.patch +++ /dev/null @@ -1,19 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Thu, 8 Jun 2023 21:51:50 -0700 -Subject: [PATCH] Ignore inline definitions of trim material & pattern - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -@@ -0,0 +0,0 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { - if (tag.contains(CraftMetaArmor.TRIM.NBT)) { - CompoundTag trimCompound = tag.getCompound(CraftMetaArmor.TRIM.NBT); - -- if (trimCompound.contains(CraftMetaArmor.TRIM_MATERIAL.NBT) && trimCompound.contains(CraftMetaArmor.TRIM_PATTERN.NBT)) { -+ if (trimCompound.contains(CraftMetaArmor.TRIM_MATERIAL.NBT, net.minecraft.nbt.Tag.TAG_STRING) && trimCompound.contains(CraftMetaArmor.TRIM_PATTERN.NBT, net.minecraft.nbt.Tag.TAG_STRING)) { // Paper - for now, ignore inline definitions of trim material & pattern - TrimMaterial trimMaterial = Registry.TRIM_MATERIAL.get(NamespacedKey.fromString(trimCompound.getString(CraftMetaArmor.TRIM_MATERIAL.NBT))); - TrimPattern trimPattern = Registry.TRIM_PATTERN.get(NamespacedKey.fromString(trimCompound.getString(CraftMetaArmor.TRIM_PATTERN.NBT))); - diff --git a/patches/server/Suppress-Item-Meta-Validation-Checks.patch b/patches/server/Suppress-Item-Meta-Validation-Checks.patch deleted file mode 100644 index 601c285c40..0000000000 --- a/patches/server/Suppress-Item-Meta-Validation-Checks.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> -Date: Mon, 12 Jun 2023 14:42:49 -0400 -Subject: [PATCH] Suppress Item Meta Validation Checks - -In some cases ItemMeta could validate tags in an ItemStack. This suppresses those warnings and ignores reading the value. - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -@@ -0,0 +0,0 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { - CompoundTag trimCompound = tag.getCompound(CraftMetaArmor.TRIM.NBT); - - if (trimCompound.contains(CraftMetaArmor.TRIM_MATERIAL.NBT, net.minecraft.nbt.Tag.TAG_STRING) && trimCompound.contains(CraftMetaArmor.TRIM_PATTERN.NBT, net.minecraft.nbt.Tag.TAG_STRING)) { // Paper - for now, ignore inline definitions of trim material & pattern -- TrimMaterial trimMaterial = Registry.TRIM_MATERIAL.get(NamespacedKey.fromString(trimCompound.getString(CraftMetaArmor.TRIM_MATERIAL.NBT))); -- TrimPattern trimPattern = Registry.TRIM_PATTERN.get(NamespacedKey.fromString(trimCompound.getString(CraftMetaArmor.TRIM_PATTERN.NBT))); -+ // Paper start -+ TrimMaterial trimMaterial = getRegistry(Registry.TRIM_MATERIAL, trimCompound.getString(TRIM_MATERIAL.NBT)); -+ TrimPattern trimPattern = getRegistry(Registry.TRIM_PATTERN, trimCompound.getString(TRIM_PATTERN.NBT)); -+ // Paper end - -- this.trim = new ArmorTrim(trimMaterial, trimPattern); -+ this.trim = trimMaterial == null || trimPattern == null ? null : new ArmorTrim(trimMaterial, trimPattern); // Paper - } - } - } -+ // Paper start -+ public T getRegistry(Registry registry, String value) { -+ if (value == null || value.isEmpty()) { -+ return null; -+ } -+ NamespacedKey namespacedKey = NamespacedKey.fromString(value); -+ if (namespacedKey == null) { -+ return null; -+ } -+ -+ T registryValue = registry.get(namespacedKey); -+ if (registryValue == null) { -+ return null; -+ } -+ -+ return registryValue; -+ } -+ // Paper end - - CraftMetaArmor(Map map) { - super(map); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -0,0 +0,0 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - continue; - } - -- Attribute attribute = CraftAttribute.stringToBukkit(attributeName); -+ // Paper start -+ Attribute attribute; -+ try { -+ attribute = CraftAttribute.stringToBukkit(attributeName); -+ } catch (IllegalArgumentException e) { -+ attribute = null; -+ } -+ // Paper end - if (attribute == null) { - continue; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -@@ -0,0 +0,0 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { - CraftMetaSkull(CompoundTag tag) { - super(tag); - -+ try { // Paper - Ignore invalid game profiles - if (tag.contains(CraftMetaSkull.SKULL_OWNER.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { - this.setProfile(NbtUtils.readGameProfile(tag.getCompound(CraftMetaSkull.SKULL_OWNER.NBT))); - } else if (tag.contains(CraftMetaSkull.SKULL_OWNER.NBT, CraftMagicNumbers.NBT.TAG_STRING) && !tag.getString(CraftMetaSkull.SKULL_OWNER.NBT).isEmpty()) { - this.setProfile(new GameProfile(Util.NIL_UUID, tag.getString(CraftMetaSkull.SKULL_OWNER.NBT))); - } -+ } catch (Exception ignored) {} // Paper - - if (tag.contains(CraftMetaSkull.BLOCK_ENTITY_TAG.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND)) { - CompoundTag nbtTagCompound = tag.getCompound(CraftMetaSkull.BLOCK_ENTITY_TAG.NBT).copy();