aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/repo/Reforge.kt
blob: dc0d93dbf03c442515a37b6fa1160136b7b87821 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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<Rarity>? = null,
	val itemTypes: @Serializable(with = ReforgeEligibilityFilter.ItemTypesSerializer::class) List<ReforgeEligibilityFilter>? = null,
	val allowOn: List<ReforgeEligibilityFilter>? = null,
	val reforgeCosts: RarityMapped<Double>? = null,
	val reforgeAbility: RarityMapped<String>? = null,
	val reforgeStats: RarityMapped<Map<String, Double>>? = null,
) {
	val eligibleItems get() = allowOn ?: itemTypes ?: listOf()

	val statUniverse: Set<String> = Rarity.entries.flatMapTo(mutableSetOf()) {
		reforgeStats?.get(it)?.keys ?: emptySet()
	}

	@Serializable(with = ReforgeEligibilityFilter.Serializer::class)
	sealed interface ReforgeEligibilityFilter {
		object ItemTypesSerializer : KSerializer<List<ReforgeEligibilityFilter>> {
			override val descriptor: SerialDescriptor
				get() = JsonElement.serializer().descriptor

			override fun deserialize(decoder: Decoder): List<ReforgeEligibilityFilter> {
				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<List<ReforgeEligibilityFilter>>(), jsonElement)
				}
				jsonElement as JsonObject
				val filters = mutableListOf<ReforgeEligibilityFilter>()
				jsonElement["internalName"]?.let {
					decoder.json.decodeFromJsonElement(serializer<List<SkyblockId>>(), it).forEach {
						filters.add(AllowsInternalName(it))
					}
				}
				jsonElement["itemId"]?.let {
					decoder.json.decodeFromJsonElement(serializer<List<String>>(), 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<ReforgeEligibilityFilter>) {
				TODO("Not yet implemented")
			}
		}

		object Serializer : KSerializer<ReforgeEligibilityFilter> {
			override val descriptor: SerialDescriptor
				get() = serializer<JsonElement>().descriptor

			override fun deserialize(decoder: Decoder): ReforgeEligibilityFilter {
				val jsonObject = serializer<JsonObject>().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<Item>) : ReforgeEligibilityFilter
	}


	val reforgeId get() = nbtModifier ?: ReforgeId(reforgeName.lowercase())

	@Serializable(with = RarityMapped.Serializer::class)
	sealed interface RarityMapped<T> {
		fun get(rarity: Rarity?): T?

		class Serializer<T>(
			val values: KSerializer<T>
		) : KSerializer<RarityMapped<T>> {
			override val descriptor: SerialDescriptor
				get() = JsonElement.serializer().descriptor

			val indirect = MapSerializer(Rarity.serializer(), values)
			override fun deserialize(decoder: Decoder): RarityMapped<T> {
				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<T>) {
				when (value) {
					is Direct<T> ->
						values.serialize(encoder, value.value)

					is PerRarity<T> ->
						indirect.serialize(encoder, value.values)
				}
			}
		}

		@Serializable
		data class Direct<T>(val value: T) : RarityMapped<T> {
			override fun get(rarity: Rarity?): T {
				return value
			}
		}

		@Serializable
		data class PerRarity<T>(val values: Map<Rarity, T>) : RarityMapped<T> {
			override fun get(rarity: Rarity?): T? {
				return values[rarity]
			}
		}
	}

}