From c68b9317ba9d6c97f12fa3eb29e405c8d26972df Mon Sep 17 00:00:00 2001 From: Aaron <51387595+AzureAaron@users.noreply.github.com> Date: Sun, 11 Aug 2024 17:57:23 -0400 Subject: Fix a lot of config crashes because of null values (#902) * Fix a lot of config crashes because of null values * Implement suggestion --- .../java/de/hysky/skyblocker/SkyblockerMod.java | 3 ++ .../skyblocker/config/ConfigNullFieldsFix.java | 63 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/main/java/de/hysky/skyblocker/config/ConfigNullFieldsFix.java (limited to 'src/main/java') diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 4e110e15..7ede3c63 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -2,6 +2,8 @@ package de.hysky.skyblocker; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + +import de.hysky.skyblocker.config.ConfigNullFieldsFix; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.datafixer.ConfigDataFixer; import de.hysky.skyblocker.debug.Debug; @@ -109,6 +111,7 @@ public class SkyblockerMod implements ClientModInitializer { ConfigDataFixer.apply(); Utils.init(); SkyblockerConfigManager.init(); + ConfigNullFieldsFix.init(); //DO NOT INIT ANY CLASS THAT USES CONFIG FIELDS BEFORE THIS! SkyblockerScreen.initClass(); ProfileViewerScreen.initClass(); Tips.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/ConfigNullFieldsFix.java b/src/main/java/de/hysky/skyblocker/config/ConfigNullFieldsFix.java new file mode 100644 index 00000000..a16b3359 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/config/ConfigNullFieldsFix.java @@ -0,0 +1,63 @@ +package de.hysky.skyblocker.config; + +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.Map; + +import org.slf4j.Logger; + +import com.mojang.logging.LogUtils; + +import dev.isxander.yacl3.config.v2.api.SerialEntry; + +/** + * While this sounds like a data fixer it isn't. - It's the only reasonable solution to deal with the mine field + * that is YACL's null handling. + */ +public class ConfigNullFieldsFix { + private static final Logger LOGGER = LogUtils.getLogger(); + private static final String CONFIGS_PACKAGE = "de.hysky.skyblocker.config.configs"; + + public static void init() { + SkyblockerConfig current = SkyblockerConfigManager.get(); + SkyblockerConfig clean = new SkyblockerConfig(); + + try { + fixNullFields(current, clean); + SkyblockerConfigManager.save(); + } catch (Exception e) { + LOGGER.error("[Skyblocker Config Null Fields Fixer] Failed to ensure that the config has no null fields! You may encounter crashes :(", e); + } + } + + /** + * Traverse through every config field to ensure that is isn't null, if it is then reset the value. + */ + private static void fixNullFields(Object target, Object source) throws Exception { + for (Field field : target.getClass().getDeclaredFields()) { + if (field.isAnnotationPresent(SerialEntry.class)) { + field.setAccessible(true); + + Object targetValue = field.get(target); + Object sourceValue = field.get(source); + + if (targetValue == null && sourceValue != null) { + field.set(target, sourceValue); + } else if (targetValue != null && sourceValue != null && isFixable(field.getType())) { + fixNullFields(targetValue, sourceValue); + } + } + } + } + + private static boolean isFixable(Class clazz) { + return !clazz.isPrimitive() + && !clazz.isEnum() + && !clazz.isRecord() + && !clazz.equals(String.class) + && !Number.class.isAssignableFrom(clazz) + && !Map.class.isAssignableFrom(clazz) + && !Collection.class.isAssignableFrom(clazz) + && clazz.getPackageName().startsWith(CONFIGS_PACKAGE); + } +} -- cgit