aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCalMWolfs <94038482+CalMWolfs@users.noreply.github.com>2024-06-05 22:06:54 +1000
committerGitHub <noreply@github.com>2024-06-05 14:06:54 +0200
commite61f260fa2a094a43ebe1ab3d3305874dee6b716 (patch)
treeb94d2f328d07a6adecfcd9bdc011cc3b7168a3c4
parenta5687208788bf54491e1341dbd5b2e99ee408221 (diff)
downloadskyhanni-e61f260fa2a094a43ebe1ab3d3305874dee6b716.tar.gz
skyhanni-e61f260fa2a094a43ebe1ab3d3305874dee6b716.tar.bz2
skyhanni-e61f260fa2a094a43ebe1ab3d3305874dee6b716.zip
Fix: Config reset on unknown enum values (#1990)
-rw-r--r--src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt1
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt4
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/json/EnumSkippingTypeAdapterFactory.kt53
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt6
4 files changed, 63 insertions, 1 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt
index b7fd4838b..4f5f0aa50 100644
--- a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt
+++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt
@@ -111,6 +111,7 @@ object ConfigUpdaterMigrator {
val lastVersion = (config["lastVersion"] as? JsonPrimitive)?.asIntOrNull ?: -1
if (lastVersion > CONFIG_VERSION) {
logger.log("Attempted to downgrade config version")
+ config.add("lastVersion", JsonPrimitive(CONFIG_VERSION))
return config
}
if (lastVersion == CONFIG_VERSION) return config
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt
index d73edc0b0..bc9f706f8 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/json/BaseGsonBuilder.kt
@@ -33,5 +33,7 @@ object BaseGsonBuilder {
.registerTypeAdapter(SimpleTimeMark::class.java, SkyHanniTypeAdapters.TIME_MARK.nullSafe())
.enableComplexMapKeySerialization()
- fun lenientGson(): GsonBuilder = gson().registerTypeAdapterFactory(SkippingTypeAdapterFactory)
+ fun lenientGson(): GsonBuilder = gson()
+ .registerTypeAdapterFactory(SkippingTypeAdapterFactory)
+ .registerTypeAdapterFactory(ListEnumSkippingTypeAdapterFactory)
}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/EnumSkippingTypeAdapterFactory.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/EnumSkippingTypeAdapterFactory.kt
new file mode 100644
index 000000000..c17462472
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/json/EnumSkippingTypeAdapterFactory.kt
@@ -0,0 +1,53 @@
+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.JsonToken
+import com.google.gson.stream.JsonWriter
+import java.lang.reflect.ParameterizedType
+
+object ListEnumSkippingTypeAdapterFactory : TypeAdapterFactory {
+ override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
+ val rawType = type.rawType
+ if (rawType == List::class.java) {
+ val actualType = (type.type as ParameterizedType).actualTypeArguments[0]
+ if (actualType is Class<*> && actualType.isEnum) {
+ @Suppress("UNCHECKED_CAST")
+ return ListEnumSkippingTypeAdapter(actualType as Class<out Enum<*>>) as TypeAdapter<T>
+ }
+ }
+ return null
+ }
+}
+
+/*
+ Instead of saving null to the config when the enum value is unknown we instead skip the value.
+ We also skip the value if it is null inside a list of enums. This ensures we don't crash later,
+ either in moulconfig or outside of it, as we assume lists of enums don't contain null values.
+ */
+class ListEnumSkippingTypeAdapter<T : Enum<T>>(private val enumClass: Class<T>) : TypeAdapter<List<T>>() {
+ override fun write(out: JsonWriter, value: List<T>?) {
+ value ?: return
+ out.beginArray()
+ value.forEach { out.value(it.name) }
+ out.endArray()
+ }
+
+ override fun read(reader: JsonReader): List<T> {
+ val list = mutableListOf<T>()
+ reader.beginArray()
+ while (reader.hasNext()) {
+ if (reader.peek() == JsonToken.NULL) {
+ reader.skipValue()
+ continue
+ }
+ val name = reader.nextString()
+ enumClass.enumConstants.firstOrNull { it.name == name }?.let { list.add(it) }
+ }
+ reader.endArray()
+ return list
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt b/src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt
index 3a2505495..d99650f0c 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/json/SkippingTypeAdapterFactory.kt
@@ -8,6 +8,12 @@ import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
+/*
+ Instead of crashing on a wrong value in the config we set the value to null and log a warning.
+ This prevents user's config from resetting to default values.
+ Which is especially important for when people downgrade their mod version, either on purpose or by accident.
+ This does not always work, and can cause a crash later on, but the full config reset is avoided.
+ */
object SkippingTypeAdapterFactory : TypeAdapterFactory {
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {