From 2fde56df0de12e336b891671d143601999abd22e Mon Sep 17 00:00:00 2001 From: Auxilor Date: Wed, 20 Apr 2022 11:19:24 +0100 Subject: [PATCH] Added ability to modify full item NBT via PersistentDataContainers and FastItemStack --- .../willfp/eco/core/fast/FastItemStack.java | 57 +++++++++++++++- .../spigot/proxy/common/NMSCommons.kt | 12 ++-- .../proxy/common/fast/EcoFastItemStack.kt | 10 ++- .../proxy/v1_17_R1/CommonsInitializer.kt | 68 ++++++++++++++----- .../proxy/v1_18_R1/CommonsInitializer.kt | 68 ++++++++++++++----- .../proxy/v1_18_R2/CommonsInitializer.kt | 68 ++++++++++++++----- 6 files changed, 225 insertions(+), 58 deletions(-) diff --git a/eco-api/src/main/java/com/willfp/eco/core/fast/FastItemStack.java b/eco-api/src/main/java/com/willfp/eco/core/fast/FastItemStack.java index 95a2b09f..d4f6cf5a 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/fast/FastItemStack.java +++ b/eco-api/src/main/java/com/willfp/eco/core/fast/FastItemStack.java @@ -6,6 +6,7 @@ import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,6 +48,7 @@ public interface FastItemStack extends PersistentDataHolder { * @param checkStored If stored enchantments should be accounted for. * @return A map of all enchantments. */ + @NotNull Map getEnchants(boolean checkStored); /** @@ -54,9 +56,11 @@ public interface FastItemStack extends PersistentDataHolder { * * @param enchantment The enchantment. * @return The enchantment level, or 0 if not found. + * @deprecated Poorly named method. Use getEnchantmentLevel instead. */ + @Deprecated(since = "6.34.0", forRemoval = true) default int getLevelOnItem(@NotNull Enchantment enchantment) { - return getLevelOnItem(enchantment, false); + return getEnchantmentLevel(enchantment, false); } /** @@ -65,9 +69,33 @@ public interface FastItemStack extends PersistentDataHolder { * @param enchantment The enchantment. * @param checkStored If the stored NBT should also be checked. * @return The enchantment level, or 0 if not found. + * @deprecated Poorly named method. Use getEnchantmentLevel instead. */ - int getLevelOnItem(@NotNull Enchantment enchantment, - boolean checkStored); + @Deprecated(since = "6.34.0", forRemoval = true) + default int getLevelOnItem(@NotNull Enchantment enchantment, + boolean checkStored) { + return getEnchantmentLevel(enchantment, checkStored); + } + + /** + * Get the level of an enchantment. + * + * @param enchantment The enchantment. + * @return The enchantment level, or 0 if not found. + */ + default int getEnchantmentLevel(@NotNull Enchantment enchantment) { + return getLevelOnItem(enchantment, false); + } + + /** + * Get the level of an enchantment. + * + * @param enchantment The enchantment. + * @param checkStored If the stored NBT should also be checked. + * @return The enchantment level, or 0 if not found. + */ + int getEnchantmentLevel(@NotNull Enchantment enchantment, + boolean checkStored); /** * Set the item lore. @@ -88,6 +116,7 @@ public interface FastItemStack extends PersistentDataHolder { * * @return The lore. */ + @NotNull List getLore(); /** @@ -95,6 +124,7 @@ public interface FastItemStack extends PersistentDataHolder { * * @return The lore. */ + @NotNull List getLoreComponents(); /** @@ -116,6 +146,7 @@ public interface FastItemStack extends PersistentDataHolder { * * @return The display name. */ + @NotNull Component getDisplayNameComponent(); /** @@ -123,6 +154,7 @@ public interface FastItemStack extends PersistentDataHolder { * * @return The display name. */ + @NotNull String getDisplayName(); /** @@ -159,6 +191,7 @@ public interface FastItemStack extends PersistentDataHolder { * * @return The flags. */ + @NotNull Set getItemFlags(); /** @@ -169,11 +202,29 @@ public interface FastItemStack extends PersistentDataHolder { */ boolean hasItemFlag(@NotNull ItemFlag flag); + /** + * Get the base NBT tag (Not PublicBukkitValues, the base) as a PersistentDataContainer. + *

+ * The returned PersistentDataContainer will not modify the item until the tag is set. + * + * @return The base NBT tag. + */ + @NotNull + PersistentDataContainer getBaseTag(); + + /** + * Set the base NBT tag (Not PublicBukkitValues, the base) from a PersistentDataContainer. + * + * @param container The PersistentDataContainer. + */ + void setBaseTag(@Nullable PersistentDataContainer container); + /** * Get the Bukkit ItemStack again. * * @return The ItemStack. */ + @NotNull ItemStack unwrap(); /** diff --git a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt index f8814693..4490a4cb 100644 --- a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt +++ b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/NMSCommons.kt @@ -52,18 +52,18 @@ fun Material.toItem(): Item = .orElseThrow { IllegalArgumentException("Material is not item!") } } -fun CompoundTag.makePdc(): PersistentDataContainer = - impl.makePdc(this) +fun CompoundTag.makePdc(base: Boolean = false): PersistentDataContainer = + impl.makePdc(this, base) -fun CompoundTag.setPdc(pdc: PersistentDataContainer) = - impl.setPdc(this, pdc) +fun CompoundTag.setPdc(pdc: PersistentDataContainer?, item: net.minecraft.world.item.ItemStack? = null) = + impl.setPdc(this, pdc, item) interface CommonsProvider { val nbtTagString: Int - fun makePdc(tag: CompoundTag): PersistentDataContainer + fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer - fun setPdc(tag: CompoundTag, pdc: PersistentDataContainer) + fun setPdc(tag: CompoundTag, pdc: PersistentDataContainer?, item: net.minecraft.world.item.ItemStack? = null) fun toPathfinderMob(mob: Mob): PathfinderMob? diff --git a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/fast/EcoFastItemStack.kt b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/fast/EcoFastItemStack.kt index 1fb56be1..9f0c5aed 100644 --- a/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/fast/EcoFastItemStack.kt +++ b/eco-core/core-nms/nms-common/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/common/fast/EcoFastItemStack.kt @@ -50,7 +50,7 @@ class EcoFastItemStack( return foundEnchantments } - override fun getLevelOnItem( + override fun getEnchantmentLevel( enchantment: Enchantment, checkStored: Boolean ): Int { @@ -183,6 +183,14 @@ class EcoFastItemStack( return this.flagBits and bitModifier == bitModifier } + override fun getBaseTag(): PersistentDataContainer = + (if (handle.hasTag()) handle.getTag()!! else CompoundTag()).makePdc(base = true) + + override fun setBaseTag(container: PersistentDataContainer?) { + (if (handle.hasTag()) handle.getTag()!! else CompoundTag()).setPdc(container, item = handle) + apply() + } + @Suppress("UNNECESSARY_NOT_NULL_ASSERTION") private var flagBits: Int get() = diff --git a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt index 5f35d2a4..0e581fa1 100644 --- a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt +++ b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/CommonsInitializer.kt @@ -32,9 +32,10 @@ class CommonsInitializer : CommonsInitializerProxy { isAccessible = true } - private val pdcRegsitry: Field = Class.forName("org.bukkit.craftbukkit.v1_17_R1.inventory.CraftMetaItem") + private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_17_R1.inventory.CraftMetaItem") .getDeclaredField("DATA_TYPE_REGISTRY") .apply { isAccessible = true } + .get(null) as CraftPersistentDataTypeRegistry override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING @@ -67,29 +68,64 @@ class CommonsInitializer : CommonsInitializerProxy { override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? = CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity - override fun makePdc(tag: CompoundTag): PersistentDataContainer { - val pdc = CraftPersistentDataContainer(pdcRegsitry.get(null) as CraftPersistentDataTypeRegistry) - if (tag.contains("PublicBukkitValues")) { - val compound = tag.getCompound("PublicBukkitValues") - val keys = compound.allKeys + override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer { + fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry) + + fun CompoundTag?.toPdc(): PersistentDataContainer { + val pdc = emptyPdc() + this ?: return pdc + val keys = this.allKeys for (key in keys) { - pdc.put(key, compound[key]) + pdc.put(key, this[key]) } + + return pdc } - return pdc + return if (base) { + tag.toPdc() + } else { + if (tag.contains("PublicBukkitValues")) { + tag.getCompound("PublicBukkitValues").toPdc() + } else { + emptyPdc() + } + } } - override fun setPdc(tag: CompoundTag, pdc: PersistentDataContainer) { - pdc as CraftPersistentDataContainer - - if (!pdc.isEmpty) { - val bukkitCustomCompound = CompoundTag() - val rawPublicMap: Map = pdc.raw + override fun setPdc( + tag: CompoundTag, + pdc: PersistentDataContainer?, + item: net.minecraft.world.item.ItemStack? + ) { + fun CraftPersistentDataContainer.toTag(): CompoundTag { + val compound = CompoundTag() + val rawPublicMap: Map = this.raw for ((key, value) in rawPublicMap) { - bukkitCustomCompound.put(key, value) + compound.put(key, value) + } + + return compound + } + + pdc as CraftPersistentDataContainer? + + if (item != null) { + if (pdc != null && !pdc.isEmpty) { + for (key in tag.allKeys.toSet()) { + tag.remove(key) + } + + tag.merge(pdc.toTag()) + } else { + item.setTag(null) + } + } else { + if (pdc != null && !pdc.isEmpty) { + tag.put("PublicBukkitValues", pdc.toTag()) + } else { + tag.remove("PublicBukkitValues") } - tag.put("PublicBukkitValues", bukkitCustomCompound) } } } diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt index 8f4d4c01..2a1586e1 100644 --- a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt +++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/CommonsInitializer.kt @@ -32,9 +32,10 @@ class CommonsInitializer : CommonsInitializerProxy { isAccessible = true } - private val pdcRegsitry: Field = Class.forName("org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMetaItem") + private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_18_R1.inventory.CraftMetaItem") .getDeclaredField("DATA_TYPE_REGISTRY") .apply { isAccessible = true } + .get(null) as CraftPersistentDataTypeRegistry override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING @@ -67,29 +68,64 @@ class CommonsInitializer : CommonsInitializerProxy { override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? = CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity - override fun makePdc(tag: CompoundTag): PersistentDataContainer { - val pdc = CraftPersistentDataContainer(pdcRegsitry.get(null) as CraftPersistentDataTypeRegistry) - if (tag.contains("PublicBukkitValues")) { - val compound = tag.getCompound("PublicBukkitValues") - val keys = compound.allKeys + override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer { + fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry) + + fun CompoundTag?.toPdc(): PersistentDataContainer { + val pdc = emptyPdc() + this ?: return pdc + val keys = this.allKeys for (key in keys) { - pdc.put(key, compound[key]) + pdc.put(key, this[key]) } + + return pdc } - return pdc + return if (base) { + tag.toPdc() + } else { + if (tag.contains("PublicBukkitValues")) { + tag.getCompound("PublicBukkitValues").toPdc() + } else { + emptyPdc() + } + } } - override fun setPdc(tag: CompoundTag, pdc: PersistentDataContainer) { - pdc as CraftPersistentDataContainer - - if (!pdc.isEmpty) { - val bukkitCustomCompound = CompoundTag() - val rawPublicMap: Map = pdc.raw + override fun setPdc( + tag: CompoundTag, + pdc: PersistentDataContainer?, + item: net.minecraft.world.item.ItemStack? + ) { + fun CraftPersistentDataContainer.toTag(): CompoundTag { + val compound = CompoundTag() + val rawPublicMap: Map = this.raw for ((key, value) in rawPublicMap) { - bukkitCustomCompound.put(key, value) + compound.put(key, value) + } + + return compound + } + + pdc as CraftPersistentDataContainer? + + if (item != null) { + if (pdc != null && !pdc.isEmpty) { + for (key in tag.allKeys.toSet()) { + tag.remove(key) + } + + tag.merge(pdc.toTag()) + } else { + item.setTag(null) + } + } else { + if (pdc != null && !pdc.isEmpty) { + tag.put("PublicBukkitValues", pdc.toTag()) + } else { + tag.remove("PublicBukkitValues") } - tag.put("PublicBukkitValues", bukkitCustomCompound) } } } diff --git a/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt index 19675728..ff011987 100644 --- a/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt +++ b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/CommonsInitializer.kt @@ -32,9 +32,10 @@ class CommonsInitializer : CommonsInitializerProxy { isAccessible = true } - private val pdcRegsitry: Field = Class.forName("org.bukkit.craftbukkit.v1_18_R2.inventory.CraftMetaItem") + private val pdcRegsitry = Class.forName("org.bukkit.craftbukkit.v1_18_R2.inventory.CraftMetaItem") .getDeclaredField("DATA_TYPE_REGISTRY") .apply { isAccessible = true } + .get(null) as CraftPersistentDataTypeRegistry override val nbtTagString = CraftMagicNumbers.NBT.TAG_STRING @@ -67,29 +68,64 @@ class CommonsInitializer : CommonsInitializerProxy { override fun toBukkitEntity(entity: net.minecraft.world.entity.LivingEntity): LivingEntity? = CraftEntity.getEntity(Bukkit.getServer() as CraftServer, entity) as? LivingEntity - override fun makePdc(tag: CompoundTag): PersistentDataContainer { - val pdc = CraftPersistentDataContainer(pdcRegsitry.get(null) as CraftPersistentDataTypeRegistry) - if (tag.contains("PublicBukkitValues")) { - val compound = tag.getCompound("PublicBukkitValues") - val keys = compound.allKeys + override fun makePdc(tag: CompoundTag, base: Boolean): PersistentDataContainer { + fun emptyPdc(): CraftPersistentDataContainer = CraftPersistentDataContainer(pdcRegsitry) + + fun CompoundTag?.toPdc(): PersistentDataContainer { + val pdc = emptyPdc() + this ?: return pdc + val keys = this.allKeys for (key in keys) { - pdc.put(key, compound[key]) + pdc.put(key, this[key]) } + + return pdc } - return pdc + return if (base) { + tag.toPdc() + } else { + if (tag.contains("PublicBukkitValues")) { + tag.getCompound("PublicBukkitValues").toPdc() + } else { + emptyPdc() + } + } } - override fun setPdc(tag: CompoundTag, pdc: PersistentDataContainer) { - pdc as CraftPersistentDataContainer - - if (!pdc.isEmpty) { - val bukkitCustomCompound = CompoundTag() - val rawPublicMap: Map = pdc.raw + override fun setPdc( + tag: CompoundTag, + pdc: PersistentDataContainer?, + item: net.minecraft.world.item.ItemStack? + ) { + fun CraftPersistentDataContainer.toTag(): CompoundTag { + val compound = CompoundTag() + val rawPublicMap: Map = this.raw for ((key, value) in rawPublicMap) { - bukkitCustomCompound.put(key, value) + compound.put(key, value) + } + + return compound + } + + pdc as CraftPersistentDataContainer? + + if (item != null) { + if (pdc != null && !pdc.isEmpty) { + for (key in tag.allKeys.toSet()) { + tag.remove(key) + } + + tag.merge(pdc.toTag()) + } else { + item.setTag(null) + } + } else { + if (pdc != null && !pdc.isEmpty) { + tag.put("PublicBukkitValues", pdc.toTag()) + } else { + tag.remove("PublicBukkitValues") } - tag.put("PublicBukkitValues", bukkitCustomCompound) } } }