2021-04-11 16:00:37 +02:00
|
|
|
package io.gitlab.jfronny.libjf.config;
|
|
|
|
|
|
|
|
import io.gitlab.jfronny.libjf.Libjf;
|
2021-05-15 15:34:19 +02:00
|
|
|
import io.gitlab.jfronny.libjf.gson.GsonHidden;
|
|
|
|
import net.fabricmc.api.EnvType;
|
|
|
|
import net.fabricmc.api.Environment;
|
2021-04-11 16:00:37 +02:00
|
|
|
import net.fabricmc.loader.api.FabricLoader;
|
2021-05-15 15:34:19 +02:00
|
|
|
import net.minecraft.client.gui.widget.*;
|
|
|
|
import net.minecraft.text.*;
|
|
|
|
import net.minecraft.util.Formatting;
|
2021-04-11 16:00:37 +02:00
|
|
|
|
|
|
|
import java.lang.reflect.Field;
|
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.util.*;
|
2021-05-15 15:34:19 +02:00
|
|
|
import java.util.function.BiFunction;
|
|
|
|
import java.util.function.Function;
|
|
|
|
import java.util.function.Predicate;
|
|
|
|
import java.util.regex.Pattern;
|
2021-04-11 16:00:37 +02:00
|
|
|
|
2021-05-15 15:34:19 +02:00
|
|
|
/** Based on https://github.com/TeamMidnightDust/MidnightLib which is based on https://github.com/Minenash/TinyConfig
|
|
|
|
* Credits to TeamMidnightDust and Minenash */
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
2021-04-11 16:00:37 +02:00
|
|
|
public class Config {
|
2021-05-15 15:34:19 +02:00
|
|
|
private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)");
|
|
|
|
private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
|
|
|
|
|
2021-04-11 16:00:37 +02:00
|
|
|
public final List<EntryInfo> entries = new ArrayList<>();
|
2021-05-15 15:34:19 +02:00
|
|
|
public Path path;
|
|
|
|
public final String modid;
|
|
|
|
public final Class<?> configClass;
|
|
|
|
|
2021-04-11 16:00:37 +02:00
|
|
|
public Config(String modid, Class<?> config) {
|
2021-05-15 15:34:19 +02:00
|
|
|
this.modid = modid;
|
2021-04-11 16:00:37 +02:00
|
|
|
configClass = config;
|
2021-05-15 15:34:19 +02:00
|
|
|
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
|
2021-04-11 16:00:37 +02:00
|
|
|
|
|
|
|
for (Field field : config.getFields()) {
|
|
|
|
EntryInfo info = new EntryInfo();
|
2021-05-15 15:34:19 +02:00
|
|
|
if (field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(GsonHidden.class))
|
|
|
|
try {
|
|
|
|
initClient(field, info);
|
|
|
|
} catch (Exception e) {continue;}
|
|
|
|
if (field.isAnnotationPresent(Entry.class))
|
|
|
|
try {
|
|
|
|
info.defaultValue = field.get(null);
|
|
|
|
} catch (IllegalAccessException ignored) {}
|
2021-04-11 16:00:37 +02:00
|
|
|
}
|
2021-05-15 15:34:19 +02:00
|
|
|
try {
|
|
|
|
Libjf.GSON.fromJson(Files.newBufferedReader(path), config); }
|
2021-04-11 16:00:37 +02:00
|
|
|
catch (Exception e) { write(); }
|
|
|
|
|
|
|
|
for (EntryInfo info : entries) {
|
2021-05-15 15:34:19 +02:00
|
|
|
if (info.field.isAnnotationPresent(Entry.class))
|
|
|
|
try {
|
|
|
|
info.value = info.field.get(null);
|
|
|
|
info.tempValue = info.value.toString();
|
|
|
|
} catch (IllegalAccessException ignored) {
|
|
|
|
}
|
2021-04-11 16:00:37 +02:00
|
|
|
}
|
|
|
|
}
|
2021-05-15 15:34:19 +02:00
|
|
|
@Environment(EnvType.CLIENT)
|
|
|
|
public void initClient(Field field, EntryInfo info) {
|
|
|
|
Class<?> type = field.getType();
|
|
|
|
Entry e = field.getAnnotation(Entry.class);
|
|
|
|
info.width = e != null ? e.width() : 0;
|
|
|
|
info.field = field;
|
|
|
|
|
|
|
|
if (e != null)
|
|
|
|
if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true);
|
|
|
|
else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(),false);
|
|
|
|
else if (type == String.class) textField(info, String::length, null, Math.min(e.min(),0), Math.max(e.max(),1),true);
|
|
|
|
else if (type == boolean.class) {
|
|
|
|
Function<Object,Text> func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
|
|
|
|
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
|
|
|
|
info.value = !(Boolean) info.value;
|
|
|
|
button.setMessage(func.apply(info.value));
|
|
|
|
}, func);
|
|
|
|
} else if (type.isEnum()) {
|
|
|
|
List<?> values = Arrays.asList(field.getType().getEnumConstants());
|
|
|
|
Function<Object,Text> func = value -> new TranslatableText(modid + ".jfconfig." + "enum." + type.getSimpleName() + "." + info.value.toString());
|
|
|
|
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object,Text>>( button -> {
|
|
|
|
int index = values.indexOf(info.value) + 1;
|
|
|
|
info.value = values.get(index >= values.size()? 0 : index);
|
|
|
|
button.setMessage(func.apply(info.value));
|
|
|
|
}, func);
|
|
|
|
}
|
|
|
|
entries.add(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) {
|
|
|
|
boolean isNumber = pattern != null;
|
|
|
|
info.widget = (BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) (t, b) -> s -> {
|
|
|
|
s = s.trim();
|
|
|
|
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) return false;
|
|
|
|
|
|
|
|
Number value = 0;
|
|
|
|
boolean inLimits = false;
|
|
|
|
System.out.println(((isNumber ^ s.isEmpty())));
|
|
|
|
System.out.println(!s.equals("-") && !s.equals("."));
|
|
|
|
info.error = null;
|
|
|
|
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
|
|
|
|
value = f.apply(s);
|
|
|
|
inLimits = value.doubleValue() >= min && value.doubleValue() <= max;
|
|
|
|
info.error = inLimits? null : new AbstractMap.SimpleEntry<>(t, new LiteralText(value.doubleValue() < min ?
|
|
|
|
"§cMinimum " + (isNumber? "value" : "length") + (cast? " is " + (int)min : " is " + min) :
|
|
|
|
"§cMaximum " + (isNumber? "value" : "length") + (cast? " is " + (int)max : " is " + max)));
|
|
|
|
}
|
|
|
|
|
|
|
|
info.tempValue = s;
|
|
|
|
t.setEditableColor(inLimits? 0xFFFFFFFF : 0xFFFF7777);
|
|
|
|
info.inLimits = inLimits;
|
|
|
|
b.active = entries.stream().allMatch(e -> e.inLimits);
|
|
|
|
|
|
|
|
if (inLimits)
|
|
|
|
info.value = isNumber? value : s;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
}
|
2021-04-11 16:00:37 +02:00
|
|
|
|
|
|
|
public void write() {
|
2021-05-15 15:34:19 +02:00
|
|
|
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
|
2021-04-11 16:00:37 +02:00
|
|
|
try {
|
|
|
|
if (!Files.exists(path)) Files.createFile(path);
|
2021-04-11 20:23:52 +02:00
|
|
|
Files.write(path, Libjf.GSON.toJson(configClass.getDeclaredConstructor().newInstance()).getBytes());
|
2021-04-11 16:00:37 +02:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
2021-05-15 15:34:19 +02:00
|
|
|
}
|