From 863893933929c75bb2fc5d3785d1f30e04e90a76 Mon Sep 17 00:00:00 2001 From: BlayTheNinth <1933180+BlayTheNinth@users.noreply.github.com> Date: Fri, 29 Dec 2023 20:24:37 +0100 Subject: [PATCH] fix: Fix configs still failing to load on Forge and NeoForge --- CHANGELOG.md | 1 + .../balm/forge/config/ForgeBalmConfig.java | 47 +++++++++++-------- .../neoforge/config/NeoForgeBalmConfig.java | 46 +++++++++++------- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 466fe16a..7f21bfad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,3 @@ +- Fixed startup failure due to broken config loading in Forge and NeoForge again - Fixed startup failure due to broken config loading in Forge and NeoForge - Fixed config saving of ResourceLocation and Set types on Fabric \ No newline at end of file diff --git a/forge/src/main/java/net/blay09/mods/balm/forge/config/ForgeBalmConfig.java b/forge/src/main/java/net/blay09/mods/balm/forge/config/ForgeBalmConfig.java index 7b6fa041..c01fff66 100644 --- a/forge/src/main/java/net/blay09/mods/balm/forge/config/ForgeBalmConfig.java +++ b/forge/src/main/java/net/blay09/mods/balm/forge/config/ForgeBalmConfig.java @@ -20,11 +20,14 @@ import net.minecraftforge.server.ServerLifecycleHooks; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.NotNull; import java.io.File; import java.lang.reflect.Field; import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collectors; public class ForgeBalmConfig extends AbstractBalmConfig { @@ -59,26 +62,23 @@ private void buildConfigSpec(String parentPath, ForgeConfigSpec.Builder builder, builder.define(path, (String) defaultValue); } else if (ResourceLocation.class.isAssignableFrom(type)) { builder.define(path, ((ResourceLocation) defaultValue).toString()); - } else if (List.class.isAssignableFrom(type)) { + } else if (Collection.class.isAssignableFrom(type)) { ExpectedType expectedType = field.getAnnotation(ExpectedType.class); if (expectedType == null) { logger.warn("Config field without expected type, will not validate list content ({} in {})", field.getName(), clazz.getName()); } - builder.defineListAllowEmpty(Arrays.asList(path.split("\\.")), - () -> ((List) defaultValue), - it -> expectedType == null || expectedType.value().isAssignableFrom(it.getClass()) || (expectedType.value().isEnum() && Arrays.stream( - expectedType.value().getEnumConstants()).anyMatch(constant -> constant.toString().equals(it)))); - } else if (Set.class.isAssignableFrom(type)) { - ExpectedType expectedType = field.getAnnotation(ExpectedType.class); - if (expectedType == null) { - logger.warn("Config field without expected type, will not validate list content ({} in {})", field.getName(), clazz.getName()); + Supplier> defaultSupplier = () -> new ArrayList<>((Collection) defaultValue); + Predicate validator = (Object it) -> expectedType == null || expectedType.value() + .isAssignableFrom(it.getClass()) || (expectedType.value() + .isEnum() && Arrays.stream( + expectedType.value().getEnumConstants()).anyMatch(constant -> constant.toString().equals(it))); + if (expectedType != null && ResourceLocation.class.isAssignableFrom(expectedType.value())) { + defaultSupplier = () -> ((Collection) defaultValue).stream().map(it -> ((ResourceLocation) it).toString()).collect(Collectors.toList()); + validator = (Object it) -> it instanceof String stringValue && ResourceLocation.tryParse(stringValue) != null; } - builder.defineListAllowEmpty(Arrays.asList(path.split("\\.")), - () -> (((Set) defaultValue).stream().toList()), - it -> expectedType == null || expectedType.value().isAssignableFrom(it.getClass()) || (expectedType.value().isEnum() && Arrays.stream( - expectedType.value().getEnumConstants()).anyMatch(constant -> constant.toString().equals(it)))); + builder.defineListAllowEmpty(List.of(path.split("\\.")), defaultSupplier, validator); } else if (Enum.class.isAssignableFrom(type)) { builder.defineEnum(path, (Enum) defaultValue); } else if (int.class.isAssignableFrom(type)) { @@ -136,14 +136,21 @@ private void readConfigValues(String parentPath, T instance, ModConfig confi } else { logger.error("Invalid config value for " + path + ", expected " + type.getName() + " but got " + value.getClass()); } + } else if (hasValue && ResourceLocation.class.isAssignableFrom(type)) { + field.set(instance, new ResourceLocation(config.getConfigData().get(path))); } else if (hasValue && (Collection.class.isAssignableFrom(type))) { Object raw = config.getConfigData().getRaw(path); if (raw instanceof List list) { + ExpectedType expectedType = field.getAnnotation(ExpectedType.class); + Function mapper = (it) -> it; + if (expectedType != null && ResourceLocation.class.isAssignableFrom(expectedType.value())) { + mapper = (it) -> new ResourceLocation((String) it); + } try { if (List.class.isAssignableFrom(type)) { - field.set(instance, list); + field.set(instance, list.stream().map(mapper).collect(Collectors.toList())); } else if (Set.class.isAssignableFrom(type)) { - field.set(instance, new HashSet<>(list)); + field.set(instance, list.stream().map(mapper).collect(Collectors.toSet())); } } catch (IllegalArgumentException e) { logger.error("Invalid config value for " + path + ", expected " + type.getName() + " but got " + raw.getClass()); @@ -188,10 +195,12 @@ private void writeConfigValues(String parentPath, ModConfig config, T instan String path = parentPath + field.getName(); Class type = field.getType(); Object value = field.get(instance); - if (type.isPrimitive() || Enum.class.isAssignableFrom(type) || String.class.isAssignableFrom(type) || List.class.isAssignableFrom(type)) { + if (type.isPrimitive() || Enum.class.isAssignableFrom(type) || String.class.isAssignableFrom(type)) { config.getConfigData().set(path, value); - } else if(Set.class.isAssignableFrom(type)) { - config.getConfigData().set(path, new ArrayList<>((Set) value)); + } else if (ResourceLocation.class.isAssignableFrom(type)) { + config.getConfigData().set(path, ((ResourceLocation) value).toString()); + } else if (Collection.class.isAssignableFrom(type)) { + config.getConfigData().set(path, new ArrayList<>((Collection) value)); } else { writeConfigValues(path + ".", config, field.get(instance)); } diff --git a/neoforge/src/main/java/net/blay09/mods/balm/neoforge/config/NeoForgeBalmConfig.java b/neoforge/src/main/java/net/blay09/mods/balm/neoforge/config/NeoForgeBalmConfig.java index 433f2c8c..9d582d89 100644 --- a/neoforge/src/main/java/net/blay09/mods/balm/neoforge/config/NeoForgeBalmConfig.java +++ b/neoforge/src/main/java/net/blay09/mods/balm/neoforge/config/NeoForgeBalmConfig.java @@ -22,6 +22,10 @@ import java.io.File; import java.lang.reflect.Field; import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collectors; public class NeoForgeBalmConfig extends AbstractBalmConfig { @@ -56,26 +60,23 @@ private void buildConfigSpec(String parentPath, ModConfigSpec.Builder builder, C builder.define(path, (String) defaultValue); } else if (ResourceLocation.class.isAssignableFrom(type)) { builder.define(path, ((ResourceLocation) defaultValue).toString()); - } else if (List.class.isAssignableFrom(type)) { + } else if (Collection.class.isAssignableFrom(type)) { ExpectedType expectedType = field.getAnnotation(ExpectedType.class); if (expectedType == null) { logger.warn("Config field without expected type, will not validate list content ({} in {})", field.getName(), clazz.getName()); } - builder.defineListAllowEmpty(Arrays.asList(path.split("\\.")), - () -> ((List) defaultValue), - it -> expectedType == null || expectedType.value().isAssignableFrom(it.getClass()) || (expectedType.value().isEnum() && Arrays.stream( - expectedType.value().getEnumConstants()).anyMatch(constant -> constant.toString().equals(it)))); - } else if (Set.class.isAssignableFrom(type)) { - ExpectedType expectedType = field.getAnnotation(ExpectedType.class); - if (expectedType == null) { - logger.warn("Config field without expected type, will not validate list content ({} in {})", field.getName(), clazz.getName()); + Supplier> defaultSupplier = () -> new ArrayList<>((Collection) defaultValue); + Predicate validator = (Object it) -> expectedType == null || expectedType.value() + .isAssignableFrom(it.getClass()) || (expectedType.value() + .isEnum() && Arrays.stream( + expectedType.value().getEnumConstants()).anyMatch(constant -> constant.toString().equals(it))); + if (expectedType != null && ResourceLocation.class.isAssignableFrom(expectedType.value())) { + defaultSupplier = () -> ((Collection) defaultValue).stream().map(it -> ((ResourceLocation) it).toString()).collect(Collectors.toList()); + validator = (Object it) -> it instanceof String stringValue && ResourceLocation.tryParse(stringValue) != null; } - builder.defineListAllowEmpty(Arrays.asList(path.split("\\.")), - () -> (((Set) defaultValue).stream().toList()), - it -> expectedType == null || expectedType.value().isAssignableFrom(it.getClass()) || (expectedType.value().isEnum() && Arrays.stream( - expectedType.value().getEnumConstants()).anyMatch(constant -> constant.toString().equals(it)))); + builder.defineListAllowEmpty(List.of(path.split("\\.")), defaultSupplier, validator); } else if (Enum.class.isAssignableFrom(type)) { builder.defineEnum(path, (Enum) defaultValue); } else if (int.class.isAssignableFrom(type)) { @@ -133,14 +134,21 @@ private void readConfigValues(String parentPath, T instance, ModConfig confi } else { logger.error("Invalid config value for " + path + ", expected " + type.getName() + " but got " + value.getClass()); } + } else if (hasValue && ResourceLocation.class.isAssignableFrom(type)) { + field.set(instance, new ResourceLocation(config.getConfigData().get(path))); } else if (hasValue && (Collection.class.isAssignableFrom(type))) { Object raw = config.getConfigData().getRaw(path); if (raw instanceof List list) { + ExpectedType expectedType = field.getAnnotation(ExpectedType.class); + Function mapper = (it) -> it; + if (expectedType != null && ResourceLocation.class.isAssignableFrom(expectedType.value())) { + mapper = (it) -> new ResourceLocation((String) it); + } try { if (List.class.isAssignableFrom(type)) { - field.set(instance, list); + field.set(instance, list.stream().map(mapper).collect(Collectors.toList())); } else if (Set.class.isAssignableFrom(type)) { - field.set(instance, new HashSet<>(list)); + field.set(instance, list.stream().map(mapper).collect(Collectors.toSet())); } } catch (IllegalArgumentException e) { logger.error("Invalid config value for " + path + ", expected " + type.getName() + " but got " + raw.getClass()); @@ -185,10 +193,12 @@ private void writeConfigValues(String parentPath, ModConfig config, T instan String path = parentPath + field.getName(); Class type = field.getType(); Object value = field.get(instance); - if (type.isPrimitive() || Enum.class.isAssignableFrom(type) || String.class.isAssignableFrom(type) || List.class.isAssignableFrom(type)) { + if (type.isPrimitive() || Enum.class.isAssignableFrom(type) || String.class.isAssignableFrom(type)) { config.getConfigData().set(path, value); - } else if(Set.class.isAssignableFrom(type)) { - config.getConfigData().set(path, new ArrayList<>((Set) value)); + } else if (ResourceLocation.class.isAssignableFrom(type)) { + config.getConfigData().set(path, ((ResourceLocation) value).toString()); + } else if(Collection.class.isAssignableFrom(type)) { + config.getConfigData().set(path, new ArrayList<>((Collection) value)); } else { writeConfigValues(path + ".", config, field.get(instance)); }