package ru.betterend.config; import java.lang.reflect.Type; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; import org.jetbrains.annotations.Nullable; import com.google.common.collect.Maps; import com.google.common.reflect.TypeToken; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.util.JsonHelper; import ru.betterend.util.JsonFactory; public final class ConfigKeeper { private Map> configEntries = Maps.newHashMap(); private final JsonObject configObject; private final ConfigWriter writer; private boolean changed = false; public ConfigKeeper(String group) { this.writer = new ConfigWriter(group); this.configObject = writer.load(); } public void save() { if (!changed) return; this.writer.save(); this.changed = false; } private > void initializeEntry(ConfigKey key, E entry) { if (configObject == null) { return; } String[] path = key.getPath(); JsonObject obj = configObject; if (!key.isRoot()) { for (String group: path) { JsonElement element = obj.get(group); if (element == null || !element.isJsonObject()) { element = new JsonObject(); obj.add(group, element); } obj = element.getAsJsonObject(); } } String paramKey = key.getEntry(); paramKey += " [default: " + entry.getDefault() + "]"; this.changed = entry.setLocation(obj, paramKey); } private > void storeValue(E entry, T value) { if (configObject == null) { return; } T val = entry.getValue(); if (value.equals(val)) return; entry.toJson(value); this.changed = true; } private > T getValue(E entry) { if (!entry.hasLocation()) { return entry.getDefault(); } return entry.fromJson(); } @Nullable public > E getEntry(ConfigKey key, Class type) { Entry entry = this.configEntries.get(key); if (type.isInstance(entry)) { return type.cast(entry); } return null; } @Nullable public > T getValue(ConfigKey key, Class type) { Entry entry = this.getEntry(key, type); if (entry == null) { return null; } return entry.getValue(); } public > E registerEntry(ConfigKey key, E entry) { entry.setWriter(value -> this.storeValue(entry, value)); entry.setReader(() -> { return this.getValue(entry); }); this.initializeEntry(key, entry); this.configEntries.put(key, entry); return entry; } public static class BooleanEntry extends Entry { public BooleanEntry(Boolean defaultValue) { super(defaultValue); } @Override public Boolean fromJson() { return JsonHelper.getBoolean(location, key, defaultValue); } @Override public void toJson(Boolean value) { this.location.addProperty(key, value); } } public static class FloatEntry extends Entry { public FloatEntry(Float defaultValue) { super(defaultValue); } @Override public Float fromJson() { return JsonHelper.getFloat(location, key, defaultValue); } @Override public void toJson(Float value) { this.location.addProperty(key, value); } } public static class FloatRange extends RangeEntry { public FloatRange(Float defaultValue, float minVal, float maxVal) { super(defaultValue, minVal, maxVal); } @Override public Float fromJson() { return JsonHelper.getFloat(location, key, defaultValue); } @Override public void toJson(Float value) { this.location.addProperty(key, value); } } public static class IntegerEntry extends Entry { public IntegerEntry(Integer defaultValue) { super(defaultValue); } @Override public Integer getDefault() { return this.defaultValue; } @Override public Integer fromJson() { return JsonHelper.getInt(location, key, defaultValue); } @Override public void toJson(Integer value) { this.location.addProperty(key, value); } } public static class IntegerRange extends RangeEntry { public IntegerRange(Integer defaultValue, int minVal, int maxVal) { super(defaultValue, minVal, maxVal); } @Override public Integer fromJson() { return JsonHelper.getInt(location, key, defaultValue); } @Override public void toJson(Integer value) { this.location.addProperty(key, value); } } public static class StringEntry extends Entry { public StringEntry(String defaultValue) { super(defaultValue); } @Override public String fromJson() { return JsonHelper.getString(location, key, defaultValue); } @Override public void toJson(String value) { this.location.addProperty(key, value); } } public static class EnumEntry> extends Entry { private final Type type; public EnumEntry(T defaultValue) { super(defaultValue); TypeToken token = new TypeToken(){ private static final long serialVersionUID = 1L; }; this.type = token.getType(); } @Override public T getDefault() { return this.defaultValue; } @Override public T fromJson() { return JsonFactory.GSON.fromJson(location.get(key), type); } @Override public void toJson(T value) { location.addProperty(key, JsonFactory.GSON.toJson(value, type)); } } public static abstract class RangeEntry> extends Entry { private final T min, max; public RangeEntry(T defaultValue, T minVal, T maxVal) { super(defaultValue); this.min = minVal; this.max = maxVal; } @Override public void setValue(T value) { super.setValue(value.compareTo(min) < 0 ? min : value.compareTo(max) > 0 ? max : value); } public T minValue() { return this.min; } public T maxValue() { return this.max; } } public static abstract class Entry { protected final T defaultValue; protected Consumer writer; protected Supplier reader; protected JsonObject location; protected String key; public abstract T fromJson(); public abstract void toJson(T value); public Entry (T defaultValue) { this.defaultValue = defaultValue; } protected void setWriter(Consumer writer) { this.writer = writer; } protected void setReader(Supplier reader) { this.reader = reader; } protected boolean setLocation(JsonObject location, String key) { this.location = location; this.key = key; if (!location.has(key)) { this.toJson(defaultValue); return true; } return false; } protected boolean hasLocation() { return this.location != null && this.key != null; } public T getValue() { return this.reader.get(); } public void setValue(T value) { this.writer.accept(value); } public T getDefault() { return this.defaultValue; } public void setDefault() { this.setValue(defaultValue); } } }