From aa66334dba2c2c086b94eab1767abd4765e006f7 Mon Sep 17 00:00:00 2001 From: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Date: Tue, 4 Jun 2024 04:16:22 +1000 Subject: Fix: Config resetting on wrong value (#1979) Co-authored-by: Brady --- .../at/hannibal2/skyhanni/config/ConfigManager.kt | 134 ++------------------- .../skyhanni/config/ConfigUpdaterMigrator.kt | 5 +- .../java/at/hannibal2/skyhanni/data/MayorAPI.kt | 2 +- .../skyhanni/data/bazaar/HypixelBazaarFetcher.kt | 2 +- .../skyhanni/data/jsonobjects/local/HotmTree.kt | 2 +- .../java/at/hannibal2/skyhanni/data/model/Graph.kt | 7 +- .../skyhanni/events/NeuRepositoryReloadEvent.kt | 2 +- .../garden/farming/FarmingWeightDisplay.kt | 26 +--- .../features/inventory/bazaar/BazaarDataHolder.kt | 2 +- .../mining/eventtracker/MiningEventTracker.kt | 2 +- .../at/hannibal2/skyhanni/test/TestExportTools.kt | 6 +- .../utils/FeatureTogglesByDefaultAdapter.kt | 89 -------------- .../skyhanni/utils/ItemStackTypeAdapter.kt | 29 ----- .../java/at/hannibal2/skyhanni/utils/JsonUtils.kt | 37 ------ .../at/hannibal2/skyhanni/utils/NBTTypeAdapter.kt | 24 ---- .../java/at/hannibal2/skyhanni/utils/NEUItems.kt | 4 +- .../skyhanni/utils/json/BaseGsonBuilder.kt | 37 ++++++ .../utils/json/FeatureTogglesByDefaultAdapter.kt | 89 ++++++++++++++ .../skyhanni/utils/json/ItemStackTypeAdapter.kt | 29 +++++ .../at/hannibal2/skyhanni/utils/json/JsonUtils.kt | 37 ++++++ .../skyhanni/utils/json/NBTTypeAdapter.kt | 24 ++++ .../skyhanni/utils/json/SimpleStringTypeAdapter.kt | 29 +++++ .../utils/json/SkippingTypeAdapterFactory.kt | 32 +++++ .../skyhanni/utils/json/SkyHanniTypeAdapters.kt | 79 ++++++++++++ 24 files changed, 388 insertions(+), 341 deletions(-) delete mode 100644 src/main/java/at/hannibal2/skyhanni/utils/FeatureTogglesByDefaultAdapter.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/utils/ItemStackTypeAdapter.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/utils/NBTTypeAdapter.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/FeatureTogglesByDefaultAdapter.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/ItemStackTypeAdapter.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/JsonUtils.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/NBTTypeAdapter.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/SimpleStringTypeAdapter.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/json/SkyHanniTypeAdapters.kt (limited to 'src/main/java/at/hannibal2/skyhanni') diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt index 16b0fcfa3..fc654983c 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt @@ -2,42 +2,28 @@ package at.hannibal2.skyhanni.config import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.core.config.Position -import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.jsonobjects.local.FriendsJson import at.hannibal2.skyhanni.data.jsonobjects.local.JacobContestsJson import at.hannibal2.skyhanni.data.jsonobjects.local.KnownFeaturesJson import at.hannibal2.skyhanni.data.jsonobjects.local.VisualWordsJson import at.hannibal2.skyhanni.events.LorenzEvent -import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity import at.hannibal2.skyhanni.features.misc.update.UpdateManager import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.IdentityCharacteristics -import at.hannibal2.skyhanni.utils.KotlinTypeAdapterFactory import at.hannibal2.skyhanni.utils.LorenzLogger -import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzVec -import at.hannibal2.skyhanni.utils.NEUInternalName -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName -import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.SimpleTimeMark -import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.asTimeMark -import at.hannibal2.skyhanni.utils.tracker.SkyHanniTracker +import at.hannibal2.skyhanni.utils.json.BaseGsonBuilder import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.JsonObject -import com.google.gson.TypeAdapter import com.google.gson.TypeAdapterFactory -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter import io.github.notenoughupdates.moulconfig.annotations.ConfigLink -import io.github.notenoughupdates.moulconfig.observer.PropertyTypeAdapterFactory import io.github.notenoughupdates.moulconfig.processor.BuiltinMoulConfigGuis import io.github.notenoughupdates.moulconfig.processor.ConfigProcessorDriver import io.github.notenoughupdates.moulconfig.processor.MoulConfigProcessor -import net.minecraft.item.ItemStack import java.io.BufferedReader import java.io.BufferedWriter import java.io.File @@ -49,12 +35,9 @@ import java.io.OutputStreamWriter import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.StandardCopyOption -import java.util.UUID import kotlin.concurrent.fixedRateTimer -typealias TrackerDisplayMode = SkyHanniTracker.DefaultDisplayMode - -private fun GsonBuilder.reigsterIfBeta(create: TypeAdapterFactory): GsonBuilder { +private fun GsonBuilder.registerIfBeta(create: TypeAdapterFactory): GsonBuilder { return if (LorenzUtils.isBetaVersion()) { registerTypeAdapterFactory(create) } else this @@ -62,114 +45,12 @@ private fun GsonBuilder.reigsterIfBeta(create: TypeAdapterFactory): GsonBuilder class ConfigManager { companion object { - fun createBaseGsonBuilder(): GsonBuilder { - return GsonBuilder().setPrettyPrinting() - .excludeFieldsWithoutExposeAnnotation() - .serializeSpecialFloatingPointValues() - .registerTypeAdapterFactory(PropertyTypeAdapterFactory()) - .registerTypeAdapterFactory(KotlinTypeAdapterFactory()) - .registerTypeAdapter(UUID::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: UUID) { - out.value(value.toString()) - } - - override fun read(reader: JsonReader): UUID { - return UUID.fromString(reader.nextString()) - } - }.nullSafe()) - .registerTypeAdapter(LorenzVec::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: LorenzVec) { - value.run { out.value("$x:$y:$z") } - } - - override fun read(reader: JsonReader): LorenzVec { - return LorenzVec.decodeFromString(reader.nextString()) - } - }.nullSafe()) - .registerTypeAdapter(TrophyRarity::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: TrophyRarity) { - value.run { out.value(value.name) } - } - override fun read(reader: JsonReader): TrophyRarity { - val text = reader.nextString() - return TrophyRarity.getByName(text) ?: error("Could not parse TrophyRarity from '$text'") - } - }.nullSafe()) - .registerTypeAdapter(ItemStack::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: ItemStack) { - out.value(NEUItems.saveNBTData(value)) - } - - override fun read(reader: JsonReader): ItemStack { - return NEUItems.loadNBTData(reader.nextString()) - } - }.nullSafe()) - .registerTypeAdapter(NEUInternalName::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: NEUInternalName) { - out.value(value.asString()) - } - - override fun read(reader: JsonReader): NEUInternalName { - return reader.nextString().asInternalName() - } - }.nullSafe()) - .registerTypeAdapter(LorenzRarity::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: LorenzRarity) { - out.value(value.name) - } - - override fun read(reader: JsonReader): LorenzRarity { - return LorenzRarity.valueOf(reader.nextString().uppercase().replace(" ", "_")) - } - }.nullSafe()) - .registerTypeAdapter(IslandType::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: IslandType) { - out.value(value.name) - } - - override fun read(reader: JsonReader): IslandType { - return IslandType.valueOf(reader.nextString().uppercase()) - } - }.nullSafe()) - .registerTypeAdapter(TrackerDisplayMode::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: TrackerDisplayMode) { - out.value(value.name) - } - - override fun read(reader: JsonReader): TrackerDisplayMode { - return TrackerDisplayMode.valueOf(reader.nextString()) - } - }.nullSafe()) - .registerTypeAdapter(SimpleTimeMark::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: SimpleTimeMark) { - out.value(value.toMillis()) - } - - override fun read(reader: JsonReader): SimpleTimeMark { - return reader.nextString().toLong().asTimeMark() - } - }.nullSafe()) - .enableComplexMapKeySerialization() - } - - val gson: Gson = createBaseGsonBuilder() - // TODO reenable with toggle that is default disabled -// .reigsterIfBeta(FeatureTogglesByDefaultAdapter) + val gson: Gson = BaseGsonBuilder.gson() +// .registerIfBeta(FeatureTogglesByDefaultAdapter) .create() var configDirectory = File("config/skyhanni") - - inline fun GsonBuilder.registerTypeAdapter( - crossinline write: (JsonWriter, T) -> Unit, - crossinline read: (JsonReader) -> T, - ): GsonBuilder { - this.registerTypeAdapter(T::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: T) = write(out, value) - override fun read(reader: JsonReader) = read(reader) - }.nullSafe()) - return this - } } val features get() = jsonHolder[ConfigFileType.FEATURES] as Features @@ -281,13 +162,14 @@ class ConfigManager { try { val inputStreamReader = InputStreamReader(FileInputStream(file), StandardCharsets.UTF_8) val bufferedReader = BufferedReader(inputStreamReader) + val lenientGson = BaseGsonBuilder.lenientGson().create() logger.log("load-$fileName-now") output = if (fileType == ConfigFileType.FEATURES) { - val jsonObject = gson.fromJson(bufferedReader.readText(), JsonObject::class.java) + val jsonObject = lenientGson.fromJson(bufferedReader.readText(), JsonObject::class.java) val newJsonObject = ConfigUpdaterMigrator.fixConfig(jsonObject) - val run = { gson.fromJson(newJsonObject, defaultValue.javaClass) } + val run = { lenientGson.fromJson(newJsonObject, defaultValue.javaClass) } if (LorenzUtils.isInDevEnvironment()) { try { run() @@ -299,7 +181,7 @@ class ConfigManager { run() } } else { - gson.fromJson(bufferedReader.readText(), defaultValue.javaClass) + lenientGson.fromJson(bufferedReader.readText(), defaultValue.javaClass) } logger.log("Loaded $fileName from file") diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index 56118f4db..b7fd4838b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt @@ -4,7 +4,7 @@ import at.hannibal2.skyhanni.events.LorenzEvent import at.hannibal2.skyhanni.features.misc.limbo.LimboTimeTracker import at.hannibal2.skyhanni.utils.LorenzLogger import at.hannibal2.skyhanni.utils.LorenzUtils.asIntOrNull -import at.hannibal2.skyhanni.utils.shDeepCopy +import at.hannibal2.skyhanni.utils.json.shDeepCopy import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonPrimitive @@ -110,7 +110,8 @@ object ConfigUpdaterMigrator { fun fixConfig(config: JsonObject): JsonObject { val lastVersion = (config["lastVersion"] as? JsonPrimitive)?.asIntOrNull ?: -1 if (lastVersion > CONFIG_VERSION) { - error("Cannot downgrade config") + logger.log("Attempted to downgrade config version") + return config } if (lastVersion == CONFIG_VERSION) return config return (lastVersion until CONFIG_VERSION).fold(config) { accumulator, i -> diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt index 666713c70..584d2291f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt @@ -19,7 +19,7 @@ import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.asTimeMark import at.hannibal2.skyhanni.utils.SkyBlockTime -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.fromJson import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt index db39e98c5..6ed9b8e6a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt @@ -13,7 +13,7 @@ import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.NEUItems.getItemStackOrNull import at.hannibal2.skyhanni.utils.SimpleTimeMark -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.fromJson import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/local/HotmTree.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/local/HotmTree.kt index b9fba9ca0..3c0118089 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/local/HotmTree.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/local/HotmTree.kt @@ -1,6 +1,6 @@ package at.hannibal2.skyhanni.data.jsonobjects.local; -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.fromJson import com.google.gson.Gson import com.google.gson.annotations.Expose diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt index b6e6f7b8e..c25a567fb 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt @@ -1,8 +1,8 @@ package at.hannibal2.skyhanni.data.model -import at.hannibal2.skyhanni.config.ConfigManager.Companion.registerTypeAdapter import at.hannibal2.skyhanni.utils.LorenzVec -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.SkyHanniTypeAdapters.registerTypeAdapter +import at.hannibal2.skyhanni.utils.json.fromJson import com.google.gson.GsonBuilder import com.google.gson.JsonElement import com.google.gson.annotations.Expose @@ -36,8 +36,7 @@ value class Graph( override fun lastIndexOf(element: GraphNode) = graph.lastIndexOf(element) companion object { - val gson = GsonBuilder().setPrettyPrinting() - /* ConfigManager.createBaseGsonBuilder() */.registerTypeAdapter({ out, value -> + val gson = GsonBuilder().setPrettyPrinting().registerTypeAdapter({ out, value -> out.beginObject() value.forEach { out.name(it.id.toString()).beginObject() diff --git a/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt index bb741ae80..a02cb308f 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt @@ -3,7 +3,7 @@ package at.hannibal2.skyhanni.events import at.hannibal2.skyhanni.config.ConfigManager import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.NEUItems.manager -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.fromJson import com.google.gson.JsonObject import com.google.gson.JsonSyntaxException import java.io.File diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt index 3025ae7d1..6f8523c34 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt @@ -1,7 +1,6 @@ package at.hannibal2.skyhanni.features.garden.farming import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.config.ConfigManager import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.config.enums.OutsideSbFeature import at.hannibal2.skyhanni.data.HypixelData @@ -30,12 +29,11 @@ import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.StringUtils import at.hannibal2.skyhanni.utils.TimeUtils -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.BaseGsonBuilder +import at.hannibal2.skyhanni.utils.json.SkyHanniTypeAdapters +import at.hannibal2.skyhanni.utils.json.fromJson import at.hannibal2.skyhanni.utils.renderables.Renderable import com.google.gson.JsonObject -import com.google.gson.TypeAdapter -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter import kotlinx.coroutines.launch import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.time.Duration.Companion.minutes @@ -132,21 +130,9 @@ class FarmingWeightDisplay { } private val eliteWeightApiGson by lazy { - ConfigManager.createBaseGsonBuilder() - .registerTypeAdapter(CropType::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: CropType) {} - - override fun read(reader: JsonReader): CropType { - return CropType.getByName(reader.nextString()) - } - }.nullSafe()) - .registerTypeAdapter(PestType::class.java, object : TypeAdapter() { - override fun write(out: JsonWriter, value: PestType) {} - - override fun read(reader: JsonReader): PestType { - return PestType.getByName(reader.nextString()) - } - }.nullSafe()) + BaseGsonBuilder.gson() + .registerTypeAdapter(CropType::class.java, SkyHanniTypeAdapters.CROP_TYPE.nullSafe()) + .registerTypeAdapter(PestType::class.java, SkyHanniTypeAdapters.PEST_TYPE.nullSafe()) .create() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt index 8911e1e2b..3d7867ad9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt @@ -8,7 +8,7 @@ import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.APIUtil import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUItems -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.fromJson import kotlinx.coroutines.launch class BazaarDataHolder { diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt index 6fa28a83b..698335f27 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt @@ -19,7 +19,7 @@ import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.TimeUtils -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.fromJson import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.JsonPrimitive import kotlinx.coroutines.launch diff --git a/src/main/java/at/hannibal2/skyhanni/test/TestExportTools.kt b/src/main/java/at/hannibal2/skyhanni/test/TestExportTools.kt index 44a147c07..303c41bbe 100644 --- a/src/main/java/at/hannibal2/skyhanni/test/TestExportTools.kt +++ b/src/main/java/at/hannibal2/skyhanni/test/TestExportTools.kt @@ -5,13 +5,13 @@ import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.events.GuiKeyPressEvent import at.hannibal2.skyhanni.test.command.CopyItemCommand.copyItemToClipboard import at.hannibal2.skyhanni.utils.ChatUtils -import at.hannibal2.skyhanni.utils.ItemStackTypeAdapterFactory import at.hannibal2.skyhanni.utils.KSerializable import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld import at.hannibal2.skyhanni.utils.KotlinTypeAdapterFactory -import at.hannibal2.skyhanni.utils.NBTTypeAdapter import at.hannibal2.skyhanni.utils.OSUtils -import at.hannibal2.skyhanni.utils.fromJson +import at.hannibal2.skyhanni.utils.json.ItemStackTypeAdapterFactory +import at.hannibal2.skyhanni.utils.json.NBTTypeAdapter +import at.hannibal2.skyhanni.utils.json.fromJson import com.google.gson.GsonBuilder import com.google.gson.JsonElement import net.minecraft.item.ItemStack diff --git a/src/main/java/at/hannibal2/skyhanni/utils/FeatureTogglesByDefaultAdapter.kt b/src/main/java/at/hannibal2/skyhanni/utils/FeatureTogglesByDefaultAdapter.kt deleted file mode 100644 index f78a0c4dc..000000000 --- a/src/main/java/at/hannibal2/skyhanni/utils/FeatureTogglesByDefaultAdapter.kt +++ /dev/null @@ -1,89 +0,0 @@ -package at.hannibal2.skyhanni.utils - -import at.hannibal2.skyhanni.config.FeatureToggle -import at.hannibal2.skyhanni.utils.ReflectionUtils.getDeclaredFieldOrNull -import com.google.gson.Gson -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import com.google.gson.TypeAdapter -import com.google.gson.TypeAdapterFactory -import com.google.gson.internal.bind.JsonTreeReader -import com.google.gson.reflect.TypeToken -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonToken -import com.google.gson.stream.JsonWriter -import java.lang.reflect.Field -import java.lang.reflect.Type -import com.google.gson.internal.`$Gson$Types` as InternalGsonTypes - -object FeatureTogglesByDefaultAdapter : TypeAdapterFactory { - fun getType(typeToken: TypeToken, field: Field): Type { - return InternalGsonTypes.resolve(typeToken.type, typeToken.rawType, field.genericType) - } - - class Adapter( - val originalWrite: TypeAdapter, - val clazz: Class, - val gson: Gson, - val type: TypeToken, - ) : TypeAdapter() { - override fun write(out: JsonWriter, value: T) { - // Delegate the original config write, since that one is unchanged - originalWrite.write(out, value) - } - - override fun read(reader: JsonReader): T { - reader.beginObject() - // Create a default initialized instance - val obj = clazz.newInstance() - - // Overwrite the default with true (or false) for feature toggles - clazz.fields.forEach { - val featureToggle = it.getAnnotation(FeatureToggle::class.java) - val adapt = gson.getAdapter(TypeToken.get(getType(type, it))) - if (featureToggle != null) - it.set(obj, adapt.read(JsonTreeReader(JsonPrimitive(featureToggle.trueIsEnabled)))) - if (adapt is Adapter) { - it.set(obj, adapt.read(JsonTreeReader(JsonObject()))) - } - } - - // Read the actual JSON Object - while (reader.peek() != JsonToken.END_OBJECT) { - // IllegalStateException: Expected NAME but was BOOLEAN - if (reader.peek() != JsonToken.NAME) { - reader.skipValue() - continue - } - val name = reader.nextName() - val field = clazz.getDeclaredFieldOrNull(name) - if (field == null) { - println("field is in config file, but not in object file: $name") - continue - } - val fieldType = gson.getAdapter(TypeToken.get(getType(type, field))) - // Read the field data - val data = fieldType.read(reader) - // Set the field or override the feature toggle with the saved data, leaving only the unset feature toggles to deviate from their defaults - field.set(obj, data) - } - - reader.endObject() - return obj - } - } - - override fun create(gson: Gson?, type: TypeToken): TypeAdapter? { - gson!! - val t = type.rawType - - // Check if this object has any feature toggles present - if (t.fields.none { - it.isAnnotationPresent(FeatureToggle::class.java) || - gson.getAdapter(TypeToken.get(getType(type, it))) is Adapter - }) return null - - val originalWrite = gson.getDelegateAdapter(this, type) - return Adapter(originalWrite, t as Class, gson, type) - } -} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ItemStackTypeAdapter.kt b/src/main/java/at/hannibal2/skyhanni/utils/ItemStackTypeAdapter.kt deleted file mode 100644 index 602bffa2d..000000000 --- a/src/main/java/at/hannibal2/skyhanni/utils/ItemStackTypeAdapter.kt +++ /dev/null @@ -1,29 +0,0 @@ -package at.hannibal2.skyhanni.utils - -import com.google.gson.Gson -import com.google.gson.TypeAdapter -import com.google.gson.TypeAdapterFactory -import com.google.gson.reflect.TypeToken -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound - -object ItemStackTypeAdapterFactory : TypeAdapterFactory { - - override fun create(gson: Gson?, type: TypeToken): TypeAdapter? { - if (type.rawType == ItemStack::class.java) { - val nbtCompoundTypeAdapter = gson!!.getAdapter(NBTTagCompound::class.java) - return object : TypeAdapter() { - override fun write(out: JsonWriter, value: ItemStack) { - nbtCompoundTypeAdapter.write(out, value.serializeNBT()) - } - - override fun read(reader: JsonReader): ItemStack { - return ItemStack.loadItemStackFromNBT(nbtCompoundTypeAdapter.read(reader)) - } - } as TypeAdapter - } - return null - } -} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt deleted file mode 100644 index cc3dda044..000000000 --- a/src/main/java/at/hannibal2/skyhanni/utils/JsonUtils.kt +++ /dev/null @@ -1,37 +0,0 @@ -package at.hannibal2.skyhanni.utils - -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import java.io.Reader -import kotlin.reflect.jvm.javaType -import kotlin.reflect.typeOf - -inline fun Gson.fromJson(string: String): T = this.fromJson(string, typeOf().javaType) - -inline fun Gson.fromJson(jsonElement: JsonElement): T = - this.fromJson(jsonElement, typeOf().javaType) - -inline fun Gson.fromJson(reader: Reader): T = this.fromJson(reader, typeOf().javaType) - -/** - * Straight forward deep copy. This is included in gson as well, but different versions have it exposed privately instead of publicly, - * so this reimplementation is here as an always public alternative. - */ -fun JsonElement.shDeepCopy(): JsonElement { - return when (this) { - is JsonObject -> JsonObject().also { - for (entry in this.entrySet()) - it.add(entry.key, entry.value.shDeepCopy()) - } - - is JsonArray -> JsonArray().also { - for (entry in this) { - it.add(entry.shDeepCopy()) - } - } - - else -> this - } -} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/NBTTypeAdapter.kt b/src/main/java/at/hannibal2/skyhanni/utils/NBTTypeAdapter.kt deleted file mode 100644 index 4e0762895..000000000 --- a/src/main/java/at/hannibal2/skyhanni/utils/NBTTypeAdapter.kt +++ /dev/null @@ -1,24 +0,0 @@ -package at.hannibal2.skyhanni.utils - -import com.google.gson.TypeAdapter -import com.google.gson.stream.JsonReader -import com.google.gson.stream.JsonWriter -import net.minecraft.nbt.CompressedStreamTools -import net.minecraft.nbt.NBTTagCompound -import java.io.ByteArrayInputStream -import java.io.ByteArrayOutputStream -import java.util.Base64 - -object NBTTypeAdapter : TypeAdapter() { - - override fun write(out: JsonWriter, value: NBTTagCompound) { - val baos = ByteArrayOutputStream() - CompressedStreamTools.writeCompressed(value, baos) - out.value(Base64.getEncoder().encode(baos.toByteArray()).decodeToString()) - } - - override fun read(reader: JsonReader): NBTTagCompound { - val bais = ByteArrayInputStream(Base64.getDecoder().decode(reader.nextString())) - return CompressedStreamTools.readCompressed(bais) - } -} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt index b3d92e68f..297a40585 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt @@ -15,6 +15,8 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.isInt import at.hannibal2.skyhanni.utils.PrimitiveItemStack.Companion.makePrimitiveStack +import at.hannibal2.skyhanni.utils.json.BaseGsonBuilder +import at.hannibal2.skyhanni.utils.json.fromJson import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import com.google.gson.TypeAdapter @@ -51,7 +53,7 @@ object NEUItems { private val ingredientsCache = mutableMapOf>() private val hypixelApiGson by lazy { - ConfigManager.createBaseGsonBuilder() + BaseGsonBuilder.gson() .registerTypeAdapter(HypixelApiTrophyFish::class.java, object : TypeAdapter() { override fun write(out: JsonWriter, value: HypixelApiTrophyFish) {} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt new file mode 100644 index 000000000..d73edc0b0 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt @@ -0,0 +1,37 @@ +package at.hannibal2.skyhanni.utils.json + +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity +import at.hannibal2.skyhanni.utils.KotlinTypeAdapterFactory +import at.hannibal2.skyhanni.utils.LorenzRarity +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.tracker.SkyHanniTracker +import com.google.gson.GsonBuilder +import io.github.notenoughupdates.moulconfig.observer.PropertyTypeAdapterFactory +import net.minecraft.item.ItemStack +import java.util.UUID + +object BaseGsonBuilder { + fun gson(): GsonBuilder = GsonBuilder().setPrettyPrinting() + .excludeFieldsWithoutExposeAnnotation() + .serializeSpecialFloatingPointValues() + .registerTypeAdapterFactory(PropertyTypeAdapterFactory()) + .registerTypeAdapterFactory(KotlinTypeAdapterFactory()) + .registerTypeAdapter(UUID::class.java, SkyHanniTypeAdapters.UUID.nullSafe()) + .registerTypeAdapter(LorenzVec::class.java, SkyHanniTypeAdapters.VEC_STRING.nullSafe()) + .registerTypeAdapter(TrophyRarity::class.java, SkyHanniTypeAdapters.TROPHY_RARITY.nullSafe()) + .registerTypeAdapter(ItemStack::class.java, SkyHanniTypeAdapters.NEU_ITEMSTACK.nullSafe()) + .registerTypeAdapter(NEUInternalName::class.java, SkyHanniTypeAdapters.INTERNAL_NAME.nullSafe()) + .registerTypeAdapter(LorenzRarity::class.java, SkyHanniTypeAdapters.RARITY.nullSafe()) + .registerTypeAdapter(IslandType::class.java, SkyHanniTypeAdapters.ISLAND_TYPE.nullSafe()) + .registerTypeAdapter( + SkyHanniTracker.DefaultDisplayMode::class.java, + SkyHanniTypeAdapters.TRACKER_DISPLAY_MODE.nullSafe() + ) + .registerTypeAdapter(SimpleTimeMark::class.java, SkyHanniTypeAdapters.TIME_MARK.nullSafe()) + .enableComplexMapKeySerialization() + + fun lenientGson(): GsonBuilder = gson().registerTypeAdapterFactory(SkippingTypeAdapterFactory) +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/FeatureTogglesByDefaultAdapter.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/FeatureTogglesByDefaultAdapter.kt new file mode 100644 index 000000000..bcc9c2edf --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/FeatureTogglesByDefaultAdapter.kt @@ -0,0 +1,89 @@ +package at.hannibal2.skyhanni.utils.json + +import at.hannibal2.skyhanni.config.FeatureToggle +import at.hannibal2.skyhanni.utils.ReflectionUtils.getDeclaredFieldOrNull +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.internal.bind.JsonTreeReader +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonToken +import com.google.gson.stream.JsonWriter +import java.lang.reflect.Field +import java.lang.reflect.Type +import com.google.gson.internal.`$Gson$Types` as InternalGsonTypes + +object FeatureTogglesByDefaultAdapter : TypeAdapterFactory { + fun getType(typeToken: TypeToken, field: Field): Type { + return InternalGsonTypes.resolve(typeToken.type, typeToken.rawType, field.genericType) + } + + class Adapter( + val originalWrite: TypeAdapter, + val clazz: Class, + val gson: Gson, + val type: TypeToken, + ) : TypeAdapter() { + override fun write(out: JsonWriter, value: T) { + // Delegate the original config write, since that one is unchanged + originalWrite.write(out, value) + } + + override fun read(reader: JsonReader): T { + reader.beginObject() + // Create a default initialized instance + val obj = clazz.newInstance() + + // Overwrite the default with true (or false) for feature toggles + clazz.fields.forEach { + val featureToggle = it.getAnnotation(FeatureToggle::class.java) + val adapt = gson.getAdapter(TypeToken.get(getType(type, it))) + if (featureToggle != null) + it.set(obj, adapt.read(JsonTreeReader(JsonPrimitive(featureToggle.trueIsEnabled)))) + if (adapt is Adapter) { + it.set(obj, adapt.read(JsonTreeReader(JsonObject()))) + } + } + + // Read the actual JSON Object + while (reader.peek() != JsonToken.END_OBJECT) { + // IllegalStateException: Expected NAME but was BOOLEAN + if (reader.peek() != JsonToken.NAME) { + reader.skipValue() + continue + } + val name = reader.nextName() + val field = clazz.getDeclaredFieldOrNull(name) + if (field == null) { + println("field is in config file, but not in object file: $name") + continue + } + val fieldType = gson.getAdapter(TypeToken.get(getType(type, field))) + // Read the field data + val data = fieldType.read(reader) + // Set the field or override the feature toggle with the saved data, leaving only the unset feature toggles to deviate from their defaults + field.set(obj, data) + } + + reader.endObject() + return obj + } + } + + override fun create(gson: Gson?, type: TypeToken): TypeAdapter? { + gson!! + val t = type.rawType + + // Check if this object has any feature toggles present + if (t.fields.none { + it.isAnnotationPresent(FeatureToggle::class.java) || + gson.getAdapter(TypeToken.get(getType(type, it))) is Adapter + }) return null + + val originalWrite = gson.getDelegateAdapter(this, type) + return Adapter(originalWrite, t as Class, gson, type) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/ItemStackTypeAdapter.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/ItemStackTypeAdapter.kt new file mode 100644 index 000000000..1940b03c0 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/ItemStackTypeAdapter.kt @@ -0,0 +1,29 @@ +package at.hannibal2.skyhanni.utils.json + +import com.google.gson.Gson +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound + +object ItemStackTypeAdapterFactory : TypeAdapterFactory { + + override fun create(gson: Gson?, type: TypeToken): TypeAdapter? { + if (type.rawType == ItemStack::class.java) { + val nbtCompoundTypeAdapter = gson!!.getAdapter(NBTTagCompound::class.java) + return object : TypeAdapter() { + override fun write(out: JsonWriter, value: ItemStack) { + nbtCompoundTypeAdapter.write(out, value.serializeNBT()) + } + + override fun read(reader: JsonReader): ItemStack { + return ItemStack.loadItemStackFromNBT(nbtCompoundTypeAdapter.read(reader)) + } + } as TypeAdapter + } + return null + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/JsonUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/JsonUtils.kt new file mode 100644 index 000000000..750bd96aa --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/JsonUtils.kt @@ -0,0 +1,37 @@ +package at.hannibal2.skyhanni.utils.json + +import com.google.gson.Gson +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import java.io.Reader +import kotlin.reflect.jvm.javaType +import kotlin.reflect.typeOf + +inline fun Gson.fromJson(string: String): T = this.fromJson(string, typeOf().javaType) + +inline fun Gson.fromJson(jsonElement: JsonElement): T = + this.fromJson(jsonElement, typeOf().javaType) + +inline fun Gson.fromJson(reader: Reader): T = this.fromJson(reader, typeOf().javaType) + +/** + * Straight forward deep copy. This is included in gson as well, but different versions have it exposed privately instead of publicly, + * so this reimplementation is here as an always public alternative. + */ +fun JsonElement.shDeepCopy(): JsonElement { + return when (this) { + is JsonObject -> JsonObject().also { + for (entry in this.entrySet()) + it.add(entry.key, entry.value.shDeepCopy()) + } + + is JsonArray -> JsonArray().also { + for (entry in this) { + it.add(entry.shDeepCopy()) + } + } + + else -> this + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/NBTTypeAdapter.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/NBTTypeAdapter.kt new file mode 100644 index 000000000..e2e782636 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/NBTTypeAdapter.kt @@ -0,0 +1,24 @@ +package at.hannibal2.skyhanni.utils.json + +import com.google.gson.TypeAdapter +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import net.minecraft.nbt.CompressedStreamTools +import net.minecraft.nbt.NBTTagCompound +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.util.Base64 + +object NBTTypeAdapter : TypeAdapter() { + + override fun write(out: JsonWriter, value: NBTTagCompound) { + val baos = ByteArrayOutputStream() + CompressedStreamTools.writeCompressed(value, baos) + out.value(Base64.getEncoder().encode(baos.toByteArray()).decodeToString()) + } + + override fun read(reader: JsonReader): NBTTagCompound { + val bais = ByteArrayInputStream(Base64.getDecoder().decode(reader.nextString())) + return CompressedStreamTools.readCompressed(bais) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/SimpleStringTypeAdapter.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/SimpleStringTypeAdapter.kt new file mode 100644 index 000000000..21f601932 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/SimpleStringTypeAdapter.kt @@ -0,0 +1,29 @@ +package at.hannibal2.skyhanni.utils.json + +import com.google.gson.TypeAdapter +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter + +class SimpleStringTypeAdapter( + val serializer: T.() -> String, + val deserializer: String.() -> T +) : TypeAdapter() { + + override fun write(writer: JsonWriter, value: T) { + writer.value(serializer(value)) + } + + override fun read(reader: JsonReader): T { + return deserializer(reader.nextString()) + } + + companion object { + + inline fun > forEnum(): SimpleStringTypeAdapter { + return SimpleStringTypeAdapter( + { name }, + { enumValueOf(this.replace(" ", "_").uppercase()) } + ) + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt new file mode 100644 index 000000000..a926976ca --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt @@ -0,0 +1,32 @@ +package at.hannibal2.skyhanni.utils.json + +import at.hannibal2.skyhanni.SkyHanniMod +import com.google.gson.Gson +import com.google.gson.TypeAdapter +import com.google.gson.TypeAdapterFactory +import com.google.gson.reflect.TypeToken +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter + +object SkippingTypeAdapterFactory : TypeAdapterFactory { + + override fun create(gson: Gson, type: TypeToken): TypeAdapter { + return SafeTypeAdapter(gson.getDelegateAdapter(this, type)) + } + + private class SafeTypeAdapter(val parent: TypeAdapter) : TypeAdapter() { + override fun write(writer: JsonWriter, value: T) { + parent.write(writer, value) + } + + override fun read(reader: JsonReader): T? { + return try { + parent.read(reader) + } catch (e: Exception) { + SkyHanniMod.logger.warn("Failed to read value from JSON, skipping", e) + reader.skipValue() + null + } + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/SkyHanniTypeAdapters.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/SkyHanniTypeAdapters.kt new file mode 100644 index 000000000..dc50eef74 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/json/SkyHanniTypeAdapters.kt @@ -0,0 +1,79 @@ +package at.hannibal2.skyhanni.utils.json + +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity +import at.hannibal2.skyhanni.features.garden.CropType +import at.hannibal2.skyhanni.features.garden.pests.PestType +import at.hannibal2.skyhanni.utils.LorenzRarity +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.asTimeMark +import at.hannibal2.skyhanni.utils.tracker.SkyHanniTracker +import com.google.gson.GsonBuilder +import com.google.gson.TypeAdapter +import com.google.gson.stream.JsonReader +import com.google.gson.stream.JsonWriter +import net.minecraft.item.ItemStack +import java.util.UUID + +object SkyHanniTypeAdapters { + val NEU_ITEMSTACK: TypeAdapter = SimpleStringTypeAdapter(NEUItems::saveNBTData, NEUItems::loadNBTData) + + val UUID: TypeAdapter = SimpleStringTypeAdapter( + { this.toString() }, + { java.util.UUID.fromString(this) } + ) + + val INTERNAL_NAME: TypeAdapter = SimpleStringTypeAdapter( + { this.asString() }, + { this.asInternalName() } + ) + + val VEC_STRING: TypeAdapter = SimpleStringTypeAdapter( + { "$x:$y:$z" }, + { LorenzVec.decodeFromString(this) } + ) + + val TROPHY_RARITY: TypeAdapter = SimpleStringTypeAdapter( + { name }, + { TrophyRarity.getByName(this) ?: error("Could not parse TrophyRarity from '$this'") } + ) + + val TIME_MARK: TypeAdapter = object : TypeAdapter() { + override fun write(out: JsonWriter, value: SimpleTimeMark) { + out.value(value.toMillis()) + } + + override fun read(reader: JsonReader): SimpleTimeMark { + return reader.nextString().toLong().asTimeMark() + } + } + + val CROP_TYPE: TypeAdapter = SimpleStringTypeAdapter( + { name }, + { CropType.getByName(this) } + ) + + val PEST_TYPE: TypeAdapter = SimpleStringTypeAdapter( + { name }, + { PestType.getByName(this) } + ) + + val TRACKER_DISPLAY_MODE = SimpleStringTypeAdapter.forEnum() + val ISLAND_TYPE = SimpleStringTypeAdapter.forEnum() + val RARITY = SimpleStringTypeAdapter.forEnum() + + inline fun GsonBuilder.registerTypeAdapter( + crossinline write: (JsonWriter, T) -> Unit, + crossinline read: (JsonReader) -> T, + ): GsonBuilder { + this.registerTypeAdapter(T::class.java, object : TypeAdapter() { + override fun write(out: JsonWriter, value: T) = write(out, value) + override fun read(reader: JsonReader) = read(reader) + }.nullSafe()) + return this + } +} -- cgit