Reorganized Imports/Packages

This commit is contained in:
Frank 2022-05-18 23:56:23 +02:00
parent cb9459f176
commit 3ee10482ab
721 changed files with 34873 additions and 33558 deletions

View file

@ -0,0 +1,10 @@
package org.betterx.bclib.config;
public class CategoryConfig extends IdConfig {
public CategoryConfig(String modID, String group) {
super(modID, group, (id, category) -> {
return new ConfigKey(id.getPath(), id.getNamespace(), category);
});
}
}

View file

@ -0,0 +1,92 @@
package org.betterx.bclib.config;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.dataexchange.handler.autosync.AutoSync;
public class ClientConfig extends NamedPathConfig {
public static final ConfigToken<Boolean> SUPPRESS_EXPERIMENTAL_DIALOG = ConfigToken.Boolean(false,
"suppressExperimentalDialogOnLoad",
"ui");
@ConfigUI(topPadding = 12)
public static final ConfigToken<Boolean> ENABLED = ConfigToken.Boolean(true, "enabled", AutoSync.SYNC_CATEGORY);
@ConfigUI(leftPadding = 8)
public static final DependendConfigToken<Boolean> ACCEPT_CONFIGS = DependendConfigToken.Boolean(true,
"acceptConfigs",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
@ConfigUI(leftPadding = 8)
public static final DependendConfigToken<Boolean> ACCEPT_FILES = DependendConfigToken.Boolean(true,
"acceptFiles",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
@ConfigUI(leftPadding = 8)
public static final DependendConfigToken<Boolean> ACCEPT_MODS = DependendConfigToken.Boolean(false,
"acceptMods",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
@ConfigUI(leftPadding = 8)
public static final DependendConfigToken<Boolean> DISPLAY_MOD_INFO = DependendConfigToken.Boolean(true,
"displayModInfo",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
@ConfigUI(topPadding = 12)
public static final ConfigToken<Boolean> DEBUG_HASHES = ConfigToken.Boolean(false,
"debugHashes",
AutoSync.SYNC_CATEGORY);
@ConfigUI(leftPadding = 8)
public static final ConfigToken<Boolean> CUSTOM_FOG_RENDERING = ConfigToken.Boolean(true,
"customFogRendering",
"rendering");
@ConfigUI(leftPadding = 8)
public static final ConfigToken<Boolean> NETHER_THICK_FOG = ConfigToken.Boolean(true,
"netherThickFog",
"rendering");
public ClientConfig() {
super(BCLib.MOD_ID, "client", false);
}
public boolean shouldPrintDebugHashes() {
return get(DEBUG_HASHES);
}
public boolean isAllowingAutoSync() {
return get(ENABLED);
}
public boolean isAcceptingMods() {
return get(ACCEPT_MODS) /*&& isAllowingAutoSync()*/;
}
public boolean isAcceptingConfigs() {
return get(ACCEPT_CONFIGS) /*&& isAllowingAutoSync()*/;
}
public boolean isAcceptingFiles() {
return get(ACCEPT_FILES) /*&& isAllowingAutoSync()*/;
}
public boolean isShowingModInfo() {
return get(DISPLAY_MOD_INFO) /*&& isAllowingAutoSync()*/;
}
public boolean suppressExperimentalDialog() {
return get(SUPPRESS_EXPERIMENTAL_DIALOG);
}
public boolean netherThickFog() {
return get(NETHER_THICK_FOG);
}
public boolean renderCustomFog() {
return get(CUSTOM_FOG_RENDERING);
}
}

View file

@ -0,0 +1,234 @@
package org.betterx.bclib.config;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.dataexchange.DataExchangeAPI;
import org.betterx.bclib.api.dataexchange.SyncFileHash;
import org.betterx.bclib.api.dataexchange.handler.autosync.AutoSyncID;
import org.betterx.bclib.api.dataexchange.handler.autosync.FileContentWrapper;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
public abstract class Config {
protected final static Map<AutoSyncID, Config> AUTO_SYNC_CONFIGS = new HashMap<>();
public static final String CONFIG_SYNC_PREFIX = "CONFIG_";
protected final ConfigKeeper keeper;
protected final boolean autoSync;
public final String configID;
protected abstract void registerEntries();
protected Config(String modID, String group) {
this(modID, group, true, false);
}
protected Config(String modID, String group, boolean autoSync) {
this(modID, group, autoSync, false);
}
protected Config(String modID, String group, boolean autoSync, boolean diffContent) {
configID = modID + "." + group;
this.keeper = new ConfigKeeper(modID, group);
this.registerEntries();
this.autoSync = autoSync;
if (autoSync) {
final String uid = CONFIG_SYNC_PREFIX + configID;
final AutoSyncID aid = new AutoSyncID(BCLib.MOD_ID, uid);
if (diffContent)
DataExchangeAPI.addAutoSyncFile(aid.modID, aid.uniqueID, keeper.getConfigFile(), this::compareForSync);
else
DataExchangeAPI.addAutoSyncFile(aid.modID, aid.uniqueID, keeper.getConfigFile());
AUTO_SYNC_CONFIGS.put(aid, this);
BCLib.LOGGER.info("Added Config " + configID + " to auto sync (" + (diffContent
? "content diff"
: "file hash") + ")");
}
}
private boolean compareForSync(SyncFileHash clientHash, SyncFileHash serverHash, FileContentWrapper content) {
//identical hashes => nothing to do
if (clientHash.equals(serverHash)) {
return false;
}
return keeper.compareAndUpdateForSync(content);
}
public void saveChanges() {
this.keeper.save();
}
public static void reloadSyncedConfig(AutoSyncID aid, File file) {
Config cfg = AUTO_SYNC_CONFIGS.get(aid);
if (cfg != null) {
cfg.reload();
}
}
public void reload() {
this.keeper.reload();
BCLib.LOGGER.info("Did Reload " + keeper.getConfigFile());
}
@Nullable
public <T, E extends ConfigKeeper.Entry<T>> E getEntry(ConfigKey key, Class<E> type) {
return this.keeper.getEntry(key, type);
}
@Nullable
public <T, E extends ConfigKeeper.Entry<T>> T getDefault(ConfigKey key, Class<E> type) {
ConfigKeeper.Entry<T> entry = keeper.getEntry(key, type);
return entry != null ? entry.getDefault() : null;
}
protected String getString(ConfigKey key, String defaultValue) {
String str = keeper.getValue(key, ConfigKeeper.StringEntry.class);
if (str == null) {
ConfigKeeper.StringEntry entry = keeper.registerEntry(key, new ConfigKeeper.StringEntry(defaultValue));
return entry.getValue();
}
return str != null ? str : defaultValue;
}
protected String getString(ConfigKey key) {
String str = keeper.getValue(key, ConfigKeeper.StringEntry.class);
return str != null ? str : "";
}
protected boolean setString(ConfigKey key, String value) {
try {
ConfigKeeper.StringEntry entry = keeper.getEntry(key, ConfigKeeper.StringEntry.class);
if (entry == null) return false;
entry.setValue(value);
return true;
} catch (NullPointerException ex) {
BCLib.LOGGER.catching(ex);
}
return false;
}
protected int getInt(ConfigKey key, int defaultValue) {
Integer val = keeper.getValue(key, ConfigKeeper.IntegerEntry.class);
if (val == null) {
ConfigKeeper.IntegerEntry entry = keeper.registerEntry(key, new ConfigKeeper.IntegerEntry(defaultValue));
return entry.getValue();
}
return val != null ? val : defaultValue;
}
protected int getInt(ConfigKey key) {
Integer val = keeper.getValue(key, ConfigKeeper.IntegerEntry.class);
return val != null ? val : 0;
}
protected boolean setInt(ConfigKey key, int value) {
try {
ConfigKeeper.IntegerEntry entry = keeper.getEntry(key, ConfigKeeper.IntegerEntry.class);
if (entry == null) return false;
entry.setValue(value);
return true;
} catch (NullPointerException ex) {
BCLib.LOGGER.catching(ex);
}
return false;
}
protected <T extends Comparable<T>, RE extends ConfigKeeper.RangeEntry<T>> boolean setRanged(ConfigKey key,
T value,
Class<RE> type) {
try {
ConfigKeeper.RangeEntry<T> entry = keeper.getEntry(key, type);
if (entry == null) return false;
entry.setValue(value);
return true;
} catch (NullPointerException | ClassCastException ex) {
BCLib.LOGGER.catching(ex);
}
return false;
}
protected float getFloat(ConfigKey key, float defaultValue) {
Float val = keeper.getValue(key, ConfigKeeper.FloatEntry.class);
if (val == null) {
ConfigKeeper.FloatEntry entry = keeper.registerEntry(key, new ConfigKeeper.FloatEntry(defaultValue));
return entry.getValue();
}
return val;
}
protected float getFloat(ConfigKey key) {
Float val = keeper.getValue(key, ConfigKeeper.FloatEntry.class);
return val != null ? val : 0.0F;
}
protected boolean setFloat(ConfigKey key, float value) {
try {
ConfigKeeper.FloatEntry entry = keeper.getEntry(key, ConfigKeeper.FloatEntry.class);
if (entry == null) return false;
entry.setValue(value);
return true;
} catch (NullPointerException ex) {
BCLib.LOGGER.catching(ex);
}
return false;
}
protected boolean getBoolean(ConfigKey key, boolean defaultValue) {
Boolean val = keeper.getValue(key, ConfigKeeper.BooleanEntry.class);
if (val == null) {
ConfigKeeper.BooleanEntry entry = keeper.registerEntry(key, new ConfigKeeper.BooleanEntry(defaultValue));
return entry.getValue();
}
return val;
}
protected boolean getBoolean(ConfigKey key) {
Boolean val = keeper.getValue(key, ConfigKeeper.BooleanEntry.class);
return val != null ? val : false;
}
protected boolean setBoolean(ConfigKey key, boolean value) {
try {
ConfigKeeper.BooleanEntry entry = keeper.getEntry(key, ConfigKeeper.BooleanEntry.class);
if (entry == null) return false;
entry.setValue(value);
return true;
} catch (NullPointerException ex) {
BCLib.LOGGER.catching(ex);
}
return false;
}
protected List<String> getStringArray(ConfigKey key, List<String> defaultValue) {
List<String> str = keeper.getValue(key, ConfigKeeper.StringArrayEntry.class);
if (str == null) {
ConfigKeeper.StringArrayEntry entry = keeper.registerEntry(key,
new ConfigKeeper.StringArrayEntry(defaultValue));
return entry.getValue();
}
return str != null ? str : defaultValue;
}
protected List<String> getStringArray(ConfigKey key) {
List<String> str = keeper.getValue(key, ConfigKeeper.StringArrayEntry.class);
return str != null ? str : new ArrayList<>(0);
}
protected boolean setStringArray(ConfigKey key, List<String> value) {
try {
ConfigKeeper.StringArrayEntry entry = keeper.getEntry(key, ConfigKeeper.StringArrayEntry.class);
if (entry == null) return false;
entry.setValue(value);
return true;
} catch (NullPointerException ex) {
BCLib.LOGGER.catching(ex);
}
return false;
}
}

View file

@ -0,0 +1,457 @@
package org.betterx.bclib.config;
import net.minecraft.util.GsonHelper;
import com.google.common.collect.Maps;
import com.google.common.reflect.TypeToken;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.betterx.bclib.api.dataexchange.handler.autosync.FileContentWrapper;
import org.betterx.bclib.util.JsonFactory;
import org.betterx.bclib.util.Pair;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
public final class ConfigKeeper {
private final Map<ConfigKey, Entry<?>> configEntries = Maps.newHashMap();
private final ConfigWriter writer;
private JsonObject configObject;
private boolean changed = false;
public ConfigKeeper(String modID, String group) {
this.writer = new ConfigWriter(modID, group);
this.configObject = writer.load();
}
public File getConfigFile() {
return this.writer.getConfigFile();
}
boolean compareAndUpdateForSync(FileContentWrapper content) {
ByteArrayInputStream inputStream = content.getInputStream();
final JsonObject other = JsonFactory.getJsonObject(inputStream);
boolean changed = this.compareAndUpdateForSync(other);
if (changed) {
OutputStream outStream = content.getEmptyOutputStream();
JsonFactory.storeJson(outStream, this.configObject);
content.syncWithOutputStream();
}
return changed;
}
boolean compareAndUpdateForSync(JsonObject other) {
return compareAndUpdateForSync(this.configObject, other);
}
private static Pair<JsonElement, Pair<String, String>> find(JsonObject json, Pair<String, String> key) {
for (var entry : json.entrySet()) {
final Pair<String, String> otherKey = ConfigKey.realKey(entry.getKey());
if (otherKey.first.equals(key.first)) return new Pair<>(entry.getValue(), otherKey);
}
return null;
}
/**
* Called for content based auto-sync.
*
* @param me - When called in AutoSync this represents the content of the client.
* @param other - When called in AutoSync, this represents the content of the server
* @return {@code true} if content was changed
*/
static boolean compareAndUpdateForSync(JsonObject me, JsonObject other) {
boolean changed = false;
for (var otherEntry : other.entrySet()) {
final Pair<String, String> otherKey = ConfigKey.realKey(otherEntry.getKey());
final JsonElement otherValue = otherEntry.getValue();
Pair<JsonElement, Pair<String, String>> temp = find(me, otherKey);
//we already have an entry
if (temp != null) {
final Pair<String, String> myKey = temp.second;
final JsonElement myValue = temp.first;
if ((otherValue.isJsonNull() && !myValue.isJsonNull()) || (otherValue.isJsonPrimitive() && !myValue.isJsonPrimitive()) || (otherValue.isJsonObject() && !myValue.isJsonObject()) || (otherValue.isJsonArray() && !myValue.isJsonArray())) {
//types are different => replace with "server"-version in other
changed = true;
me.add(myKey.first + myKey.second, otherValue);
} else if (otherValue.isJsonPrimitive() || otherValue.isJsonArray() || otherValue.isJsonNull()) {
if (!otherValue.equals(myValue)) {
changed = true;
me.add(myKey.first + myKey.second, otherValue);
}
} else if (otherValue.isJsonObject()) {
changed |= compareAndUpdateForSync(myValue.getAsJsonObject(), otherValue.getAsJsonObject());
}
} else { //no entry, just copy the value from other
if (!otherValue.isJsonNull()) {
changed = true;
temp = find(me, otherKey);
me.add(otherKey.first + otherKey.second, otherValue);
}
}
}
return changed;
}
public void save() {
if (!changed) return;
this.writer.save();
this.changed = false;
}
void reload() {
this.configObject = this.writer.reload();
this.configEntries.clear();
this.changed = false;
}
private <T, E extends Entry<T>> 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();
if (entry.hasDefaultInName()) {
paramKey += " [default: " + entry.getDefault() + "]";
}
this.changed |= entry.setLocation(obj, paramKey);
}
private <T, E extends Entry<T>> 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, E extends Entry<T>> T getValue(E entry) {
if (!entry.hasLocation()) {
return entry.getDefault();
}
return entry.fromJson();
}
@Nullable
public <T, E extends Entry<T>> E getEntry(ConfigKey key, Class<E> type) {
Entry<?> entry = this.configEntries.get(key);
if (type.isInstance(entry)) {
return type.cast(entry);
}
return null;
}
@Nullable
public <T, E extends Entry<T>> T getValue(ConfigKey key, Class<E> type) {
Entry<T> entry = this.getEntry(key, type);
if (entry == null) {
return null;
}
return entry.getValue();
}
public <T, E extends Entry<T>> 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<Boolean> {
public BooleanEntry(Boolean defaultValue) {
super(defaultValue);
}
@Override
public Boolean fromJson() {
return GsonHelper.getAsBoolean(location, key, defaultValue);
}
@Override
public void toJson(Boolean value) {
this.location.addProperty(key, value);
}
}
public static class FloatEntry extends Entry<Float> {
public FloatEntry(Float defaultValue) {
super(defaultValue);
}
@Override
public Float fromJson() {
return GsonHelper.getAsFloat(location, key, defaultValue);
}
@Override
public void toJson(Float value) {
this.location.addProperty(key, value);
}
}
public static class FloatRange extends RangeEntry<Float> {
public FloatRange(Float defaultValue, float minVal, float maxVal) {
super(defaultValue, minVal, maxVal);
}
@Override
public Float fromJson() {
return GsonHelper.getAsFloat(location, key, defaultValue);
}
@Override
public void toJson(Float value) {
this.location.addProperty(key, value);
}
}
public static class IntegerEntry extends Entry<Integer> {
public IntegerEntry(Integer defaultValue) {
super(defaultValue);
}
@Override
public Integer getDefault() {
return this.defaultValue;
}
@Override
public Integer fromJson() {
return GsonHelper.getAsInt(location, key, defaultValue);
}
@Override
public void toJson(Integer value) {
this.location.addProperty(key, value);
}
}
public static class IntegerRange extends RangeEntry<Integer> {
public IntegerRange(Integer defaultValue, int minVal, int maxVal) {
super(defaultValue, minVal, maxVal);
}
@Override
public Integer fromJson() {
return GsonHelper.getAsInt(location, key, defaultValue);
}
@Override
public void toJson(Integer value) {
this.location.addProperty(key, value);
}
}
public static class StringEntry extends Entry<String> {
public StringEntry(String defaultValue) {
super(defaultValue);
}
@Override
public String fromJson() {
return GsonHelper.getAsString(location, key, defaultValue);
}
@Override
public void toJson(String value) {
this.location.addProperty(key, value);
}
}
public static abstract class ArrayEntry<T> extends Entry<List<T>> {
public ArrayEntry(List<T> defaultValue) {
super(defaultValue);
}
protected abstract T getValue(JsonElement element);
protected abstract void add(JsonArray array, T element);
private JsonArray toArray(List<T> input) {
final JsonArray array = new JsonArray();
input.forEach(s -> add(array, s));
return array;
}
@Override
public List<T> fromJson() {
final JsonArray resArray = GsonHelper.getAsJsonArray(location, key, toArray(defaultValue));
final List<T> res = new ArrayList<>(resArray.size());
resArray.forEach(e -> res.add(getValue(e)));
return res;
}
@Override
public void toJson(List<T> value) {
this.location.add(key, toArray(value));
}
}
public static class StringArrayEntry extends ArrayEntry<String> {
public StringArrayEntry(List<String> defaultValue) {
super(defaultValue);
}
@Override
protected String getValue(JsonElement el) {
return el.getAsString();
}
protected void add(JsonArray array, String el) {
array.add(el);
}
@Override
protected boolean hasDefaultInName() {
return false;
}
}
public static class EnumEntry<T extends Enum<T>> extends Entry<T> {
private final Type type;
public EnumEntry(T defaultValue) {
super(defaultValue);
TypeToken<T> token = new TypeToken<T>() {
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<T extends Comparable<T>> extends Entry<T> {
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<T> {
protected final T defaultValue;
protected Consumer<T> writer;
protected Supplier<T> 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<T> writer) {
this.writer = writer;
}
protected void setReader(Supplier<T> 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);
}
protected boolean hasDefaultInName() {
return true;
}
}
}

View file

@ -0,0 +1,97 @@
package org.betterx.bclib.config;
import net.minecraft.resources.ResourceLocation;
import org.betterx.bclib.util.Pair;
import java.util.Arrays;
import org.jetbrains.annotations.NotNull;
public class ConfigKey {
private final String[] path;
private final String entry;
private final boolean root;
public ConfigKey(String entry, String... path) {
this.validate(entry);
this.path = path;
this.entry = entry;
this.root = path.length == 0 || (path.length == 1 && path[0].isEmpty());
}
public ConfigKey(String entry, ResourceLocation path) {
this(entry, path.getNamespace(), path.getPath());
}
public String[] getPath() {
return path;
}
public String getEntry() {
return entry;
}
public boolean isRoot() {
return root;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(path);
result = prime * result + entry.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ConfigKey)) {
return false;
}
ConfigKey other = (ConfigKey) obj;
if (other.path.length != path.length) {
return false;
}
for (int i = 0; i < path.length; i++) {
if (!path[i].equals(other.path[i])) {
return false;
}
}
return entry.equals(other.entry);
}
@Override
public String toString() {
if (root) {
return String.format("[root]:%s", entry);
}
String p = path[0];
for (int i = 1; i < path.length; i++) {
p += "." + path[i];
}
return String.format("%s:%s", p, entry);
}
private void validate(String entry) {
if (entry == null) {
throw new NullPointerException("Config key must be not null!");
}
if (entry.isEmpty()) {
throw new IndexOutOfBoundsException("Config key must be not empty!");
}
}
public static Pair<String, String> realKey(@NotNull String key) {
String[] parts = key.split("\\[default:", 2);
if (parts.length == 1) {
return new Pair(parts[0].trim(), "");
} else if (parts.length == 2) {
return new Pair(parts[0].trim(), " " + ("[default:" + parts[1]).trim());
}
return new Pair(key, "");
}
}

View file

@ -0,0 +1,25 @@
package org.betterx.bclib.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ConfigUI {
/**
* When {@code true}, this option will not generate UI-Elements.
*/
boolean hide() default false;
/**
* When a Widget is generated for this option, it will be indented by this Value
*/
int leftPadding() default 0;
/**
* When a Widget is generated for this option, it will be indented by this Value
*/
int topPadding() default 0;
}

View file

@ -0,0 +1,72 @@
package org.betterx.bclib.config;
import net.fabricmc.loader.api.FabricLoader;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.betterx.bclib.util.JsonFactory;
import java.io.File;
import java.nio.file.Path;
public class ConfigWriter {
private final static Path GAME_CONFIG_DIR = FabricLoader.getInstance().getConfigDir();
private final File configFile;
private JsonObject configObject;
public ConfigWriter(String modID, String configFile) {
this.configFile = new File(GAME_CONFIG_DIR.resolve(modID).toFile(), configFile + ".json");
File parent = this.configFile.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
this.load();
}
File getConfigFile() {
return this.configFile;
}
public JsonObject getConfig() {
return configObject;
}
public void save() {
if (configObject == null) {
return;
}
save(configFile, configObject);
}
JsonObject reload() {
configObject = load(configFile);
return configObject;
}
public JsonObject load() {
if (configObject == null) {
configObject = load(configFile);
}
return configObject;
}
public void save(JsonElement config) {
this.configObject = config.getAsJsonObject();
save(configFile, config);
}
public static JsonObject load(File configFile) {
return JsonFactory.getJsonObject(configFile);
}
public static void save(File configFile, JsonElement config) {
JsonFactory.storeJson(configFile, config);
}
public static String scrubFileName(String input) {
input = input.replaceAll("[/\\ ]+", "_");
input = input.replaceAll("[,:&\"\\|\\<\\>\\?\\*]", "_");
return input;
}
}

View file

@ -0,0 +1,42 @@
package org.betterx.bclib.config;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.betterx.bclib.BCLib;
import java.util.Collections;
public class Configs {
// Client and Server-Config must be the first entries. They are not part of the Auto-Sync process
// But will be needed by other Auto-Sync Config-Files
@Environment(EnvType.CLIENT)
public static final ClientConfig CLIENT_CONFIG = new ClientConfig();
public static final ServerConfig SERVER_CONFIG = new ServerConfig();
public static final GeneratorConfig GENERATOR_CONFIG = new GeneratorConfig();
public static final MainConfig MAIN_CONFIG = new MainConfig();
public static final PathConfig RECIPE_CONFIG = new PathConfig(BCLib.MOD_ID, "recipes");
public static final PathConfig BIOMES_CONFIG = new PathConfig(BCLib.MOD_ID, "biomes", false);
public static final String MAIN_PATCH_CATEGORY = "patches";
public static void save() {
MAIN_CONFIG.saveChanges();
RECIPE_CONFIG.saveChanges();
GENERATOR_CONFIG.saveChanges();
BIOMES_CONFIG.saveChanges();
}
static {
BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("end_land_biomes", "force_include"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST));
BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("end_void_biomes", "force_include"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST));
BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("nether_biomes", "force_include"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST));
BIOMES_CONFIG.keeper.registerEntry(new ConfigKey("nether_biomes", "force_exclude"),
new ConfigKeeper.StringArrayEntry(Collections.EMPTY_LIST));
}
}

