From 7d4cce94ae30af6e091d59af33979eeab3e72175 Mon Sep 17 00:00:00 2001 From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:02:45 -0400 Subject: Patch --- .../0945-Support-old-UUID-format-for-NBT.patch | 63 ++ .../0946-Fix-shield-disable-inconsistency.patch | 22 + ...Handle-Large-Packets-disconnecting-client.patch | 135 ++++ patches/server/0948-Fix-ItemFlags.patch | 199 +++++ ...x-helmet-damage-reduction-inconsistencies.patch | 21 + ...anilla-handling-of-LivingEntity-actuallyH.patch | 50 ++ ...improve-checking-handled-tags-in-itemmeta.patch | 887 +++++++++++++++++++++ .../0952-Expose-hasColor-to-leather-armor.patch | 38 + ...-Added-API-to-get-player-ha-proxy-address.patch | 65 ++ .../0953-Support-old-UUID-format-for-NBT.patch | 63 -- .../0954-Fix-shield-disable-inconsistency.patch | 22 - ...Handle-Large-Packets-disconnecting-client.patch | 135 ---- patches/unapplied/server/0956-Fix-ItemFlags.patch | 199 ----- ...x-helmet-damage-reduction-inconsistencies.patch | 21 - ...anilla-handling-of-LivingEntity-actuallyH.patch | 50 -- ...improve-checking-handled-tags-in-itemmeta.patch | 873 -------------------- .../0961-Expose-hasColor-to-leather-armor.patch | 38 - ...-Added-API-to-get-player-ha-proxy-address.patch | 65 -- 18 files changed, 1480 insertions(+), 1466 deletions(-) create mode 100644 patches/server/0945-Support-old-UUID-format-for-NBT.patch create mode 100644 patches/server/0946-Fix-shield-disable-inconsistency.patch create mode 100644 patches/server/0947-Handle-Large-Packets-disconnecting-client.patch create mode 100644 patches/server/0948-Fix-ItemFlags.patch create mode 100644 patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch create mode 100644 patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch create mode 100644 patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch create mode 100644 patches/server/0952-Expose-hasColor-to-leather-armor.patch create mode 100644 patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch delete mode 100644 patches/unapplied/server/0953-Support-old-UUID-format-for-NBT.patch delete mode 100644 patches/unapplied/server/0954-Fix-shield-disable-inconsistency.patch delete mode 100644 patches/unapplied/server/0955-Handle-Large-Packets-disconnecting-client.patch delete mode 100644 patches/unapplied/server/0956-Fix-ItemFlags.patch delete mode 100644 patches/unapplied/server/0957-Fix-helmet-damage-reduction-inconsistencies.patch delete mode 100644 patches/unapplied/server/0958-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch delete mode 100644 patches/unapplied/server/0959-improve-checking-handled-tags-in-itemmeta.patch delete mode 100644 patches/unapplied/server/0961-Expose-hasColor-to-leather-armor.patch delete mode 100644 patches/unapplied/server/0962-Added-API-to-get-player-ha-proxy-address.patch diff --git a/patches/server/0945-Support-old-UUID-format-for-NBT.patch b/patches/server/0945-Support-old-UUID-format-for-NBT.patch new file mode 100644 index 0000000000..68ff8a5255 --- /dev/null +++ b/patches/server/0945-Support-old-UUID-format-for-NBT.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Mon, 29 Jun 2020 03:26:17 -0400 +Subject: [PATCH] Support old UUID format for NBT + +We have stored UUID in plenty of places that did not get DFU'd + +So just look for old format and load it if it exists. + +diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java +index e88161e662d5605b50aead673c9b3794874e5f7f..d7bb00a946346dff0b0269cbd65276e146a63fb0 100644 +--- a/src/main/java/net/minecraft/nbt/CompoundTag.java ++++ b/src/main/java/net/minecraft/nbt/CompoundTag.java +@@ -232,6 +232,12 @@ public class CompoundTag implements Tag { + } + + public void putUUID(String key, UUID value) { ++ // Paper start - Support old UUID format ++ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { ++ this.tags.remove(key + "Most"); ++ this.tags.remove(key + "Least"); ++ } ++ // Paper end - Support old UUID format + this.tags.put(key, NbtUtils.createUUID(value)); + } + +@@ -240,10 +246,20 @@ public class CompoundTag implements Tag { + * You must use {@link #hasUUID(String)} before or else it will throw an NPE. + */ + public UUID getUUID(String key) { ++ // Paper start - Support old UUID format ++ if (!contains(key, 11) && this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { ++ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least")); ++ } ++ // Paper end - Support old UUID format + return NbtUtils.loadUUID(this.get(key)); + } + + public boolean hasUUID(String key) { ++ // Paper start - Support old UUID format ++ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { ++ return true; ++ } ++ // Paper end - Support old UUID format + Tag tag = this.get(key); + return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4; + } +diff --git a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java +index 78863e72239a0f3535bc85758479da84d58c11c1..38bbe39a5cd96710b208d70ed78619057bb6e6fa 100644 +--- a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java ++++ b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java +@@ -20,9 +20,10 @@ public record ResolvableProfile(Optional name, Optional id, Proper + instance -> instance.group( + ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile::name), + UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile::id), ++ UUIDUtil.STRING_CODEC.lenientOptionalFieldOf("Id").forGetter($ -> Optional.empty()), // Paper + ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", new PropertyMap()).forGetter(ResolvableProfile::properties) + ) +- .apply(instance, ResolvableProfile::new) ++ .apply(instance, (s, uuid, uuid2, propertyMap) -> new ResolvableProfile(s, uuid2.or(() -> uuid), propertyMap)) // Paper + ); + public static final Codec CODEC = Codec.withAlternative( + FULL_CODEC, ExtraCodecs.PLAYER_NAME, name -> new ResolvableProfile(Optional.of(name), Optional.empty(), new PropertyMap()) diff --git a/patches/server/0946-Fix-shield-disable-inconsistency.patch b/patches/server/0946-Fix-shield-disable-inconsistency.patch new file mode 100644 index 0000000000..79d8304020 --- /dev/null +++ b/patches/server/0946-Fix-shield-disable-inconsistency.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Fri, 26 Apr 2024 19:08:37 -0700 +Subject: [PATCH] Fix shield disable inconsistency + +In vanilla, if the damage source is tagged as a projectile, +it will not disable the shield if the attacker is holding +an axe item. + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index a7f0d49637eb72b4645997a97cc6927b16a59738..1b9f03dcf63c44c11e79022cb6cce5f6bd1ea30a 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -2426,7 +2426,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING)); + Entity entity = damagesource.getDirectEntity(); + +- if (entity instanceof LivingEntity) { ++ if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency + this.blockUsingShield((LivingEntity) entity); + } + } diff --git a/patches/server/0947-Handle-Large-Packets-disconnecting-client.patch b/patches/server/0947-Handle-Large-Packets-disconnecting-client.patch new file mode 100644 index 0000000000..32e463a242 --- /dev/null +++ b/patches/server/0947-Handle-Large-Packets-disconnecting-client.patch @@ -0,0 +1,135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 27 Nov 2018 21:18:06 -0500 +Subject: [PATCH] Handle Large Packets disconnecting client + +If a players inventory is too big to send in a single packet, +split the inventory set into multiple packets instead. + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index a8dfe7a4b3d01bf75587be078f471d1ef1d7a667..ea16dfa718b526d6520d7fcfc21d28f972f1f2bf 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -176,6 +176,21 @@ public class Connection extends SimpleChannelInboundHandler> { + } + + public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) { ++ // Paper start - Handle large packets disconnecting client ++ if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) { ++ final Packet packet = packetTooLargeException.getPacket(); ++ if (packet.packetTooLarge(this)) { ++ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); ++ return; ++ } else if (packet.isSkippable()) { ++ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); ++ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); ++ return; ++ } else { ++ throwable = throwable.getCause(); ++ } ++ } ++ // Paper end - Handle large packets disconnecting client + if (throwable instanceof SkipPacketException) { + Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); + } else { +diff --git a/src/main/java/net/minecraft/network/PacketEncoder.java b/src/main/java/net/minecraft/network/PacketEncoder.java +index 046bfc212b640de174b300e7a05cc30bb3cac93e..af3ec112e142a2c91c46882dad6180b18f39eec2 100644 +--- a/src/main/java/net/minecraft/network/PacketEncoder.java ++++ b/src/main/java/net/minecraft/network/PacketEncoder.java +@@ -40,7 +40,33 @@ public class PacketEncoder extends MessageToByteEncode + + throw var9; + } finally { ++ // Paper start - Handle large packets disconnecting client ++ int packetLength = byteBuf.readableBytes(); ++ if (packetLength > MAX_PACKET_SIZE || (packetLength > MAX_FINAL_PACKET_SIZE && packet.hasLargePacketFallback())) { ++ throw new PacketTooLargeException(packet, packetLength); ++ } ++ // Paper end - Handle large packets disconnecting client + ProtocolSwapHandler.handleOutboundTerminalPacket(channelHandlerContext, packet); + } + } ++ ++ // Paper start ++ // packet size is encoded into 3-byte varint ++ private static final int MAX_FINAL_PACKET_SIZE = (1 << 21) - 1; ++ // Vanilla Max size for the encoder (before compression) ++ private static final int MAX_PACKET_SIZE = 8388608; ++ ++ public static class PacketTooLargeException extends RuntimeException { ++ private final Packet packet; ++ ++ PacketTooLargeException(Packet packet, int packetLength) { ++ super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE); ++ this.packet = packet; ++ } ++ ++ public Packet getPacket() { ++ return this.packet; ++ } ++ } ++ // Paper end + } +diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main/java/net/minecraft/network/protocol/Packet.java +index 4c776c591dd0a7b36945a6487fdfe86d1187b4af..82fc12ffbd1585b4a8d09a025914830af77b0f8d 100644 +--- a/src/main/java/net/minecraft/network/protocol/Packet.java ++++ b/src/main/java/net/minecraft/network/protocol/Packet.java +@@ -11,6 +11,19 @@ public interface Packet { + + void handle(T listener); + ++ // Paper start ++ default boolean hasLargePacketFallback() { ++ return false; ++ } ++ ++ /** ++ * override {@link #hasLargePacketFallback()} to return true when overriding in subclasses ++ */ ++ default boolean packetTooLarge(net.minecraft.network.Connection manager) { ++ return false; ++ } ++ // Paper end ++ + default boolean isSkippable() { + return false; + } +diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java +index f53c74fb1863a2d1268a4ddf8cf69d1fda32d73f..8d5939e03a065197af125d95a10134abbccd07ec 100644 +--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java ++++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java +@@ -36,6 +36,21 @@ public class ClientboundContainerSetContentPacket implements Packet 2097152) { ++ if (i > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder + throw new RuntimeException("Chunk Packet trying to allocate too much memory on read."); + } else { + this.buffer = new byte[i]; diff --git a/patches/server/0948-Fix-ItemFlags.patch b/patches/server/0948-Fix-ItemFlags.patch new file mode 100644 index 0000000000..e045394f3c --- /dev/null +++ b/patches/server/0948-Fix-ItemFlags.patch @@ -0,0 +1,199 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 27 Apr 2024 12:16:38 -0700 +Subject: [PATCH] Fix ItemFlags + +Re-adds missing functionality for HIDE_DESTROYS and +HIDE_PLACED_ON. Also adds new flag in HIDE_STORED_ENCHANTS +which was split from HIDE_ADDITIONAL_TOOLTIP. + +== AT == +public net.minecraft.world.item.AdventureModePredicate predicates + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +index 73fe41322e0349ad1d46a760f621b6c91112e90e..19af55ec2bf62b70bd3be44f499b32f5efe71ab1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +@@ -38,7 +38,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage + getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { + this.enchantments = buildEnchantments(itemEnchantments); + if (!itemEnchantments.showInTooltip) { +- this.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); ++ this.addItemFlags(ItemFlag.HIDE_STORED_ENCHANTS); // Paper - new ItemFlag + } + }); + } +@@ -53,7 +53,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage + void applyToItem(CraftMetaItem.Applicator itemTag) { + super.applyToItem(itemTag); + +- this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_ADDITIONAL_TOOLTIP); ++ this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_STORED_ENCHANTS); + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 8d13505c36d732f17293c6a6d65cac20919b8b7a..6b3eed94c26bc16177f9b9fadd140f9a89163af2 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -275,6 +275,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + static final ItemMetaKeyType HIDE_ADDITIONAL_TOOLTIP = new ItemMetaKeyType(DataComponents.HIDE_ADDITIONAL_TOOLTIP); + @Specific(Specific.To.NBT) + static final ItemMetaKeyType CUSTOM_DATA = new ItemMetaKeyType<>(DataComponents.CUSTOM_DATA); ++ // Paper start - fix ItemFlags ++ static final ItemMetaKeyType CAN_PLACE_ON = new ItemMetaKeyType<>(DataComponents.CAN_PLACE_ON); ++ static final ItemMetaKeyType CAN_BREAK = new ItemMetaKeyType<>(DataComponents.CAN_BREAK); ++ private List canPlaceOnPredicates; ++ private List canBreakPredicates; ++ // Paper end - fix ItemFlags + + // We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304 + private Component displayName; +@@ -377,6 +383,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.customTag = meta.customTag; + + this.version = meta.version; ++ // Paper start ++ this.canPlaceOnPredicates = meta.canPlaceOnPredicates; ++ this.canBreakPredicates = meta.canBreakPredicates; ++ // Paper end + } + + CraftMetaItem(DataComponentPatch tag) { +@@ -496,6 +506,20 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.customTag = null; + } + }); ++ // Paper start - fix ItemFlags ++ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { ++ this.canPlaceOnPredicates = List.copyOf(data.predicates); ++ if (!data.showInTooltip()) { ++ this.addItemFlags(ItemFlag.HIDE_PLACED_ON); ++ } ++ }); ++ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_BREAK).ifPresent(data -> { ++ this.canBreakPredicates = List.copyOf(data.predicates); ++ if (!data.showInTooltip()) { ++ this.addItemFlags(ItemFlag.HIDE_DESTROYS); ++ } ++ }); ++ // Paper end - fix ItemFlags + + Set, Optional>> keys = tag.entrySet(); + for (Map.Entry, Optional> key : keys) { +@@ -735,7 +759,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + try { + CompoundTag unhandledTag = NbtIo.readCompressed(buf, NbtAccounter.unlimitedHeap()); + DataComponentPatch unhandledPatch = DataComponentPatch.CODEC.parse(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), unhandledTag).result().get(); +- this.unhandledTags.copy(unhandledPatch); ++ // Paper start ++ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { ++ this.canPlaceOnPredicates = List.copyOf(data.predicates); ++ }); ++ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_BREAK).ifPresent(data -> { ++ this.canBreakPredicates = List.copyOf(data.predicates); ++ }); ++ this.unhandledTags.copy(unhandledPatch.forget(type -> type == CraftMetaItem.CAN_PLACE_ON.TYPE || type == CraftMetaItem.CAN_BREAK.TYPE)); ++ // Paper end + + for (Entry, Optional> entry : unhandledPatch.entrySet()) { + // Move removed unhandled tags to dedicated removedTags +@@ -1006,6 +1038,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + itemTag.put(CraftMetaItem.MAX_DAMAGE, this.maxDamage); + } + ++ // Paper start ++ if (this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty()) { ++ itemTag.put(CraftMetaItem.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); ++ } ++ if (this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty()) { ++ itemTag.put(CraftMetaItem.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); ++ } ++ // Paper end ++ + for (Map.Entry, Optional> e : this.unhandledTags.build().entrySet()) { + e.getValue().ifPresent((value) -> { + itemTag.builder.set((DataComponentType) e.getKey(), value); +@@ -1096,7 +1137,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + + @Overridden + boolean isEmpty() { +- return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null); ++ return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasEnchantable() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.hasTooltipStyle() || this.hasItemModel() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isGlider() || this.hasDamageResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasUseRemainder() || this.hasUseCooldown() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasEquippable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper + } + + // Paper start +@@ -1889,6 +1930,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + && (this.hasJukeboxPlayable() ? that.hasJukeboxPlayable() && this.jukebox.equals(that.jukebox) : !that.hasJukeboxPlayable()) + && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) + && (this.hasMaxDamage() ? that.hasMaxDamage() && this.maxDamage.equals(that.maxDamage) : !that.hasMaxDamage()) ++ && (this.canPlaceOnPredicates != null ? that.canPlaceOnPredicates != null && this.canPlaceOnPredicates.equals(that.canPlaceOnPredicates) : that.canPlaceOnPredicates == null) // Paper ++ && (this.canBreakPredicates != null ? that.canBreakPredicates != null && this.canBreakPredicates.equals(that.canBreakPredicates) : that.canBreakPredicates == null) // Paper + && (this.version == that.version); + } + +@@ -1941,6 +1984,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + hash = 61 * hash + (this.hasDamage() ? this.damage : 0); + hash = 61 * hash + (this.hasMaxDamage() ? 1231 : 1237); + hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); ++ hash = 61 * hash + (this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates.hashCode() : 0); // Paper ++ hash = 61 * hash + (this.canBreakPredicates != null ? this.canBreakPredicates.hashCode() : 0); // Paper + hash = 61 * hash + this.version; + return hash; + } +@@ -1998,6 +2043,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + clone.damage = this.damage; + clone.maxDamage = this.maxDamage; + clone.version = this.version; ++ // Paper start ++ if (this.canPlaceOnPredicates != null) { ++ clone.canPlaceOnPredicates = List.copyOf(this.canPlaceOnPredicates); ++ } ++ if (this.canBreakPredicates != null) { ++ clone.canBreakPredicates = List.copyOf(this.canBreakPredicates); ++ } ++ // Paper end + return clone; + } catch (CloneNotSupportedException e) { + throw new Error(e); +@@ -2142,6 +2195,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + } + ++ // Paper start ++ final boolean canBreakAddToUnhandled = this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty(); ++ if (canBreakAddToUnhandled) { ++ this.unhandledTags.set(DataComponents.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); ++ } ++ final boolean canPlaceOnAddToUnhandled = this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty(); ++ if (canPlaceOnAddToUnhandled) { ++ this.unhandledTags.set(DataComponents.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); ++ } ++ // Paper end + if (!this.unhandledTags.isEmpty()) { + net.minecraft.nbt.Tag unhandled = DataComponentPatch.CODEC.encodeStart(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), this.unhandledTags.build()).getOrThrow(IllegalStateException::new); + try { +@@ -2152,6 +2215,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex); + } + } ++ // Paper start ++ if (canBreakAddToUnhandled) { ++ this.unhandledTags.clear(DataComponents.CAN_BREAK); ++ } ++ if (canPlaceOnAddToUnhandled) { ++ this.unhandledTags.clear(DataComponents.CAN_PLACE_ON); ++ } ++ // Paper end + + if (!this.removedTags.isEmpty()) { + RegistryAccess registryAccess = CraftRegistry.getMinecraftRegistry(); +@@ -2312,6 +2383,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + CraftMetaItem.MAX_DAMAGE.TYPE, + CraftMetaItem.CUSTOM_DATA.TYPE, + CraftMetaItem.ATTRIBUTES.TYPE, ++ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper ++ CraftMetaItem.CAN_BREAK.TYPE, // Paper + CraftMetaArmor.TRIM.TYPE, + CraftMetaArmorStand.ENTITY_TAG.TYPE, + CraftMetaBanner.PATTERNS.TYPE, diff --git a/patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch b/patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch new file mode 100644 index 0000000000..186441aa4d --- /dev/null +++ b/patches/server/0949-Fix-helmet-damage-reduction-inconsistencies.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> +Date: Sat, 27 Apr 2024 21:51:58 +0200 +Subject: [PATCH] Fix helmet damage reduction inconsistencies + +Affect the falling stalactite damage type where the +reduction is not applied like in Vanilla + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index b0e7d1841d71e377d5ad596a22dfafb90d4f80cc..659d38c90f20f744261190c451235dbca8352e38 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -1226,7 +1226,7 @@ public class CraftEventFactory { + modifiers.put(DamageModifier.FREEZING, freezingModifier); + modifierFunctions.put(DamageModifier.FREEZING, freezing); + } +- if (source.is(DamageTypes.FALLING_BLOCK) || source.is(DamageTypes.FALLING_ANVIL)) { ++ if (source.is(DamageTypeTags.DAMAGES_HELMET)) { // Paper + modifiers.put(DamageModifier.HARD_HAT, hardHatModifier); + modifierFunctions.put(DamageModifier.HARD_HAT, hardHat); + } diff --git a/patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch b/patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch new file mode 100644 index 0000000000..b4178f2bef --- /dev/null +++ b/patches/server/0950-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 27 Apr 2024 09:44:53 -0700 +Subject: [PATCH] Revert to vanilla handling of LivingEntity#actuallyHurt + + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index 1b9f03dcf63c44c11e79022cb6cce5f6bd1ea30a..6f9c4a5a87bdfb8ce32ce40c4a34997695d15ce3 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1457,7 +1457,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + amount = 0.0F; + } + +- float f1 = amount; ++ float f1 = amount; final float originalAmount = f1; // Paper - revert to vanilla #hurt - OBFHELPER + boolean flag = amount > 0.0F && this.isDamageSourceBlocked(source); // Copied from below + float f2 = 0.0F; + +@@ -1515,6 +1515,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (!this.actuallyHurt(world, source, (float) event.getFinalDamage() - this.lastHurt, event)) { + return false; + } ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. + // CraftBukkit end + this.lastHurt = amount; + flag1 = false; +@@ -1523,6 +1524,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + if (!this.actuallyHurt(world, source, (float) event.getFinalDamage(), event)) { + return false; + } ++ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. + this.lastHurt = amount; + this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks + // this.actuallyHurt(worldserver, damagesource, f); +@@ -2488,12 +2490,12 @@ public abstract class LivingEntity extends Entity implements Attackable { + + return true; + } else { +- return originalDamage > 0; ++ return true; // Paper - return false ONLY if event was cancelled + } + // CraftBukkit end + } + } +- return false; // CraftBukkit ++ return true; // CraftBukkit // Paper - return false ONLY if event was cancelled + } + + public CombatTracker getCombatTracker() { diff --git a/patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch b/patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch new file mode 100644 index 0000000000..41f857627a --- /dev/null +++ b/patches/server/0951-improve-checking-handled-tags-in-itemmeta.patch @@ -0,0 +1,887 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Mon, 10 Jul 2023 16:10:15 -0700 +Subject: [PATCH] improve checking handled tags in itemmeta + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java +index d29f4dd9808e2001c79535d663ca77d6840f6092..1fd6e5a1ada184f9b399b7c41718ffd7db086d91 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java +@@ -40,120 +40,120 @@ import org.bukkit.inventory.meta.TropicalFishBucketMeta; + + public final class CraftItemMetas { + +- public record ItemMetaData(Class metaClass, Function fromItemStack, ++ public record ItemMetaData(Class metaClass, BiFunction>, I> fromItemStack, + BiFunction, CraftMetaItem, I> fromItemMeta) { + } + + private static final ItemMetaData EMPTY_META_DATA = new ItemMetaData<>(ItemMeta.class, +- item -> null, ++ (item, extras) -> null, + (type, meta) -> null); + + private static final ItemMetaData ITEM_META_DATA = new ItemMetaData<>(ItemMeta.class, +- item -> new CraftMetaItem(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaItem(item.getComponentsPatch(), extras), + (type, meta) -> new CraftMetaItem(meta)); + + private static final ItemMetaData SIGNED_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, +- item -> new CraftMetaBookSigned(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBookSigned(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaBookSigned signed ? signed : new CraftMetaBookSigned(meta)); + + private static final ItemMetaData WRITABLE_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, +- item -> new CraftMetaBook(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBook(item.getComponentsPatch(), extras), + (type, meta) -> meta != null && meta.getClass().equals(CraftMetaBook.class) ? (BookMeta) meta : new CraftMetaBook(meta)); + + private static final ItemMetaData SKULL_META_DATA = new ItemMetaData<>(SkullMeta.class, +- item -> new CraftMetaSkull(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaSkull(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaSkull skull ? skull : new CraftMetaSkull(meta)); + + private static final ItemMetaData ARMOR_META_DATA = new ItemMetaData<>(ArmorMeta.class, +- item -> new CraftMetaArmor(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaArmor(item.getComponentsPatch(), extras), + (type, meta) -> meta != null && meta.getClass().equals(CraftMetaArmor.class) ? (ArmorMeta) meta : new CraftMetaArmor(meta)); + + private static final ItemMetaData COLORABLE_ARMOR_META_DATA = new ItemMetaData<>(ColorableArmorMeta.class, +- item -> new CraftMetaColorableArmor(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaColorableArmor(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof ColorableArmorMeta colorable ? colorable : new CraftMetaColorableArmor(meta)); + + private static final ItemMetaData LEATHER_ARMOR_META_DATA = new ItemMetaData<>(LeatherArmorMeta.class, +- item -> new CraftMetaLeatherArmor(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaLeatherArmor(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaLeatherArmor leather ? leather : new CraftMetaLeatherArmor(meta)); + + private static final ItemMetaData POTION_META_DATA = new ItemMetaData<>(PotionMeta.class, +- item -> new CraftMetaPotion(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaPotion(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaPotion potion ? potion : new CraftMetaPotion(meta)); + + private static final ItemMetaData MAP_META_DATA = new ItemMetaData<>(MapMeta.class, +- item -> new CraftMetaMap(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaMap(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaMap map ? map : new CraftMetaMap(meta)); + + private static final ItemMetaData FIREWORK_META_DATA = new ItemMetaData<>(FireworkMeta.class, +- item -> new CraftMetaFirework(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaFirework(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaFirework firework ? firework : new CraftMetaFirework(meta)); + + private static final ItemMetaData CHARGE_META_DATA = new ItemMetaData<>(FireworkEffectMeta.class, +- item -> new CraftMetaCharge(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaCharge(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaCharge charge ? charge : new CraftMetaCharge(meta)); + + private static final ItemMetaData ENCHANTED_BOOK_META_DATA = new ItemMetaData<>(EnchantmentStorageMeta.class, +- item -> new CraftMetaEnchantedBook(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaEnchantedBook(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaEnchantedBook enchantedBook ? enchantedBook : new CraftMetaEnchantedBook(meta)); + + private static final ItemMetaData BANNER_META_DATA = new ItemMetaData<>(BannerMeta.class, +- item -> new CraftMetaBanner(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBanner(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaBanner banner ? banner : new CraftMetaBanner(meta)); + + private static final ItemMetaData SPAWN_EGG_META_DATA = new ItemMetaData<>(SpawnEggMeta.class, +- item -> new CraftMetaSpawnEgg(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaSpawnEgg(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaSpawnEgg spawnEgg ? spawnEgg : new CraftMetaSpawnEgg(meta)); + + private static final ItemMetaData ARMOR_STAND_META_DATA = new ItemMetaData<>(ArmorStandMeta.class, // paper +- item -> new CraftMetaArmorStand(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaArmorStand(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaArmorStand armorStand ? armorStand : new CraftMetaArmorStand(meta)); + + private static final ItemMetaData KNOWLEDGE_BOOK_META_DATA = new ItemMetaData<>(KnowledgeBookMeta.class, +- item -> new CraftMetaKnowledgeBook(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaKnowledgeBook(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaKnowledgeBook knowledgeBook ? knowledgeBook : new CraftMetaKnowledgeBook(meta)); + + private static final ItemMetaData BLOCK_STATE_META_DATA = new ItemMetaData<>(BlockStateMeta.class, +- item -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem())), ++ (item, extras) -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem()), extras), + (type, meta) -> new CraftMetaBlockState(meta, type.asMaterial())); + + private static final ItemMetaData SHIELD_META_DATA = new ItemMetaData<>(ShieldMeta.class, +- item -> new CraftMetaShield(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaShield(item.getComponentsPatch(), extras), + (type, meta) -> new CraftMetaShield(meta)); + + private static final ItemMetaData TROPICAL_FISH_BUCKET_META_DATA = new ItemMetaData<>(TropicalFishBucketMeta.class, +- item -> new CraftMetaTropicalFishBucket(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaTropicalFishBucket(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaTropicalFishBucket tropicalFishBucket ? tropicalFishBucket : new CraftMetaTropicalFishBucket(meta)); + + private static final ItemMetaData AXOLOTL_BUCKET_META_DATA = new ItemMetaData<>(AxolotlBucketMeta.class, +- item -> new CraftMetaAxolotlBucket(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaAxolotlBucket(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaAxolotlBucket axolotlBucket ? axolotlBucket : new CraftMetaAxolotlBucket(meta)); + + private static final ItemMetaData CROSSBOW_META_DATA = new ItemMetaData<>(CrossbowMeta.class, +- item -> new CraftMetaCrossbow(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaCrossbow(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaCrossbow crossbow ? crossbow : new CraftMetaCrossbow(meta)); + + private static final ItemMetaData SUSPICIOUS_STEW_META_DATA = new ItemMetaData<>(SuspiciousStewMeta.class, +- item -> new CraftMetaSuspiciousStew(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaSuspiciousStew(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaSuspiciousStew suspiciousStew ? suspiciousStew : new CraftMetaSuspiciousStew(meta)); + + private static final ItemMetaData ENTITY_TAG_META_DATA = new ItemMetaData<>(ItemMeta.class, +- item -> new CraftMetaEntityTag(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaEntityTag(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaEntityTag entityTag ? entityTag : new CraftMetaEntityTag(meta)); + + private static final ItemMetaData COMPASS_META_DATA = new ItemMetaData<>(CompassMeta.class, +- item -> new CraftMetaCompass(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaCompass(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaCompass compass ? compass : new CraftMetaCompass(meta)); + + private static final ItemMetaData BUNDLE_META_DATA = new ItemMetaData<>(BundleMeta.class, +- item -> new CraftMetaBundle(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaBundle(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaBundle bundle ? bundle : new CraftMetaBundle(meta)); + + private static final ItemMetaData MUSIC_INSTRUMENT_META_DATA = new ItemMetaData<>(MusicInstrumentMeta.class, +- item -> new CraftMetaMusicInstrument(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaMusicInstrument(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaMusicInstrument musicInstrument ? musicInstrument : new CraftMetaMusicInstrument(meta)); + + private static final ItemMetaData OMINOUS_BOTTLE_META_DATA = new ItemMetaData<>(OminousBottleMeta.class, +- item -> new CraftMetaOminousBottle(item.getComponentsPatch()), ++ (item, extras) -> new CraftMetaOminousBottle(item.getComponentsPatch(), extras), + (type, meta) -> meta instanceof CraftMetaOminousBottle musicInstrument ? musicInstrument : new CraftMetaOminousBottle(meta)); + + // We use if instead of a set, since the result gets cached in CraftItemType, +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 7228d43d331de16cbaa0e97c7e3fa45c0bc89558..dfdabf86433d323966a748baef769cf0462d3f38 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -173,10 +173,11 @@ public final class CraftItemStack extends ItemStack { + } else if (this.handle == null) { + this.handle = new net.minecraft.world.item.ItemStack(CraftItemType.bukkitToMinecraft(type), 1); + } else { ++ final Material oldType = CraftMagicNumbers.getMaterial(this.handle.getItem()); // Paper + this.handle.setItem(CraftItemType.bukkitToMinecraft(type)); + if (this.hasItemMeta()) { + // This will create the appropriate item meta, which will contain all the data we intend to keep +- CraftItemStack.setItemMeta(this.handle, CraftItemStack.getItemMeta(this.handle)); ++ this.adjustTagForItemMeta(oldType); // Paper + } + } + this.setData(null); +@@ -337,6 +338,19 @@ public final class CraftItemStack extends ItemStack { + public ItemMeta getItemMeta() { + return CraftItemStack.getItemMeta(this.handle); + } ++ // Paper start - improve handled tags on type change ++ public void adjustTagForItemMeta(final Material oldType) { ++ final CraftMetaItem oldMeta = (CraftMetaItem) CraftItemFactory.instance().getItemMeta(oldType); ++ final ItemMeta newMeta; ++ if (oldMeta == null) { ++ newMeta = getItemMeta(this.handle); ++ } else { ++ final java.util.Set> extraHandledDcts = new java.util.HashSet<>(CraftMetaItem.getTopLevelHandledDcts(oldMeta.getClass())); ++ newMeta = getItemMeta(this.handle, CraftItemType.minecraftToBukkitNew(this.handle.getItem()), extraHandledDcts); ++ } ++ this.setItemMeta(newMeta); ++ } ++ // Paper end - improve handled tags on type change + // Paper start + public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { + final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); +@@ -349,12 +363,17 @@ public final class CraftItemStack extends ItemStack { + } + public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType) { + // Paper end ++ // Paper start - handled tags on type change ++ return getItemMeta(item, metaForType, null); ++ } ++ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType, final java.util.Set> extraHandledDcts) { ++ // Paper end - handled tags on type change + if (!CraftItemStack.hasItemMeta(item)) { + return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item)); + } + +- if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item); } // Paper +- return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item); ++ if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item, extraHandledDcts); } // Paper ++ return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item, extraHandledDcts); // Paper + } + + static Material getType(net.minecraft.world.item.ItemStack item) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +index 6d76cc1db3ac3f1ae74c13511937fb86082a0b3d..f4a6ee6dfcb2d516a9a1a9c81494b50a629110e4 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java +@@ -114,8 +114,8 @@ public class CraftItemType implements ItemType.Typed, Han + return this.item; + } + +- public M getItemMeta(net.minecraft.world.item.ItemStack itemStack) { +- return this.itemMetaData.get().fromItemStack().apply(itemStack); ++ public M getItemMeta(net.minecraft.world.item.ItemStack itemStack, final java.util.Set> extraHandledDcts) { ++ return this.itemMetaData.get().fromItemStack().apply(itemStack, extraHandledDcts); + } + + public M getItemMeta(ItemMeta itemMeta) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +index 0d3b1692af010bfd7ea83e22e9571dc954906f71..e83a662f82b144b11a003a682633cd0ee797fd19 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java +@@ -34,8 +34,8 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { + } + } + +- CraftMetaArmor(DataComponentPatch tag) { +- super(tag); ++ CraftMetaArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaArmor.TRIM).ifPresent((trimCompound) -> { + TrimMaterial trimMaterial = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL, trimCompound.material()).orElse(null); // Paper - fix upstream not being correct +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java +index ecce5d0da946ca279c5608068442cc53437dd2a5..00b5c4ab6111f980db1b9e99f901667741266440 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java +@@ -35,8 +35,8 @@ public class CraftMetaArmorStand extends CraftMetaItem implements com.destroysto + this.entityTag = armorStand.entityTag; + } + +- CraftMetaArmorStand(DataComponentPatch tag) { +- super(tag); ++ CraftMetaArmorStand(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaArmorStand.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java +index c4beb94d8e5448e69f31f30299448f344b5d8f59..169fefb64e1af444f7c2efb1234cb6e7779fb717 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java +@@ -36,8 +36,8 @@ public class CraftMetaAxolotlBucket extends CraftMetaItem implements AxolotlBuck + this.bucketEntityTag = bucket.bucketEntityTag; + } + +- CraftMetaAxolotlBucket(DataComponentPatch tag) { +- super(tag); ++ CraftMetaAxolotlBucket(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaAxolotlBucket.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +index eb44c19f6af624df458981e46c73a64358d6e1ce..d0a8cd89da3b8d87248494056470c306f8fb5ae8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java +@@ -34,8 +34,8 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { + this.patterns = new ArrayList(banner.patterns); + } + +- CraftMetaBanner(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBanner(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBanner.PATTERNS).ifPresent((entityTag) -> { + List patterns = entityTag.layers(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +index 3985e5b4e2d65faa8eaea1d4a2acc6fb1e64f959..413e41f113226b8a2e9b30bb519076d78e451fa0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java +@@ -73,8 +73,8 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta + this.position = te.position; + } + +- CraftMetaBlockState(DataComponentPatch tag, Material material) { +- super(tag); ++ CraftMetaBlockState(DataComponentPatch tag, Material material, final Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + this.material = material; + + getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((blockTag) -> { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +index 32e5188442551b3e72e1d4826d836d622d0e438a..257c835bc280eee9ee73ae75b5249bb568a687d0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java +@@ -64,8 +64,8 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta, WritableBo + } + } + +- CraftMetaBook(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBook.BOOK_CONTENT).ifPresent((writable) -> { + List> pages = writable.pages(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java +index fd3b12477c30d1eabdbe57ea779027931e9dd957..cbb3d80cc7cd81b2505dff999a0baede737165f7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java +@@ -78,8 +78,8 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta { + } + } + +- CraftMetaBookSigned(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBookSigned(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBookSigned.BOOK_CONTENT).ifPresent((written) -> { + this.title = written.title().raw(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java +index 30533ce683e0471742b27d1d31df20def8ea169c..2736a87a6c481da0575e6e29ea08faa539c24378 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java +@@ -34,8 +34,8 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { + } + } + +- CraftMetaBundle(DataComponentPatch tag) { +- super(tag); ++ CraftMetaBundle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaBundle.ITEMS).ifPresent((bundle) -> { + bundle.items().forEach((item) -> { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java +index 72340e7269a5464d72abe8370c8113f3de9573d2..56c6784e29cecf8655282235959de536d07c1e08 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java +@@ -29,8 +29,8 @@ class CraftMetaCharge extends CraftMetaItem implements FireworkEffectMeta { + this.setEffect(SerializableMeta.getObject(FireworkEffect.class, map, CraftMetaCharge.EXPLOSION.BUKKIT, true)); + } + +- CraftMetaCharge(DataComponentPatch tag) { +- super(tag); ++ CraftMetaCharge(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaCharge.EXPLOSION).ifPresent((f) -> { + try { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +index 366fec1aee66de4031727a1383acebd319eeef88..6517ec4933b0eae761fceb117ea1db175755d0b1 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +@@ -18,8 +18,8 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable + CraftMetaLeatherArmor.readColor(this, meta); + } + +- CraftMetaColorableArmor(DataComponentPatch tag) { +- super(tag); ++ CraftMetaColorableArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + CraftMetaLeatherArmor.readColor(this, tag); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java +index 607e23040383576b2805c25947a69f6efe6d2c88..69a112b3a9726966aecbe687d905fd1a11cfa1e3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java +@@ -50,8 +50,8 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { + this.tracked = compassMeta.tracked; + } + +- CraftMetaCompass(DataComponentPatch tag) { +- super(tag); ++ CraftMetaCompass(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaCompass.LODESTONE_TARGET).ifPresent((lodestoneTarget) -> { + lodestoneTarget.target().ifPresent((target) -> { + this.lodestoneWorld = target.dimension(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java +index c278af519308c84ad76fc2312046980c01c528ba..0807c2172c5a4bee675cef265a45a9350e98b880 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java +@@ -36,8 +36,8 @@ public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta { + } + } + +- CraftMetaCrossbow(DataComponentPatch tag) { +- super(tag); ++ CraftMetaCrossbow(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaCrossbow.CHARGED_PROJECTILES).ifPresent((p) -> { + List list = p.getItems(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +index 19af55ec2bf62b70bd3be44f499b32f5efe71ab1..c93f769ee6c55022653696da45de568fcf7589fe 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +@@ -32,8 +32,8 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage + } + } + +- CraftMetaEnchantedBook(DataComponentPatch tag) { +- super(tag); ++ CraftMetaEnchantedBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { + this.enchantments = buildEnchantments(itemEnchantments); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +index 3ff0340c40e9dc9a6e690de15ccade7a0c4e8f02..3f6c5cbbf63631e4b72dc43558651ea94f31ca78 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java +@@ -39,8 +39,8 @@ public class CraftMetaEntityTag extends CraftMetaItem { + this.entityTag = entity.entityTag; + } + +- CraftMetaEntityTag(DataComponentPatch tag) { +- super(tag); ++ CraftMetaEntityTag(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaEntityTag.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +index 4941e0afff8df5f10f06c715b54bf58eb86051c5..566d893a413fd04b99e83dc2da8fe958a48492a8 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java +@@ -60,8 +60,8 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { + } + } + +- CraftMetaFirework(DataComponentPatch tag) { +- super(tag); ++ CraftMetaFirework(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaFirework.FIREWORKS).ifPresent((fireworks) -> { + this.power = fireworks.flightDuration(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 6b3eed94c26bc16177f9b9fadd140f9a89163af2..86045b7c4aa6ce9007cdeb1bb1ffdce98de6568b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -389,7 +389,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + // Paper end + } + +- CraftMetaItem(DataComponentPatch tag) { ++ CraftMetaItem(DataComponentPatch tag, Set> extraHandledTags) { // Paper - improve handled tags on type changes + CraftMetaItem.getOrEmpty(tag, CraftMetaItem.NAME).ifPresent((component) -> { + this.displayName = component; + }); +@@ -521,9 +521,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + }); + // Paper end - fix ItemFlags + ++ // Paper start - improve checking handled data component types ++ Set> handledTags = getTopLevelHandledDcts(this.getClass()); ++ if (extraHandledTags != null) { ++ extraHandledTags.addAll(handledTags); ++ handledTags = extraHandledTags; ++ } ++ // Paper end - improve checking handled data component types + Set, Optional>> keys = tag.entrySet(); + for (Map.Entry, Optional> key : keys) { +- if (!CraftMetaItem.getHandledTags().contains(key.getKey())) { ++ if (!handledTags.contains(key.getKey())) { // Paper - improve checking handled data component types + key.getValue().ifPresent((value) -> { + this.unhandledTags.set((DataComponentType) key.getKey(), value); + }); +@@ -2351,75 +2358,83 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + this.version = version; + } + +- public static Set getHandledTags() { +- synchronized (CraftMetaItem.HANDLED_TAGS) { +- if (CraftMetaItem.HANDLED_TAGS.isEmpty()) { +- CraftMetaItem.HANDLED_TAGS.addAll(Arrays.asList( +- CraftMetaItem.NAME.TYPE, +- CraftMetaItem.ITEM_NAME.TYPE, +- CraftMetaItem.LORE.TYPE, +- CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, +- CraftMetaItem.ENCHANTABLE.TYPE, +- CraftMetaItem.BLOCK_DATA.TYPE, +- CraftMetaItem.REPAIR.TYPE, +- CraftMetaItem.ENCHANTMENTS.TYPE, +- CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, +- CraftMetaItem.HIDE_TOOLTIP.TYPE, +- CraftMetaItem.TOOLTIP_STYLE.TYPE, +- CraftMetaItem.ITEM_MODEL.TYPE, +- CraftMetaItem.UNBREAKABLE.TYPE, +- CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, +- CraftMetaItem.GLIDER.TYPE, +- CraftMetaItem.DAMAGE_RESISTANT.TYPE, +- CraftMetaItem.MAX_STACK_SIZE.TYPE, +- CraftMetaItem.RARITY.TYPE, +- CraftMetaItem.USE_REMAINDER.TYPE, +- CraftMetaItem.USE_COOLDOWN.TYPE, +- CraftMetaItem.FOOD.TYPE, +- CraftMetaItem.TOOL.TYPE, +- CraftMetaItem.EQUIPPABLE.TYPE, +- CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, +- CraftMetaItem.DAMAGE.TYPE, +- CraftMetaItem.MAX_DAMAGE.TYPE, +- CraftMetaItem.CUSTOM_DATA.TYPE, +- CraftMetaItem.ATTRIBUTES.TYPE, +- CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper +- CraftMetaItem.CAN_BREAK.TYPE, // Paper +- CraftMetaArmor.TRIM.TYPE, +- CraftMetaArmorStand.ENTITY_TAG.TYPE, +- CraftMetaBanner.PATTERNS.TYPE, +- CraftMetaEntityTag.ENTITY_TAG.TYPE, +- CraftMetaLeatherArmor.COLOR.TYPE, +- CraftMetaMap.MAP_POST_PROCESSING.TYPE, +- CraftMetaMap.MAP_COLOR.TYPE, +- CraftMetaMap.MAP_ID.TYPE, +- CraftMetaPotion.POTION_CONTENTS.TYPE, +- CraftMetaShield.BASE_COLOR.TYPE, +- CraftMetaSkull.SKULL_PROFILE.TYPE, +- CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE, +- CraftMetaSpawnEgg.ENTITY_TAG.TYPE, +- CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE, +- CraftMetaBook.BOOK_CONTENT.TYPE, +- CraftMetaBookSigned.BOOK_CONTENT.TYPE, +- CraftMetaFirework.FIREWORKS.TYPE, +- CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE, +- CraftMetaCharge.EXPLOSION.TYPE, +- CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE, +- CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, +- CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE, +- CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, +- CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE, +- CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE, +- CraftMetaSuspiciousStew.EFFECTS.TYPE, +- CraftMetaCompass.LODESTONE_TARGET.TYPE, +- CraftMetaBundle.ITEMS.TYPE, +- CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE, +- CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE +- )); +- } +- return CraftMetaItem.HANDLED_TAGS; ++ // Paper start - improve checking handled tags ++ @org.jetbrains.annotations.VisibleForTesting ++ public static final Map, Set>> HANDLED_DCTS_PER_TYPE = new HashMap<>(); ++ private static final Set> DEFAULT_HANDLED_DCTS = Set.of( ++ CraftMetaItem.NAME.TYPE, ++ CraftMetaItem.ITEM_NAME.TYPE, ++ CraftMetaItem.LORE.TYPE, ++ CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, ++ CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, ++ CraftMetaItem.BLOCK_DATA.TYPE, ++ CraftMetaItem.REPAIR.TYPE, ++ CraftMetaItem.ENCHANTMENTS.TYPE, ++ CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, ++ CraftMetaItem.HIDE_TOOLTIP.TYPE, ++ CraftMetaItem.TOOLTIP_STYLE.TYPE, ++ CraftMetaItem.ITEM_MODEL.TYPE, ++ CraftMetaItem.UNBREAKABLE.TYPE, ++ CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, ++ CraftMetaItem.GLIDER.TYPE, ++ CraftMetaItem.DAMAGE_RESISTANT.TYPE, ++ CraftMetaItem.ENCHANTABLE.TYPE, ++ CraftMetaItem.MAX_STACK_SIZE.TYPE, ++ CraftMetaItem.RARITY.TYPE, ++ CraftMetaItem.USE_REMAINDER.TYPE, ++ CraftMetaItem.USE_COOLDOWN.TYPE, ++ CraftMetaItem.FOOD.TYPE, ++ CraftMetaItem.TOOL.TYPE, ++ CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, ++ CraftMetaItem.DAMAGE.TYPE, ++ CraftMetaItem.MAX_DAMAGE.TYPE, ++ CraftMetaItem.CUSTOM_DATA.TYPE, ++ CraftMetaItem.ATTRIBUTES.TYPE, ++ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper ++ CraftMetaItem.CAN_BREAK.TYPE // Paper ++ ); ++ public static Set> getTopLevelHandledDcts(final Class clazz) { ++ synchronized (HANDLED_DCTS_PER_TYPE) { ++ if (HANDLED_DCTS_PER_TYPE.isEmpty()) { ++ final Map, Set>> map = new HashMap<>(); ++ map.put(CraftMetaArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE)); ++ map.put(CraftMetaArmorStand.class, Set.of(CraftMetaArmorStand.ENTITY_TAG.TYPE)); ++ map.put(CraftMetaAxolotlBucket.class, Set.of(CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE)); ++ map.put(CraftMetaBanner.class, Set.of(CraftMetaBanner.PATTERNS.TYPE)); // banner uses same tag as block state ++ map.put(CraftMetaShield.class, Set.of(CraftMetaShield.BASE_COLOR.TYPE, CraftMetaBanner.PATTERNS.TYPE)); ++ map.put(CraftMetaBlockState.class, Set.of(CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE)); ++ map.put(CraftMetaBook.class, Set.of(CraftMetaBook.BOOK_CONTENT.TYPE)); ++ map.put(CraftMetaBookSigned.class, Set.of(CraftMetaBookSigned.BOOK_CONTENT.TYPE)); ++ map.put(CraftMetaBundle.class, Set.of(CraftMetaBundle.ITEMS.TYPE)); ++ map.put(CraftMetaCharge.class, Set.of(CraftMetaCharge.EXPLOSION.TYPE)); ++ map.put(CraftMetaColorableArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE, CraftMetaLeatherArmor.COLOR.TYPE)); ++ map.put(CraftMetaCompass.class, Set.of(CraftMetaCompass.LODESTONE_TARGET.TYPE)); ++ map.put(CraftMetaCrossbow.class, Set.of(CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE)); ++ map.put(CraftMetaEnchantedBook.class, Set.of(CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE)); ++ map.put(CraftMetaEntityTag.class, Set.of(CraftMetaEntityTag.ENTITY_TAG.TYPE)); ++ map.put(CraftMetaFirework.class, Set.of(CraftMetaFirework.FIREWORKS.TYPE)); ++ map.put(CraftMetaKnowledgeBook.class, Set.of(CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE)); ++ map.put(CraftMetaLeatherArmor.class, Set.of(CraftMetaLeatherArmor.COLOR.TYPE)); ++ map.put(CraftMetaMap.class, Set.of(CraftMetaMap.MAP_COLOR.TYPE, CraftMetaMap.MAP_POST_PROCESSING.TYPE, CraftMetaMap.MAP_ID.TYPE)); ++ map.put(CraftMetaMusicInstrument.class, Set.of(CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE)); ++ map.put(CraftMetaOminousBottle.class, Set.of(CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE)); ++ map.put(CraftMetaPotion.class, Set.of(CraftMetaPotion.POTION_CONTENTS.TYPE)); ++ map.put(CraftMetaSkull.class, Set.of(CraftMetaSkull.SKULL_PROFILE.TYPE, CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE)); ++ map.put(CraftMetaSpawnEgg.class, Set.of(CraftMetaSpawnEgg.ENTITY_TAG.TYPE)); ++ map.put(CraftMetaSuspiciousStew.class, Set.of(CraftMetaSuspiciousStew.EFFECTS.TYPE)); ++ map.put(CraftMetaTropicalFishBucket.class, Set.of(CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE)); ++ ++ for (final Map.Entry, Set>> entry : map.entrySet()) { ++ final ArrayList> topLevelTags = new ArrayList<>(entry.getValue()); ++ // add tags common to CraftMetaItem to all ++ topLevelTags.addAll(DEFAULT_HANDLED_DCTS); ++ HANDLED_DCTS_PER_TYPE.put(entry.getKey(), Set.copyOf(topLevelTags)); ++ } ++ } ++ return HANDLED_DCTS_PER_TYPE.getOrDefault(clazz, DEFAULT_HANDLED_DCTS); + } + } ++ // Paper end - improve checking handled data component types + + protected static Optional getOrEmpty(DataComponentPatch tag, ItemMetaKeyType type) { + Optional result = tag.get(type.TYPE); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java +index 68c0a6d5e06a44ddddddb9cbe093ed6814380444..4dc7adb626ccb74b7e3a60c5a7250d0dc9703997 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java +@@ -32,8 +32,8 @@ public class CraftMetaKnowledgeBook extends CraftMetaItem implements KnowledgeBo + } + } + +- CraftMetaKnowledgeBook(DataComponentPatch tag) { +- super(tag); ++ CraftMetaKnowledgeBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaKnowledgeBook.BOOK_RECIPES).ifPresent((pages) -> { + for (int i = 0; i < pages.size(); i++) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +index 75a8ad69902103a2e33a457c3225a33860d075ed..e8c950aa74d31bf7a9128f4acc4bccee26bbcd7f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +@@ -25,8 +25,8 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + CraftMetaLeatherArmor.readColor(this, meta); + } + +- CraftMetaLeatherArmor(DataComponentPatch tag) { +- super(tag); ++ CraftMetaLeatherArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + CraftMetaLeatherArmor.readColor(this, tag); + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java +index 08e18dcabbf52aae5c3843d49a72d1d52baa729b..149356981e586e4f67d4543d3df94a2ea99333fc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java +@@ -44,8 +44,8 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { + this.color = map.color; + } + +- CraftMetaMap(DataComponentPatch tag) { +- super(tag); ++ CraftMetaMap(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaMap.MAP_ID).ifPresent((mapId) -> { + this.mapId = mapId.id(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +index 76a3e4893cbdba903a712d6db1d30b9c644795be..a80b9b142ca99c7c0257b1bdeb059dce5f92ae93 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java +@@ -26,8 +26,8 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst + } + } + +- CraftMetaMusicInstrument(DataComponentPatch tag) { +- super(tag); ++ CraftMetaMusicInstrument(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT).ifPresent((instrument) -> { + this.instrument = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.INSTRUMENT, instrument).orElse(null); // Paper - fix upstream not handling inlined instrument +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java +index ed272c7eb435677de5f6b106a6012c472decbb62..b118d8ecb505d187c02bb158f14df333f487a87f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java +@@ -24,8 +24,8 @@ public class CraftMetaOminousBottle extends CraftMetaItem implements OminousBott + this.ominousBottleAmplifier = bottleMeta.ominousBottleAmplifier; + } + +- CraftMetaOminousBottle(DataComponentPatch tag) { +- super(tag); ++ CraftMetaOminousBottle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER).ifPresent((amplifier) -> { + this.ominousBottleAmplifier = amplifier.value(); + }); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +index 533c600d632eb733c121f5d8189142726b091713..6f0eebcaffa20337cf5a7f8485f891c690d948ae 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +@@ -54,8 +54,8 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { + } + } + +- CraftMetaPotion(DataComponentPatch tag) { +- super(tag); ++ CraftMetaPotion(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaPotion.POTION_CONTENTS).ifPresent((potionContents) -> { + potionContents.potion().ifPresent((potion) -> { + this.type = CraftPotionType.minecraftHolderToBukkit(potion); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +index bcd6cc29e4e621805cbd923d747f652ced240c6d..967d8940aec0065bce496d5d7a8c73de5733bd2c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java +@@ -42,8 +42,8 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS + } + } + +- CraftMetaShield(DataComponentPatch tag) { +- super(tag); ++ CraftMetaShield(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper - improve checking handled tags in item meta ++ super(tag, extraHandledDcts); // Paper - improve checking handled tags in item meta + + getOrEmpty(tag, CraftMetaShield.BASE_COLOR).ifPresent((color) -> { + this.banner = CraftMetaShield.getBlockState(DyeColor.getByWoolData((byte) color.getId())); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +index ca714e165e453d1072d083441d8b985290ada75a..302906467b12189e21633369c005736863f46dd5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java +@@ -48,8 +48,8 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { + this.noteBlockSound = skullMeta.noteBlockSound; + } + +- CraftMetaSkull(DataComponentPatch tag) { +- super(tag); ++ CraftMetaSkull(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaSkull.SKULL_PROFILE).ifPresent(this::setProfile); + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +index 6c2c3b514be0dab47f3e44f65bdc6a3574e59b7c..8ddf091b3ff1262b6c97e8fe72e0a80db5e1037d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java +@@ -33,8 +33,8 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { + this.entityTag = egg.entityTag; + } + +- CraftMetaSpawnEgg(DataComponentPatch tag) { +- super(tag); ++ CraftMetaSpawnEgg(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaSpawnEgg.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java +index 248efddbad2bfee4f9aa33ec738b5353054eda61..7a43e326e51300306b9c5c23a16ffae92030bd2b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java +@@ -33,8 +33,8 @@ public class CraftMetaSuspiciousStew extends CraftMetaItem implements Suspicious + } + } + +- CraftMetaSuspiciousStew(DataComponentPatch tag) { +- super(tag); ++ CraftMetaSuspiciousStew(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + getOrEmpty(tag, CraftMetaSuspiciousStew.EFFECTS).ifPresent((suspiciousStewEffects) -> { + List list = suspiciousStewEffects.effects(); + int length = list.size(); +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +index a514fe98d3d2b65d2cfd029079c69189bcb99c01..17705059b81942e4df43a4a5180092e09c985ade 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java +@@ -38,8 +38,8 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB + this.bucketEntityTag = bucket.bucketEntityTag; + } + +- CraftMetaTropicalFishBucket(DataComponentPatch tag) { +- super(tag); ++ CraftMetaTropicalFishBucket(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper ++ super(tag, extraHandledDcts); // Paper + + getOrEmpty(tag, CraftMetaTropicalFishBucket.ENTITY_TAG).ifPresent((nbt) -> { + this.entityTag = nbt.copyTag(); +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java +index 91cfa32272770cdfe56d97154ea9db4e2ed8a328..9cc1ef5c9221dd7d2069b280f0c91ce9439a995a 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java +@@ -97,7 +97,7 @@ public class DeprecatedItemMetaCustomValueTest { + CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); + itemMeta.applyToItem(compound); + +- assertEquals(itemMeta, new CraftMetaItem(compound.build())); ++ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper + } + + @Test +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java +new file mode 100644 +index 0000000000000000000000000000000000000000..df20446af3d43c624278d1a25f31f702677c8d96 +--- /dev/null ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java +@@ -0,0 +1,33 @@ ++package org.bukkit.craftbukkit.inventory; ++ ++import io.github.classgraph.ClassGraph; ++import io.github.classgraph.ClassInfo; ++import io.github.classgraph.ClassInfoList; ++import io.github.classgraph.ScanResult; ++import org.bukkit.support.environment.AllFeatures; ++import org.junit.jupiter.api.Test; ++ ++import static org.junit.jupiter.api.Assertions.assertFalse; ++import static org.junit.jupiter.api.Assertions.assertTrue; ++ ++// in cb package because of package-private stuff ++@AllFeatures ++class MetaHandledTagsTest { ++ ++ @Test ++ public void checkAllMetasHaveHandledTags() { ++ try (final ScanResult result = new ClassGraph() ++ .whitelistPackages("org.bukkit.craftbukkit.inventory") ++ .enableClassInfo().scan()) { ++ final ClassInfoList subclasses = result.getSubclasses(CraftMetaItem.class.getName()); ++ assertFalse(subclasses.isEmpty(), "found 0 sub types"); ++ for (final ClassInfo subclass : subclasses) { ++ final Class clazz = subclass.loadClass(CraftMetaItem.class); ++ CraftMetaItem.getTopLevelHandledDcts(clazz); // load into map ++ assertTrue(CraftMetaItem.HANDLED_DCTS_PER_TYPE.containsKey(clazz), subclass.getName() + " not found in handled tags map"); ++ } ++ } catch (Exception e) { ++ throw new RuntimeException(e); ++ } ++ } ++} +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java +index 5b16e6f5e5517eed218e4b60ecd75f8b80712e89..130c4500a5e854480962c8f720b1df4c67d43c33 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java +@@ -131,7 +131,7 @@ public class PersistentDataContainerTest { + CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); + itemMeta.applyToItem(compound); + +- assertEquals(itemMeta, new CraftMetaItem(compound.build())); ++ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper + } + + @Test +@@ -464,7 +464,7 @@ public class PersistentDataContainerTest { + + @Test + public void testEmptyListApplicationToAnyType() throws IOException { +- final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY); ++ final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY, null); // Paper + final PersistentDataContainer container = craftItem.getPersistentDataContainer(); + + container.set(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings(), List.of()); +@@ -477,7 +477,7 @@ public class PersistentDataContainerTest { + final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator(); + craftItem.applyToItem(storage); + +- final CraftMetaItem readItem = new CraftMetaItem(storage.build()); ++ final CraftMetaItem readItem = new CraftMetaItem(storage.build(), null); // Paper + final PersistentDataContainer readContainer = readItem.getPersistentDataContainer(); + + assertTrue(readContainer.has(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings())); diff --git a/patches/server/0952-Expose-hasColor-to-leather-armor.patch b/patches/server/0952-Expose-hasColor-to-leather-armor.patch new file mode 100644 index 0000000000..9166ad6261 --- /dev/null +++ b/patches/server/0952-Expose-hasColor-to-leather-armor.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: SoSeDiK +Date: Wed, 1 May 2024 10:58:50 +0300 +Subject: [PATCH] Expose #hasColor to leather armor + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +index 6517ec4933b0eae761fceb117ea1db175755d0b1..dc6398cfbd6e749733c3a681e1eb8ce15c3b2c5e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java +@@ -100,4 +100,11 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable + } + return original != hash ? CraftMetaColorableArmor.class.hashCode() ^ hash : hash; + } ++ ++ // Paper start - Expose #hasColor to leather armor ++ @Override ++ public boolean isDyed() { ++ return hasColor(); ++ } ++ // Paper end - Expose #hasColor to leather armor + } +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +index e8c950aa74d31bf7a9128f4acc4bccee26bbcd7f..e76749bffaf5a0bbd3a8d35f882edcc3598351b9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java +@@ -156,4 +156,11 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { + builder.put(CraftMetaLeatherArmor.COLOR.BUKKIT, meta.getColor()); + } + } ++ ++ // Paper start - Expose #hasColor to leather armor ++ @Override ++ public boolean isDyed() { ++ return hasColor(); ++ } ++ // Paper end - Expose #hasColor to leather armor + } diff --git a/patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch b/patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch new file mode 100644 index 0000000000..4ff67e86ed --- /dev/null +++ b/patches/server/0953-Added-API-to-get-player-ha-proxy-address.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: nostalfinals +Date: Mon, 8 Apr 2024 23:24:38 +0800 +Subject: [PATCH] Added API to get player ha proxy address + + +diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java +index ea16dfa718b526d6520d7fcfc21d28f972f1f2bf..4b9da6e2140b14f1e56056f5e9e94b2169d85501 100644 +--- a/src/main/java/net/minecraft/network/Connection.java ++++ b/src/main/java/net/minecraft/network/Connection.java +@@ -153,6 +153,7 @@ public class Connection extends SimpleChannelInboundHandler> { + this.stopReadingPackets = true; + } + // Paper end - packet limiter ++ @Nullable public SocketAddress haProxyAddress; // Paper - Add API to get player's proxy address + + public Connection(PacketFlow side) { + this.receiving = side; +diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +index c62df32af11636ad408b584fcc590590ce4fb0d0..baed0bb80d44973f9323bbe536551182979caff2 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java ++++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +@@ -144,6 +144,13 @@ public class ServerConnectionListener { + + Connection connection = (Connection) channel.pipeline().get("packet_handler"); + connection.address = socketaddr; ++ ++ // Paper start - Add API to get player's proxy address ++ final String proxyAddress = message.destinationAddress(); ++ final int proxyPort = message.destinationPort(); ++ ++ connection.haProxyAddress = new java.net.InetSocketAddress(proxyAddress, proxyPort); ++ // Paper end - Add API to get player's proxy address + } + } else { + super.channelRead(ctx, msg); +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 24b05e9b21ec84a4677f58ed790d308e700741b5..60a5eb5bd23bb267648bc55c1ee6bdfb29f806ce 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -266,7 +266,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public InetSocketAddress getAddress() { +- if (this.getHandle().connection.protocol() == null) return null; ++ if (this.getHandle().connection == null) return null; + + SocketAddress addr = this.getHandle().connection.getRemoteAddress(); + if (addr instanceof InetSocketAddress) { +@@ -276,6 +276,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + } + } + ++ // Paper start - Add API to get player's proxy address ++ @Override ++ public @Nullable InetSocketAddress getHAProxyAddress() { ++ if (this.getHandle().connection == null) return null; ++ ++ return this.getHandle().connection.connection.haProxyAddress instanceof final InetSocketAddress inetSocketAddress ? inetSocketAddress : null; ++ } ++ // Paper end - Add API to get player's proxy address ++ + public interface TransferCookieConnection { + + boolean isTransferred(); diff --git a/patches/unapplied/server/0953-Support-old-UUID-format-for-NBT.patch b/patches/unapplied/server/0953-Support-old-UUID-format-for-NBT.patch deleted file mode 100644 index 68ff8a5255..0000000000 --- a/patches/unapplied/server/0953-Support-old-UUID-format-for-NBT.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Mon, 29 Jun 2020 03:26:17 -0400 -Subject: [PATCH] Support old UUID format for NBT - -We have stored UUID in plenty of places that did not get DFU'd - -So just look for old format and load it if it exists. - -diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java -index e88161e662d5605b50aead673c9b3794874e5f7f..d7bb00a946346dff0b0269cbd65276e146a63fb0 100644 ---- a/src/main/java/net/minecraft/nbt/CompoundTag.java -+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java -@@ -232,6 +232,12 @@ public class CompoundTag implements Tag { - } - - public void putUUID(String key, UUID value) { -+ // Paper start - Support old UUID format -+ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -+ this.tags.remove(key + "Most"); -+ this.tags.remove(key + "Least"); -+ } -+ // Paper end - Support old UUID format - this.tags.put(key, NbtUtils.createUUID(value)); - } - -@@ -240,10 +246,20 @@ public class CompoundTag implements Tag { - * You must use {@link #hasUUID(String)} before or else it will throw an NPE. - */ - public UUID getUUID(String key) { -+ // Paper start - Support old UUID format -+ if (!contains(key, 11) && this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -+ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least")); -+ } -+ // Paper end - Support old UUID format - return NbtUtils.loadUUID(this.get(key)); - } - - public boolean hasUUID(String key) { -+ // Paper start - Support old UUID format -+ if (this.contains(key + "Most", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC) && this.contains(key + "Least", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -+ return true; -+ } -+ // Paper end - Support old UUID format - Tag tag = this.get(key); - return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4; - } -diff --git a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java -index 78863e72239a0f3535bc85758479da84d58c11c1..38bbe39a5cd96710b208d70ed78619057bb6e6fa 100644 ---- a/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java -+++ b/src/main/java/net/minecraft/world/item/component/ResolvableProfile.java -@@ -20,9 +20,10 @@ public record ResolvableProfile(Optional name, Optional id, Proper - instance -> instance.group( - ExtraCodecs.PLAYER_NAME.optionalFieldOf("name").forGetter(ResolvableProfile::name), - UUIDUtil.CODEC.optionalFieldOf("id").forGetter(ResolvableProfile::id), -+ UUIDUtil.STRING_CODEC.lenientOptionalFieldOf("Id").forGetter($ -> Optional.empty()), // Paper - ExtraCodecs.PROPERTY_MAP.optionalFieldOf("properties", new PropertyMap()).forGetter(ResolvableProfile::properties) - ) -- .apply(instance, ResolvableProfile::new) -+ .apply(instance, (s, uuid, uuid2, propertyMap) -> new ResolvableProfile(s, uuid2.or(() -> uuid), propertyMap)) // Paper - ); - public static final Codec CODEC = Codec.withAlternative( - FULL_CODEC, ExtraCodecs.PLAYER_NAME, name -> new ResolvableProfile(Optional.of(name), Optional.empty(), new PropertyMap()) diff --git a/patches/unapplied/server/0954-Fix-shield-disable-inconsistency.patch b/patches/unapplied/server/0954-Fix-shield-disable-inconsistency.patch deleted file mode 100644 index 61614305d9..0000000000 --- a/patches/unapplied/server/0954-Fix-shield-disable-inconsistency.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Fri, 26 Apr 2024 19:08:37 -0700 -Subject: [PATCH] Fix shield disable inconsistency - -In vanilla, if the damage source is tagged as a projectile, -it will not disable the shield if the attacker is holding -an axe item. - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 94169703c5a8111df1ed550d57f59f4a3bb97ae1..6ff33a6d46daffd15310f21ec00d4861478b360f 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2349,7 +2349,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING)); - Entity entity = damagesource.getDirectEntity(); - -- if (entity instanceof LivingEntity) { -+ if (!damagesource.is(DamageTypeTags.IS_PROJECTILE) && entity instanceof LivingEntity) { // Paper - Fix shield disable inconsistency - this.blockUsingShield((LivingEntity) entity); - } - } diff --git a/patches/unapplied/server/0955-Handle-Large-Packets-disconnecting-client.patch b/patches/unapplied/server/0955-Handle-Large-Packets-disconnecting-client.patch deleted file mode 100644 index ea20a101a7..0000000000 --- a/patches/unapplied/server/0955-Handle-Large-Packets-disconnecting-client.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Tue, 27 Nov 2018 21:18:06 -0500 -Subject: [PATCH] Handle Large Packets disconnecting client - -If a players inventory is too big to send in a single packet, -split the inventory set into multiple packets instead. - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index a8dfe7a4b3d01bf75587be078f471d1ef1d7a667..ea16dfa718b526d6520d7fcfc21d28f972f1f2bf 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -176,6 +176,21 @@ public class Connection extends SimpleChannelInboundHandler> { - } - - public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) { -+ // Paper start - Handle large packets disconnecting client -+ if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) { -+ final Packet packet = packetTooLargeException.getPacket(); -+ if (packet.packetTooLarge(this)) { -+ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); -+ return; -+ } else if (packet.isSkippable()) { -+ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); -+ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); -+ return; -+ } else { -+ throwable = throwable.getCause(); -+ } -+ } -+ // Paper end - Handle large packets disconnecting client - if (throwable instanceof SkipPacketException) { - Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); - } else { -diff --git a/src/main/java/net/minecraft/network/PacketEncoder.java b/src/main/java/net/minecraft/network/PacketEncoder.java -index 046bfc212b640de174b300e7a05cc30bb3cac93e..af3ec112e142a2c91c46882dad6180b18f39eec2 100644 ---- a/src/main/java/net/minecraft/network/PacketEncoder.java -+++ b/src/main/java/net/minecraft/network/PacketEncoder.java -@@ -40,7 +40,33 @@ public class PacketEncoder extends MessageToByteEncode - - throw var9; - } finally { -+ // Paper start - Handle large packets disconnecting client -+ int packetLength = byteBuf.readableBytes(); -+ if (packetLength > MAX_PACKET_SIZE || (packetLength > MAX_FINAL_PACKET_SIZE && packet.hasLargePacketFallback())) { -+ throw new PacketTooLargeException(packet, packetLength); -+ } -+ // Paper end - Handle large packets disconnecting client - ProtocolSwapHandler.handleOutboundTerminalPacket(channelHandlerContext, packet); - } - } -+ -+ // Paper start -+ // packet size is encoded into 3-byte varint -+ private static final int MAX_FINAL_PACKET_SIZE = (1 << 21) - 1; -+ // Vanilla Max size for the encoder (before compression) -+ private static final int MAX_PACKET_SIZE = 8388608; -+ -+ public static class PacketTooLargeException extends RuntimeException { -+ private final Packet packet; -+ -+ PacketTooLargeException(Packet packet, int packetLength) { -+ super("PacketTooLarge - " + packet.getClass().getSimpleName() + " is " + packetLength + ". Max is " + MAX_PACKET_SIZE); -+ this.packet = packet; -+ } -+ -+ public Packet getPacket() { -+ return this.packet; -+ } -+ } -+ // Paper end - } -diff --git a/src/main/java/net/minecraft/network/protocol/Packet.java b/src/main/java/net/minecraft/network/protocol/Packet.java -index 4c776c591dd0a7b36945a6487fdfe86d1187b4af..82fc12ffbd1585b4a8d09a025914830af77b0f8d 100644 ---- a/src/main/java/net/minecraft/network/protocol/Packet.java -+++ b/src/main/java/net/minecraft/network/protocol/Packet.java -@@ -11,6 +11,19 @@ public interface Packet { - - void handle(T listener); - -+ // Paper start -+ default boolean hasLargePacketFallback() { -+ return false; -+ } -+ -+ /** -+ * override {@link #hasLargePacketFallback()} to return true when overriding in subclasses -+ */ -+ default boolean packetTooLarge(net.minecraft.network.Connection manager) { -+ return false; -+ } -+ // Paper end -+ - default boolean isSkippable() { - return false; - } -diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java -index 7e555ece0555b3d2a983ab2c39c5e7ec23fc7e88..8cca2ac616a2c80268c96b9f95e33f834a0fc8fd 100644 ---- a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java -+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java -@@ -36,6 +36,21 @@ public class ClientboundContainerSetContentPacket implements Packet 2097152) { -+ if (i > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder - throw new RuntimeException("Chunk Packet trying to allocate too much memory on read."); - } else { - this.buffer = new byte[i]; diff --git a/patches/unapplied/server/0956-Fix-ItemFlags.patch b/patches/unapplied/server/0956-Fix-ItemFlags.patch deleted file mode 100644 index 78bc31a514..0000000000 --- a/patches/unapplied/server/0956-Fix-ItemFlags.patch +++ /dev/null @@ -1,199 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 27 Apr 2024 12:16:38 -0700 -Subject: [PATCH] Fix ItemFlags - -Re-adds missing functionality for HIDE_DESTROYS and -HIDE_PLACED_ON. Also adds new flag in HIDE_STORED_ENCHANTS -which was split from HIDE_ADDITIONAL_TOOLTIP. - -== AT == -public net.minecraft.world.item.AdventureModePredicate predicates - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -index 73fe41322e0349ad1d46a760f621b6c91112e90e..19af55ec2bf62b70bd3be44f499b32f5efe71ab1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -@@ -38,7 +38,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage - getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { - this.enchantments = buildEnchantments(itemEnchantments); - if (!itemEnchantments.showInTooltip) { -- this.addItemFlags(ItemFlag.HIDE_ADDITIONAL_TOOLTIP); -+ this.addItemFlags(ItemFlag.HIDE_STORED_ENCHANTS); // Paper - new ItemFlag - } - }); - } -@@ -53,7 +53,7 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage - void applyToItem(CraftMetaItem.Applicator itemTag) { - super.applyToItem(itemTag); - -- this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_ADDITIONAL_TOOLTIP); -+ this.applyEnchantments(this.enchantments, itemTag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS, ItemFlag.HIDE_STORED_ENCHANTS); - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 7ad1076de76c81c25b656e52237c2f60a2eca085..c2a215544589d903633c5aed51522870bea556d8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -245,6 +245,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - static final ItemMetaKeyType HIDE_ADDITIONAL_TOOLTIP = new ItemMetaKeyType(DataComponents.HIDE_ADDITIONAL_TOOLTIP); - @Specific(Specific.To.NBT) - static final ItemMetaKeyType CUSTOM_DATA = new ItemMetaKeyType<>(DataComponents.CUSTOM_DATA); -+ // Paper start - fix ItemFlags -+ static final ItemMetaKeyType CAN_PLACE_ON = new ItemMetaKeyType<>(DataComponents.CAN_PLACE_ON); -+ static final ItemMetaKeyType CAN_BREAK = new ItemMetaKeyType<>(DataComponents.CAN_BREAK); -+ private List canPlaceOnPredicates; -+ private List canBreakPredicates; -+ // Paper end - fix ItemFlags - - // We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304 - private Component displayName; -@@ -327,6 +333,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.customTag = meta.customTag; - - this.version = meta.version; -+ // Paper start -+ this.canPlaceOnPredicates = meta.canPlaceOnPredicates; -+ this.canBreakPredicates = meta.canBreakPredicates; -+ // Paper end - } - - CraftMetaItem(DataComponentPatch tag) { -@@ -425,6 +435,20 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.customTag = null; - } - }); -+ // Paper start - fix ItemFlags -+ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { -+ this.canPlaceOnPredicates = List.copyOf(data.predicates); -+ if (!data.showInTooltip()) { -+ this.addItemFlags(ItemFlag.HIDE_PLACED_ON); -+ } -+ }); -+ CraftMetaItem.getOrEmpty(tag, CraftMetaItem.CAN_BREAK).ifPresent(data -> { -+ this.canBreakPredicates = List.copyOf(data.predicates); -+ if (!data.showInTooltip()) { -+ this.addItemFlags(ItemFlag.HIDE_DESTROYS); -+ } -+ }); -+ // Paper end - fix ItemFlags - - Set, Optional>> keys = tag.entrySet(); - for (Map.Entry, Optional> key : keys) { -@@ -627,7 +651,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - try { - CompoundTag unhandledTag = NbtIo.readCompressed(buf, NbtAccounter.unlimitedHeap()); - DataComponentPatch unhandledPatch = DataComponentPatch.CODEC.parse(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), unhandledTag).result().get(); -- this.unhandledTags.copy(unhandledPatch); -+ // Paper start -+ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { -+ this.canPlaceOnPredicates = List.copyOf(data.predicates); -+ }); -+ CraftMetaItem.getOrEmpty(unhandledPatch, CraftMetaItem.CAN_BREAK).ifPresent(data -> { -+ this.canBreakPredicates = List.copyOf(data.predicates); -+ }); -+ this.unhandledTags.copy(unhandledPatch.forget(type -> type == CraftMetaItem.CAN_PLACE_ON.TYPE || type == CraftMetaItem.CAN_BREAK.TYPE)); -+ // Paper end - - for (Entry, Optional> entry : unhandledPatch.entrySet()) { - // Move removed unhandled tags to dedicated removedTags -@@ -870,6 +902,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - itemTag.put(CraftMetaItem.MAX_DAMAGE, this.maxDamage); - } - -+ // Paper start -+ if (this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty()) { -+ itemTag.put(CraftMetaItem.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); -+ } -+ if (this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty()) { -+ itemTag.put(CraftMetaItem.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); -+ } -+ // Paper end -+ - for (Map.Entry, Optional> e : this.unhandledTags.build().entrySet()) { - e.getValue().ifPresent((value) -> { - itemTag.builder.set((DataComponentType) e.getKey(), value); -@@ -960,7 +1001,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Overridden - boolean isEmpty() { -- return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isFireResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null); -+ return !(this.hasDisplayName() || this.hasItemName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.build().isEmpty() || !this.removedTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isFireResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasFood() || this.hasTool() || this.hasJukeboxPlayable() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper - } - - // Paper start -@@ -1630,6 +1671,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - && (this.hasJukeboxPlayable() ? that.hasJukeboxPlayable() && this.jukebox.equals(that.jukebox) : !that.hasJukeboxPlayable()) - && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) - && (this.hasMaxDamage() ? that.hasMaxDamage() && this.maxDamage.equals(that.maxDamage) : !that.hasMaxDamage()) -+ && (this.canPlaceOnPredicates != null ? that.canPlaceOnPredicates != null && this.canPlaceOnPredicates.equals(that.canPlaceOnPredicates) : that.canPlaceOnPredicates == null) // Paper -+ && (this.canBreakPredicates != null ? that.canBreakPredicates != null && this.canBreakPredicates.equals(that.canBreakPredicates) : that.canBreakPredicates == null) // Paper - && (this.version == that.version); - } - -@@ -1675,6 +1718,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - hash = 61 * hash + (this.hasDamage() ? this.damage : 0); - hash = 61 * hash + (this.hasMaxDamage() ? 1231 : 1237); - hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); -+ hash = 61 * hash + (this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates.hashCode() : 0); // Paper -+ hash = 61 * hash + (this.canBreakPredicates != null ? this.canBreakPredicates.hashCode() : 0); // Paper - hash = 61 * hash + this.version; - return hash; - } -@@ -1719,6 +1764,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - clone.damage = this.damage; - clone.maxDamage = this.maxDamage; - clone.version = this.version; -+ // Paper start -+ if (this.canPlaceOnPredicates != null) { -+ clone.canPlaceOnPredicates = List.copyOf(this.canPlaceOnPredicates); -+ } -+ if (this.canBreakPredicates != null) { -+ clone.canBreakPredicates = List.copyOf(this.canBreakPredicates); -+ } -+ // Paper end - return clone; - } catch (CloneNotSupportedException e) { - throw new Error(e); -@@ -1836,6 +1889,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - } - -+ // Paper start -+ final boolean canBreakAddToUnhandled = this.canBreakPredicates != null && !this.canBreakPredicates.isEmpty(); -+ if (canBreakAddToUnhandled) { -+ this.unhandledTags.set(DataComponents.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates, !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); -+ } -+ final boolean canPlaceOnAddToUnhandled = this.canPlaceOnPredicates != null && !this.canPlaceOnPredicates.isEmpty(); -+ if (canPlaceOnAddToUnhandled) { -+ this.unhandledTags.set(DataComponents.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates, !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); -+ } -+ // Paper end - if (!this.unhandledTags.isEmpty()) { - Tag unhandled = DataComponentPatch.CODEC.encodeStart(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), this.unhandledTags.build()).getOrThrow(IllegalStateException::new); - try { -@@ -1846,6 +1909,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex); - } - } -+ // Paper start -+ if (canBreakAddToUnhandled) { -+ this.unhandledTags.clear(DataComponents.CAN_BREAK); -+ } -+ if (canPlaceOnAddToUnhandled) { -+ this.unhandledTags.clear(DataComponents.CAN_PLACE_ON); -+ } -+ // Paper end - - if (!this.removedTags.isEmpty()) { - RegistryAccess registryAccess = CraftRegistry.getMinecraftRegistry(); -@@ -1999,6 +2070,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - CraftMetaItem.MAX_DAMAGE.TYPE, - CraftMetaItem.CUSTOM_DATA.TYPE, - CraftMetaItem.ATTRIBUTES.TYPE, -+ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper -+ CraftMetaItem.CAN_BREAK.TYPE, // Paper - CraftMetaArmor.TRIM.TYPE, - CraftMetaArmorStand.ENTITY_TAG.TYPE, - CraftMetaBanner.PATTERNS.TYPE, diff --git a/patches/unapplied/server/0957-Fix-helmet-damage-reduction-inconsistencies.patch b/patches/unapplied/server/0957-Fix-helmet-damage-reduction-inconsistencies.patch deleted file mode 100644 index a8b503a8ea..0000000000 --- a/patches/unapplied/server/0957-Fix-helmet-damage-reduction-inconsistencies.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> -Date: Sat, 27 Apr 2024 21:51:58 +0200 -Subject: [PATCH] Fix helmet damage reduction inconsistencies - -Affect the falling stalactite damage type where the -reduction is not applied like in Vanilla - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index 1b21fdab4269df375d2f445df3bd56f7b1fd2b15..4632eb883e9f5efde520ee543bcad25827c0da2c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1228,7 +1228,7 @@ public class CraftEventFactory { - modifiers.put(DamageModifier.FREEZING, freezingModifier); - modifierFunctions.put(DamageModifier.FREEZING, freezing); - } -- if (source.is(DamageTypes.FALLING_BLOCK) || source.is(DamageTypes.FALLING_ANVIL)) { -+ if (source.is(DamageTypeTags.DAMAGES_HELMET)) { // Paper - modifiers.put(DamageModifier.HARD_HAT, hardHatModifier); - modifierFunctions.put(DamageModifier.HARD_HAT, hardHat); - } diff --git a/patches/unapplied/server/0958-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch b/patches/unapplied/server/0958-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch deleted file mode 100644 index 2965a66127..0000000000 --- a/patches/unapplied/server/0958-Revert-to-vanilla-handling-of-LivingEntity-actuallyH.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 27 Apr 2024 09:44:53 -0700 -Subject: [PATCH] Revert to vanilla handling of LivingEntity#actuallyHurt - - -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 6ff33a6d46daffd15310f21ec00d4861478b360f..b1e894e9a9cd87f7259302d15d5b5b0e2b32c4ea 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1425,7 +1425,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - } - - this.noActionTime = 0; -- float f1 = amount; -+ float f1 = amount; final float originalAmount = f1; // Paper - revert to vanilla #hurt - OBFHELPER - boolean flag = amount > 0.0F && this.isDamageSourceBlocked(source); // Copied from below - float f2 = 0.0F; - -@@ -1479,6 +1479,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (!this.actuallyHurt(source, (float) event.getFinalDamage() - this.lastHurt, event)) { - return false; - } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. - // CraftBukkit end - this.lastHurt = amount; - flag1 = false; -@@ -1487,6 +1488,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - if (!this.actuallyHurt(source, (float) event.getFinalDamage(), event)) { - return false; - } -+ if (this instanceof ServerPlayer && event.getDamage() == 0 && originalAmount == 0) return false; // Paper - revert to vanilla damage - players are not affected by damage that is 0 - skip damage if the vanilla damage is 0 and was not modified by plugins in the event. - this.lastHurt = amount; - this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks - // this.actuallyHurt(damagesource, f); -@@ -2411,12 +2413,12 @@ public abstract class LivingEntity extends Entity implements Attackable { - - return true; - } else { -- return originalDamage > 0; -+ return true; // Paper - return false ONLY if event was cancelled - } - // CraftBukkit end - } - } -- return false; // CraftBukkit -+ return true; // CraftBukkit // Paper - return false ONLY if event was cancelled - } - - public CombatTracker getCombatTracker() { diff --git a/patches/unapplied/server/0959-improve-checking-handled-tags-in-itemmeta.patch b/patches/unapplied/server/0959-improve-checking-handled-tags-in-itemmeta.patch deleted file mode 100644 index 83c83dde68..0000000000 --- a/patches/unapplied/server/0959-improve-checking-handled-tags-in-itemmeta.patch +++ /dev/null @@ -1,873 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Mon, 10 Jul 2023 16:10:15 -0700 -Subject: [PATCH] improve checking handled tags in itemmeta - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -index a4c4ba0d02f9a072236ce86c1e98e2c60b059cb8..0930d827e96e0b41296d7723238e6735106fd3d5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java -@@ -39,120 +39,120 @@ import org.bukkit.inventory.meta.TropicalFishBucketMeta; - - public final class CraftItemMetas { - -- public record ItemMetaData(Class metaClass, Function fromItemStack, -+ public record ItemMetaData(Class metaClass, BiFunction>, I> fromItemStack, - BiFunction, CraftMetaItem, I> fromItemMeta) { - } - - private static final ItemMetaData EMPTY_META_DATA = new ItemMetaData<>(ItemMeta.class, -- item -> null, -+ (item, extras) -> null, - (type, meta) -> null); - - private static final ItemMetaData ITEM_META_DATA = new ItemMetaData<>(ItemMeta.class, -- item -> new CraftMetaItem(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaItem(item.getComponentsPatch(), extras), - (type, meta) -> new CraftMetaItem(meta)); - - private static final ItemMetaData SIGNED_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, -- item -> new CraftMetaBookSigned(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBookSigned(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaBookSigned signed ? signed : new CraftMetaBookSigned(meta)); - - private static final ItemMetaData WRITABLE_BOOK_META_DATA = new ItemMetaData<>(BookMeta.class, -- item -> new CraftMetaBook(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBook(item.getComponentsPatch(), extras), - (type, meta) -> meta != null && meta.getClass().equals(CraftMetaBook.class) ? (BookMeta) meta : new CraftMetaBook(meta)); - - private static final ItemMetaData SKULL_META_DATA = new ItemMetaData<>(SkullMeta.class, -- item -> new CraftMetaSkull(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaSkull(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaSkull skull ? skull : new CraftMetaSkull(meta)); - - private static final ItemMetaData ARMOR_META_DATA = new ItemMetaData<>(ArmorMeta.class, -- item -> new CraftMetaArmor(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaArmor(item.getComponentsPatch(), extras), - (type, meta) -> meta != null && meta.getClass().equals(CraftMetaArmor.class) ? (ArmorMeta) meta : new CraftMetaArmor(meta)); - - private static final ItemMetaData COLORABLE_ARMOR_META_DATA = new ItemMetaData<>(ColorableArmorMeta.class, -- item -> new CraftMetaColorableArmor(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaColorableArmor(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof ColorableArmorMeta colorable ? colorable : new CraftMetaColorableArmor(meta)); - - private static final ItemMetaData LEATHER_ARMOR_META_DATA = new ItemMetaData<>(LeatherArmorMeta.class, -- item -> new CraftMetaLeatherArmor(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaLeatherArmor(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaLeatherArmor leather ? leather : new CraftMetaLeatherArmor(meta)); - - private static final ItemMetaData POTION_META_DATA = new ItemMetaData<>(PotionMeta.class, -- item -> new CraftMetaPotion(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaPotion(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaPotion potion ? potion : new CraftMetaPotion(meta)); - - private static final ItemMetaData MAP_META_DATA = new ItemMetaData<>(MapMeta.class, -- item -> new CraftMetaMap(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaMap(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaMap map ? map : new CraftMetaMap(meta)); - - private static final ItemMetaData FIREWORK_META_DATA = new ItemMetaData<>(FireworkMeta.class, -- item -> new CraftMetaFirework(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaFirework(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaFirework firework ? firework : new CraftMetaFirework(meta)); - - private static final ItemMetaData CHARGE_META_DATA = new ItemMetaData<>(FireworkEffectMeta.class, -- item -> new CraftMetaCharge(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaCharge(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaCharge charge ? charge : new CraftMetaCharge(meta)); - - private static final ItemMetaData ENCHANTED_BOOK_META_DATA = new ItemMetaData<>(EnchantmentStorageMeta.class, -- item -> new CraftMetaEnchantedBook(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaEnchantedBook(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaEnchantedBook enchantedBook ? enchantedBook : new CraftMetaEnchantedBook(meta)); - - private static final ItemMetaData BANNER_META_DATA = new ItemMetaData<>(BannerMeta.class, -- item -> new CraftMetaBanner(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBanner(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaBanner banner ? banner : new CraftMetaBanner(meta)); - - private static final ItemMetaData SPAWN_EGG_META_DATA = new ItemMetaData<>(SpawnEggMeta.class, -- item -> new CraftMetaSpawnEgg(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaSpawnEgg(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaSpawnEgg spawnEgg ? spawnEgg : new CraftMetaSpawnEgg(meta)); - - private static final ItemMetaData ARMOR_STAND_META_DATA = new ItemMetaData<>(ArmorStandMeta.class, // paper -- item -> new CraftMetaArmorStand(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaArmorStand(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaArmorStand armorStand ? armorStand : new CraftMetaArmorStand(meta)); - - private static final ItemMetaData KNOWLEDGE_BOOK_META_DATA = new ItemMetaData<>(KnowledgeBookMeta.class, -- item -> new CraftMetaKnowledgeBook(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaKnowledgeBook(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaKnowledgeBook knowledgeBook ? knowledgeBook : new CraftMetaKnowledgeBook(meta)); - - private static final ItemMetaData BLOCK_STATE_META_DATA = new ItemMetaData<>(BlockStateMeta.class, -- item -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem())), -+ (item, extras) -> new CraftMetaBlockState(item.getComponentsPatch(), CraftItemType.minecraftToBukkit(item.getItem()), extras), - (type, meta) -> new CraftMetaBlockState(meta, type.asMaterial())); - - private static final ItemMetaData SHIELD_META_DATA = new ItemMetaData<>(ShieldMeta.class, -- item -> new CraftMetaShield(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaShield(item.getComponentsPatch(), extras), - (type, meta) -> new CraftMetaShield(meta)); - - private static final ItemMetaData TROPICAL_FISH_BUCKET_META_DATA = new ItemMetaData<>(TropicalFishBucketMeta.class, -- item -> new CraftMetaTropicalFishBucket(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaTropicalFishBucket(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaTropicalFishBucket tropicalFishBucket ? tropicalFishBucket : new CraftMetaTropicalFishBucket(meta)); - - private static final ItemMetaData AXOLOTL_BUCKET_META_DATA = new ItemMetaData<>(AxolotlBucketMeta.class, -- item -> new CraftMetaAxolotlBucket(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaAxolotlBucket(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaAxolotlBucket axolotlBucket ? axolotlBucket : new CraftMetaAxolotlBucket(meta)); - - private static final ItemMetaData CROSSBOW_META_DATA = new ItemMetaData<>(CrossbowMeta.class, -- item -> new CraftMetaCrossbow(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaCrossbow(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaCrossbow crossbow ? crossbow : new CraftMetaCrossbow(meta)); - - private static final ItemMetaData SUSPICIOUS_STEW_META_DATA = new ItemMetaData<>(SuspiciousStewMeta.class, -- item -> new CraftMetaSuspiciousStew(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaSuspiciousStew(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaSuspiciousStew suspiciousStew ? suspiciousStew : new CraftMetaSuspiciousStew(meta)); - - private static final ItemMetaData ENTITY_TAG_META_DATA = new ItemMetaData<>(ItemMeta.class, -- item -> new CraftMetaEntityTag(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaEntityTag(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaEntityTag entityTag ? entityTag : new CraftMetaEntityTag(meta)); - - private static final ItemMetaData COMPASS_META_DATA = new ItemMetaData<>(CompassMeta.class, -- item -> new CraftMetaCompass(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaCompass(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaCompass compass ? compass : new CraftMetaCompass(meta)); - - private static final ItemMetaData BUNDLE_META_DATA = new ItemMetaData<>(BundleMeta.class, -- item -> new CraftMetaBundle(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaBundle(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaBundle bundle ? bundle : new CraftMetaBundle(meta)); - - private static final ItemMetaData MUSIC_INSTRUMENT_META_DATA = new ItemMetaData<>(MusicInstrumentMeta.class, -- item -> new CraftMetaMusicInstrument(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaMusicInstrument(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaMusicInstrument musicInstrument ? musicInstrument : new CraftMetaMusicInstrument(meta)); - - private static final ItemMetaData OMINOUS_BOTTLE_META_DATA = new ItemMetaData<>(OminousBottleMeta.class, -- item -> new CraftMetaOminousBottle(item.getComponentsPatch()), -+ (item, extras) -> new CraftMetaOminousBottle(item.getComponentsPatch(), extras), - (type, meta) -> meta instanceof CraftMetaOminousBottle musicInstrument ? musicInstrument : new CraftMetaOminousBottle(meta)); - - // We use if instead of a set, since the result gets cached in CraftItemType, -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -index 9be7859ccb5283b2040ba68d72d6dbdafb4d6835..6a449bfc765bf427d82df4a90bc60471b5de2fd3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java -@@ -161,10 +161,11 @@ public final class CraftItemStack extends ItemStack { - } else if (this.handle == null) { - this.handle = new net.minecraft.world.item.ItemStack(CraftItemType.bukkitToMinecraft(type), 1); - } else { -+ final Material oldType = CraftMagicNumbers.getMaterial(this.handle.getItem()); // Paper - this.handle.setItem(CraftItemType.bukkitToMinecraft(type)); - if (this.hasItemMeta()) { - // This will create the appropriate item meta, which will contain all the data we intend to keep -- CraftItemStack.setItemMeta(this.handle, CraftItemStack.getItemMeta(this.handle)); -+ this.adjustTagForItemMeta(oldType); // Paper - } - } - this.setData(null); -@@ -325,6 +326,19 @@ public final class CraftItemStack extends ItemStack { - public ItemMeta getItemMeta() { - return CraftItemStack.getItemMeta(this.handle); - } -+ // Paper start - improve handled tags on type change -+ public void adjustTagForItemMeta(final Material oldType) { -+ final CraftMetaItem oldMeta = (CraftMetaItem) CraftItemFactory.instance().getItemMeta(oldType); -+ final ItemMeta newMeta; -+ if (oldMeta == null) { -+ newMeta = getItemMeta(this.handle); -+ } else { -+ final java.util.Set> extraHandledDcts = new java.util.HashSet<>(CraftMetaItem.getTopLevelHandledDcts(oldMeta.getClass())); -+ newMeta = getItemMeta(this.handle, CraftItemType.minecraftToBukkitNew(this.handle.getItem()), extraHandledDcts); -+ } -+ this.setItemMeta(newMeta); -+ } -+ // Paper end - improve handled tags on type change - // Paper start - public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) { - final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator(); -@@ -337,12 +351,17 @@ public final class CraftItemStack extends ItemStack { - } - public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType) { - // Paper end -+ // Paper start - handled tags on type change -+ return getItemMeta(item, metaForType, null); -+ } -+ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, org.bukkit.inventory.ItemType metaForType, final java.util.Set> extraHandledDcts) { -+ // Paper end - handled tags on type change - if (!CraftItemStack.hasItemMeta(item)) { - return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item)); - } - -- if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item); } // Paper -- return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item); -+ if (metaForType != null) { return ((CraftItemType) metaForType).getItemMeta(item, extraHandledDcts); } // Paper -+ return ((CraftItemType) CraftItemType.minecraftToBukkitNew(item.getItem())).getItemMeta(item, extraHandledDcts); // Paper - } - - static Material getType(net.minecraft.world.item.ItemStack item) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -index a1f2b9d40d374e8cdbaf916b25fa74b6c0970f81..d03f4a767f6c7fe7d6bcef20e6676c39d9657584 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemType.java -@@ -114,8 +114,8 @@ public class CraftItemType implements ItemType.Typed, Han - return this.item; - } - -- public M getItemMeta(net.minecraft.world.item.ItemStack itemStack) { -- return this.itemMetaData.get().fromItemStack().apply(itemStack); -+ public M getItemMeta(net.minecraft.world.item.ItemStack itemStack, final java.util.Set> extraHandledDcts) { -+ return this.itemMetaData.get().fromItemStack().apply(itemStack, extraHandledDcts); - } - - public M getItemMeta(ItemMeta itemMeta) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -index 865977ce17fbb8793a1eefd71079729e83f5cfaf..889d43acf4cf7a5917f110105ed05838e24c8cf7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java -@@ -34,8 +34,8 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta { - } - } - -- CraftMetaArmor(DataComponentPatch tag) { -- super(tag); -+ CraftMetaArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaArmor.TRIM).ifPresent((trimCompound) -> { - TrimMaterial trimMaterial = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(io.papermc.paper.registry.RegistryKey.TRIM_MATERIAL, trimCompound.material()).orElse(null); // Paper - fix upstream not being correct -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java -index ecce5d0da946ca279c5608068442cc53437dd2a5..00b5c4ab6111f980db1b9e99f901667741266440 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java -@@ -35,8 +35,8 @@ public class CraftMetaArmorStand extends CraftMetaItem implements com.destroysto - this.entityTag = armorStand.entityTag; - } - -- CraftMetaArmorStand(DataComponentPatch tag) { -- super(tag); -+ CraftMetaArmorStand(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaArmorStand.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -index c4beb94d8e5448e69f31f30299448f344b5d8f59..169fefb64e1af444f7c2efb1234cb6e7779fb717 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaAxolotlBucket.java -@@ -36,8 +36,8 @@ public class CraftMetaAxolotlBucket extends CraftMetaItem implements AxolotlBuck - this.bucketEntityTag = bucket.bucketEntityTag; - } - -- CraftMetaAxolotlBucket(DataComponentPatch tag) { -- super(tag); -+ CraftMetaAxolotlBucket(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaAxolotlBucket.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -index eb44c19f6af624df458981e46c73a64358d6e1ce..d0a8cd89da3b8d87248494056470c306f8fb5ae8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java -@@ -34,8 +34,8 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta { - this.patterns = new ArrayList(banner.patterns); - } - -- CraftMetaBanner(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBanner(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBanner.PATTERNS).ifPresent((entityTag) -> { - List patterns = entityTag.layers(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -index 3985e5b4e2d65faa8eaea1d4a2acc6fb1e64f959..413e41f113226b8a2e9b30bb519076d78e451fa0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBlockState.java -@@ -73,8 +73,8 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta - this.position = te.position; - } - -- CraftMetaBlockState(DataComponentPatch tag, Material material) { -- super(tag); -+ CraftMetaBlockState(DataComponentPatch tag, Material material, final Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - this.material = material; - - getOrEmpty(tag, CraftMetaBlockState.BLOCK_ENTITY_TAG).ifPresent((blockTag) -> { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -index 32e5188442551b3e72e1d4826d836d622d0e438a..257c835bc280eee9ee73ae75b5249bb568a687d0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBook.java -@@ -64,8 +64,8 @@ public class CraftMetaBook extends CraftMetaItem implements BookMeta, WritableBo - } - } - -- CraftMetaBook(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBook.BOOK_CONTENT).ifPresent((writable) -> { - List> pages = writable.pages(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -index fd3b12477c30d1eabdbe57ea779027931e9dd957..cbb3d80cc7cd81b2505dff999a0baede737165f7 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java -@@ -78,8 +78,8 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta { - } - } - -- CraftMetaBookSigned(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBookSigned(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBookSigned.BOOK_CONTENT).ifPresent((written) -> { - this.title = written.title().raw(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -index 30533ce683e0471742b27d1d31df20def8ea169c..2736a87a6c481da0575e6e29ea08faa539c24378 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBundle.java -@@ -34,8 +34,8 @@ public class CraftMetaBundle extends CraftMetaItem implements BundleMeta { - } - } - -- CraftMetaBundle(DataComponentPatch tag) { -- super(tag); -+ CraftMetaBundle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaBundle.ITEMS).ifPresent((bundle) -> { - bundle.items().forEach((item) -> { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java -index 72340e7269a5464d72abe8370c8113f3de9573d2..56c6784e29cecf8655282235959de536d07c1e08 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCharge.java -@@ -29,8 +29,8 @@ class CraftMetaCharge extends CraftMetaItem implements FireworkEffectMeta { - this.setEffect(SerializableMeta.getObject(FireworkEffect.class, map, CraftMetaCharge.EXPLOSION.BUKKIT, true)); - } - -- CraftMetaCharge(DataComponentPatch tag) { -- super(tag); -+ CraftMetaCharge(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaCharge.EXPLOSION).ifPresent((f) -> { - try { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -index 366fec1aee66de4031727a1383acebd319eeef88..6517ec4933b0eae761fceb117ea1db175755d0b1 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -@@ -18,8 +18,8 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable - CraftMetaLeatherArmor.readColor(this, meta); - } - -- CraftMetaColorableArmor(DataComponentPatch tag) { -- super(tag); -+ CraftMetaColorableArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - CraftMetaLeatherArmor.readColor(this, tag); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -index 607e23040383576b2805c25947a69f6efe6d2c88..69a112b3a9726966aecbe687d905fd1a11cfa1e3 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCompass.java -@@ -50,8 +50,8 @@ public class CraftMetaCompass extends CraftMetaItem implements CompassMeta { - this.tracked = compassMeta.tracked; - } - -- CraftMetaCompass(DataComponentPatch tag) { -- super(tag); -+ CraftMetaCompass(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaCompass.LODESTONE_TARGET).ifPresent((lodestoneTarget) -> { - lodestoneTarget.target().ifPresent((target) -> { - this.lodestoneWorld = target.dimension(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -index c278af519308c84ad76fc2312046980c01c528ba..0807c2172c5a4bee675cef265a45a9350e98b880 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaCrossbow.java -@@ -36,8 +36,8 @@ public class CraftMetaCrossbow extends CraftMetaItem implements CrossbowMeta { - } - } - -- CraftMetaCrossbow(DataComponentPatch tag) { -- super(tag); -+ CraftMetaCrossbow(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaCrossbow.CHARGED_PROJECTILES).ifPresent((p) -> { - List list = p.getItems(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -index 19af55ec2bf62b70bd3be44f499b32f5efe71ab1..c93f769ee6c55022653696da45de568fcf7589fe 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java -@@ -32,8 +32,8 @@ class CraftMetaEnchantedBook extends CraftMetaItem implements EnchantmentStorage - } - } - -- CraftMetaEnchantedBook(DataComponentPatch tag) { -- super(tag); -+ CraftMetaEnchantedBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaEnchantedBook.STORED_ENCHANTMENTS).ifPresent((itemEnchantments) -> { - this.enchantments = buildEnchantments(itemEnchantments); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -index 3ff0340c40e9dc9a6e690de15ccade7a0c4e8f02..3f6c5cbbf63631e4b72dc43558651ea94f31ca78 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java -@@ -39,8 +39,8 @@ public class CraftMetaEntityTag extends CraftMetaItem { - this.entityTag = entity.entityTag; - } - -- CraftMetaEntityTag(DataComponentPatch tag) { -- super(tag); -+ CraftMetaEntityTag(DataComponentPatch tag, final java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaEntityTag.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -index 4941e0afff8df5f10f06c715b54bf58eb86051c5..566d893a413fd04b99e83dc2da8fe958a48492a8 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java -@@ -60,8 +60,8 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta { - } - } - -- CraftMetaFirework(DataComponentPatch tag) { -- super(tag); -+ CraftMetaFirework(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaFirework.FIREWORKS).ifPresent((fireworks) -> { - this.power = fireworks.flightDuration(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index c2a215544589d903633c5aed51522870bea556d8..85bc581d0807f07212bf0cd4c85c65f0ec7ef547 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -339,7 +339,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - // Paper end - } - -- CraftMetaItem(DataComponentPatch tag) { -+ CraftMetaItem(DataComponentPatch tag, Set> extraHandledTags) { // Paper - improve handled tags on type changes - CraftMetaItem.getOrEmpty(tag, CraftMetaItem.NAME).ifPresent((component) -> { - this.displayName = component; - }); -@@ -450,9 +450,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - }); - // Paper end - fix ItemFlags - -+ // Paper start - improve checking handled data component types -+ Set> handledTags = getTopLevelHandledDcts(this.getClass()); -+ if (extraHandledTags != null) { -+ extraHandledTags.addAll(handledTags); -+ handledTags = extraHandledTags; -+ } -+ // Paper end - improve checking handled data component types - Set, Optional>> keys = tag.entrySet(); - for (Map.Entry, Optional> key : keys) { -- if (!CraftMetaItem.getHandledTags().contains(key.getKey())) { -+ if (!handledTags.contains(key.getKey())) { // Paper - improve checking handled data component types - key.getValue().ifPresent((value) -> { - this.unhandledTags.set((DataComponentType) key.getKey(), value); - }); -@@ -2045,68 +2052,76 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.version = version; - } - -- public static Set getHandledTags() { -- synchronized (CraftMetaItem.HANDLED_TAGS) { -- if (CraftMetaItem.HANDLED_TAGS.isEmpty()) { -- CraftMetaItem.HANDLED_TAGS.addAll(Arrays.asList( -- CraftMetaItem.NAME.TYPE, -- CraftMetaItem.ITEM_NAME.TYPE, -- CraftMetaItem.LORE.TYPE, -- CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, -- CraftMetaItem.BLOCK_DATA.TYPE, -- CraftMetaItem.REPAIR.TYPE, -- CraftMetaItem.ENCHANTMENTS.TYPE, -- CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, -- CraftMetaItem.HIDE_TOOLTIP.TYPE, -- CraftMetaItem.UNBREAKABLE.TYPE, -- CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, -- CraftMetaItem.FIRE_RESISTANT.TYPE, -- CraftMetaItem.MAX_STACK_SIZE.TYPE, -- CraftMetaItem.RARITY.TYPE, -- CraftMetaItem.FOOD.TYPE, -- CraftMetaItem.TOOL.TYPE, -- CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, -- CraftMetaItem.DAMAGE.TYPE, -- CraftMetaItem.MAX_DAMAGE.TYPE, -- CraftMetaItem.CUSTOM_DATA.TYPE, -- CraftMetaItem.ATTRIBUTES.TYPE, -- CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper -- CraftMetaItem.CAN_BREAK.TYPE, // Paper -- CraftMetaArmor.TRIM.TYPE, -- CraftMetaArmorStand.ENTITY_TAG.TYPE, -- CraftMetaBanner.PATTERNS.TYPE, -- CraftMetaEntityTag.ENTITY_TAG.TYPE, -- CraftMetaLeatherArmor.COLOR.TYPE, -- CraftMetaMap.MAP_POST_PROCESSING.TYPE, -- CraftMetaMap.MAP_COLOR.TYPE, -- CraftMetaMap.MAP_ID.TYPE, -- CraftMetaPotion.POTION_CONTENTS.TYPE, -- CraftMetaShield.BASE_COLOR.TYPE, -- CraftMetaSkull.SKULL_PROFILE.TYPE, -- CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE, -- CraftMetaSpawnEgg.ENTITY_TAG.TYPE, -- CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE, -- CraftMetaBook.BOOK_CONTENT.TYPE, -- CraftMetaBookSigned.BOOK_CONTENT.TYPE, -- CraftMetaFirework.FIREWORKS.TYPE, -- CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE, -- CraftMetaCharge.EXPLOSION.TYPE, -- CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE, -- CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, -- CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE, -- CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, -- CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE, -- CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE, -- CraftMetaSuspiciousStew.EFFECTS.TYPE, -- CraftMetaCompass.LODESTONE_TARGET.TYPE, -- CraftMetaBundle.ITEMS.TYPE, -- CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE, -- CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE -- )); -- } -- return CraftMetaItem.HANDLED_TAGS; -+ // Paper start - improve checking handled tags -+ @org.jetbrains.annotations.VisibleForTesting -+ public static final Map, Set>> HANDLED_DCTS_PER_TYPE = new HashMap<>(); -+ private static final Set> DEFAULT_HANDLED_DCTS = Set.of( -+ CraftMetaItem.NAME.TYPE, -+ CraftMetaItem.ITEM_NAME.TYPE, -+ CraftMetaItem.LORE.TYPE, -+ CraftMetaItem.CUSTOM_MODEL_DATA.TYPE, -+ CraftMetaItem.BLOCK_DATA.TYPE, -+ CraftMetaItem.REPAIR.TYPE, -+ CraftMetaItem.ENCHANTMENTS.TYPE, -+ CraftMetaItem.HIDE_ADDITIONAL_TOOLTIP.TYPE, -+ CraftMetaItem.HIDE_TOOLTIP.TYPE, -+ CraftMetaItem.UNBREAKABLE.TYPE, -+ CraftMetaItem.ENCHANTMENT_GLINT_OVERRIDE.TYPE, -+ CraftMetaItem.FIRE_RESISTANT.TYPE, -+ CraftMetaItem.MAX_STACK_SIZE.TYPE, -+ CraftMetaItem.RARITY.TYPE, -+ CraftMetaItem.FOOD.TYPE, -+ CraftMetaItem.TOOL.TYPE, -+ CraftMetaItem.JUKEBOX_PLAYABLE.TYPE, -+ CraftMetaItem.DAMAGE.TYPE, -+ CraftMetaItem.MAX_DAMAGE.TYPE, -+ CraftMetaItem.CUSTOM_DATA.TYPE, -+ CraftMetaItem.ATTRIBUTES.TYPE, -+ CraftMetaItem.CAN_PLACE_ON.TYPE, // Paper -+ CraftMetaItem.CAN_BREAK.TYPE // Paper -+ ); -+ public static Set> getTopLevelHandledDcts(final Class clazz) { -+ synchronized (HANDLED_DCTS_PER_TYPE) { -+ if (HANDLED_DCTS_PER_TYPE.isEmpty()) { -+ final Map, Set>> map = new HashMap<>(); -+ map.put(CraftMetaArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE)); -+ map.put(CraftMetaArmorStand.class, Set.of(CraftMetaArmorStand.ENTITY_TAG.TYPE)); -+ map.put(CraftMetaAxolotlBucket.class, Set.of(CraftMetaAxolotlBucket.ENTITY_TAG.TYPE, CraftMetaAxolotlBucket.BUCKET_ENTITY_TAG.TYPE)); -+ map.put(CraftMetaBanner.class, Set.of(CraftMetaBanner.PATTERNS.TYPE)); // banner uses same tag as block state -+ map.put(CraftMetaShield.class, Set.of(CraftMetaShield.BASE_COLOR.TYPE, CraftMetaBanner.PATTERNS.TYPE)); -+ map.put(CraftMetaBlockState.class, Set.of(CraftMetaBlockState.BLOCK_ENTITY_TAG.TYPE)); -+ map.put(CraftMetaBook.class, Set.of(CraftMetaBook.BOOK_CONTENT.TYPE)); -+ map.put(CraftMetaBookSigned.class, Set.of(CraftMetaBookSigned.BOOK_CONTENT.TYPE)); -+ map.put(CraftMetaBundle.class, Set.of(CraftMetaBundle.ITEMS.TYPE)); -+ map.put(CraftMetaCharge.class, Set.of(CraftMetaCharge.EXPLOSION.TYPE)); -+ map.put(CraftMetaColorableArmor.class, Set.of(CraftMetaArmor.TRIM.TYPE, CraftMetaLeatherArmor.COLOR.TYPE)); -+ map.put(CraftMetaCompass.class, Set.of(CraftMetaCompass.LODESTONE_TARGET.TYPE)); -+ map.put(CraftMetaCrossbow.class, Set.of(CraftMetaCrossbow.CHARGED_PROJECTILES.TYPE)); -+ map.put(CraftMetaEnchantedBook.class, Set.of(CraftMetaEnchantedBook.STORED_ENCHANTMENTS.TYPE)); -+ map.put(CraftMetaEntityTag.class, Set.of(CraftMetaEntityTag.ENTITY_TAG.TYPE)); -+ map.put(CraftMetaFirework.class, Set.of(CraftMetaFirework.FIREWORKS.TYPE)); -+ map.put(CraftMetaKnowledgeBook.class, Set.of(CraftMetaKnowledgeBook.BOOK_RECIPES.TYPE)); -+ map.put(CraftMetaLeatherArmor.class, Set.of(CraftMetaLeatherArmor.COLOR.TYPE)); -+ map.put(CraftMetaMap.class, Set.of(CraftMetaMap.MAP_COLOR.TYPE, CraftMetaMap.MAP_POST_PROCESSING.TYPE, CraftMetaMap.MAP_ID.TYPE)); -+ map.put(CraftMetaMusicInstrument.class, Set.of(CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT.TYPE)); -+ map.put(CraftMetaOminousBottle.class, Set.of(CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER.TYPE)); -+ map.put(CraftMetaPotion.class, Set.of(CraftMetaPotion.POTION_CONTENTS.TYPE)); -+ map.put(CraftMetaSkull.class, Set.of(CraftMetaSkull.SKULL_PROFILE.TYPE, CraftMetaSkull.NOTE_BLOCK_SOUND.TYPE)); -+ map.put(CraftMetaSpawnEgg.class, Set.of(CraftMetaSpawnEgg.ENTITY_TAG.TYPE)); -+ map.put(CraftMetaSuspiciousStew.class, Set.of(CraftMetaSuspiciousStew.EFFECTS.TYPE)); -+ map.put(CraftMetaTropicalFishBucket.class, Set.of(CraftMetaTropicalFishBucket.ENTITY_TAG.TYPE, CraftMetaTropicalFishBucket.BUCKET_ENTITY_TAG.TYPE)); -+ -+ for (final Map.Entry, Set>> entry : map.entrySet()) { -+ final ArrayList> topLevelTags = new ArrayList<>(entry.getValue()); -+ // add tags common to CraftMetaItem to all -+ topLevelTags.addAll(DEFAULT_HANDLED_DCTS); -+ HANDLED_DCTS_PER_TYPE.put(entry.getKey(), Set.copyOf(topLevelTags)); -+ } -+ } -+ return HANDLED_DCTS_PER_TYPE.getOrDefault(clazz, DEFAULT_HANDLED_DCTS); - } - } -+ // Paper end - improve checking handled data component types - - protected static Optional getOrEmpty(DataComponentPatch tag, ItemMetaKeyType type) { - Optional result = tag.get(type.TYPE); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java -index 573806b9200282f9842ab5289af4e2987905cafc..e47c1b9a52c938b145b721d9c088f4a916a01424 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaKnowledgeBook.java -@@ -30,8 +30,8 @@ public class CraftMetaKnowledgeBook extends CraftMetaItem implements KnowledgeBo - } - } - -- CraftMetaKnowledgeBook(DataComponentPatch tag) { -- super(tag); -+ CraftMetaKnowledgeBook(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaKnowledgeBook.BOOK_RECIPES).ifPresent((pages) -> { - for (int i = 0; i < pages.size(); i++) { -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -index 75a8ad69902103a2e33a457c3225a33860d075ed..e8c950aa74d31bf7a9128f4acc4bccee26bbcd7f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -@@ -25,8 +25,8 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - CraftMetaLeatherArmor.readColor(this, meta); - } - -- CraftMetaLeatherArmor(DataComponentPatch tag) { -- super(tag); -+ CraftMetaLeatherArmor(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - CraftMetaLeatherArmor.readColor(this, tag); - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -index 08e18dcabbf52aae5c3843d49a72d1d52baa729b..149356981e586e4f67d4543d3df94a2ea99333fc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMap.java -@@ -44,8 +44,8 @@ class CraftMetaMap extends CraftMetaItem implements MapMeta { - this.color = map.color; - } - -- CraftMetaMap(DataComponentPatch tag) { -- super(tag); -+ CraftMetaMap(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaMap.MAP_ID).ifPresent((mapId) -> { - this.mapId = mapId.id(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -index 76a3e4893cbdba903a712d6db1d30b9c644795be..a80b9b142ca99c7c0257b1bdeb059dce5f92ae93 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaMusicInstrument.java -@@ -26,8 +26,8 @@ public class CraftMetaMusicInstrument extends CraftMetaItem implements MusicInst - } - } - -- CraftMetaMusicInstrument(DataComponentPatch tag) { -- super(tag); -+ CraftMetaMusicInstrument(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaMusicInstrument.GOAT_HORN_INSTRUMENT).ifPresent((instrument) -> { - this.instrument = org.bukkit.craftbukkit.CraftRegistry.unwrapAndConvertHolder(org.bukkit.Registry.INSTRUMENT, instrument).orElse(null); // Paper - fix upstream not handling inlined instrument -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -index 17336c177a969f04c51ff12de4599ef261d79fef..90c554dcbfe2bcca3f742379499f1e8e8665c512 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaOminousBottle.java -@@ -23,8 +23,8 @@ public class CraftMetaOminousBottle extends CraftMetaItem implements OminousBott - this.ominousBottleAmplifier = bottleMeta.ominousBottleAmplifier; - } - -- CraftMetaOminousBottle(DataComponentPatch tag) { -- super(tag); -+ CraftMetaOminousBottle(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaOminousBottle.OMINOUS_BOTTLE_AMPLIFIER).ifPresent((amplifier) -> { - this.ominousBottleAmplifier = amplifier; - }); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -index 8404520a3d15464f9dc9fa2292048e9fb1b06930..1a18779f9796704c8690226dbe491b0fa6ba99ea 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java -@@ -51,8 +51,8 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { - } - } - -- CraftMetaPotion(DataComponentPatch tag) { -- super(tag); -+ CraftMetaPotion(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaPotion.POTION_CONTENTS).ifPresent((potionContents) -> { - potionContents.potion().ifPresent((potion) -> { - this.type = CraftPotionType.minecraftHolderToBukkit(potion); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -index bcd6cc29e4e621805cbd923d747f652ced240c6d..967d8940aec0065bce496d5d7a8c73de5733bd2c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaShield.java -@@ -42,8 +42,8 @@ public class CraftMetaShield extends CraftMetaItem implements ShieldMeta, BlockS - } - } - -- CraftMetaShield(DataComponentPatch tag) { -- super(tag); -+ CraftMetaShield(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper - improve checking handled tags in item meta -+ super(tag, extraHandledDcts); // Paper - improve checking handled tags in item meta - - getOrEmpty(tag, CraftMetaShield.BASE_COLOR).ifPresent((color) -> { - this.banner = CraftMetaShield.getBlockState(DyeColor.getByWoolData((byte) color.getId())); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -index ca714e165e453d1072d083441d8b985290ada75a..302906467b12189e21633369c005736863f46dd5 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java -@@ -48,8 +48,8 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta { - this.noteBlockSound = skullMeta.noteBlockSound; - } - -- CraftMetaSkull(DataComponentPatch tag) { -- super(tag); -+ CraftMetaSkull(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaSkull.SKULL_PROFILE).ifPresent(this::setProfile); - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -index 6c2c3b514be0dab47f3e44f65bdc6a3574e59b7c..8ddf091b3ff1262b6c97e8fe72e0a80db5e1037d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java -@@ -33,8 +33,8 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta { - this.entityTag = egg.entityTag; - } - -- CraftMetaSpawnEgg(DataComponentPatch tag) { -- super(tag); -+ CraftMetaSpawnEgg(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaSpawnEgg.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java -index 248efddbad2bfee4f9aa33ec738b5353054eda61..7a43e326e51300306b9c5c23a16ffae92030bd2b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSuspiciousStew.java -@@ -33,8 +33,8 @@ public class CraftMetaSuspiciousStew extends CraftMetaItem implements Suspicious - } - } - -- CraftMetaSuspiciousStew(DataComponentPatch tag) { -- super(tag); -+ CraftMetaSuspiciousStew(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - getOrEmpty(tag, CraftMetaSuspiciousStew.EFFECTS).ifPresent((suspiciousStewEffects) -> { - List list = suspiciousStewEffects.effects(); - int length = list.size(); -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -index a514fe98d3d2b65d2cfd029079c69189bcb99c01..17705059b81942e4df43a4a5180092e09c985ade 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaTropicalFishBucket.java -@@ -38,8 +38,8 @@ class CraftMetaTropicalFishBucket extends CraftMetaItem implements TropicalFishB - this.bucketEntityTag = bucket.bucketEntityTag; - } - -- CraftMetaTropicalFishBucket(DataComponentPatch tag) { -- super(tag); -+ CraftMetaTropicalFishBucket(DataComponentPatch tag, java.util.Set> extraHandledDcts) { // Paper -+ super(tag, extraHandledDcts); // Paper - - getOrEmpty(tag, CraftMetaTropicalFishBucket.ENTITY_TAG).ifPresent((nbt) -> { - this.entityTag = nbt.copyTag(); -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -index 91cfa32272770cdfe56d97154ea9db4e2ed8a328..9cc1ef5c9221dd7d2069b280f0c91ce9439a995a 100644 ---- a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java -@@ -97,7 +97,7 @@ public class DeprecatedItemMetaCustomValueTest { - CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); - itemMeta.applyToItem(compound); - -- assertEquals(itemMeta, new CraftMetaItem(compound.build())); -+ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper - } - - @Test -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java -new file mode 100644 -index 0000000000000000000000000000000000000000..df20446af3d43c624278d1a25f31f702677c8d96 ---- /dev/null -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/MetaHandledTagsTest.java -@@ -0,0 +1,33 @@ -+package org.bukkit.craftbukkit.inventory; -+ -+import io.github.classgraph.ClassGraph; -+import io.github.classgraph.ClassInfo; -+import io.github.classgraph.ClassInfoList; -+import io.github.classgraph.ScanResult; -+import org.bukkit.support.environment.AllFeatures; -+import org.junit.jupiter.api.Test; -+ -+import static org.junit.jupiter.api.Assertions.assertFalse; -+import static org.junit.jupiter.api.Assertions.assertTrue; -+ -+// in cb package because of package-private stuff -+@AllFeatures -+class MetaHandledTagsTest { -+ -+ @Test -+ public void checkAllMetasHaveHandledTags() { -+ try (final ScanResult result = new ClassGraph() -+ .whitelistPackages("org.bukkit.craftbukkit.inventory") -+ .enableClassInfo().scan()) { -+ final ClassInfoList subclasses = result.getSubclasses(CraftMetaItem.class.getName()); -+ assertFalse(subclasses.isEmpty(), "found 0 sub types"); -+ for (final ClassInfo subclass : subclasses) { -+ final Class clazz = subclass.loadClass(CraftMetaItem.class); -+ CraftMetaItem.getTopLevelHandledDcts(clazz); // load into map -+ assertTrue(CraftMetaItem.HANDLED_DCTS_PER_TYPE.containsKey(clazz), subclass.getName() + " not found in handled tags map"); -+ } -+ } catch (Exception e) { -+ throw new RuntimeException(e); -+ } -+ } -+} -diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -index 5b16e6f5e5517eed218e4b60ecd75f8b80712e89..130c4500a5e854480962c8f720b1df4c67d43c33 100644 ---- a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -+++ b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java -@@ -131,7 +131,7 @@ public class PersistentDataContainerTest { - CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator(); - itemMeta.applyToItem(compound); - -- assertEquals(itemMeta, new CraftMetaItem(compound.build())); -+ assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper - } - - @Test -@@ -464,7 +464,7 @@ public class PersistentDataContainerTest { - - @Test - public void testEmptyListApplicationToAnyType() throws IOException { -- final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY); -+ final CraftMetaItem craftItem = new CraftMetaItem(DataComponentPatch.EMPTY, null); // Paper - final PersistentDataContainer container = craftItem.getPersistentDataContainer(); - - container.set(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings(), List.of()); -@@ -477,7 +477,7 @@ public class PersistentDataContainerTest { - final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator(); - craftItem.applyToItem(storage); - -- final CraftMetaItem readItem = new CraftMetaItem(storage.build()); -+ final CraftMetaItem readItem = new CraftMetaItem(storage.build(), null); // Paper - final PersistentDataContainer readContainer = readItem.getPersistentDataContainer(); - - assertTrue(readContainer.has(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings())); diff --git a/patches/unapplied/server/0961-Expose-hasColor-to-leather-armor.patch b/patches/unapplied/server/0961-Expose-hasColor-to-leather-armor.patch deleted file mode 100644 index fb4dc944de..0000000000 --- a/patches/unapplied/server/0961-Expose-hasColor-to-leather-armor.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: SoSeDiK -Date: Wed, 1 May 2024 10:58:50 +0300 -Subject: [PATCH] Expose #hasColor to leather armor - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -index 299f2f4f143f753f3cd8a020c8e6ae46298e0f6f..51d7263cdd34359d9cdf72cc01ba654b519f838d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaColorableArmor.java -@@ -118,4 +118,11 @@ public class CraftMetaColorableArmor extends CraftMetaArmor implements Colorable - } - return original != hash ? CraftMetaColorableArmor.class.hashCode() ^ hash : hash; - } -+ -+ // Paper start - Expose #hasColor to leather armor -+ @Override -+ public boolean isDyed() { -+ return hasColor(); -+ } -+ // Paper end - Expose #hasColor to leather armor - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -index f1dbfba7ec11b12ead627f098a0b833f49be8000..49889026661fb2a558e14569324016d637de27a0 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaLeatherArmor.java -@@ -177,4 +177,11 @@ class CraftMetaLeatherArmor extends CraftMetaItem implements LeatherArmorMeta { - builder.put(CraftMetaLeatherArmor.COLOR.BUKKIT, meta.getColor()); - } - } -+ -+ // Paper start - Expose #hasColor to leather armor -+ @Override -+ public boolean isDyed() { -+ return hasColor(); -+ } -+ // Paper end - Expose #hasColor to leather armor - } diff --git a/patches/unapplied/server/0962-Added-API-to-get-player-ha-proxy-address.patch b/patches/unapplied/server/0962-Added-API-to-get-player-ha-proxy-address.patch deleted file mode 100644 index a21e9c27e9..0000000000 --- a/patches/unapplied/server/0962-Added-API-to-get-player-ha-proxy-address.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: nostalfinals -Date: Mon, 8 Apr 2024 23:24:38 +0800 -Subject: [PATCH] Added API to get player ha proxy address - - -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index ea16dfa718b526d6520d7fcfc21d28f972f1f2bf..4b9da6e2140b14f1e56056f5e9e94b2169d85501 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -153,6 +153,7 @@ public class Connection extends SimpleChannelInboundHandler> { - this.stopReadingPackets = true; - } - // Paper end - packet limiter -+ @Nullable public SocketAddress haProxyAddress; // Paper - Add API to get player's proxy address - - public Connection(PacketFlow side) { - this.receiving = side; -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index c62df32af11636ad408b584fcc590590ce4fb0d0..baed0bb80d44973f9323bbe536551182979caff2 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -144,6 +144,13 @@ public class ServerConnectionListener { - - Connection connection = (Connection) channel.pipeline().get("packet_handler"); - connection.address = socketaddr; -+ -+ // Paper start - Add API to get player's proxy address -+ final String proxyAddress = message.destinationAddress(); -+ final int proxyPort = message.destinationPort(); -+ -+ connection.haProxyAddress = new java.net.InetSocketAddress(proxyAddress, proxyPort); -+ // Paper end - Add API to get player's proxy address - } - } else { - super.channelRead(ctx, msg); -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 6db4d21ee4dc97820943d3fd2aa55054cac95f50..5f12c91ea598b4b133bf41532a9864645ebf6cea 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -265,7 +265,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public InetSocketAddress getAddress() { -- if (this.getHandle().connection.protocol() == null) return null; -+ if (this.getHandle().connection == null) return null; - - SocketAddress addr = this.getHandle().connection.getRemoteAddress(); - if (addr instanceof InetSocketAddress) { -@@ -275,6 +275,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - } - } - -+ // Paper start - Add API to get player's proxy address -+ @Override -+ public @Nullable InetSocketAddress getHAProxyAddress() { -+ if (this.getHandle().connection == null) return null; -+ -+ return this.getHandle().connection.connection.haProxyAddress instanceof final InetSocketAddress inetSocketAddress ? inetSocketAddress : null; -+ } -+ // Paper end - Add API to get player's proxy address -+ - public interface TransferCookieConnection { - - boolean isTransferred(); -- cgit v1.2.3