diff --git a/build.gradle.kts b/build.gradle.kts index 43086c2..ebedd96 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,13 +14,14 @@ subprojects { maven("https://repo.mineinabyss.com/releases") maven("https://repo.mineinabyss.com/snapshots") maven("https://erethon.de/repo/") + mavenLocal() maven("https://repo.papermc.io/repository/maven-public/") maven("https://repo.spaceio.xyz/repository/maven-snapshots/") maven("https://jitpack.io") maven("https://mvn.lumine.io/repository/maven-public/") { metadataSources { artifact() } }// MythicMobs maven("https://repo.unnamed.team/repository/unnamed-public/") - maven("https://repo.oraxen.com/releases") - maven("https://repo.oraxen.com/snapshots") + maven("https://repo.nexomc.com/releases") + maven("https://repo.nexomc.com/snapshots") } tasks { diff --git a/gradle.properties b/gradle.properties index c2fb94b..12c64f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=com.mineinabyss -version=0.25 +version=0.26 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 02067f4..105e868 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,13 +1,13 @@ [versions] anvilgui = "1.10.3-SNAPSHOT" -compose = "1.6.11" -coroutines = "1.9.0-RC" +compose = "1.7.1" +coroutines = "1.9.0" creative = "1.7.3" dependencyversions = "0.51.0" dokka = "1.9.20" -exposed = "0.55.0" +exposed = "0.56.0" fastutil = "8.5.14" -fawe = "2.8.4" +fawe = "2.12.2" itemsadder = "3.6.1" junit = "5.11.0" jvm = "21" @@ -22,19 +22,19 @@ ktor = "2.3.11" logback = "1.5.9" mccoroutine = "2.20.0" # @pin -minecraft = "1.21.1-R0.1-SNAPSHOT" -mockbukkit = "3.133.0" +minecraft = "1.21.3-R0.1-SNAPSHOT" +mockbukkit = "3.133.2" mockk = "1.13.13" modelengine = "R4.0.7" -mythic-dist = "5.7.2" -mythiccrucible = "2.0.0" -oraxen = "1.182.0" +mythic-dist = "5.8.0-SNAPSHOT" +mythiccrucible = "2.2.0-SNAPSHOT" +nexo = "0.1.0-dev.52" protocollib = "5.3.0-SNAPSHOT" reflections = "0.10.2" serialization = "1.7.3" -shadowjar = "8.3.0" +shadowjar = "8.3.5" sqlite-jdbc = "3.46.0.0" -userdev = "1.7.3" +userdev = "1.7.5" vault = "1.7" version-catalog-update = "0.8.4" worldguard = "7.1.0-SNAPSHOT" @@ -78,13 +78,14 @@ minecraft-mccoroutine = { module = "com.github.shynixn.mccoroutine:mccoroutine-b minecraft-mccoroutine-core = { module = "com.github.shynixn.mccoroutine:mccoroutine-bukkit-core", version.ref = "mccoroutine" } minecraft-mockbukkit = { module = "com.github.seeseemelk:MockBukkit-v1.21", version.ref = "mockbukkit" } minecraft-papermc = { module = "io.papermc.paper:paper-api", version.ref = "minecraft" } +#minecraft-cartridge = { module = "com.mineinabyss.cartridge:cartridge-api", version.ref = "minecraft" } minecraft-plugin-fawe-bukkit = { module = "com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit", version.ref = "fawe" } minecraft-plugin-fawe-core = { module = "com.fastasyncworldedit:FastAsyncWorldEdit-Core", version.ref = "fawe" } minecraft-plugin-itemsadder = { module = "com.github.LoneDev6:api-itemsadder", version.ref = "itemsadder" } minecraft-plugin-modelengine = { module = "com.ticxo.modelengine:ModelEngine", version.ref = "modelengine" } minecraft-plugin-mythic-crucible = { module = "io.lumine:MythicCrucible", version.ref = "mythiccrucible" } minecraft-plugin-mythic-dist = { module = "io.lumine:Mythic-Dist", version.ref = "mythic-dist" } -minecraft-plugin-oraxen = { module = "io.th0rgal:oraxen", version.ref = "oraxen" } +minecraft-plugin-nexo = { module = "com.nexomc:nexo", version.ref = "nexo" } minecraft-plugin-protocollib = { module = "com.comphenix.protocol:ProtocolLib", version.ref = "protocollib" } minecraft-plugin-vault = { module = "com.github.MilkBowl:VaultAPI", version.ref = "vault" } minecraft-plugin-worldguard = { module = "com.sk89q.worldguard:worldguard-bukkit", version.ref = "worldguard" } diff --git a/idofront-gradle/src/main/kotlin/com.mineinabyss.conventions.cartridge.gradle.kts b/idofront-gradle/src/main/kotlin/com.mineinabyss.conventions.cartridge.gradle.kts new file mode 100644 index 0000000..97de082 --- /dev/null +++ b/idofront-gradle/src/main/kotlin/com.mineinabyss.conventions.cartridge.gradle.kts @@ -0,0 +1,22 @@ +plugins { + java +} + +val libs = idofrontLibsRef + +repositories { + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") + mavenLocal() +} + +dependencies { + compileOnly(libs.findLibrary("minecraft-papermc").get()) +} + +tasks { + processResources { + filesMatching(setOf("plugin.yml", "paper-plugin.yml")) { + expand(mutableMapOf("plugin_version" to version)) + } + } +} diff --git a/idofront-gradle/src/main/kotlin/com.mineinabyss.conventions.papermc.gradle.kts b/idofront-gradle/src/main/kotlin/com.mineinabyss.conventions.papermc.gradle.kts index 8f9482b..6f10883 100644 --- a/idofront-gradle/src/main/kotlin/com.mineinabyss.conventions.papermc.gradle.kts +++ b/idofront-gradle/src/main/kotlin/com.mineinabyss.conventions.papermc.gradle.kts @@ -5,6 +5,7 @@ plugins { val libs = idofrontLibsRef repositories { + mavenLocal() maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") maven("https://repo.papermc.io/repository/maven-public/") } diff --git a/idofront-serializers/build.gradle.kts b/idofront-serializers/build.gradle.kts index d4bb818..e599068 100644 --- a/idofront-serializers/build.gradle.kts +++ b/idofront-serializers/build.gradle.kts @@ -12,7 +12,7 @@ dependencies { compileOnly(libs.kotlinx.serialization.kaml) compileOnly(libs.minecraft.plugin.mythic.dist) compileOnly(libs.minecraft.plugin.mythic.crucible) - compileOnly(libs.minecraft.plugin.oraxen) + compileOnly(libs.minecraft.plugin.nexo) compileOnly(libs.minecraft.plugin.itemsadder) compileOnly(libs.creative.api) implementation(project(":idofront-util")) diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/AttributeSerializer.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/AttributeSerializer.kt index 00e4179..b39fe4e 100644 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/AttributeSerializer.kt +++ b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/AttributeSerializer.kt @@ -1,5 +1,6 @@ package com.mineinabyss.idofront.serialization +import io.papermc.paper.datacomponent.item.ItemAttributeModifiers import kotlinx.serialization.EncodeDefault import kotlinx.serialization.EncodeDefault.Mode.NEVER import kotlinx.serialization.KSerializer @@ -8,22 +9,27 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import net.kyori.adventure.key.Key import org.bukkit.NamespacedKey import org.bukkit.attribute.Attribute import org.bukkit.attribute.AttributeModifier import org.bukkit.inventory.EquipmentSlotGroup -import java.util.* @Serializable @SerialName("SerializableAttribute") -class SerializableAttribute ( +class SerializableAttribute( val attribute: Attribute, val modifier: @Serializable(with = AttributeModifierSerializer::class) AttributeModifier, ) { + + constructor(itemAttributeModifier: ItemAttributeModifiers.Entry) : this( + itemAttributeModifier.attribute(), + itemAttributeModifier.modifier() + ) + operator fun component1(): Attribute { return attribute } + operator fun component2(): AttributeModifier { return modifier } diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/FoodComponentSerializer.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/FoodComponentSerializer.kt deleted file mode 100644 index a362966..0000000 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/FoodComponentSerializer.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.mineinabyss.idofront.serialization - -import com.mineinabyss.idofront.time.inWholeTicks -import com.mineinabyss.idofront.time.ticks -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import org.bukkit.Material -import org.bukkit.inventory.ItemStack -import org.bukkit.inventory.meta.components.FoodComponent -import org.bukkit.inventory.meta.components.FoodComponent.FoodEffect -import org.bukkit.potion.PotionEffect -import org.bukkit.potion.PotionEffectType -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit - -@Serializable -@SerialName("FoodComponent") -class FoodComponentSurrogate( - val nutrition: Int, - val saturation: Float, - val eatSeconds: Float = 1.6f, - val canAlwaysEat: Boolean = false, - val usingConvertsTo: SerializableItemStack? = null, - val effects: List = emptyList() -) { - - constructor(food: FoodComponent) : this( - food.nutrition, - food.saturation, - food.eatSeconds, - food.canAlwaysEat(), - food.usingConvertsTo?.toSerializable(), - food.effects.map { FoodEffectWrapper(it.effect, it.probability) }) - - init { - require(nutrition >= 0) { "FoodComponent must have a positive nutrition" } - require(saturation >= 0) { "FoodComponent must have a positive saturation" } - require(eatSeconds >= 0) { "FoodComponent must have a positive eatSeconds" } - require(effects.all { it.probability in 0.0..1.0 }) { "FoodEffect-probability must be between 0.0..1.0" } - } - - val foodComponent: FoodComponent - get() = ItemStack.of(Material.PAPER).itemMeta.food.also { - it.nutrition = nutrition - it.saturation = saturation - it.eatSeconds = eatSeconds - it.setCanAlwaysEat(canAlwaysEat) - it.usingConvertsTo = usingConvertsTo?.toItemStackOrNull() - effects.forEach { e -> it.addEffect(e.effect, e.probability) } - } -} diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/FoodEffectWrapper.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/FoodEffectWrapper.kt deleted file mode 100644 index beae932..0000000 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/FoodEffectWrapper.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.mineinabyss.idofront.serialization - -import kotlinx.serialization.Serializable -import org.bukkit.potion.PotionEffect - -@Serializable -class FoodEffectWrapper(val effect: @Serializable(PotionEffectSerializer::class) PotionEffect, val probability: Float = 1.0f) \ No newline at end of file diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableDataTypes.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableDataTypes.kt new file mode 100644 index 0000000..0a006f1 --- /dev/null +++ b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableDataTypes.kt @@ -0,0 +1,670 @@ +package com.mineinabyss.idofront.serialization + +import com.mineinabyss.idofront.serialization.SerializableDataTypes.ConsumeEffect.ClearAllEffectsConsumeEffect.toSerializable +import io.papermc.paper.block.BlockPredicate +import io.papermc.paper.datacomponent.DataComponentType +import io.papermc.paper.datacomponent.DataComponentTypes +import io.papermc.paper.datacomponent.item.* +import io.papermc.paper.datacomponent.item.MapDecorations.DecorationEntry +import io.papermc.paper.datacomponent.item.Tool.Rule +import io.papermc.paper.datacomponent.item.consumable.* +import io.papermc.paper.registry.RegistryAccess +import io.papermc.paper.registry.RegistryKey +import io.papermc.paper.registry.TypedKey +import io.papermc.paper.registry.set.RegistrySet +import io.papermc.paper.registry.tag.TagKey +import kotlinx.serialization.Serializable +import net.kyori.adventure.key.Key +import net.kyori.adventure.text.Component +import net.kyori.adventure.util.TriState +import org.bukkit.Color +import org.bukkit.Registry +import org.bukkit.entity.EntityType +import org.bukkit.inventory.EquipmentSlot +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.ItemType +import org.bukkit.inventory.meta.trim.ArmorTrim +import org.bukkit.map.MapCursor +import org.bukkit.potion.PotionEffect +import org.bukkit.potion.PotionEffectType + +object SerializableDataTypes { + + fun setData(itemStack: ItemStack, dataComponent: DataComponentType.Valued, any: T?) { + any?.let { itemStack.setData(dataComponent, any) } + } + + fun setData(itemStack: ItemStack, dataComponent: DataComponentType.NonValued, any: T?) { + any?.let { itemStack.setData(dataComponent) } + } + + interface DataType { + fun setDataType(itemStack: ItemStack) + } + + @Serializable + data class Unbreakable(val shownInTooltip: Boolean = true) : DataType { + constructor(unbreakable: io.papermc.paper.datacomponent.item.Unbreakable) : this(unbreakable.showInTooltip()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.UNBREAKABLE, + io.papermc.paper.datacomponent.item.Unbreakable.unbreakable(shownInTooltip) + ) + } + } + + @Serializable + @JvmInline + value class CustomModelData(val customModelData: Int) : DataType { + constructor(customModelData: io.papermc.paper.datacomponent.item.CustomModelData) : this(customModelData.id()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.CUSTOM_MODEL_DATA, + io.papermc.paper.datacomponent.item.CustomModelData.customModelData(customModelData) + ) + } + } + + /*@Serializable + @JvmInline + value class LockCode(val lockCode: Int) : DataType { + constructor(customModelData: io.papermc.paper.datacomponent.item.CustomModelData) : this(customModelData.id()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.CUSTOM_MODEL_DATA, + io.papermc.paper.datacomponent.item.LockCode (customModelData) + ) + } + }*/ + + @Serializable + data class PotionContents( + val potionType: @Serializable(PotionTypeSerializer::class) org.bukkit.potion.PotionType?, + val color: @Serializable(ColorSerializer::class) Color?, + val customEffects: List<@Serializable(PotionEffectSerializer::class) PotionEffect> = emptyList() + ) : DataType { + + constructor(potionContents: io.papermc.paper.datacomponent.item.PotionContents) : this( + potionContents.potion(), + potionContents.customColor(), + potionContents.customEffects() + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.POTION_CONTENTS, + io.papermc.paper.datacomponent.item.PotionContents.potionContents().potion(potionType).customColor(color) + .addCustomEffects(customEffects).build() + ) + } + } + + @Serializable + data class Enchantments( + val enchantments: List, + val showInToolTip: Boolean = true + ) : DataType { + constructor(itemEnchantments: ItemEnchantments) : this( + itemEnchantments.enchantments().map(::SerializableEnchantment), itemEnchantments.showInTooltip() + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.ENCHANTMENTS, + ItemEnchantments.itemEnchantments(enchantments.associate { it.enchant to it.level }, showInToolTip) + ) + } + } + + @Serializable + data class StoredEnchantments( + val enchantments: List, + val showInToolTip: Boolean = true + ) : DataType { + constructor(itemEnchantments: ItemEnchantments) : this( + itemEnchantments.enchantments().map(::SerializableEnchantment), itemEnchantments.showInTooltip() + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.STORED_ENCHANTMENTS, + ItemEnchantments.itemEnchantments(enchantments.associate { it.enchant to it.level }, showInToolTip) + ) + } + } + + @Serializable + @JvmInline + value class ChargedProjectiles(private val projectiles: List) : DataType { + constructor(vararg projectiles: ItemStack) : this(projectiles.map { it.toSerializable() }) + constructor(projectiles: io.papermc.paper.datacomponent.item.ChargedProjectiles) : this( + projectiles.projectiles().map { it.toSerializable() }) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.CHARGED_PROJECTILES, + io.papermc.paper.datacomponent.item.ChargedProjectiles.chargedProjectiles(projectiles.mapNotNull { it.toItemStackOrNull() }) + ) + } + } + + @Serializable + @JvmInline + value class BundleContent(private val contents: List) : DataType { + constructor(vararg contents: ItemStack) : this(contents.map { it.toSerializable() }) + constructor(contents: BundleContents) : this(contents.contents().map { it.toSerializable() }) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.BUNDLE_CONTENTS, + BundleContents.bundleContents(contents.mapNotNull { it.toItemStackOrNull() }) + ) + } + } + + @Serializable + data class WrittenBook( + val title: String, + val author: String, + val generation: Int, + val resolved: Boolean, + val pages: List<@Serializable(MiniMessageSerializer::class) Component> = emptyList() + ) : DataType { + constructor(written: WrittenBookContent) : this( + written.title().raw(), + written.author(), + written.generation(), + written.resolved(), + written.pages().map { it.raw() } + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.WRITTEN_BOOK_CONTENT, + WrittenBookContent.writtenBookContent(title, author).resolved(resolved).generation(generation) + .addPages(pages).build() + ) + } + } + + @Serializable + data class WritableBook(val pages: List) : DataType { + constructor(writable: WritableBookContent) : this(writable.pages().map { it.raw() }) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.WRITABLE_BOOK_CONTENT, + WritableBookContent.writeableBookContent().addPages(pages).build() + ) + } + } + + @Serializable + data class MapDecoration(val type: MapCursor.Type, val x: Double, val z: Double, val rotation: Float) { + constructor(entry: MapDecorations.DecorationEntry) : this(entry.type(), entry.x(), entry.z(), entry.rotation()) + val paperDecoration: DecorationEntry = DecorationEntry.of(type, x, z, rotation) + + companion object { + fun toPaperDecorations(decorations: List) = + decorations.mapIndexed { i, mapDecoration -> i.toString() to mapDecoration.paperDecoration }.toMap() + } + } + + @Serializable + @JvmInline + value class Enchantable(val enchantable: Int) : DataType { + constructor(enchantable: io.papermc.paper.datacomponent.item.Enchantable) : this(enchantable.value()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.ENCHANTABLE, io.papermc.paper.datacomponent.item.Enchantable.enchantable(enchantable)) + } + } + + @Serializable + @JvmInline + value class Repairable(val repairable: List<@Serializable(KeySerializer::class) Key>) : DataType { + constructor(repairable: io.papermc.paper.datacomponent.item.Repairable) : + this(repairable.types().resolve(Registry.ITEM).map { it.key() }) + + override fun setDataType(itemStack: ItemStack) { + val items = repairable.mapNotNull { Registry.ITEM.get(it)?.key()?.let { TypedKey.create(RegistryKey.ITEM, it) } } + val tags = repairable.mapNotNull { + runCatching { Registry.ITEM.getTag(TagKey.create(RegistryKey.ITEM, it)) }.getOrNull()?.values() + }.flatten() + + itemStack.setData(DataComponentTypes.REPAIRABLE, io.papermc.paper.datacomponent.item.Repairable.repairable( + RegistrySet.keySet(RegistryKey.ITEM, items.plus(tags).filterNotNull().toMutableList()) + )) + } + } + + @Serializable + data class Tool( + val rules: List = emptyList(), + val defaultMiningSpeed: Float, + val damagePerBlock: Int + ) : BlockTags(), DataType { + constructor(tool: io.papermc.paper.datacomponent.item.Tool) : this( + tool.rules().map(::Rule), + tool.defaultMiningSpeed(), + tool.damagePerBlock() + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.TOOL, io.papermc.paper.datacomponent.item.Tool.tool() + .damagePerBlock(damagePerBlock) + .defaultMiningSpeed(defaultMiningSpeed) + .addRules(rules.toPaperRules()) + .build() + ) + } + + @Serializable + data class Rule( + val blockTypes: List<@Serializable(KeySerializer::class) Key>, + val speed: Float? = null, + val correctForDrops: TriState + ) { + constructor(rule: io.papermc.paper.datacomponent.item.Tool.Rule) : this( + rule.blocks().map { it.key() }, + rule.speed(), + rule.correctForDrops() + ) + } + } + + @Serializable + data class CanPlaceOn( + val showInToolTip: Boolean = true, + val modifiers: List + ) : BlockTags(), DataType { + constructor(predicate: ItemAdventurePredicate) : this(predicate.showInTooltip(), predicate.predicates().map(::BlockPredicate)) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.CAN_PLACE_ON, ItemAdventurePredicate.itemAdventurePredicate() + .showInTooltip(showInToolTip).apply { + modifiers.toPaperBlockPredicate().forEach { blockPredicate -> + addPredicate(blockPredicate) + } + } + .build() + ) + } + } + + @Serializable + data class CanBreak( + val showInToolTip: Boolean = true, + val modifiers: List + ) : BlockTags(), DataType { + constructor(predicate: ItemAdventurePredicate) : this(predicate.showInTooltip(), predicate.predicates().map(::BlockPredicate)) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.CAN_BREAK, ItemAdventurePredicate.itemAdventurePredicate() + .showInTooltip(showInToolTip).apply { + modifiers.toPaperBlockPredicate().forEach { blockPredicate -> + addPredicate(blockPredicate) + } + } + .build() + ) + } + } + + @Serializable + sealed class BlockTags { + fun List.toPaperRules(): List { + val rules = mutableListOf() + + this.forEach { rule -> + val blockTagKeys = + rule.blockTypes.map { TagKey.create(RegistryKey.BLOCK, it) }.filter(Registry.BLOCK::hasTag) + blockTagKeys.map(Registry.BLOCK::getTag).forEach { blockTag -> + rules += Rule.rule(blockTag, rule.speed, rule.correctForDrops) + } + val blockKeys = rule.blockTypes.filter { Registry.BLOCK.get(it) != null } + .map { TypedKey.create(RegistryKey.BLOCK, it.key()) } + val keySet = RegistrySet.keySet(RegistryKey.BLOCK, blockKeys) + rules += Rule.rule(keySet, rule.speed, rule.correctForDrops) + } + + return rules + } + + fun List.toPaperBlockPredicate(): List { + val blockPredicates = mutableListOf() + + this.forEach { blockPredicate -> + blockPredicate.blocks + ?.map { TagKey.create(RegistryKey.BLOCK, it) } + ?.filter(Registry.BLOCK::hasTag)?.map(Registry.BLOCK::getTag) + ?.forEach { blockTag -> + blockPredicates += io.papermc.paper.block.BlockPredicate.predicate().blocks(blockTag).build() + } + + blockPredicate.blocks?.filter { Registry.BLOCK.get(it) != null } + ?.map { TypedKey.create(RegistryKey.BLOCK, it.key()) } + ?.let { blockKeys -> + val keySet = RegistrySet.keySet(RegistryKey.BLOCK, blockKeys) + blockPredicates += io.papermc.paper.block.BlockPredicate.predicate().blocks(keySet).build() + } + } + + return blockPredicates + } + + @Serializable + data class BlockPredicate( + val blocks: List<@Serializable(KeySerializer::class) Key>? + ) { + constructor(blockPredicate: io.papermc.paper.block.BlockPredicate) : this( + blockPredicate.blocks()?.map { it.key() }) + } + } + + @Serializable + sealed interface ConsumeEffect { + + fun io.papermc.paper.datacomponent.item.consumable.ConsumeEffect.toSerializable() = when (this) { + is ApplyStatusEffectsConsumeEffect -> ApplyEffectsConsumeEffect(effects(), probability()) + is RemoveStatusEffectsConsumeEffect -> RemoveEffectsConsumeEffect(removeEffects().resolve(Registry.POTION_EFFECT_TYPE).toList()) + is TeleportRandomlyConsumeEffect -> TeleportConsumeEffect(diameter()) + is io.papermc.paper.datacomponent.item.consumable.PlaySoundConsumeEffect -> PlaySoundConsumeEffect(sound()) + is ClearAllStatusEffectsConsumeEffect -> ClearAllEffectsConsumeEffect + else -> ApplyEffectsConsumeEffect(emptyList(), 0f) + } + + fun toPaperEffect() : io.papermc.paper.datacomponent.item.consumable.ConsumeEffect { + return when (this) { + is ApplyEffectsConsumeEffect -> ApplyStatusEffectsConsumeEffect.applyStatusEffects(effects, probability) + is RemoveEffectsConsumeEffect -> RemoveStatusEffectsConsumeEffect.removeEffects(RegistrySet.keySetFromValues(RegistryKey.MOB_EFFECT, effects)) + is TeleportConsumeEffect -> TeleportRandomlyConsumeEffect.teleportRandomlyEffect(diameter) + is PlaySoundConsumeEffect -> io.papermc.paper.datacomponent.item.consumable.PlaySoundConsumeEffect.playSoundConsumeEffect(key) + is ClearAllEffectsConsumeEffect -> ClearAllStatusEffectsConsumeEffect.clearAllStatusEffects() + } + } + + @Serializable + data class ApplyEffectsConsumeEffect( + val effects: List<@Serializable(PotionEffectSerializer::class) PotionEffect>, + val probability: Float = 1.0f + ): ConsumeEffect + + @Serializable + data class RemoveEffectsConsumeEffect(val effects: List<@Serializable(PotionEffectTypeSerializer::class) PotionEffectType>): ConsumeEffect + + @Serializable + data class TeleportConsumeEffect(val diameter: Float = 16.0f): ConsumeEffect + + @Serializable + data class PlaySoundConsumeEffect(val key: @Serializable(KeySerializer::class) Key) : ConsumeEffect + + @Serializable + object ClearAllEffectsConsumeEffect : ConsumeEffect, ClearAllStatusEffectsConsumeEffect + } + + @Serializable + @JvmInline + value class UseRemainder(val useRemainder: SerializableItemStack) : DataType { + constructor(useRemainder: io.papermc.paper.datacomponent.item.UseRemainder) : this(useRemainder.transformInto().toSerializable()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.USE_REMAINDER, + io.papermc.paper.datacomponent.item.UseRemainder.useRemainder(useRemainder.toItemStack()) + ) + } + } + + @Serializable + @JvmInline + value class DamageResistant(val damageResistant: @Serializable(KeySerializer::class) Key) : DataType { + constructor(damageResistant: io.papermc.paper.datacomponent.item.DamageResistant) : this(damageResistant.types().key()) + + private val damageTypeRegistry get() = RegistryAccess.registryAccess().getRegistry(RegistryKey.DAMAGE_TYPE) + + init { + require(damageTypeRegistry.get(damageResistant) != null) { "${damageResistant.asString()} was not a valid DamageType"} + } + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.DAMAGE_RESISTANT, io.papermc.paper.datacomponent.item.DamageResistant.damageResistant(TagKey.create(RegistryKey.DAMAGE_TYPE, damageResistant))) + } + } + + @Serializable + class DeathProtection(val consumeEffects: List) : DataType { + constructor(deathProtection: io.papermc.paper.datacomponent.item.DeathProtection) : this(deathProtection.deathEffects().map { it.toSerializable() }) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.DEATH_PROTECTION, io.papermc.paper.datacomponent.item.DeathProtection.deathProtection(consumeEffects.map { it.toPaperEffect() })) + } + } + + @Serializable + data class Consumable( + val seconds: Float, + val sound: @Serializable(KeySerializer::class) Key?, + val animation: ItemUseAnimation, + val particles: Boolean, + val consumeEffects: List + ) : DataType { + constructor(consumable: io.papermc.paper.datacomponent.item.Consumable) : this( + consumable.consumeSeconds(), + consumable.sound(), + consumable.animation(), + consumable.hasConsumeParticles(), + consumable.consumeEffects().map { it.toSerializable() } + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.CONSUMABLE, io.papermc.paper.datacomponent.item.Consumable.consumable() + .consumeSeconds(seconds).sound(sound).animation(animation).hasConsumeParticles(particles) + .addEffects(consumeEffects.map { it.toPaperEffect() }) + ) + } + } + + @Serializable + data class FoodProperties( + val nutrition: Int, + val saturation: Float, + val canAlwaysEat: Boolean = false + ) : DataType { + + constructor(foodProperties: io.papermc.paper.datacomponent.item.FoodProperties) : this( + foodProperties.nutrition(), + foodProperties.saturation(), + foodProperties.canAlwaysEat() + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.FOOD, io.papermc.paper.datacomponent.item.FoodProperties.food() + .nutrition(nutrition).saturation(saturation).canAlwaysEat(canAlwaysEat) + ) + } + } + + @Serializable + data class DyedColor( + val color: @Serializable(ColorSerializer::class) Color, + val showInToolTip: Boolean + ) : DataType { + constructor(dyedItemColor: DyedItemColor) : this(dyedItemColor.color(), dyedItemColor.showInTooltip()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.DYED_COLOR, DyedItemColor.dyedItemColor(color, showInToolTip)) + } + } + + @Serializable + @JvmInline + value class MapColor( + private val color: @Serializable(ColorSerializer::class) Color, + ) : DataType { + constructor(mapItemColor: MapItemColor) : this(mapItemColor.color()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.MAP_COLOR, MapItemColor.mapItemColor().color(color).build()) + } + + } + + @Serializable + data class Equippable( + val slot: EquipmentSlot, + val model: @Serializable(KeySerializer::class) Key? = null, + val cameraOverlay: @Serializable(KeySerializer::class) Key? = null, + val equipSound: @Serializable(KeySerializer::class) Key? = null, + val allowedEntities: List? = EntityType.entries, + val damageOnHurt: Boolean = true, + val swappable: Boolean = true, + val dispensable: Boolean = true, + + ) : DataType { + constructor(equippable: io.papermc.paper.datacomponent.item.Equippable) : this( + equippable.slot(), equippable.model(), equippable.cameraOverlay(), equippable.equipSound(), + equippable.allowedEntities()?.resolve(Registry.ENTITY_TYPE)?.toList(), + equippable.damageOnHurt(), equippable.swappable(), equippable.dispensable() + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData( + DataComponentTypes.EQUIPPABLE, + io.papermc.paper.datacomponent.item.Equippable.equippable(slot).model(model).cameraOverlay(cameraOverlay) + .equipSound(equipSound).allowedEntities(allowedEntities?.let { RegistrySet.keySetFromValues(RegistryKey.ENTITY_TYPE, it) }) + .damageOnHurt(damageOnHurt).swappable(swappable).dispensable(dispensable) + ) + } + } + + @Serializable + class Trim( + val material: @Serializable(KeySerializer::class) Key, + val pattern: @Serializable(KeySerializer::class) Key, + val showInToolTip: Boolean = true + ) : DataType { + constructor(trim: ItemArmorTrim) : this( + trim.armorTrim().material.key(), + trim.armorTrim().pattern.key(), + trim.showInTooltip() + ) + + override fun setDataType(itemStack: ItemStack) { + val trimMaterial = RegistryAccess.registryAccess().getRegistry(RegistryKey.TRIM_MATERIAL).get(material) + ?: error("Invalid TrimMaterial: " + material.asString()) + val trimPattern = RegistryAccess.registryAccess().getRegistry(RegistryKey.TRIM_PATTERN).get(pattern) + ?: error("Invalid TrimPattern: " + pattern.asString()) + itemStack.setData( + DataComponentTypes.TRIM, + ItemArmorTrim.itemArmorTrim(ArmorTrim(trimMaterial, trimPattern), showInToolTip) + ) + } + + } + + @Serializable + data class JukeboxPlayable( + val jukeboxSong: @Serializable(KeySerializer::class) Key, + val showInToolTip: Boolean = true + ) : DataType { + constructor(jukeboxPlayable: io.papermc.paper.datacomponent.item.JukeboxPlayable) : + this(jukeboxPlayable.jukeboxSong().key(), jukeboxPlayable.showInTooltip()) + + override fun setDataType(itemStack: ItemStack) { + val jukeboxRegistry = RegistryAccess.registryAccess().getRegistry(RegistryKey.JUKEBOX_SONG) + val jukeboxSong = jukeboxRegistry.get(jukeboxSong) ?: return + itemStack.setData( + DataComponentTypes.JUKEBOX_PLAYABLE, + io.papermc.paper.datacomponent.item.JukeboxPlayable.jukeboxPlayable(jukeboxSong).showInTooltip(showInToolTip) + ) + } + } + + @Serializable + data class AttributeModifiers( + val attributes: List, + val showInToolTip: Boolean = true + ) : DataType { + + constructor(attributeModifiers: ItemAttributeModifiers) : this( + attributeModifiers.modifiers().map(::SerializableAttribute), attributeModifiers.showInTooltip() + ) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.itemAttributes().apply { + attributes.forEach { addModifier(it.attribute, it.modifier) } + }.showInTooltip(showInToolTip).build()) + } + } + + @Serializable + data class UseCooldown( + val seconds: Float, + val group: @Serializable(KeySerializer::class) Key? = null + ) : DataType { + + init { + require(seconds <= 0) { "Seconds cannot be below 0" } + } + + constructor(cooldown: io.papermc.paper.datacomponent.item.UseCooldown) : this(cooldown.seconds(), cooldown.cooldownGroup()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.USE_COOLDOWN, io.papermc.paper.datacomponent.item.UseCooldown.useCooldown(seconds).cooldownGroup(group).build()) + } + } + + + + @Serializable + data class PotDecorations( + val backItem: @Serializable(KeySerializer::class) Key? = null, + val frontItem: @Serializable(KeySerializer::class) Key? = null, + val leftItem: @Serializable(KeySerializer::class) Key? = null, + val rightItem: @Serializable(KeySerializer::class) Key? = null, + ) : DataType { + constructor(potDecorations: io.papermc.paper.datacomponent.item.PotDecorations) : + this(potDecorations.back()?.key(), potDecorations.front()?.key(), potDecorations.left()?.key(), potDecorations.right()?.key()) + + override fun setDataType(itemStack: ItemStack) { + val (back, front) = backItem?.let { Registry.ITEM.get(it) } to frontItem?.let { Registry.ITEM.get(it) } + val (left, right) = leftItem?.let { Registry.ITEM.get(it) } to rightItem?.let { Registry.ITEM.get(it) } + itemStack.setData(DataComponentTypes.POT_DECORATIONS, io.papermc.paper.datacomponent.item.PotDecorations.potDecorations(back, left, right, front)) + } + } + + @Serializable + @JvmInline + value class MapId(val mapId: Int) : DataType { + constructor(mapId: io.papermc.paper.datacomponent.item.MapId) : this(mapId.id()) + + override fun setDataType(itemStack: ItemStack) { + itemStack.setData(DataComponentTypes.MAP_ID, io.papermc.paper.datacomponent.item.MapId.mapId(mapId)) + } + } + + @Serializable + object HideToolTip + + @Serializable + object HideAdditionalTooltip + + @Serializable + object CreativeSlotLock + + @Serializable + object IntangibleProjectile + + @Serializable + object Glider + +} \ No newline at end of file diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableEnchantment.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableEnchantment.kt index 8b45b38..4cc5d41 100644 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableEnchantment.kt +++ b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableEnchantment.kt @@ -17,6 +17,7 @@ data class SerializableEnchantment( val enchant: @Serializable(with = EnchantmentSerializer::class) Enchantment, val level: Int = 1, ) { + constructor(itemEnchantment: Map.Entry) : this(itemEnchantment.key, itemEnchantment.value) init { require(level > 0) { "Level must be atleast 1" } } diff --git a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt index 41ca897..ecb4fb7 100644 --- a/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt +++ b/idofront-serializers/src/main/kotlin/com/mineinabyss/idofront/serialization/SerializableItemStack.kt @@ -3,95 +3,122 @@ package com.mineinabyss.idofront.serialization import com.mineinabyss.idofront.di.DI -import com.mineinabyss.idofront.items.asColorable import com.mineinabyss.idofront.messaging.idofrontLogger -import com.mineinabyss.idofront.nms.hideAttributeTooltipWithItemFlagSet import com.mineinabyss.idofront.plugin.Plugins import com.mineinabyss.idofront.serialization.recipes.options.IngredientOption import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize +import com.nexomc.nexo.NexoPlugin +import com.nexomc.nexo.api.NexoItems import dev.lone.itemsadder.api.CustomStack import io.lumine.mythiccrucible.MythicCrucible -import io.th0rgal.oraxen.OraxenPlugin -import io.th0rgal.oraxen.api.OraxenItems +import io.papermc.paper.datacomponent.DataComponentTypes +import io.papermc.paper.datacomponent.item.ItemLore +import io.papermc.paper.datacomponent.item.MapDecorations +import io.papermc.paper.item.MapPostProcessing import kotlinx.serialization.* import kotlinx.serialization.EncodeDefault.Mode.NEVER +import net.kyori.adventure.key.Key +import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.TextDecoration -import org.bukkit.* -import org.bukkit.inventory.ItemFlag +import org.bukkit.Bukkit +import org.bukkit.Keyed +import org.bukkit.Material +import org.bukkit.NamespacedKey import org.bukkit.inventory.ItemRarity import org.bukkit.inventory.ItemStack -import org.bukkit.inventory.meta.Damageable -import org.bukkit.inventory.meta.KnowledgeBookMeta -import org.bukkit.inventory.meta.LeatherArmorMeta -import org.bukkit.inventory.meta.PotionMeta -import org.bukkit.inventory.meta.components.FoodComponent -import org.bukkit.inventory.meta.components.JukeboxPlayableComponent -import org.bukkit.inventory.meta.components.ToolComponent -import org.bukkit.potion.PotionEffect -import org.bukkit.potion.PotionType typealias SerializableItemStack = @Serializable(with = SerializableItemStackSerializer::class) BaseSerializableItemStack /** * A wrapper for [ItemStack] that uses [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization). * Allows for easy-to-use serialization to JSON (or YAML with kaml). - * - * Currently missing many things spigot's item serialization contains, but way cleaner to use! - * - * See [MiniMessage docs](https://docs.adventure.kyori.net/minimessage/format.html) for formatting info! */ @Serializable data class BaseSerializableItemStack( @EncodeDefault(NEVER) val type: @Serializable(with = MaterialByNameSerializer::class) Material? = null, @EncodeDefault(NEVER) val amount: Int? = null, - @EncodeDefault(NEVER) val customModelData: Int? = null, + @EncodeDefault(NEVER) val customModelData: SerializableDataTypes.CustomModelData? = null, + @EncodeDefault(NEVER) val itemModel: @Serializable(KeySerializer::class) Key? = null, + @EncodeDefault(NEVER) val tooltipStyle: @Serializable(KeySerializer::class) Key? = null, + @EncodeDefault(NEVER) @SerialName("itemName") private val _itemName: String? = null, // This is private as we only want to use itemName in configs @EncodeDefault(NEVER) @SerialName("customName") private val _customName: String? = null, @EncodeDefault(NEVER) @SerialName("lore") private val _lore: List? = null, - @EncodeDefault(NEVER) val unbreakable: Boolean? = null, + + @EncodeDefault(NEVER) val unbreakable: SerializableDataTypes.Unbreakable? = null, @EncodeDefault(NEVER) val damage: Int? = null, - @EncodeDefault(NEVER) val durability: Int? = null, - @EncodeDefault(NEVER) val prefab: String? = null, - @EncodeDefault(NEVER) val enchantments: List? = null, - @EncodeDefault(NEVER) val itemFlags: List? = null, - @EncodeDefault(NEVER) val attributeModifiers: List? = null, - @EncodeDefault(NEVER) val basePotionType: @Serializable(with = PotionTypeSerializer::class) PotionType? = null, - @EncodeDefault(NEVER) val customPotionEffects: List<@Serializable(with = PotionEffectSerializer::class) PotionEffect> = listOf(), - @EncodeDefault(NEVER) val knowledgeBookRecipes: List? = null, - @EncodeDefault(NEVER) val color: @Serializable(with = ColorSerializer::class) Color? = null, - @EncodeDefault(NEVER) val food: FoodComponentSurrogate? = null, - @EncodeDefault(NEVER) val tool: @Serializable(with = ToolComponentSerializer::class) ToolComponent? = null, - @EncodeDefault(NEVER) val jukeboxPlayable: @Serializable(with = JukeboxPlayableSerializer::class) JukeboxPlayableComponent? = null, - @EncodeDefault(NEVER) val hideTooltip: Boolean? = null, - @EncodeDefault(NEVER) val isFireResistant: Boolean? = null, + @EncodeDefault(NEVER) val maxDamage: Int? = null, + @EncodeDefault(NEVER) val enchantments: SerializableDataTypes.Enchantments? = null, + @EncodeDefault(NEVER) val storedEnchantments: SerializableDataTypes.StoredEnchantments? = null, + @EncodeDefault(NEVER) val potionContents: SerializableDataTypes.PotionContents? = null, + @EncodeDefault(NEVER) val attributeModifiers: SerializableDataTypes.AttributeModifiers? = null, + @EncodeDefault(NEVER) val useCooldown: SerializableDataTypes.UseCooldown? = null, + @EncodeDefault(NEVER) val useRemainder: SerializableDataTypes.UseRemainder? = null, + @EncodeDefault(NEVER) val consumable: SerializableDataTypes.Consumable? = null, + @EncodeDefault(NEVER) val food: SerializableDataTypes.FoodProperties? = null, + @EncodeDefault(NEVER) val tool: SerializableDataTypes.Tool? = null, + @EncodeDefault(NEVER) val enchantable: SerializableDataTypes.Enchantable? = null, + @EncodeDefault(NEVER) val repairable: SerializableDataTypes.Repairable? = null, + @EncodeDefault(NEVER) val canPlaceOn: SerializableDataTypes.CanPlaceOn? = null, + @EncodeDefault(NEVER) val canBreak: SerializableDataTypes.CanBreak? = null, + @EncodeDefault(NEVER) val dyedColor: SerializableDataTypes.DyedColor? = null, + @EncodeDefault(NEVER) val mapColor: SerializableDataTypes.MapColor? = null, + @EncodeDefault(NEVER) val mapDecorations: List? = null, + @EncodeDefault(NEVER) val equippable: SerializableDataTypes.Equippable? = null, + @EncodeDefault(NEVER) val trim: SerializableDataTypes.Trim? = null, + @EncodeDefault(NEVER) val jukeboxPlayable: SerializableDataTypes.JukeboxPlayable? = null, + @EncodeDefault(NEVER) val chargedProjectiles: SerializableDataTypes.ChargedProjectiles? = null, + @EncodeDefault(NEVER) val bundleContents: SerializableDataTypes.BundleContent? = null, + @EncodeDefault(NEVER) val writableBook: SerializableDataTypes.WritableBook? = null, + @EncodeDefault(NEVER) val writtenBook: SerializableDataTypes.WrittenBook? = null, + @EncodeDefault(NEVER) val damageResistant: SerializableDataTypes.DamageResistant? = null, + @EncodeDefault(NEVER) val deathProtection: SerializableDataTypes.DeathProtection? = null, + + @EncodeDefault(NEVER) val recipes: List<@Serializable(KeySerializer::class) Key>? = null, @EncodeDefault(NEVER) val enchantmentGlintOverride: Boolean? = null, @EncodeDefault(NEVER) val maxStackSize: Int? = null, @EncodeDefault(NEVER) val rarity: ItemRarity? = null, + @EncodeDefault(NEVER) val repairCost: Int? = null, + @EncodeDefault(NEVER) val mapId: SerializableDataTypes.MapId? = null, + @EncodeDefault(NEVER) val mapPostProcessing: MapPostProcessing? = null, - // Custom recipes + // Block-specific DataTypes + //@EncodeDefault(NEVER) val lock: String? = null, + @EncodeDefault(NEVER) val noteBlockSound: @Serializable(KeySerializer::class) Key? = null, + @EncodeDefault(NEVER) val profile: SerializableDataTypes.PotDecorations? = null, + @EncodeDefault(NEVER) val potDecorations: SerializableDataTypes.PotDecorations? = null, + + + @EncodeDefault(NEVER) val prefab: String? = null, @EncodeDefault(NEVER) val tag: String? = null, @EncodeDefault(NEVER) val recipeOptions: List = listOf(), + // Unvalued DataTypes + @EncodeDefault(NEVER) @Contextual val hideTooltip: SerializableDataTypes.HideToolTip? = null, + @EncodeDefault(NEVER) @Contextual val hideAdditionalTooltip: SerializableDataTypes.HideAdditionalTooltip? = null, + @EncodeDefault(NEVER) @Contextual val creativeSlotLock: SerializableDataTypes.CreativeSlotLock? = null, + @EncodeDefault(NEVER) @Contextual val intangibleProjectile: SerializableDataTypes.IntangibleProjectile? = null, + @EncodeDefault(NEVER) @Contextual val glider: SerializableDataTypes.Glider? = null, + // Third-party plugins @EncodeDefault(NEVER) val crucibleItem: String? = null, @EncodeDefault(NEVER) val oraxenItem: String? = null, @EncodeDefault(NEVER) val itemsadderItem: String? = null, ) { + private fun Component.removeItalics() = + Component.text().decoration(TextDecoration.ITALIC, false).build().append(this) - @Transient - val itemName = _itemName?.miniMsg() - @Transient - val customName = _customName?.miniMsg() - @Transient - val lore = _lore?.map { it.miniMsg() } + @Transient val itemName = _itemName?.miniMsg() + @Transient val customName = _customName?.miniMsg() + @Transient val lore = _lore?.map { it.miniMsg() } /** * Converts this serialized item's data to an [ItemStack], optionally applying the changes to an * [existing item][applyTo]. */ - fun toItemStack(applyTo: ItemStack = ItemStack(type ?: Material.AIR)): ItemStack { + fun toItemStack(applyTo: ItemStack = ItemStack.of(type ?: Material.AIR)): ItemStack { // Import ItemStack from Crucible crucibleItem?.let { id -> if (Plugins.isEnabled()) { @@ -104,15 +131,15 @@ data class BaseSerializableItemStack( } } - // Import ItemStack from Oraxen + // Import ItemStack from Nexo oraxenItem?.let { id -> - if (Plugins.isEnabled()) { - OraxenItems.getItemById(id)?.build()?.let { + if (Plugins.isEnabled()) { + NexoItems.itemFromId(id)?.build()?.let { applyTo.type = it.type applyTo.itemMeta = it.itemMeta - } ?: idofrontLogger.w("No Oraxen item found with id $id") + } ?: idofrontLogger.w("No Nexo item found with id $id") } else { - idofrontLogger.w("Tried to import Oraxen item, but Oraxen was not enabled") + idofrontLogger.w("Tried to import Nexo item, but Nexo was not enabled") } } @@ -129,53 +156,74 @@ data class BaseSerializableItemStack( } // Support for our prefab system in geary. - prefab?.let { encodePrefab.invoke(applyTo, it) } + prefab?.let { encodePrefab.invoke(applyTo, it) } ?: applyTo // Modify item - amount?.let(applyTo::setAmount) - type?.let(applyTo::setType) - - // Modify meta - applyTo.editMeta { meta -> - itemName?.let(meta::itemName) - customName?.let(meta::displayName) - customModelData?.let(meta::setCustomModelData) - lore?.let { - meta.lore(it.map { line -> - line.decorationIfAbsent(TextDecoration.ITALIC, TextDecoration.State.FALSE) - }) - } + amount?.let { applyTo.amount = it } + type?.let { applyTo.type = type } - unbreakable?.let(meta::setUnbreakable) - damage?.let { (meta as? Damageable)?.damage = damage } - durability?.let { (meta as? Damageable)?.setMaxDamage(it) } - itemFlags?.let { meta.addItemFlags(*itemFlags.toTypedArray()) } - color?.let { meta.asColorable()?.color = color } - basePotionType?.let { (meta as? PotionMeta)?.basePotionType = basePotionType } - customPotionEffects.forEach { (meta as? PotionMeta)?.addCustomEffect(it, true) } - enchantments?.forEach { meta.addEnchant(it.enchant, it.level, true) } - attributeModifiers?.forEach { meta.addAttributeModifier(it.attribute, it.modifier) } - - knowledgeBookRecipes?.let { - (meta as? KnowledgeBookMeta)?.recipes = knowledgeBookRecipes.map { it.getSubRecipeIDs() }.flatten() - } + SerializableDataTypes.setData(applyTo, DataComponentTypes.ITEM_NAME, itemName) + SerializableDataTypes.setData(applyTo, DataComponentTypes.CUSTOM_NAME, customName) + SerializableDataTypes.setData(applyTo, DataComponentTypes.LORE, lore?.let(ItemLore::lore)) + SerializableDataTypes.setData(applyTo, DataComponentTypes.ITEM_MODEL, itemModel) + SerializableDataTypes.setData(applyTo, DataComponentTypes.TOOLTIP_STYLE, tooltipStyle) - enchantmentGlintOverride?.let(meta::setEnchantmentGlintOverride) - food?.foodComponent?.let(meta::setFood) - tool?.let(meta::setTool) - jukeboxPlayable?.let(meta::setJukeboxPlayable) - maxStackSize?.let(meta::setMaxStackSize) - rarity?.let(meta::setRarity) - isFireResistant?.let(meta::setFireResistant) - hideTooltip?.let(meta::setHideTooltip) + enchantments?.setDataType(applyTo) + storedEnchantments?.setDataType(applyTo) + potionContents?.setDataType(applyTo) + attributeModifiers?.setDataType(applyTo) + customModelData?.setDataType(applyTo) + + SerializableDataTypes.setData(applyTo, DataComponentTypes.REPAIR_COST, repairCost) + SerializableDataTypes.setData(applyTo, DataComponentTypes.DAMAGE, damage) + SerializableDataTypes.setData(applyTo, DataComponentTypes.MAX_DAMAGE, maxDamage) + SerializableDataTypes.setData(applyTo, DataComponentTypes.MAX_STACK_SIZE, maxStackSize) + SerializableDataTypes.setData(applyTo, DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE, enchantmentGlintOverride) + SerializableDataTypes.setData(applyTo, DataComponentTypes.RECIPES, recipes) + + unbreakable?.setDataType(applyTo) + useCooldown?.setDataType(applyTo) + useRemainder?.setDataType(applyTo) + consumable?.setDataType(applyTo) + food?.setDataType(applyTo) + tool?.setDataType(applyTo) + enchantable?.setDataType(applyTo) + repairable?.setDataType(applyTo) + canPlaceOn?.setDataType(applyTo) + canBreak?.setDataType(applyTo) + equippable?.setDataType(applyTo) + trim?.setDataType(applyTo) + jukeboxPlayable?.setDataType(applyTo) + chargedProjectiles?.setDataType(applyTo) + bundleContents?.setDataType(applyTo) + writableBook?.setDataType(applyTo) + writtenBook?.setDataType(applyTo) + damageResistant?.setDataType(applyTo) + mapColor?.setDataType(applyTo) + mapId?.setDataType(applyTo) + + mapPostProcessing?.let { applyTo.setData(DataComponentTypes.MAP_POST_PROCESSING, it) } + mapDecorations?.let { + applyTo.setData( + DataComponentTypes.MAP_DECORATIONS, + MapDecorations.mapDecorations(SerializableDataTypes.MapDecoration.toPaperDecorations(mapDecorations)) + ) } - applyTo.hideAttributeTooltipWithItemFlagSet() + //SerializableDataTypes.setData(applyTo, DataComponentTypes.LOCK, LockCode) + SerializableDataTypes.setData(applyTo, DataComponentTypes.NOTE_BLOCK_SOUND, noteBlockSound) + potDecorations?.setDataType(applyTo) + + SerializableDataTypes.setData(applyTo, DataComponentTypes.HIDE_TOOLTIP, hideTooltip) + SerializableDataTypes.setData(applyTo, DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP, hideAdditionalTooltip) + SerializableDataTypes.setData(applyTo, DataComponentTypes.CREATIVE_SLOT_LOCK, creativeSlotLock) + SerializableDataTypes.setData(applyTo, DataComponentTypes.INTANGIBLE_PROJECTILE, intangibleProjectile) + return applyTo } fun toItemStackOrNull(applyTo: ItemStack = ItemStack(type ?: Material.AIR)) = - toItemStack(applyTo).takeIf { it.type != Material.AIR } + toItemStack().takeUnless { it.isEmpty } /** @return whether applying this [SerializableItemStack] to [item] would keep [item] identical. */ fun matches(item: ItemStack): Boolean { @@ -199,30 +247,60 @@ fun ItemStack.toSerializable(): SerializableItemStack = with(itemMeta) { SerializableItemStack( type = type, amount = amount.takeIf { it != 1 }, - customModelData = if (hasCustomModelData()) customModelData else null, - _itemName = if (hasItemName()) itemName().serialize() else null, - _customName = if (hasDisplayName()) displayName()!!.serialize() else null, - unbreakable = isUnbreakable.takeIf { it }, - _lore = if (this.hasLore()) this.lore()?.map { it.serialize() } else null, - damage = (this as? Damageable)?.takeIf { it.hasDamage() }?.damage, - durability = (this as? Damageable)?.takeIf { it.hasMaxDamage() }?.maxDamage, - enchantments = enchants.takeIf { it.isNotEmpty() }?.map { SerializableEnchantment(it.key, it.value) }, - knowledgeBookRecipes = ((this as? KnowledgeBookMeta)?.recipes?.map { it.getItemPrefabFromRecipe() }?.flatten() - ?: emptyList()).takeIf { it.isNotEmpty() }, - itemFlags = (this?.itemFlags?.toList() ?: listOf()).takeIf { it.isNotEmpty() }, - attributeModifiers = attributeList.takeIf { it.isNotEmpty() }, - basePotionType = (this as? PotionMeta)?.basePotionType, - color = (this as? PotionMeta)?.color ?: (this as? LeatherArmorMeta)?.color, - food = if (hasFood()) FoodComponentSurrogate(food) else null, - tool = if (hasTool()) tool else null, - jukeboxPlayable = if (hasJukeboxPlayable()) jukeboxPlayable else null, - enchantmentGlintOverride = if (hasEnchantmentGlintOverride()) enchantmentGlintOverride else null, - maxStackSize = if (hasMaxStackSize()) maxStackSize else null, - rarity = if (hasRarity()) rarity else null, - hideTooltip = isHideTooltip.takeIf { it }, - isFireResistant = isFireResistant.takeIf { it }, - - ) //TODO perhaps this should encode prefab too? + _itemName = getData(DataComponentTypes.ITEM_NAME)?.serialize(), + _customName = getData(DataComponentTypes.CUSTOM_NAME)?.serialize(), + _lore = getData(DataComponentTypes.LORE)?.lines()?.map { it.serialize() }, + + itemModel = getData(DataComponentTypes.ITEM_MODEL), + tooltipStyle = getData(DataComponentTypes.TOOLTIP_STYLE), + damage = getData(DataComponentTypes.DAMAGE), + maxDamage = getData(DataComponentTypes.MAX_DAMAGE), + maxStackSize = getData(DataComponentTypes.MAX_STACK_SIZE), + rarity = getData(DataComponentTypes.RARITY), + enchantmentGlintOverride = getData(DataComponentTypes.ENCHANTMENT_GLINT_OVERRIDE), + repairCost = getData(DataComponentTypes.REPAIR_COST), + recipes = getData(DataComponentTypes.RECIPES), + + customModelData = getData(DataComponentTypes.CUSTOM_MODEL_DATA)?.let(SerializableDataTypes::CustomModelData), + unbreakable = getData(DataComponentTypes.UNBREAKABLE)?.let(SerializableDataTypes::Unbreakable), + enchantments = getData(DataComponentTypes.ENCHANTMENTS)?.let(SerializableDataTypes::Enchantments), + storedEnchantments = getData(DataComponentTypes.STORED_ENCHANTMENTS)?.let(SerializableDataTypes::StoredEnchantments), + attributeModifiers = getData(DataComponentTypes.ATTRIBUTE_MODIFIERS)?.let(SerializableDataTypes::AttributeModifiers), + potionContents = getData(DataComponentTypes.POTION_CONTENTS)?.let(SerializableDataTypes::PotionContents), + dyedColor = getData(DataComponentTypes.DYED_COLOR)?.let(SerializableDataTypes::DyedColor), + useCooldown = getData(DataComponentTypes.USE_COOLDOWN)?.let(SerializableDataTypes::UseCooldown), + useRemainder = getData(DataComponentTypes.USE_REMAINDER)?.let(SerializableDataTypes::UseRemainder), + consumable = getData(DataComponentTypes.CONSUMABLE)?.let(SerializableDataTypes::Consumable), + food = getData(DataComponentTypes.FOOD)?.let(SerializableDataTypes::FoodProperties), + tool = getData(DataComponentTypes.TOOL)?.let(SerializableDataTypes::Tool), + enchantable = getData(DataComponentTypes.ENCHANTABLE)?.let(SerializableDataTypes::Enchantable), + repairable = getData(DataComponentTypes.REPAIRABLE)?.let(SerializableDataTypes::Repairable), + canPlaceOn = getData(DataComponentTypes.CAN_PLACE_ON)?.let(SerializableDataTypes::CanPlaceOn), + canBreak = getData(DataComponentTypes.CAN_BREAK)?.let(SerializableDataTypes::CanBreak), + equippable = getData(DataComponentTypes.EQUIPPABLE)?.let(SerializableDataTypes::Equippable), + trim = getData(DataComponentTypes.TRIM)?.let(SerializableDataTypes::Trim), + jukeboxPlayable = getData(DataComponentTypes.JUKEBOX_PLAYABLE)?.let(SerializableDataTypes::JukeboxPlayable), + chargedProjectiles = getData(DataComponentTypes.CHARGED_PROJECTILES)?.let(SerializableDataTypes::ChargedProjectiles), + bundleContents = getData(DataComponentTypes.BUNDLE_CONTENTS)?.let(SerializableDataTypes::BundleContent), + writableBook = getData(DataComponentTypes.WRITABLE_BOOK_CONTENT)?.let(SerializableDataTypes::WritableBook), + writtenBook = getData(DataComponentTypes.WRITTEN_BOOK_CONTENT)?.let(SerializableDataTypes::WrittenBook), + damageResistant = getData(DataComponentTypes.DAMAGE_RESISTANT)?.let(SerializableDataTypes::DamageResistant), + deathProtection = getData(DataComponentTypes.DEATH_PROTECTION)?.let(SerializableDataTypes::DeathProtection), + mapColor = getData(DataComponentTypes.MAP_COLOR)?.let(SerializableDataTypes::MapColor), + mapId = getData(DataComponentTypes.MAP_ID)?.let(SerializableDataTypes::MapId), + + mapPostProcessing = getData(DataComponentTypes.MAP_POST_PROCESSING), + mapDecorations = getData(DataComponentTypes.MAP_DECORATIONS)?.decorations()?.values?.map(SerializableDataTypes::MapDecoration), + + noteBlockSound = getData(DataComponentTypes.NOTE_BLOCK_SOUND), + potDecorations = getData(DataComponentTypes.POT_DECORATIONS)?.let(SerializableDataTypes::PotDecorations), + + hideTooltip = SerializableDataTypes.HideToolTip.takeIf { hasData(DataComponentTypes.HIDE_TOOLTIP) }, + hideAdditionalTooltip = SerializableDataTypes.HideAdditionalTooltip.takeIf { hasData(DataComponentTypes.HIDE_ADDITIONAL_TOOLTIP) }, + creativeSlotLock = SerializableDataTypes.CreativeSlotLock.takeIf { hasData(DataComponentTypes.CREATIVE_SLOT_LOCK) }, + intangibleProjectile = SerializableDataTypes.IntangibleProjectile.takeIf { hasData(DataComponentTypes.INTANGIBLE_PROJECTILE) }, + + ) } private fun String.getSubRecipeIDs(): MutableList {