View file

@ -0,0 +1,9 @@
package org.betterx.bclib.config;
public class EntryConfig extends IdConfig {
public EntryConfig(String modID, String group) {
super(modID, group, (id, entry) -> {
return new ConfigKey(entry, id);
});
}
}

View file

@ -0,0 +1,18 @@
package org.betterx.bclib.config;
import org.betterx.bclib.BCLib;
public class GeneratorConfig extends NamedPathConfig {
public static final ConfigToken<Boolean> USE_OLD_GENERATOR = ConfigToken.Boolean(false,
"useOldBiomeGenerator",
"options");
public GeneratorConfig() {
super(BCLib.MOD_ID, "generator", false);
}
public boolean useOldGenerator() {
return get(USE_OLD_GENERATOR);
}
}

View file

@ -0,0 +1,89 @@
package org.betterx.bclib.config;
import net.minecraft.resources.ResourceLocation;
import java.util.function.BiFunction;
import org.jetbrains.annotations.Nullable;
public class IdConfig extends Config {
protected final BiFunction<ResourceLocation, String, ConfigKey> keyFactory;
public IdConfig(String modID, String group, BiFunction<ResourceLocation, String, ConfigKey> keyFactory) {
super(modID, group);
this.keyFactory = keyFactory;
}
@Override
protected void registerEntries() {
}
protected ConfigKey createKey(ResourceLocation id, String key) {
return this.keyFactory.apply(id, key);
}
@Nullable
public <T, E extends ConfigKeeper.Entry<T>> E getEntry(ResourceLocation id, String key, Class<E> type) {
return this.getEntry(createKey(id, key), type);
}
@Nullable
public <T, E extends ConfigKeeper.Entry<T>> T getDefault(ResourceLocation id, String key, Class<E> type) {
return this.getDefault(createKey(id, key), type);
}
public String getString(ResourceLocation id, String key, String defaultValue) {
return this.getString(createKey(id, key), defaultValue);
}
public String getString(ResourceLocation id, String key) {
return this.getString(createKey(id, key));
}
public boolean setString(ResourceLocation id, String key, String value) {
return this.setString(createKey(id, key), value);
}
public int getInt(ResourceLocation id, String key, int defaultValue) {
return this.getInt(createKey(id, key), defaultValue);
}
public int getInt(ResourceLocation id, String key) {
return this.getInt(createKey(id, key));
}
public boolean setInt(ResourceLocation id, String key, int value) {
return this.setInt(createKey(id, key), value);
}
public boolean setRangedInt(ResourceLocation id, String key, int value) {
return this.setRanged(createKey(id, key), value, ConfigKeeper.IntegerRange.class);
}
public boolean setRangedFloat(ResourceLocation id, String key, float value) {
return this.setRanged(createKey(id, key), value, ConfigKeeper.FloatRange.class);
}
public float getFloat(ResourceLocation id, String key, float defaultValue) {
return this.getFloat(createKey(id, key), defaultValue);
}
public float getFloat(ResourceLocation id, String key) {
return this.getFloat(createKey(id, key));
}
public boolean setFloat(ResourceLocation id, String key, float value) {
return this.setFloat(createKey(id, key), value);
}
public boolean getBoolean(ResourceLocation id, String key, boolean defaultValue) {
return this.getBoolean(createKey(id, key), defaultValue);
}
public boolean getBoolean(ResourceLocation id, String key) {
return this.getBoolean(createKey(id, key));
}
public boolean setBoolean(ResourceLocation id, String key, boolean value) {
return this.setBoolean(createKey(id, key), value);
}
}

