diff --git a/eco-api/src/main/java/com/willfp/eco/core/Handler.java b/eco-api/src/main/java/com/willfp/eco/core/Handler.java index d790a147..2ba2786c 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/Handler.java +++ b/eco-api/src/main/java/com/willfp/eco/core/Handler.java @@ -2,6 +2,7 @@ package com.willfp.eco.core; import com.willfp.eco.core.config.updating.ConfigHandler; import com.willfp.eco.core.config.wrapper.ConfigFactory; +import com.willfp.eco.core.data.ExtendedPersistentDataContainer; import com.willfp.eco.core.data.ProfileHandler; import com.willfp.eco.core.data.keys.KeyRegistry; import com.willfp.eco.core.drops.DropQueueFactory; @@ -23,6 +24,7 @@ import org.bukkit.NamespacedKey; import org.bukkit.entity.Entity; import org.bukkit.entity.Mob; import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -280,6 +282,14 @@ public interface Handler { * @param The mob type. * @return The controlled entity. */ + @NotNull EntityController createEntityController(@NotNull T mob); + + /** + * Adapt base PDC to extended PDC. + * + * @param container The container. + * @return The extended container. + */ @NotNull - EntityController createEntityController(@NotNull T mob); + ExtendedPersistentDataContainer adaptPdc(@NotNull PersistentDataContainer container); } diff --git a/eco-api/src/main/java/com/willfp/eco/core/data/ExtendedPersistentDataContainer.java b/eco-api/src/main/java/com/willfp/eco/core/data/ExtendedPersistentDataContainer.java new file mode 100644 index 00000000..3a953e28 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/data/ExtendedPersistentDataContainer.java @@ -0,0 +1,83 @@ +package com.willfp.eco.core.data; + +import com.willfp.eco.core.Eco; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public interface ExtendedPersistentDataContainer extends PersistentDataContainer { + /** + * Set a key. + * + * @param key The key. + * @param dataType The data type. + * @param value The value. + * @param The type. + * @param The type. + */ + void set(@NotNull String key, @NotNull PersistentDataType dataType, @NotNull Z value); + + /** + * Get if there is a key. + * + * @param key The key. + * @param dataType The data type. + * @param The type. + * @param The type. + * @return If the key is present. + */ + boolean has(@NotNull String key, @NotNull PersistentDataType dataType); + + /** + * Get a value. + * + * @param key The key. + * @param dataType The data type. + * @param The type. + * @param The type. + * @return The value, or null if not found. + */ + @Nullable Z get(@NotNull String key, @NotNull PersistentDataType dataType); + + /** + * Get a value or default if not present. + * + * @param key The key. + * @param dataType The data type. + * @param defaultValue The default value. + * @param The type. + * @param The type. + * @return The value, or the default if not found. + */ + @NotNull Z getOrDefault(@NotNull String key, @NotNull PersistentDataType dataType, @NotNull Z defaultValue); + + /** + * Get all keys, including namespaced keys. + * + * @return The keys. + */ + @NotNull + Set getAllKeys(); + + /** + * Remove a key. + * + * @param key The key. + */ + void remove(@NotNull String key); + + /** + * Convert regular persistent data container to extended persistent data container. + *

+ * Only use this with FastItemStack, you're likely to create problems otherwise. + * + * @param base The base container. + * @return The extended container. + */ + static ExtendedPersistentDataContainer wrap(@NotNull PersistentDataContainer base) { + return Eco.getHandler().adaptPdc(base); + } +} 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 a6843fdb..d229d673 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 @@ -1,6 +1,7 @@ package com.willfp.eco.core.fast; import com.willfp.eco.core.Eco; +import com.willfp.eco.core.data.ExtendedPersistentDataContainer; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; @@ -203,7 +204,7 @@ public interface FastItemStack extends PersistentDataHolder { * * @return The base NBT tag. */ - PersistentDataContainer getBaseTag(); + ExtendedPersistentDataContainer getBaseTag(); /** * Set the base NBT tag (Not PublicBukkitValues, the base) from a PersistentDataContainer. diff --git a/eco-api/src/main/java/com/willfp/eco/core/items/Items.java b/eco-api/src/main/java/com/willfp/eco/core/items/Items.java index 87df7608..9402c2c2 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/items/Items.java +++ b/eco-api/src/main/java/com/willfp/eco/core/items/Items.java @@ -2,6 +2,7 @@ package com.willfp.eco.core.items; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; +import com.willfp.eco.core.data.ExtendedPersistentDataContainer; import com.willfp.eco.core.fast.FastItemStack; import com.willfp.eco.core.items.args.LookupArgParser; import com.willfp.eco.core.items.provider.ItemProvider; @@ -530,8 +531,8 @@ public final class Items { public static ItemStack setDestroySpeedMultiplier(@NotNull final ItemStack itemStack, final double multiplier) { FastItemStack fis = FastItemStack.wrap(itemStack); - PersistentDataContainer tag = fis.getBaseTag(); - tag.set(NamespacedKeyUtils.createEcoKey("break_speed"), PersistentDataType.DOUBLE, multiplier); + ExtendedPersistentDataContainer tag = fis.getBaseTag(); + tag.set("BreakSpeed", PersistentDataType.DOUBLE, multiplier); fis.setBaseTag(tag); return fis.unwrap(); } @@ -544,9 +545,9 @@ public final class Items { */ public static double getDestroySpeedMultiplier(@NotNull final ItemStack itemStack) { FastItemStack fis = FastItemStack.wrap(itemStack); - PersistentDataContainer tag = fis.getBaseTag(); + ExtendedPersistentDataContainer tag = fis.getBaseTag(); return Objects.requireNonNullElse( - tag.get(NamespacedKeyUtils.createEcoKey("break_speed"), PersistentDataType.DOUBLE), + tag.get("BreakSpeed", PersistentDataType.DOUBLE), 1.0 ); } 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 0e581fa1..ec5379ae 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 @@ -108,21 +108,25 @@ class CommonsInitializer : CommonsInitializerProxy { return compound } - pdc as CraftPersistentDataContainer? + val container = when (pdc) { + is CraftPersistentDataContainer? -> pdc + is ExtendedPersistentDataContainerFactory.EcoPersistentDataContainer? -> pdc?.handle + else -> null + } if (item != null) { - if (pdc != null && !pdc.isEmpty) { + if (container != null && !container.isEmpty) { for (key in tag.allKeys.toSet()) { tag.remove(key) } - tag.merge(pdc.toTag()) + tag.merge(container.toTag()) } else { item.setTag(null) } } else { - if (pdc != null && !pdc.isEmpty) { - tag.put("PublicBukkitValues", pdc.toTag()) + if (container != null && !container.isEmpty) { + tag.put("PublicBukkitValues", container.toTag()) } else { tag.remove("PublicBukkitValues") } diff --git a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/ExtendedPersistentDataContainerFactory.kt b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/ExtendedPersistentDataContainerFactory.kt new file mode 100644 index 00000000..274aa573 --- /dev/null +++ b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/ExtendedPersistentDataContainerFactory.kt @@ -0,0 +1,63 @@ +package com.willfp.eco.internal.spigot.proxy.v1_17_R1 + +import com.willfp.eco.core.data.ExtendedPersistentDataContainer +import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy +import net.minecraft.nbt.Tag +import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataContainer +import org.bukkit.craftbukkit.v1_17_R1.persistence.CraftPersistentDataTypeRegistry +import org.bukkit.persistence.PersistentDataContainer +import org.bukkit.persistence.PersistentDataType + +class ExtendedPersistentDataContainerFactory: ExtendedPersistentDataContainerFactoryProxy { + override fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer { + return when (pdc) { + is ExtendedPersistentDataContainer -> pdc + is CraftPersistentDataContainer -> EcoPersistentDataContainer(pdc) + else -> throw IllegalArgumentException("Custom PDC instance is not supported!") + } + } + + class EcoPersistentDataContainer( + val handle: CraftPersistentDataContainer + ) : ExtendedPersistentDataContainer, PersistentDataContainer by handle { + @Suppress("UNCHECKED_CAST") + private val customDataTags: MutableMap = + CraftPersistentDataContainer::class.java.getDeclaredField("customDataTags") + .apply { isAccessible = true }.get(handle) as MutableMap + + @Suppress("UNCHECKED_CAST") + private val registry: CraftPersistentDataTypeRegistry = + CraftPersistentDataContainer::class.java.getDeclaredField("registry") + .apply { isAccessible = true }.get(handle) as CraftPersistentDataTypeRegistry + + override fun set(key: String, dataType: PersistentDataType, value: Z) { + customDataTags[key] = registry.wrap(dataType.primitiveType, dataType.toPrimitive(value, adapterContext)) + } + + override fun has(key: String, dataType: PersistentDataType): Boolean { + val value = customDataTags[key] ?: return false + return registry.isInstanceOf(dataType.primitiveType, value) + } + + override fun get(key: String, dataType: PersistentDataType): Z? { + val value = customDataTags[key] ?: return null + return dataType.fromPrimitive(registry.extract(dataType.primitiveType, value), adapterContext) + } + + override fun getOrDefault( + key: String, + dataType: PersistentDataType, + defaultValue: Z + ): Z { + return get(key, dataType) ?: defaultValue + } + + override fun remove(key: String) { + customDataTags.remove(key) + } + + override fun getAllKeys(): MutableSet { + return customDataTags.keys + } + } +} 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 2a1586e1..67b833a6 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 @@ -108,21 +108,25 @@ class CommonsInitializer : CommonsInitializerProxy { return compound } - pdc as CraftPersistentDataContainer? + val container = when (pdc) { + is CraftPersistentDataContainer? -> pdc + is ExtendedPersistentDataContainerFactory.EcoPersistentDataContainer? -> pdc?.handle + else -> null + } if (item != null) { - if (pdc != null && !pdc.isEmpty) { + if (container != null && !container.isEmpty) { for (key in tag.allKeys.toSet()) { tag.remove(key) } - tag.merge(pdc.toTag()) + tag.merge(container.toTag()) } else { item.setTag(null) } } else { - if (pdc != null && !pdc.isEmpty) { - tag.put("PublicBukkitValues", pdc.toTag()) + if (container != null && !container.isEmpty) { + tag.put("PublicBukkitValues", container.toTag()) } else { tag.remove("PublicBukkitValues") } diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ExtendedPersistentDataContainerFactory.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ExtendedPersistentDataContainerFactory.kt new file mode 100644 index 00000000..2e062a68 --- /dev/null +++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ExtendedPersistentDataContainerFactory.kt @@ -0,0 +1,63 @@ +package com.willfp.eco.internal.spigot.proxy.v1_18_R1 + +import com.willfp.eco.core.data.ExtendedPersistentDataContainer +import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy +import net.minecraft.nbt.Tag +import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataContainer +import org.bukkit.craftbukkit.v1_18_R1.persistence.CraftPersistentDataTypeRegistry +import org.bukkit.persistence.PersistentDataContainer +import org.bukkit.persistence.PersistentDataType + +class ExtendedPersistentDataContainerFactory : ExtendedPersistentDataContainerFactoryProxy { + override fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer { + return when (pdc) { + is ExtendedPersistentDataContainer -> pdc + is CraftPersistentDataContainer -> EcoPersistentDataContainer(pdc) + else -> throw IllegalArgumentException("Custom PDC instance is not supported!") + } + } + + class EcoPersistentDataContainer( + val handle: CraftPersistentDataContainer + ) : ExtendedPersistentDataContainer, PersistentDataContainer by handle { + @Suppress("UNCHECKED_CAST") + private val customDataTags: MutableMap = + CraftPersistentDataContainer::class.java.getDeclaredField("customDataTags") + .apply { isAccessible = true }.get(handle) as MutableMap + + @Suppress("UNCHECKED_CAST") + private val registry: CraftPersistentDataTypeRegistry = + CraftPersistentDataContainer::class.java.getDeclaredField("registry") + .apply { isAccessible = true }.get(handle) as CraftPersistentDataTypeRegistry + + override fun set(key: String, dataType: PersistentDataType, value: Z) { + customDataTags[key] = registry.wrap(dataType.primitiveType, dataType.toPrimitive(value, adapterContext)) + } + + override fun has(key: String, dataType: PersistentDataType): Boolean { + val value = customDataTags[key] ?: return false + return registry.isInstanceOf(dataType.primitiveType, value) + } + + override fun get(key: String, dataType: PersistentDataType): Z? { + val value = customDataTags[key] ?: return null + return dataType.fromPrimitive(registry.extract(dataType.primitiveType, value), adapterContext) + } + + override fun getOrDefault( + key: String, + dataType: PersistentDataType, + defaultValue: Z + ): Z { + return get(key, dataType) ?: defaultValue + } + + override fun remove(key: String) { + customDataTags.remove(key) + } + + override fun getAllKeys(): MutableSet { + return customDataTags.keys + } + } +} 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 ff011987..462ae003 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 @@ -108,21 +108,25 @@ class CommonsInitializer : CommonsInitializerProxy { return compound } - pdc as CraftPersistentDataContainer? + val container = when (pdc) { + is CraftPersistentDataContainer? -> pdc + is ExtendedPersistentDataContainerFactory.EcoPersistentDataContainer? -> pdc?.handle + else -> null + } if (item != null) { - if (pdc != null && !pdc.isEmpty) { + if (container != null && !container.isEmpty) { for (key in tag.allKeys.toSet()) { tag.remove(key) } - tag.merge(pdc.toTag()) + tag.merge(container.toTag()) } else { item.setTag(null) } } else { - if (pdc != null && !pdc.isEmpty) { - tag.put("PublicBukkitValues", pdc.toTag()) + if (container != null && !container.isEmpty) { + tag.put("PublicBukkitValues", container.toTag()) } else { tag.remove("PublicBukkitValues") } diff --git a/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/ExtendedPersistentDataContainerFactory.kt b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/ExtendedPersistentDataContainerFactory.kt new file mode 100644 index 00000000..9f35db94 --- /dev/null +++ b/eco-core/core-nms/v1_18_R2/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R2/ExtendedPersistentDataContainerFactory.kt @@ -0,0 +1,63 @@ +package com.willfp.eco.internal.spigot.proxy.v1_18_R2 + +import com.willfp.eco.core.data.ExtendedPersistentDataContainer +import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy +import net.minecraft.nbt.Tag +import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataContainer +import org.bukkit.craftbukkit.v1_18_R2.persistence.CraftPersistentDataTypeRegistry +import org.bukkit.persistence.PersistentDataContainer +import org.bukkit.persistence.PersistentDataType + +class ExtendedPersistentDataContainerFactory: ExtendedPersistentDataContainerFactoryProxy { + override fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer { + return when (pdc) { + is ExtendedPersistentDataContainer -> pdc + is CraftPersistentDataContainer -> EcoPersistentDataContainer(pdc) + else -> throw IllegalArgumentException("Custom PDC instance is not supported!") + } + } + + class EcoPersistentDataContainer( + val handle: CraftPersistentDataContainer + ) : ExtendedPersistentDataContainer, PersistentDataContainer by handle { + @Suppress("UNCHECKED_CAST") + private val customDataTags: MutableMap = + CraftPersistentDataContainer::class.java.getDeclaredField("customDataTags") + .apply { isAccessible = true }.get(handle) as MutableMap + + @Suppress("UNCHECKED_CAST") + private val registry: CraftPersistentDataTypeRegistry = + CraftPersistentDataContainer::class.java.getDeclaredField("registry") + .apply { isAccessible = true }.get(handle) as CraftPersistentDataTypeRegistry + + override fun set(key: String, dataType: PersistentDataType, value: Z) { + customDataTags[key] = registry.wrap(dataType.primitiveType, dataType.toPrimitive(value, adapterContext)) + } + + override fun has(key: String, dataType: PersistentDataType): Boolean { + val value = customDataTags[key] ?: return false + return registry.isInstanceOf(dataType.primitiveType, value) + } + + override fun get(key: String, dataType: PersistentDataType): Z? { + val value = customDataTags[key] ?: return null + return dataType.fromPrimitive(registry.extract(dataType.primitiveType, value), adapterContext) + } + + override fun getOrDefault( + key: String, + dataType: PersistentDataType, + defaultValue: Z + ): Z { + return get(key, dataType) ?: defaultValue + } + + override fun remove(key: String) { + customDataTags.remove(key) + } + + override fun getAllKeys(): MutableSet { + return customDataTags.keys + } + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt index fee77dbf..e3701b72 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoHandler.kt @@ -3,6 +3,7 @@ package com.willfp.eco.internal.spigot import com.willfp.eco.core.EcoPlugin import com.willfp.eco.core.Handler import com.willfp.eco.core.PluginProps +import com.willfp.eco.core.data.ExtendedPersistentDataContainer import com.willfp.eco.core.entities.ai.EntityController import com.willfp.eco.core.fast.FastItemStack import com.willfp.eco.core.integrations.placeholder.PlaceholderIntegration @@ -32,6 +33,7 @@ import com.willfp.eco.internal.spigot.integrations.bstats.MetricHandler import com.willfp.eco.internal.spigot.proxy.CommonsInitializerProxy import com.willfp.eco.internal.spigot.proxy.DummyEntityFactoryProxy import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy +import com.willfp.eco.internal.spigot.proxy.ExtendedPersistentDataContainerFactoryProxy import com.willfp.eco.internal.spigot.proxy.FastItemStackFactoryProxy import com.willfp.eco.internal.spigot.proxy.MiniMessageTranslatorProxy import net.kyori.adventure.platform.bukkit.BukkitAudiences @@ -40,6 +42,7 @@ import org.bukkit.NamespacedKey import org.bukkit.entity.Entity import org.bukkit.entity.Mob import org.bukkit.inventory.ItemStack +import org.bukkit.persistence.PersistentDataContainer import java.util.logging.Logger @Suppress("UNUSED") @@ -150,4 +153,7 @@ class EcoHandler : EcoSpigotPlugin(), Handler { override fun formatMiniMessage(message: String): String = getProxy(MiniMessageTranslatorProxy::class.java).format(message) + + override fun adaptPdc(container: PersistentDataContainer): ExtendedPersistentDataContainer = + getProxy(ExtendedPersistentDataContainerFactoryProxy::class.java).adapt(container) } diff --git a/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/ExtendedPersistentDataContainerFactoryProxy.kt b/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/ExtendedPersistentDataContainerFactoryProxy.kt new file mode 100644 index 00000000..af2eccd9 --- /dev/null +++ b/eco-core/core-proxy/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/ExtendedPersistentDataContainerFactoryProxy.kt @@ -0,0 +1,8 @@ +package com.willfp.eco.internal.spigot.proxy + +import com.willfp.eco.core.data.ExtendedPersistentDataContainer +import org.bukkit.persistence.PersistentDataContainer + +interface ExtendedPersistentDataContainerFactoryProxy { + fun adapt(pdc: PersistentDataContainer): ExtendedPersistentDataContainer +}