Files
FalsePatternLib/src/main/java/com/falsepattern/lib/config/ConfigurationManager.java
T

144 lines
7.6 KiB
Java
Raw Normal View History

2022-05-06 23:48:24 +02:00
package com.falsepattern.lib.config;
2022-05-06 23:53:11 +02:00
import com.falsepattern.lib.StableAPI;
2022-05-06 23:58:01 +02:00
import com.falsepattern.lib.internal.CoreLoadingPlugin;
2022-05-06 23:48:24 +02:00
import cpw.mods.fml.client.event.ConfigChangedEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
2022-05-07 11:45:57 +02:00
import lombok.*;
2022-05-06 23:48:24 +02:00
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration;
2022-05-07 11:45:57 +02:00
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
2022-05-06 23:48:24 +02:00
import java.nio.file.Path;
import java.util.*;
2022-05-07 01:33:04 +02:00
import java.util.regex.Pattern;
2022-05-07 11:45:57 +02:00
import java.util.stream.Collectors;
2022-05-06 23:48:24 +02:00
/**
* Class for controlling the loading of configuration files.
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
2022-05-06 23:53:11 +02:00
@StableAPI(since = "0.6.0")
2022-05-06 23:48:24 +02:00
public class ConfigurationManager {
private static final Map<String, Set<Class<?>>> configs = new HashMap<>();
private static final ConfigurationManager instance = new ConfigurationManager();
private static boolean initialized = false;
private static Path configDir;
/**
* Registers a configuration class to be loaded.
* @param config The class to register.
*/
2022-05-07 11:45:57 +02:00
public static void registerConfig(Class<?> config) throws ConfigException {
val cfg = Optional.ofNullable(config.getAnnotation(Config.class)).orElseThrow(() -> new ConfigException("Class " + config.getName() + " does not have a @Config annotation!"));
2022-05-06 23:48:24 +02:00
val cfgSet = configs.computeIfAbsent(cfg.modid(), (ignored) -> new HashSet<>());
cfgSet.add(config);
2022-05-07 11:45:57 +02:00
try {
processConfig(config);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException | NoSuchFieldException e) {
throw new ConfigException(e);
}
2022-05-06 23:48:24 +02:00
}
/**
* Internal, do not use.
*/
public static void init() {
if (initialized) return;
2022-05-06 23:58:01 +02:00
configDir = CoreLoadingPlugin.mcDir.toPath().resolve("config");
2022-05-06 23:48:24 +02:00
MinecraftForge.EVENT_BUS.register(instance);
initialized = true;
}
/**
* Internal, do not use.
* @param event The event.
*/
@SubscribeEvent
public void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent event) {
val configClasses = configs.get(event.modID);
if (configClasses == null)
return;
configClasses.forEach((config) -> {
try {
processConfig(config);
2022-05-07 11:54:44 +02:00
} catch (Exception e) {
throw new RuntimeException(e);
2022-05-06 23:48:24 +02:00
}
});
}
2022-05-07 11:45:57 +02:00
private static void processConfig(Class<?> configClass) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, ConfigException {
2022-05-06 23:48:24 +02:00
val cfg = configClass.getAnnotation(Config.class);
val category = cfg.category();
2022-05-07 00:10:35 +02:00
var configName = cfg.name().trim();
if (configName.length() == 0) {
configName = cfg.modid();
}
val rawConfig = new Configuration(configDir.resolve(configName + ".cfg").toFile());
2022-05-07 01:39:50 +02:00
rawConfig.load();
2022-05-06 23:48:24 +02:00
val cat = rawConfig.getCategory(category);
for (val field: configClass.getDeclaredFields()) {
if (field.getAnnotation(Config.Ignore.class) != null) continue;
field.setAccessible(true);
2022-05-07 01:14:55 +02:00
val comment = Optional.ofNullable(field.getAnnotation(Config.Comment.class)).map(Config.Comment::value).map((lines) -> String.join("\n", lines)).orElse("");
val name = Optional.ofNullable(field.getAnnotation(Config.Name.class)).map(Config.Name::value).orElse(field.getName());
val langKey = Optional.ofNullable(field.getAnnotation(Config.LangKey.class)).map(Config.LangKey::value).orElse(name);
2022-05-07 12:16:05 +02:00
val fieldClass = field.getType();
2022-05-06 23:48:24 +02:00
var boxed = false;
2022-05-07 12:16:05 +02:00
if ((boxed = fieldClass.equals(Boolean.class)) || fieldClass.equals(boolean.class)) {
2022-05-07 01:33:04 +02:00
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultBoolean.class)).map(Config.DefaultBoolean::value).orElse(boxed ? (Boolean) field.get(null) : field.getBoolean(null));
field.setBoolean(null, rawConfig.getBoolean(name, category, defaultValue, comment, langKey));
2022-05-07 12:16:05 +02:00
} else if ((boxed = fieldClass.equals(Integer.class)) || fieldClass.equals(int.class)) {
2022-05-07 01:14:55 +02:00
val range = Optional.ofNullable(field.getAnnotation(Config.RangeInt.class));
2022-05-07 01:33:04 +02:00
val min = range.map(Config.RangeInt::min).orElse(Integer.MIN_VALUE);
val max = range.map(Config.RangeInt::max).orElse(Integer.MAX_VALUE);
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultInt.class)).map(Config.DefaultInt::value).orElse(boxed ? (Integer)field.get(null) : field.getInt(null));
field.setInt(null, rawConfig.getInt(name, category, defaultValue, min, max, comment, langKey));
2022-05-07 12:16:05 +02:00
} else if ((boxed = fieldClass.equals(Float.class)) || fieldClass.equals(float.class)) {
2022-05-07 01:33:04 +02:00
val range = Optional.ofNullable(field.getAnnotation(Config.RangeFloat.class));
val min = range.map(Config.RangeFloat::min).orElse(Float.MIN_VALUE);
val max = range.map(Config.RangeFloat::max).orElse(Float.MAX_VALUE);
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultFloat.class)).map(Config.DefaultFloat::value).orElse(boxed ? (Float) field.get(null) : field.getFloat(null));
field.setDouble(null, rawConfig.getFloat(name, category, defaultValue, min, max, comment, langKey));
2022-05-07 12:16:05 +02:00
} else if (fieldClass.equals(String.class)) {
2022-05-07 01:33:04 +02:00
val defaultValue = Optional.ofNullable(field.getAnnotation(Config.DefaultString.class)).map(Config.DefaultString::value).orElse((String)field.get(null));
val pattern = Optional.ofNullable(field.getAnnotation(Config.Pattern.class)).map(Config.Pattern::value).map(Pattern::compile).orElse(null);
field.set(null, rawConfig.getString(name, category, defaultValue, comment, langKey, pattern));
2022-05-07 12:16:05 +02:00
} else if (fieldClass.isEnum()) {
val enumValues = Arrays.stream((Object[])fieldClass.getDeclaredMethod("values").invoke(null)).map((obj) -> (Enum<?>)obj).collect(Collectors.toList());
2022-05-07 11:45:57 +02:00
val defaultValue = (Enum<?>)
Optional.ofNullable(field.getAnnotation(Config.DefaultEnum.class))
.map(Config.DefaultEnum::value)
2022-05-07 12:16:05 +02:00
.map((defName) -> extractField(fieldClass, defName))
2022-05-07 11:45:57 +02:00
.map(ConfigurationManager::extractValue)
.orElse(field.get(null));
val possibleValues = enumValues.stream().map(Enum::name).toArray(String[]::new);
2022-05-07 12:20:32 +02:00
field.set(null, fieldClass.getDeclaredField(rawConfig.getString(name, category, defaultValue.name(), comment, possibleValues, langKey)).get(null));
2022-05-07 11:45:57 +02:00
} else {
2022-05-07 12:16:05 +02:00
throw new ConfigException("Illegal config field: " + field.getName() + " in " + configClass.getName() + ": Unsupported type " + fieldClass.getName() + "! Did you forget an @Ignore annotation?");
2022-05-06 23:48:24 +02:00
}
if (field.isAnnotationPresent(Config.RequiresMcRestart.class)) {
cat.setRequiresMcRestart(true);
}
if (field.isAnnotationPresent(Config.RequiresWorldRestart.class)) {
cat.setRequiresWorldRestart(true);
}
}
2022-05-07 01:39:50 +02:00
rawConfig.save();
2022-05-06 23:48:24 +02:00
}
2022-05-07 11:45:57 +02:00
@SneakyThrows
private static Field extractField(Class<?> clazz, String field) {
return clazz.getDeclaredField(field);
}
@SneakyThrows
private static Object extractValue(Field field) {
return field.get(null);
}
2022-05-06 23:48:24 +02:00
}