View file

@ -0,0 +1,28 @@
package org.betterx.bclib.config;
import org.betterx.bclib.BCLib;
public class MainConfig extends NamedPathConfig {
public static final ConfigToken<Boolean> APPLY_PATCHES = ConfigToken.Boolean(true,
"applyPatches",
Configs.MAIN_PATCH_CATEGORY);
@ConfigUI(leftPadding = 8)
public static final ConfigToken<Boolean> REPAIR_BIOMES = DependendConfigToken.Boolean(true,
"repairBiomesOnLoad",
Configs.MAIN_PATCH_CATEGORY,
(config) -> config.get(
APPLY_PATCHES));
public MainConfig() {
super(BCLib.MOD_ID, "main", true, true);
}
public boolean applyPatches() {
return get(APPLY_PATCHES);
}
public boolean repairBiomes() {
return get(REPAIR_BIOMES);
}
}

View file

@ -0,0 +1,270 @@
package org.betterx.bclib.config;
import net.minecraft.resources.ResourceLocation;
import org.betterx.bclib.BCLib;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
public class NamedPathConfig extends PathConfig {
public static class ConfigTokenDescription<T> {
public final ConfigToken<T> token;
public final String internalName;
public final Boolean hidden;
public final int leftPadding;
public final int topPadding;
@SuppressWarnings("unchecked")
ConfigTokenDescription(Field fl) throws IllegalAccessException {
token = (ConfigToken<T>) fl.get(null);
internalName = fl.getName();
ConfigUI ui = fl.getAnnotation(ConfigUI.class);
if (ui != null) {
this.hidden = ui.hide();
leftPadding = ui.leftPadding();
topPadding = ui.topPadding();
} else {
this.hidden = false;
this.leftPadding = 0;
topPadding = 0;
}
}
public String getPath() {
StringBuilder path = new StringBuilder();
for (String p : token.getPath()) {
path.append(".")
.append(p);
}
path.append(".").append(token.getEntry());
return path.toString();
}
}
public static class DependendConfigToken<T> extends ConfigToken<T> {
protected final Predicate<NamedPathConfig> dependenciesTrue;
protected DependendConfigToken(Class<?> type,
T defaultValue,
String entry,
ResourceLocation path,
Predicate<NamedPathConfig> dependenciesTrue) {
this(type, defaultValue, entry, new String[]{path.getNamespace(), path.getPath()}, dependenciesTrue);
}
protected DependendConfigToken(Class<?> type,
T defaultValue,
String entry,
String path,
Predicate<NamedPathConfig> dependenciesTrue) {
super(type, defaultValue, entry, path);
this.dependenciesTrue = dependenciesTrue;
}
protected DependendConfigToken(Class<?> type,
T defaultValue,
String entry,
String[] path,
Predicate<NamedPathConfig> dependenciesTrue) {
super(type, defaultValue, entry, path);
this.dependenciesTrue = dependenciesTrue;
}
public boolean dependenciesTrue(NamedPathConfig config) {
return dependenciesTrue.test(config);
}
public static DependendConfigToken<Boolean> Boolean(boolean defaultValue,
String entry,
String path,
Predicate<NamedPathConfig> dependenciesTrue) {
return new DependendConfigToken<Boolean>(ConfigKeeper.BooleanEntry.class,
defaultValue,
entry,
path,
dependenciesTrue);
}
}
public static class ConfigToken<T> extends ConfigKey {
public final T defaultValue;
public final Class<?> type;
protected ConfigToken(Class<?> type, T defaultValue, String entry, ResourceLocation path) {
this(type, defaultValue, entry, path.getNamespace(), path.getPath());
}
@SuppressWarnings("unchecked")
protected ConfigToken(Class<?> type, T defaultValue, String entry, String... path) {
super(entry, path);
this.defaultValue = defaultValue;
this.type = type;
}
public boolean dependenciesTrue(NamedPathConfig config) {
return true;
}
public static ConfigToken<Boolean> Boolean(boolean defaultValue, String entry, String path) {
return new ConfigToken<Boolean>(ConfigKeeper.BooleanEntry.class, defaultValue, entry, path);
}
public static ConfigToken<Integer> Int(int defaultValue, String entry, String path) {
return new ConfigToken<Integer>(ConfigKeeper.IntegerEntry.class, defaultValue, entry, path);
}
public static ConfigToken<Float> Float(float defaultValue, String entry, String path) {
return new ConfigToken<Float>(ConfigKeeper.FloatEntry.class, defaultValue, entry, path);
}
public static ConfigToken<String> String(String defaultValue, String entry, String path) {
return new ConfigToken<String>(ConfigKeeper.StringEntry.class, defaultValue, entry, path);
}
public static ConfigToken<List<String>> StringArray(List<String> defaultValue, String entry, String path) {
return new ConfigToken<List<String>>(ConfigKeeper.StringArrayEntry.class, defaultValue, entry, path);
}
}
public NamedPathConfig(String modID, String group, boolean autoSync, boolean diffContent) {
super(modID, group, autoSync, diffContent);
onInit();
}
public NamedPathConfig(String modID, String group, boolean autoSync) {
super(modID, group, autoSync);
onInit();
}
public NamedPathConfig(String modID, String group) {
super(modID, group);
onInit();
}
public List<ConfigTokenDescription<?>> getAllOptions() {
List<ConfigTokenDescription<?>> res = new LinkedList<>();
for (Field fl : this.getClass().getDeclaredFields()) {
int modifiers = fl.getModifiers();
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && ConfigToken.class.isAssignableFrom(fl.getType())) {
try {
res.add(new ConfigTokenDescription<>(fl));
} catch (IllegalAccessException e) {
BCLib.LOGGER.error("Could not access " + fl);
}
}
}
return res;
}
protected void onInit() {
getAllOptions().forEach(e -> get(e.token));
this.saveChanges();
}
/**
* The value without any check of {@link DependendConfigToken}
* <p>
* In most cases you probably want to use {@link #get(ConfigToken)}, we use this Method if we
* present the actual value of the Settings from the Config File without any additional processing.
*
* @param what The Option you want to get
* @param <T> The Type of the Option
* @return The Value of the Option (without checking the {@link DependendConfigToken}):
*/
public <T> T getRaw(ConfigToken<T> what) {
return _get(what, true);
}
/**
* The value of an Option
*
* @param what he Option you want to get
* @param <T> The Type of the Option
* @return The Value of the Option. If this option is a {@link DependendConfigToken}, the returned value
* may not be the value from the config File. For Example, on a {@link Boolean}-Type the result is always false
* if {@link DependendConfigToken#dependenciesTrue} returns {@code false}.
*/
public <T> T get(ConfigToken<T> what) {
return _get(what, false);
}
@SuppressWarnings("unchecked")
private <T> T _get(ConfigToken<T> what, boolean raw) {
//TODO: Check if we can make config fully Generic to avoid runtime type checks...
if (ConfigKeeper.BooleanEntry.class.isAssignableFrom(what.type)) {
return (T) _getBoolean((ConfigToken<Boolean>) what, raw);
}
if (ConfigKeeper.IntegerEntry.class.isAssignableFrom(what.type)) {
return (T) _getInt((ConfigToken<Integer>) what);
}
if (ConfigKeeper.FloatEntry.class.isAssignableFrom(what.type)) {
return (T) _getFloat((ConfigToken<Float>) what);
}
if (ConfigKeeper.StringEntry.class.isAssignableFrom(what.type)) {
return (T) _getString((ConfigToken<String>) what);
}
if (ConfigKeeper.StringArrayEntry.class.isAssignableFrom(what.type)) {
return (T) _getStringArray((ConfigToken<List<String>>) what);
}
return this._get(what);
}
private <T> T _get(ConfigToken<T> what) {
BCLib.LOGGER.error(what + " has unsupported Type.");
return what.defaultValue;
}
public void set(ConfigToken<Boolean> what, boolean value) {
this.setBoolean(what, value);
}
private Boolean _getBoolean(ConfigToken<Boolean> what, boolean raw) {
if (!raw && !what.dependenciesTrue(this)) {
return false;
}
return this.getBoolean(what, what.defaultValue);
}
public void set(ConfigToken<Integer> what, int value) {
this.setInt(what, value);
}
private Integer _getInt(ConfigToken<Integer> what) {
return this.getInt(what, what.defaultValue);
}
public void set(ConfigToken<Float> what, float value) {
this.setFloat(what, value);
}
private Float _getFloat(ConfigToken<Float> what) {
return this.getFloat(what, what.defaultValue);
}
public void set(ConfigToken<String> what, String value) {
this.setString(what, value);
}
private String _getString(ConfigToken<String> what) {
return this.getString(what, what.defaultValue);
}
public void set(ConfigToken<List<String>> what, List<String> value) {
this.setStringArray(what, value);
}
private List<String> _getStringArray(ConfigToken<List<String>> what) {
return this.getStringArray(what, what.defaultValue);
}
}

