diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java index 5654aa986e..4167416ac6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -55,6 +55,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.SnbtPrinterTagVisitor; import net.minecraft.network.chat.IChatBaseComponent; +import net.minecraft.resources.MinecraftKey; import net.minecraft.server.MinecraftServer; import net.minecraft.util.Unit; import net.minecraft.world.entity.EnumItemSlot; @@ -272,6 +273,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { private NBTTagCompound customTag; protected DataComponentPatch.a unhandledTags = DataComponentPatch.builder(); + private Set> removedTags = Sets.newHashSet(); private CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY); private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only @@ -319,6 +321,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { this.damage = meta.damage; this.maxDamage = meta.maxDamage; this.unhandledTags = meta.unhandledTags; + this.removedTags.addAll(meta.removedTags); this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw()); this.customTag = meta.customTag; @@ -426,12 +429,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { Set, Optional>> keys = tag.entrySet(); for (Map.Entry, Optional> key : keys) { if (!getHandledTags().contains(key.getKey())) { - key.getValue().ifPresentOrElse((value) -> { + key.getValue().ifPresent((value) -> { unhandledTags.set((DataComponentType) key.getKey(), value); - }, () -> { - unhandledTags.remove(key.getKey()); }); } + + if (key.getValue().isEmpty()) { + removedTags.add(key.getKey()); + } } } @@ -620,6 +625,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { } } + Iterable removed = SerializableMeta.getObject(Iterable.class, map, "removed", true); + if (removed != null) { + IRegistryCustom registryAccess = CraftRegistry.getMinecraftRegistry(); + IRegistry> componentTypeRegistry = registryAccess.registryOrThrow(Registries.DATA_COMPONENT_TYPE); + + for (Object removedObject : removed) { + String removedString = (String) removedObject; + + DataComponentType component = componentTypeRegistry.get(MinecraftKey.parse(removedString)); + if (component != null) { + this.removedTags.add(component); + } + } + } + Object nbtMap = SerializableMeta.getObject(Object.class, map, BUKKIT_CUSTOM_TAG.BUKKIT, true); // We read both legacy maps and potential modern snbt strings here if (nbtMap != null) { this.persistentDataContainer.putAll((NBTTagCompound) CraftNBTTagConfigSerializer.deserialize(nbtMap)); @@ -838,6 +858,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { }); } + for (DataComponentType removed : removedTags) { + if (!itemTag.builder.isSet(removed)) { + itemTag.builder.remove(removed); + } + } + NBTTagCompound customTag = (this.customTag != null) ? this.customTag.copy() : null; if (!persistentDataContainer.isEmpty()) { NBTTagCompound bukkitCustomCompound = new NBTTagCompound(); @@ -914,7 +940,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { @Overridden boolean isEmpty() { - return !(hasDisplayName() || hasItemName() || hasLocalizedName() || hasEnchants() || (lore != null) || hasCustomModelData() || hasBlockData() || hasRepairCost() || !unhandledTags.build().isEmpty() || !persistentDataContainer.isEmpty() || hideFlag != 0 || isHideTooltip() || isUnbreakable() || hasEnchantmentGlintOverride() || isFireResistant() || hasMaxStackSize() || hasRarity() || hasFood() || hasTool() || hasDamage() || hasMaxDamage() || hasAttributeModifiers() || customTag != null); + return !(hasDisplayName() || hasItemName() || hasLocalizedName() || hasEnchants() || (lore != null) || hasCustomModelData() || hasBlockData() || hasRepairCost() || !unhandledTags.build().isEmpty() || !removedTags.isEmpty() || !persistentDataContainer.isEmpty() || hideFlag != 0 || isHideTooltip() || isUnbreakable() || hasEnchantmentGlintOverride() || isFireResistant() || hasMaxStackSize() || hasRarity() || hasFood() || hasTool() || hasDamage() || hasMaxDamage() || hasAttributeModifiers() || customTag != null); } @Override @@ -1498,6 +1524,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { && (this.hasRepairCost() ? that.hasRepairCost() && this.repairCost == that.repairCost : !that.hasRepairCost()) && (this.hasAttributeModifiers() ? that.hasAttributeModifiers() && compareModifiers(this.attributeModifiers, that.attributeModifiers) : !that.hasAttributeModifiers()) && (this.unhandledTags.equals(that.unhandledTags)) + && (this.removedTags.equals(that.removedTags)) && (Objects.equals(this.customTag, that.customTag)) && (this.persistentDataContainer.equals(that.persistentDataContainer)) && (this.hideFlag == that.hideFlag) @@ -1541,6 +1568,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { hash = 61 * hash + (hasEnchants() ? this.enchantments.hashCode() : 0); hash = 61 * hash + (hasRepairCost() ? this.repairCost : 0); hash = 61 * hash + unhandledTags.hashCode(); + hash = 61 * hash + removedTags.hashCode(); hash = 61 * hash + ((customTag != null) ? this.customTag.hashCode() : 0); hash = 61 * hash + (!persistentDataContainer.isEmpty() ? persistentDataContainer.hashCode() : 0); hash = 61 * hash + hideFlag; @@ -1579,6 +1607,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { if (this.customTag != null) { clone.customTag = this.customTag.copy(); } + clone.removedTags = Sets.newHashSet(this.removedTags); clone.persistentDataContainer = new CraftPersistentDataContainer(this.persistentDataContainer.getRaw(), DATA_TYPE_REGISTRY); clone.hideFlag = this.hideFlag; clone.hideTooltip = this.hideTooltip; @@ -1727,6 +1756,20 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { } } + if (!this.removedTags.isEmpty()) { + IRegistryCustom registryAccess = CraftRegistry.getMinecraftRegistry(); + IRegistry> componentTypeRegistry = registryAccess.registryOrThrow(Registries.DATA_COMPONENT_TYPE); + + List removedTags = new ArrayList<>(); + for (DataComponentType removed : this.removedTags) { + String componentKey = componentTypeRegistry.getResourceKey(removed).orElseThrow().location().toString(); + + removedTags.add(componentKey); + } + + builder.put("removed", removedTags); + } + if (!persistentDataContainer.isEmpty()) { // Store custom tags, wrapped in their compound builder.put(BUKKIT_CUSTOM_TAG.BUKKIT, persistentDataContainer.serialize()); }