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 fca0cfba14dd2cc6f24b56eaf269594b2d87fd04..8734f0b777432cd8639094b75a3da1b9595823ed 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEnchantedBook.java @@ -39,7 +39,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 } }); } @@ -54,7 +54,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 94e9213414ec08794e875c23c300bfae5dcc877e..940c2c9663657369eda6962728bd37a869209199 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -224,6 +224,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; @@ -296,6 +302,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) { @@ -384,6 +394,20 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { } } }); + // 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) { @@ -565,10 +589,19 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { String unhandled = SerializableMeta.getString(map, "unhandled", true); if (unhandled != null) { - ByteArrayInputStream buf = new ByteArrayInputStream(Base64.getDecoder().decode(internal)); + ByteArrayInputStream buf = new ByteArrayInputStream(Base64.getDecoder().decode(unhandled)); // Paper - fix deserializing unhandled tags try { CompoundTag unhandledTag = NbtIo.readCompressed(buf, NbtAccounter.unlimitedHeap()); - this.unhandledTags.copy(DataComponentPatch.CODEC.parse(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), unhandledTag).result().get()); + // Paper start + final net.minecraft.core.component.DataComponentPatch patch = net.minecraft.core.component.DataComponentPatch.CODEC.parse(net.minecraft.server.MinecraftServer.getDefaultRegistryAccess().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE), unhandledTag).result().get(); + CraftMetaItem.getOrEmpty(patch, CraftMetaItem.CAN_PLACE_ON).ifPresent(data -> { + this.canPlaceOnPredicates = List.copyOf(data.predicates); + }); + CraftMetaItem.getOrEmpty(patch, CraftMetaItem.CAN_BREAK).ifPresent(data -> { + this.canBreakPredicates = List.copyOf(data.predicates); + }); + this.unhandledTags.copy(patch.forget(type -> type == CraftMetaItem.CAN_PLACE_ON.TYPE || type == CraftMetaItem.CAN_BREAK.TYPE)); + // Paper end } catch (IOException ex) { Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex); } @@ -786,6 +819,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { itemTag.put(CraftMetaItem.MAX_DAMAGE, this.maxDamage); } + // Paper start + if (this.canPlaceOnPredicates != null || this.hasItemFlag(ItemFlag.HIDE_PLACED_ON)) { + itemTag.put(CraftMetaItem.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates : Collections.emptyList(), !this.hasItemFlag(ItemFlag.HIDE_PLACED_ON))); + } + if (this.canBreakPredicates != null || this.hasItemFlag(ItemFlag.HIDE_DESTROYS)) { + itemTag.put(CraftMetaItem.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates != null ? this.canBreakPredicates : Collections.emptyList(), !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); + } + // Paper end + for (Map.Entry, Optional> e : this.unhandledTags.build().entrySet()) { e.getValue().ifPresentOrElse((value) -> { itemTag.builder.set((DataComponentType) e.getKey(), value); @@ -858,7 +900,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.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isFireResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasFood() || 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.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isHideTooltip() || this.isUnbreakable() || this.hasEnchantmentGlintOverride() || this.isFireResistant() || this.hasMaxStackSize() || this.hasRarity() || this.hasFood() || this.hasDamage() || this.hasMaxDamage() || this.hasAttributeModifiers() || this.customTag != null || this.canPlaceOnPredicates != null || this.canBreakPredicates != null); // Paper } // Paper start @@ -1453,6 +1495,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { && (this.hasFood() ? that.hasFood() && this.food.equals(that.food) : !that.hasFood()) && (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); } @@ -1495,6 +1539,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; } @@ -1532,6 +1578,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); @@ -1641,6 +1695,16 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { } } + // Paper start + final boolean canBreakAddToUnhandled = this.canBreakPredicates != null || this.hasItemFlag(ItemFlag.HIDE_DESTROYS); + if (canBreakAddToUnhandled) { + this.unhandledTags.set(DataComponents.CAN_BREAK, new net.minecraft.world.item.AdventureModePredicate(this.canBreakPredicates != null ? this.canBreakPredicates : Collections.emptyList(), !this.hasItemFlag(ItemFlag.HIDE_DESTROYS))); + } + final boolean canPlaceOnAddToUnhandled = this.canPlaceOnPredicates != null || this.hasItemFlag(ItemFlag.HIDE_PLACED_ON); + if (canPlaceOnAddToUnhandled) { + this.unhandledTags.set(DataComponents.CAN_PLACE_ON, new net.minecraft.world.item.AdventureModePredicate(this.canPlaceOnPredicates != null ? this.canPlaceOnPredicates : Collections.emptyList(), !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 { @@ -1651,6 +1715,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.persistentDataContainer.isEmpty()) { // Store custom tags, wrapped in their compound builder.put(CraftMetaItem.BUKKIT_CUSTOM_TAG.BUKKIT, this.persistentDataContainer.serialize()); @@ -1792,6 +1864,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,