View file

@ -0,0 +1,166 @@
package org.betterx.bclib.config;
import java.util.List;
import org.jetbrains.annotations.Nullable;
public class PathConfig extends Config {
public PathConfig(String modID, String group, boolean autoSync, boolean diffContent) {
super(modID, group, autoSync, diffContent);
}
public PathConfig(String modID, String group, boolean autoSync) {
super(modID, group, autoSync);
}
public PathConfig(String modID, String group) {
super(modID, group);
}
@Override
protected void registerEntries() {
}
protected static ConfigKey createKey(String category, String key) {
return new ConfigKey(key, category.split("\\."));
}
protected static ConfigKey createKey(String key) {
return createKey("", key);
}
@Nullable
public <T, E extends ConfigKeeper.Entry<T>> E getEntry(String category, String key, Class<E> type) {
return this.getEntry(createKey(category, key), type);
}
@Nullable
public <T, E extends ConfigKeeper.Entry<T>> T getDefault(String category, String key, Class<E> type) {
return this.getDefault(createKey(category, key), type);
}
public String getString(String category, String key, String defaultValue) {
return this.getString(createKey(category, key), defaultValue);
}
public String getString(String category, String key) {
return this.getString(createKey(category, key));
}
public boolean setString(String category, String key, String value) {
return this.setString(createKey(category, key), value);
}
public int getInt(String category, String key, int defaultValue) {
return this.getInt(createKey(category, key), defaultValue);
}
public int getInt(String category, String key) {
return this.getInt(createKey(category, key));
}
public boolean setInt(String category, String key, int value) {
return this.setInt(createKey(category, key), value);
}
public boolean setRangedInt(String category, String key, int value) {
return this.setRanged(createKey(category, key), value, ConfigKeeper.IntegerRange.class);
}
public boolean setRangedFloat(String category, String key, float value) {
return this.setRanged(createKey(category, key), value, ConfigKeeper.FloatRange.class);
}
public float getFloat(String category, String key, float defaultValue) {
return this.getFloat(createKey(category, key), defaultValue);
}
public float getFloat(String category, String key) {
return this.getFloat(createKey(category, key));
}
public boolean setFloat(String category, String key, float value) {
return this.setFloat(createKey(category, key), value);
}
public boolean getBoolean(String category, String key, boolean defaultValue) {
return this.getBoolean(createKey(category, key), defaultValue);
}
public boolean getBoolean(String category, String key) {
return this.getBoolean(createKey(category, key));
}
public boolean setBoolean(String category, String key, boolean value) {
return this.setBoolean(createKey(category, key), value);
}
public List<String> getStringArray(String category, String key, List<String> defaultValue) {
return this.getStringArray(createKey(category, key), defaultValue);
}
public List<String> getStringArray(String category, String key) {
return this.getStringArray(createKey(category, key));
}
public boolean setStringArray(String category, String key, List<String> value) {
return this.setStringArray(createKey(category, key), value);
}
// From Root
public String getStringRoot(String key, String defaultValue) {
return this.getString(createKey(key), defaultValue);
}
public String getStringRoot(String key) {
return this.getString(createKey(key));
}
public boolean setStringRoot(String key, String value) {
return this.setString(createKey(key), value);
}
public int getIntRoot(String key, int defaultValue) {
return this.getInt(createKey(key), defaultValue);
}
public int getIntRoot(String key) {
return this.getInt(createKey(key));
}
public boolean setIntRoot(String key, int value) {
return this.setInt(createKey(key), value);
}
public boolean setRangedIntRoot(String key, int value) {
return this.setRanged(createKey(key), value, ConfigKeeper.IntegerRange.class);
}
public boolean setRangedFloatRoot(String key, float value) {
return this.setRanged(createKey(key), value, ConfigKeeper.FloatRange.class);
}
public float getFloatRoot(String key, float defaultValue) {
return this.getFloat(createKey(key), defaultValue);
}
public float getFloatRoot(String key) {
return this.getFloat(createKey(key));
}
public boolean setFloatRoot(String key, float value) {
return this.setFloat(createKey(key), value);
}
public boolean getBooleanRoot(String key, boolean defaultValue) {
return this.getBoolean(createKey(key), defaultValue);
}
public boolean getBooleanRoot(String key) {
return this.getBoolean(createKey(key));
}
public boolean setBooleanRoot(String key, boolean value) {
return this.setBoolean(createKey(key), value);
}
}

