package moe.nea.firmament.repo import kotlinx.serialization.KSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.serializer import net.minecraft.item.Item import net.minecraft.registry.RegistryKey import net.minecraft.registry.RegistryKeys import net.minecraft.util.Identifier import moe.nea.firmament.util.ReforgeId import moe.nea.firmament.util.SkyblockId import moe.nea.firmament.util.skyblock.ItemType import moe.nea.firmament.util.skyblock.Rarity @Serializable data class Reforge( val reforgeName: String, @SerialName("internalName") val reforgeStone: SkyblockId? = null, val nbtModifier: ReforgeId? = null, val requiredRarities: List? = null, val itemTypes: @Serializable(with = ReforgeEligibilityFilter.ItemTypesSerializer::class) List? = null, val allowOn: List? = null, val reforgeCosts: RarityMapped? = null, val reforgeAbility: RarityMapped? = null, val reforgeStats: RarityMapped>? = null, ) { val eligibleItems get() = allowOn ?: itemTypes ?: listOf() val statUniverse: Set = Rarity.entries.flatMapTo(mutableSetOf()) { reforgeStats?.get(it)?.keys ?: emptySet() } @Serializable(with = ReforgeEligibilityFilter.Serializer::class) sealed interface ReforgeEligibilityFilter { object ItemTypesSerializer : KSerializer> { override val descriptor: SerialDescriptor get() = JsonElement.serializer().descriptor override fun deserialize(decoder: Decoder): List { decoder as JsonDecoder val jsonElement = decoder.decodeJsonElement() if (jsonElement is JsonPrimitive && jsonElement.isString) { return jsonElement.content.split("/").map { AllowsItemType(ItemType.ofName(it)) } } if (jsonElement is JsonArray) { return decoder.json.decodeFromJsonElement(serializer>(), jsonElement) } jsonElement as JsonObject val filters = mutableListOf() jsonElement["internalName"]?.let { decoder.json.decodeFromJsonElement(serializer>(), it).forEach { filters.add(AllowsInternalName(it)) } } jsonElement["itemId"]?.let { decoder.json.decodeFromJsonElement(serializer>(), it).forEach { val ident = Identifier.tryParse(it) if (ident != null) filters.add(AllowsVanillaItemType(RegistryKey.of(RegistryKeys.ITEM, ident))) } } return filters } override fun serialize(encoder: Encoder, value: List) { TODO("Not yet implemented") } } object Serializer : KSerializer { override val descriptor: SerialDescriptor get() = serializer().descriptor override fun deserialize(decoder: Decoder): ReforgeEligibilityFilter { val jsonObject = serializer().deserialize(decoder) jsonObject["internalName"]?.let { return AllowsInternalName(SkyblockId((it as JsonPrimitive).content)) } jsonObject["itemType"]?.let { return AllowsItemType(ItemType.ofName((it as JsonPrimitive).content)) } jsonObject["minecraftId"]?.let { return AllowsVanillaItemType(RegistryKey.of(RegistryKeys.ITEM, Identifier.of((it as JsonPrimitive).content))) } error("Unknown item type") } override fun serialize(encoder: Encoder, value: ReforgeEligibilityFilter) { TODO("Not yet implemented") } } data class AllowsItemType(val itemType: ItemType) : ReforgeEligibilityFilter data class AllowsInternalName(val internalName: SkyblockId) : ReforgeEligibilityFilter data class AllowsVanillaItemType(val minecraftId: RegistryKey) : ReforgeEligibilityFilter } val reforgeId get() = nbtModifier ?: ReforgeId(reforgeName.lowercase()) @Serializable(with = RarityMapped.Serializer::class) sealed interface RarityMapped { fun get(rarity: Rarity?): T? class Serializer( val values: KSerializer ) : KSerializer> { override val descriptor: SerialDescriptor get() = JsonElement.serializer().descriptor val indirect = MapSerializer(Rarity.serializer(), values) override fun deserialize(decoder: Decoder): RarityMapped { decoder as JsonDecoder val element = decoder.decodeJsonElement() if (element is JsonObject) { return PerRarity(decoder.json.decodeFromJsonElement(indirect, element)) } else { return Direct(decoder.json.decodeFromJsonElement(values, element)) } } override fun serialize(encoder: Encoder, value: RarityMapped) { when (value) { is Direct -> values.serialize(encoder, value.value) is PerRarity -> indirect.serialize(encoder, value.values) } } } @Serializable data class Direct(val value: T) : RarityMapped { override fun get(rarity: Rarity?): T { return value } } @Serializable data class PerRarity(val values: Map) : RarityMapped { override fun get(rarity: Rarity?): T? { return values[rarity] } } } }