diff --git a/patches/server/1046-add-ItemFrameMeta-API.patch b/patches/server/1046-add-ItemFrameMeta-API.patch index 9d0f705af895..b5fe14a3ec80 100644 --- a/patches/server/1046-add-ItemFrameMeta-API.patch +++ b/patches/server/1046-add-ItemFrameMeta-API.patch @@ -70,22 +70,30 @@ index 5c45946f54e4b16440c15a9165ef85be43e53c84..07ad086bfa77a4b3bcaa188ea65ceb72 map.put(CraftMetaMap.class, Set.of(CraftMetaMap.MAP_COLOR.TYPE, CraftMetaMap.MAP_POST_PROCESSING.TYPE, CraftMetaMap.MAP_ID.TYPE)); diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItemFrame.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItemFrame.java new file mode 100644 -index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a83dccd1b6 +index 0000000000000000000000000000000000000000..b59e7fa357281c6282cf2c7a41c2a6c7c05b06ec --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItemFrame.java -@@ -0,0 +1,197 @@ +@@ -0,0 +1,203 @@ +// Paper start - add ItemFrameMeta API +package org.bukkit.craftbukkit.inventory; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; +import io.papermc.paper.inventory.meta.ItemFrameMeta; ++import java.io.ByteArrayInputStream; ++import java.io.ByteArrayOutputStream; ++import java.io.IOException; ++import java.util.Base64; +import java.util.Map; +import java.util.Set; ++import java.util.logging.Level; ++import java.util.logging.Logger; +import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.NbtAccounter; ++import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.Tag; +import net.minecraft.world.item.component.CustomData; +import org.bukkit.Material; @@ -102,42 +110,45 @@ index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a8 + static final ItemMetaKeyType ENTITY_TAG = new ItemMetaKeyType<>(DataComponents.ENTITY_DATA, "EntityTag", "entity-tag"); + CompoundTag entityTag; + ++ static final ItemMetaKey ENTITY_ID = new ItemMetaKey("id", "entity-id"); + static final ItemMetaKey FIXED = new ItemMetaKey("Fixed", "fixed"); + static final ItemMetaKey INVISIBLE = new ItemMetaKey("Invisible", "invisible"); -+ private Boolean fixed = null; -+ private Boolean invisible = null; + + CraftMetaItemFrame(CraftMetaItem meta) { + super(meta); + + if (meta instanceof CraftMetaItemFrame itemFrame) { + this.entityTag = itemFrame.entityTag; -+ this.fixed = itemFrame.fixed; -+ this.invisible = itemFrame.invisible; + } + } + + CraftMetaItemFrame(DataComponentPatch tag, final Set> extraHandledDcts) { + super(tag, extraHandledDcts); + -+ getOrEmpty(tag, CraftMetaItemFrame.ENTITY_TAG).ifPresent((nbt) -> { -+ this.entityTag = nbt.copyTag(); -+ -+ if (entityTag.contains(FIXED.NBT)) { -+ this.fixed = entityTag.getBoolean(FIXED.NBT); -+ } -+ -+ if (entityTag.contains(INVISIBLE.NBT)) { -+ this.invisible = entityTag.getBoolean(INVISIBLE.NBT); -+ } -+ }); ++ getOrEmpty(tag, CraftMetaItemFrame.ENTITY_TAG).ifPresent((nbt) -> this.entityTag = nbt.copyTag()); + } + + CraftMetaItemFrame(Map map) { + super(map); + -+ this.fixed = SerializableMeta.getBoolean(map, FIXED.BUKKIT); -+ this.invisible = SerializableMeta.getBoolean(map, INVISIBLE.BUKKIT); ++ String entityTag = SerializableMeta.getString(map, ENTITY_TAG.BUKKIT, true); ++ if (entityTag != null) { ++ ByteArrayInputStream buf = new ByteArrayInputStream(Base64.getDecoder().decode(entityTag)); ++ try { ++ this.entityTag = NbtIo.readCompressed(buf, NbtAccounter.unlimitedHeap()); ++ } catch (IOException ex) { ++ Logger.getLogger(CraftMetaItem.class.getName()).log(Level.SEVERE, null, ex); ++ } ++ return; ++ } ++ SerializableMeta.getObjectOptionally(Boolean.class, map, FIXED.BUKKIT, true).ifPresent((value) -> { ++ populateTagIfNull(); ++ this.entityTag.putBoolean(FIXED.NBT, value); ++ }); ++ SerializableMeta.getObjectOptionally(Boolean.class, map, INVISIBLE.BUKKIT, true).ifPresent((value) -> { ++ populateTagIfNull(); ++ this.entityTag.putBoolean(INVISIBLE.NBT, value); ++ }); + } + + @Override @@ -160,18 +171,6 @@ index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a8 + protected void applyToItem(CraftMetaItem.Applicator tag) { + super.applyToItem(tag); + -+ if (!isItemFrameEmpty() && this.entityTag == null) { -+ this.entityTag = new CompoundTag(); -+ } -+ -+ if (this.fixed != null) { -+ this.entityTag.putBoolean(FIXED.NBT, this.fixed); -+ } -+ -+ if (this.invisible != null) { -+ this.entityTag.putBoolean(INVISIBLE.NBT, this.invisible); -+ } -+ + if (this.entityTag != null) { + tag.put(CraftMetaItemFrame.ENTITY_TAG, CustomData.of(this.entityTag)); + } @@ -188,7 +187,7 @@ index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a8 + } + + boolean isItemFrameEmpty() { -+ return !(this.fixed != null || this.invisible != null || this.entityTag != null); ++ return this.entityTag == null || this.entityTag.isEmpty(); + } + + @Override @@ -197,9 +196,7 @@ index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a8 + return false; + } + if (meta instanceof CraftMetaItemFrame that) { -+ return java.util.Objects.equals(this.entityTag, that.entityTag) && -+ this.fixed == that.fixed && -+ this.invisible == that.invisible; ++ return java.util.Objects.equals(this.entityTag, that.entityTag); + } + return true; + } @@ -218,9 +215,6 @@ index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a8 + hash = 73 * hash + this.entityTag.hashCode(); + } + -+ hash = 61 * hash + (this.fixed != null ? Boolean.hashCode(this.isFixed()) : 0); -+ hash = 61 * hash + (this.invisible != null ? Boolean.hashCode(this.isInvisible()) : 0); -+ + return original != hash ? CraftMetaArmorStand.class.hashCode() ^ hash : hash; + } + @@ -228,15 +222,18 @@ index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a8 + ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { + super.serialize(builder); + -+ if (this.fixed != null) { -+ builder.put(FIXED.BUKKIT, this.fixed); -+ } -+ -+ if (this.invisible != null) { -+ builder.put(INVISIBLE.BUKKIT, this.invisible); ++ if (this.entityTag == null) { ++ return builder; ++ } else { ++ ByteArrayOutputStream buf = new ByteArrayOutputStream(); ++ try { ++ NbtIo.writeCompressed(entityTag, buf); ++ } catch (IOException ex) { ++ Logger.getLogger(CraftMetaItem.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); ++ } ++ builder.put(ENTITY_TAG.BUKKIT, Base64.getEncoder().encodeToString(buf.toByteArray())); ++ return builder; + } -+ -+ return builder; + } + + @Override @@ -250,24 +247,33 @@ index 0000000000000000000000000000000000000000..01695bfe1e2e0909cfcfc0cd9892b5a8 + return clone; + } + ++ private void populateTagIfNull() { ++ if (this.entityTag == null) { ++ this.entityTag = new CompoundTag(); ++ this.entityTag.putString(ENTITY_ID.NBT, "minecraft:item_frame"); ++ } ++ } ++ + @Override + public boolean isFixed() { -+ return this.fixed != null && this.fixed; ++ return this.entityTag != null && this.entityTag.getBoolean(FIXED.NBT); + } + + @Override -+ public void setFixed(boolean fixed) { -+ this.fixed = fixed; ++ public boolean isInvisible() { ++ return this.entityTag != null && this.entityTag.getBoolean(INVISIBLE.NBT); + } + + @Override -+ public boolean isInvisible() { -+ return this.invisible != null && this.invisible; ++ public void setFixed(boolean fixed) { ++ this.populateTagIfNull(); ++ this.entityTag.putBoolean(FIXED.NBT, fixed); + } + + @Override + public void setInvisible(boolean invisible) { -+ this.invisible = invisible; ++ this.populateTagIfNull(); ++ this.entityTag.putBoolean(INVISIBLE.NBT, invisible); + } +} +// Paper end - add ItemFrameMeta API