View file

@ -0,0 +1,74 @@
package org.betterx.bclib.config;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.dataexchange.handler.autosync.AutoSync;
import java.util.ArrayList;
import java.util.List;
public class ServerConfig extends NamedPathConfig {
public static final ConfigToken<Boolean> ENABLED = ConfigToken.Boolean(true, "enabled", AutoSync.SYNC_CATEGORY);
public static final DependendConfigToken<Boolean> OFFER_CONFIGS = DependendConfigToken.Boolean(true,
"offerConfigs",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
public static final DependendConfigToken<Boolean> OFFER_FILES = DependendConfigToken.Boolean(true,
"offerFiles",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
public static final DependendConfigToken<Boolean> OFFER_MODS = DependendConfigToken.Boolean(true,
"offerMods",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
public static final DependendConfigToken<Boolean> OFFER_ALL_MODS = DependendConfigToken.Boolean(false,
"offerAllMods",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
OFFER_MODS));
public static final DependendConfigToken<Boolean> SEND_ALL_MOD_INFO = DependendConfigToken.Boolean(false,
"sendAllModInfo",
AutoSync.SYNC_CATEGORY,
(config) -> config.get(
ENABLED));
public static final ConfigToken<List<String>> ADDITIONAL_MODS = ConfigToken.StringArray(new ArrayList<>(0),
"additionalMods",
AutoSync.SYNC_CATEGORY);
public static final ConfigToken<List<String>> EXCLUDED_MODS = ConfigToken.StringArray(new ArrayList<>(0),
"excludeMods",
AutoSync.SYNC_CATEGORY);
public ServerConfig() {
super(BCLib.MOD_ID, "server", false);
}
public boolean isAllowingAutoSync() {
return get(ENABLED);
}
public boolean isOfferingConfigs() {
return get(OFFER_CONFIGS) /*&& isAllowingAutoSync()*/;
}
public boolean isOfferingFiles() {
return get(OFFER_FILES) /*&& isAllowingAutoSync()*/;
}
public boolean isOfferingMods() {
return get(OFFER_MODS) /*&& isAllowingAutoSync()*/;
}
public boolean isOfferingAllMods() {
return get(OFFER_ALL_MODS) /*&& isAllowingAutoSync()*/;
}
public boolean isOfferingInfosForMods() {
return get(SEND_ALL_MOD_INFO) /*&& isAllowingAutoSync()*/;
}
}