From 68a3bf2d54c6cfc663c18849f3a7d156c5a7dac4 Mon Sep 17 00:00:00 2001 From: JFronny Date: Thu, 10 Jun 2021 13:10:12 +0200 Subject: [PATCH] Rewrite part 1 (doesn't work yet) --- build.gradle | 5 +- .../lumi/assets/respackopts/conf.json | 1 - .../jfronny/respackopts/GuiFactory.java | 189 +++++------------- .../jfronny/respackopts/Respackopts.java | 146 +++++--------- .../jfronny/respackopts/data/Config.java | 9 - .../respackopts/data/ConfigBooleanEntry.java | 7 + .../respackopts/data/ConfigBranch.java | 132 ++++++++++++ .../respackopts/data/ConfigEnumEntry.java | 12 ++ .../respackopts/data/ConfigNumericEntry.java | 10 + .../jfronny/respackopts/data/Entry.java | 7 + .../jfronny/respackopts/data/Respackmeta.java | 9 - .../respackopts/data/in/LegacyConfig.java | 8 + .../respackopts/data/in/Respackmeta.java | 9 + .../respackopts/data/{ => in}/Rpo.java | 2 +- .../conditions/ConditionEvaluator.java | 23 +-- .../conditions/ResourcePackFilter.java | 12 +- .../filters/fallback/FallbackFilter.java | 20 +- .../gson/BooleanEntrySerializer.java | 18 ++ .../gson/ConfigBranchSerializer.java | 54 +++++ .../respackopts/gson/EnumEntrySerializer.java | 43 ++++ .../gson/LegacyConfigDeserializer.java | 49 +++++ .../gson/NumericEntrySerializer.java | 54 +++++ .../respackopts/integration/FrexCompat.java | 50 ++--- .../integration/ModMenuCompat.java | 1 - .../mixin/ResourcePackEntryMixin.java | 19 +- .../mixin/ResourcePackManagerMixin.java | 125 ++---------- .../DirectoryResourcePackMixin.java | 8 +- .../conditions/ZipResourcePackMixin.java | 8 +- 28 files changed, 582 insertions(+), 448 deletions(-) delete mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/Config.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBooleanEntry.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBranch.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/ConfigEnumEntry.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/ConfigNumericEntry.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/Entry.java delete mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/Respackmeta.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/in/LegacyConfig.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/data/in/Respackmeta.java rename src/main/java/io/gitlab/jfronny/respackopts/data/{ => in}/Rpo.java (76%) create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/gson/BooleanEntrySerializer.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigBranchSerializer.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/gson/EnumEntrySerializer.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/gson/LegacyConfigDeserializer.java create mode 100644 src/main/java/io/gitlab/jfronny/respackopts/gson/NumericEntrySerializer.java diff --git a/build.gradle b/build.gradle index 7c4ac40..d8fa519 100644 --- a/build.gradle +++ b/build.gradle @@ -4,9 +4,8 @@ repositories { maven { url = "https://maven.terraformersmc.com/"; name = "ModMenu" } maven { url = "https://maven.shedaniel.me/"; name = "Cloth Config" } maven { url = "https://maven.dblsaiko.net/"; name = "Canvas" } + maven { url = 'https://server.bbkr.space/artifactory/libs-release'; name = "Required for canvas" } maven { url = "https://minecraft.curseforge.com/api/maven"; name = "CurseForge (for canvas)" } - maven { url = 'https://server.bbkr.space/artifactory/libs-release'; name = "LibCD" } - jcenter(); } dependencies { @@ -20,7 +19,7 @@ dependencies { modImplementation "com.terraformersmc:modmenu:2.0.0-beta.7" - modApi("me.shedaniel.cloth:cloth-config-fabric:5.+") + modApi("me.shedaniel.cloth:cloth-config-fabric:5.0.34") modImplementation("grondag:canvas-mc117-1.17:+") { exclude(group: "me.shedaniel.cloth") } diff --git a/run/resourcepacks/lumi/assets/respackopts/conf.json b/run/resourcepacks/lumi/assets/respackopts/conf.json index 0b4acda..54a8203 100644 --- a/run/resourcepacks/lumi/assets/respackopts/conf.json +++ b/run/resourcepacks/lumi/assets/respackopts/conf.json @@ -14,7 +14,6 @@ "viewDir" ], "waterVertexWavy": false, - "stringTest": "this is a string", "numTest": 15.4, "subcategoryTest": { "thisIsCool": true, diff --git a/src/main/java/io/gitlab/jfronny/respackopts/GuiFactory.java b/src/main/java/io/gitlab/jfronny/respackopts/GuiFactory.java index a56dd82..03b8701 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/GuiFactory.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/GuiFactory.java @@ -1,11 +1,9 @@ package io.gitlab.jfronny.respackopts; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; import io.gitlab.jfronny.respackopts.abstractions.JfConfigCategory; import io.gitlab.jfronny.respackopts.abstractions.JfConfigCategoryPrimary; import io.gitlab.jfronny.respackopts.abstractions.JfConfigCategorySub; +import io.gitlab.jfronny.respackopts.data.*; import me.shedaniel.clothconfig2.api.ConfigBuilder; import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; @@ -17,146 +15,71 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.*; import net.minecraft.util.Language; -import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.Set; +//TODO fix enums always showing "reset" +//TODO fix booleans and enums not properly loading public class GuiFactory { - public void buildCategory(JsonObject source, String screenId, JfConfigCategory config, ConfigEntryBuilder entryBuilder, String namePrefix) { - if (!Respackopts.boolVals.containsKey(screenId)) - Respackopts.boolVals.put(screenId, new HashMap<>()); - if (!Respackopts.numVals.containsKey(screenId)) - Respackopts.numVals.put(screenId, new HashMap<>()); - if (!Respackopts.strVals.containsKey(screenId)) - Respackopts.strVals.put(screenId, new HashMap<>()); - if (!Respackopts.enumKeys.containsKey(screenId)) - Respackopts.enumKeys.put(screenId, new HashMap<>()); + public void buildCategory(ConfigBranch source, String screenId, JfConfigCategory config, ConfigEntryBuilder entryBuilder, String namePrefix) { String b = "respackopts.field." + screenId; - for (Map.Entry entry : source.entrySet()) { - String n = ("".equals(namePrefix) ? "" : namePrefix + ".") + entry.getKey(); - JsonElement e = entry.getValue(); - if (e.isJsonPrimitive()) { - JsonPrimitive p = e.getAsJsonPrimitive(); - if (p.isBoolean()) { - boolean defaultValue = p.getAsBoolean(); - boolean currentValue = defaultValue; - if (Respackopts.boolVals.get(screenId).containsKey(n)) - currentValue = Respackopts.boolVals.get(screenId).get(n); - else - Respackopts.boolVals.get(screenId).put(n, defaultValue); - config.addEntry(entryBuilder.startBooleanToggle(getText(n, b), currentValue) - .setDefaultValue(defaultValue) - .setSaveConsumer(v -> Respackopts.boolVals.get(screenId).put(n, v)) - .setTooltipSupplier(() -> getTooltip(n, screenId)) - .build()); - } - else if (p.isNumber()) { - double defaultValue = p.getAsDouble(); - Double currentValue = defaultValue; - if (Respackopts.numVals.get(screenId).containsKey(n)) - currentValue = Respackopts.numVals.get(screenId).get(n); - else - Respackopts.numVals.get(screenId).put(n, defaultValue); - config.addEntry(entryBuilder.startDoubleField(getText(n, b), currentValue) - .setDefaultValue(defaultValue) - .setSaveConsumer(v -> Respackopts.numVals.get(screenId).put(n, v)) - .setTooltipSupplier(() -> getTooltip(n, screenId)) - .build()); - } - else if (p.isString()) { - String defaultValue = p.getAsString(); - String currentValue = defaultValue; - if (Respackopts.strVals.get(screenId).containsKey(n)) - currentValue = Respackopts.strVals.get(screenId).get(n); - else - Respackopts.strVals.get(screenId).put(n, defaultValue); - config.addEntry(entryBuilder.startStrField(getText(n, b), currentValue) - .setDefaultValue(defaultValue) - .setSaveConsumer(v -> Respackopts.strVals.get(screenId).put(n, v)) - .setTooltipSupplier(() -> getTooltip(n, screenId)) - .build()); - } + for (Map.Entry> in : source.getEntries()) { + Entry entry = in.getValue(); + String n = ("".equals(namePrefix) ? "" : namePrefix + ".") + in.getKey(); + if (entry instanceof ConfigBranch e) { + SubCategoryBuilder sc = entryBuilder.startSubCategory(getText(n, "respackopts.title." + screenId)); + buildCategory(e, screenId, new JfConfigCategorySub(sc), entryBuilder, n); + sc.setTooltipSupplier(() -> getTooltip(n, screenId)); + config.addEntry(sc.build()); } - else if (e.isJsonArray()) { - Set ev = Respackopts.enumKeys.get(screenId).get(n); - Double c = Respackopts.numVals.get(screenId).get(n); - String sel = ""; - String def = ""; - int i = 0; - for (String s1 : ev) { - if (i == 0) def = s1; - if (c.intValue() == i) sel = s1; - i++; - } - config.addEntry(entryBuilder.startDropdownMenu(getText(n, b), (DropdownBoxEntry.SelectionTopCellElement) DropdownMenuBuilder.TopCellElementBuilder.of(sel, (s) -> s, (s) -> new LiteralText(s)), new DropdownBoxEntry.DefaultSelectionCellCreator()) - .setSuggestionMode(false) - .setDefaultValue(def) - .setSelections(() -> ev.iterator()) + else if (entry instanceof ConfigBooleanEntry e) { + config.addEntry(entryBuilder.startBooleanToggle(getText(n, b), e.value) + .setDefaultValue(e.defaultValue) .setSaveConsumer(v -> { - int j = 0; - for (String s1 : ev) { - if (s1.equals(v)) - Respackopts.numVals.get(screenId).put(n, (double) j); - j++; - } + /*ConfigBooleanEntry cb = (ConfigBooleanEntry)source.get(e.name); + cb.value = v; + Respackopts.LOGGER.info(cb == e); + Respackopts.LOGGER.info(cb == entry);*/ + e.value = v; }) .setTooltipSupplier(() -> getTooltip(n, screenId)) .build()); } - else if (e.isJsonNull()) { - Respackopts.logger.error("Config definition contains null, skipping that entry"); - } - else if (e.isJsonObject()) { - JsonObject data = e.getAsJsonObject(); - //Slider - if (data.entrySet().stream().allMatch(s -> "default".equals(s.getKey()) || "min".equals(s.getKey()) || "max".equals(s.getKey()))) - { - JsonElement def = data.get("default"); - JsonElement min = data.get("min"); - JsonElement max = data.get("max"); - if (def.isJsonPrimitive() && def.getAsJsonPrimitive().isNumber() - && min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber() - && max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) { - Double defV = def.getAsNumber().doubleValue(); - Double minV = min.getAsNumber().doubleValue(); - Double maxV = max.getAsNumber().doubleValue(); - if (defV < minV || defV > maxV) { - Respackopts.logger.error("default value out of range"); - } - else if (isWhole(defV) && isWhole(minV) && isWhole(maxV)) { - Double currentValue = defV; - if (Respackopts.numVals.get(screenId).containsKey(n)) - currentValue = Respackopts.numVals.get(screenId).get(n); - else Respackopts.numVals.get(screenId).put(n, defV); - if (currentValue < minV) - currentValue = minV; - if (currentValue > maxV) - currentValue = maxV; - config.addEntry(entryBuilder.startIntSlider(getText(n, b), - currentValue.intValue(), minV.intValue(), maxV.intValue()) - .setDefaultValue(defV.intValue()) - .setSaveConsumer(v -> Respackopts.numVals.get(screenId).put(n, v.doubleValue())) - .setTooltipSupplier(() -> getTooltip(n, screenId)) - .build()); - } - else { - Respackopts.logger.error("Expected whole number in slider definition"); - } - } - else { - Respackopts.logger.error("Expected numeric values in slider definition"); - } - continue; + else if (entry instanceof ConfigEnumEntry e) { + String selected = ""; + String def = ""; + for (Map.Entry en : e.values.entrySet()) { + if (en.getValue().equals(e.value)) + selected = en.getKey(); + if (en.getValue().equals(e.defaultValue)) + def = en.getKey(); } - //Normal object - SubCategoryBuilder sc = entryBuilder.startSubCategory(getText(n, "respackopts.title." + screenId)); - buildCategory(data, screenId, new JfConfigCategorySub(sc), entryBuilder, n); - sc.setTooltipSupplier(() -> getTooltip(n, screenId)); - config.addEntry(sc.build()); + config.addEntry(entryBuilder.startDropdownMenu(getText(n, b), + DropdownMenuBuilder.TopCellElementBuilder.of(selected, LiteralText::new), + new DropdownBoxEntry.DefaultSelectionCellCreator()) + .setSuggestionMode(false) + .setDefaultValue(def) + .setSelections(() -> e.values.keySet().iterator()) + .setSaveConsumer(v -> e.value = e.values.get(v)) + .setTooltipSupplier(() -> getTooltip(n, screenId)) + .build()); } - else { - Respackopts.logger.error("Unsupported non-primitive datatype"); + else if (entry instanceof ConfigNumericEntry e) { + if (e.min != null && e.max != null) { + config.addEntry(entryBuilder.startIntSlider(getText(n, b), + e.value.intValue(), e.min.intValue(), e.max.intValue()) + .setDefaultValue(e.defaultValue.intValue()) + .setSaveConsumer(v -> e.value = v.doubleValue()) + .setTooltipSupplier(() -> getTooltip(n, screenId)) + .build()); + } + else { + config.addEntry(entryBuilder.startDoubleField(getText(n, b), e.value) + .setDefaultValue(e.defaultValue) + .setSaveConsumer(v -> e.value = v) + .setTooltipSupplier(() -> getTooltip(n, screenId)) + .build()); + } } } } @@ -172,11 +95,7 @@ public class GuiFactory { return Optional.empty(); } - private boolean isWhole(double v) { - return v == Math.floor(v) && !Double.isInfinite(v); - } - - public Screen buildGui(JsonObject source, String resourcepackid, Screen parent, Runnable onSave) { + public Screen buildGui(ConfigBranch source, String resourcepackid, Screen parent, Runnable onSave) { try { ConfigBuilder builder; builder = ConfigBuilder.create() diff --git a/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java b/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java index 7b06fc3..9d99353 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/Respackopts.java @@ -1,13 +1,23 @@ package io.gitlab.jfronny.respackopts; import com.google.gson.Gson; -import com.google.gson.JsonObject; -import io.gitlab.jfronny.respackopts.data.Config; -import io.gitlab.jfronny.respackopts.data.Respackmeta; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import io.gitlab.jfronny.respackopts.data.ConfigBooleanEntry; +import io.gitlab.jfronny.respackopts.data.ConfigBranch; +import io.gitlab.jfronny.respackopts.data.ConfigEnumEntry; +import io.gitlab.jfronny.respackopts.data.ConfigNumericEntry; +import io.gitlab.jfronny.respackopts.data.in.Respackmeta; +import io.gitlab.jfronny.respackopts.filters.conditions.SyntaxError; +import io.gitlab.jfronny.respackopts.gson.BooleanEntrySerializer; +import io.gitlab.jfronny.respackopts.gson.ConfigBranchSerializer; +import io.gitlab.jfronny.respackopts.gson.EnumEntrySerializer; +import io.gitlab.jfronny.respackopts.gson.NumericEntrySerializer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.util.Identifier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -18,118 +28,72 @@ import java.util.*; @Environment(EnvType.CLIENT) public class Respackopts implements ClientModInitializer { - public static Map> boolVals; - public static Map> numVals; - public static Map> strVals; - public static Map>> enumKeys; - public static Gson g = new Gson(); - public static GuiFactory factory = new GuiFactory(); - public static final Integer metaVersion = 1; - public static Map resPackMetas = new HashMap<>(); + public static final Integer META_VERSION = 1; public static final String ID = "respackopts"; - static final Path p = FabricLoader.getInstance().getConfigDir().resolve("respackopts"); - public static final Set saveActions = new HashSet<>(); - public static final String fileExtension = ".rpo"; + public static final Identifier CONF_ID = new Identifier(ID, "conf.json"); + public static final Logger LOGGER = LogManager.getFormatterLogger(ID); + private static final Path CONF_DIR = FabricLoader.getInstance().getConfigDir().resolve(ID); + public static final String FILE_EXTENSION = ".rpo"; + public static final Set SAVE_ACTIONS = new HashSet<>(); + + public static final Map CONFIG_BRANCH = new HashMap<>(); + + public static final Gson GSON; + public static GuiFactory factory = new GuiFactory(); + public static Map resPackMetas = new HashMap<>(); public static boolean forceRespackReload = false; - public static final Logger logger = LogManager.getFormatterLogger(ID); + + static { + GSON = new GsonBuilder() + .registerTypeAdapter(ConfigEnumEntry.class, new EnumEntrySerializer()) + .registerTypeAdapter(ConfigNumericEntry.class, new NumericEntrySerializer()) + .registerTypeAdapter(ConfigBooleanEntry.class, new BooleanEntrySerializer()) + .registerTypeAdapter(ConfigBranch.class, new ConfigBranchSerializer()) + .setPrettyPrinting() + .create(); + } + @Override public void onInitializeClient() { try { - Files.createDirectories(p); + Files.createDirectories(CONF_DIR); } catch (IOException e) { - e.printStackTrace(); + Respackopts.LOGGER.error(e); } - if (boolVals == null) - boolVals = new HashMap<>(); - if (numVals == null) - numVals = new HashMap<>(); - if (strVals == null) - strVals = new HashMap<>(); - if (enumKeys == null) - enumKeys = new HashMap<>(); if (FabricLoader.getInstance().isDevelopmentEnvironment()) - saveActions.add(() -> logger.info("Save")); + SAVE_ACTIONS.add(() -> LOGGER.info("Save")); } public static void save() { for (String s : resPackMetas.keySet()) { s = resPackMetas.get(s).id; - Config cfg = new Config(); - if (boolVals.containsKey(s)) - { - cfg.bools = new JsonObject(); - for (Map.Entry entry : boolVals.get(s).entrySet()) { - cfg.bools.addProperty(entry.getKey(), entry.getValue()); - } - } - if (numVals.containsKey(s)) - { - cfg.doubles = new JsonObject(); - for (Map.Entry entry : numVals.get(s).entrySet()) { - cfg.doubles.addProperty(entry.getKey(), entry.getValue()); - } - } - if (strVals.containsKey(s)) - { - cfg.strings = new JsonObject(); - for (Map.Entry entry : strVals.get(s).entrySet()) { - cfg.strings.addProperty(entry.getKey(), entry.getValue()); - } - } - try { - Writer writer = Files.newBufferedWriter(p.resolve(s + ".json")); - g.toJson(cfg, writer); + try (Writer writer = Files.newBufferedWriter(CONF_DIR.resolve(s + ".json"))) { + GSON.toJson(CONFIG_BRANCH.get(s), writer); writer.flush(); - writer.close(); } catch (IOException e) { - e.printStackTrace(); + Respackopts.LOGGER.error(e); } } - for (Runnable action : saveActions) { + for (Runnable action : SAVE_ACTIONS) { action.run(); } } public static void load(String id) { - Path q = p.resolve(id + ".json"); + Path q = CONF_DIR.resolve(id + ".json"); if (Files.exists(q)) { - try { - Reader reader = Files.newBufferedReader(q); - Config c = g.fromJson(reader, Config.class); - reader.close(); - if (c.bools != null) { - boolVals.get(id).forEach((i, val) -> { - if (c.bools.has(i) - && c.bools.get(i).isJsonPrimitive() - && c.bools.get(i).getAsJsonPrimitive().isBoolean()) { - boolVals.get(id).put(i, c.bools.get(i).getAsBoolean()); - } else if (FabricLoader.getInstance().isDevelopmentEnvironment()) - Respackopts.logger.error("Could not find bool " + i + " in " + id); - }); - } - if (c.doubles != null) { - numVals.get(id).forEach((i, val) -> { - if (c.doubles.has(i) - && c.doubles.get(i).isJsonPrimitive() - && c.doubles.get(i).getAsJsonPrimitive().isNumber()) { - numVals.get(id).put(i, c.doubles.get(i).getAsNumber().doubleValue()); - } else if (FabricLoader.getInstance().isDevelopmentEnvironment()) - Respackopts.logger.error("Could not find num " + i + " in " + id); - }); - } - if (c.strings != null) { - strVals.get(id).forEach((i, val) -> { - if (c.strings.has(i) - && c.strings.get(i).isJsonPrimitive() - && c.strings.get(i).getAsJsonPrimitive().isString()) { - strVals.get(id).put(i, c.strings.get(i).getAsString()); - } else if (FabricLoader.getInstance().isDevelopmentEnvironment()) - Respackopts.logger.error("Could not find str " + i + " in " + id); - }); - } - } catch (IOException e) { - e.printStackTrace(); + try (Reader reader = Files.newBufferedReader(q)) { + ConfigBranch b = GSON.fromJson(reader, ConfigBranch.class); + if (CONFIG_BRANCH.containsKey(id)) + CONFIG_BRANCH.get(id).loadValues(b, false); + else + CONFIG_BRANCH.put(id, b); + } catch (IOException | SyntaxError e) { + LOGGER.error("Failed to load " + id, e); } } + /*if ("lumi".equals(id)) { + LOGGER.info("w" + CONFIG_BRANCH.get(id).subClasses.get("subcategoryTest").booleanEntries.get("enableLangJokeFallback").value); + }*/ } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/Config.java b/src/main/java/io/gitlab/jfronny/respackopts/data/Config.java deleted file mode 100644 index 1f55ace..0000000 --- a/src/main/java/io/gitlab/jfronny/respackopts/data/Config.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.gitlab.jfronny.respackopts.data; - -import com.google.gson.JsonObject; - -public class Config { - public JsonObject bools; - public JsonObject doubles; - public JsonObject strings; -} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBooleanEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBooleanEntry.java new file mode 100644 index 0000000..eb1b456 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBooleanEntry.java @@ -0,0 +1,7 @@ +package io.gitlab.jfronny.respackopts.data; + +public class ConfigBooleanEntry extends Entry { + public ConfigBooleanEntry(boolean v) { + value = v; + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBranch.java b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBranch.java new file mode 100644 index 0000000..b3882dc --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigBranch.java @@ -0,0 +1,132 @@ +package io.gitlab.jfronny.respackopts.data; + +import io.gitlab.jfronny.respackopts.filters.conditions.SyntaxError; + +import java.io.InvalidClassException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class ConfigBranch extends Entry { + private final Map> entries = new HashMap<>(); + + public boolean getBoolean(String name) throws SyntaxError { + String[] sp = name.split("\\."); + if (!entries.containsKey(sp[0])) + throw new SyntaxError("Invalid path to key"); + Entry e = entries.get(sp[0]); + if (sp.length == 1) { + if (e instanceof ConfigBooleanEntry b) + return b.value; + throw new SyntaxError("Not a boolean"); + } + if (sp.length == 2 && e instanceof ConfigEnumEntry en) { + for (Map.Entry entry : en.values.entrySet()) { + if (entry.getKey().equals(sp[1])) + return entry.getValue().equals(en.value); + } + throw new SyntaxError("Could not find enum entry"); + } + if (e instanceof ConfigBranch b) + return b.getBoolean(name.substring(name.indexOf('.') + 1)); + throw new SyntaxError("Invalid path to key"); + } + + public void loadValues(ConfigBranch newBranch, boolean additionOnly) throws SyntaxError { + for (Map.Entry> e : newBranch.entries.entrySet()) { + if (!entries.containsKey(e.getKey())) + add(e.getKey(), e.getValue()); + else if (!additionOnly) { + if (e.getValue() instanceof ConfigEnumEntry ne) { + ConfigEnumEntry ol = (ConfigEnumEntry)entries.get(e.getKey()); + if (ne.value != null) + ol.value = ne.value; + if (ne.values != null && !ne.values.isEmpty()) + ol.values = ne.values; + } + else if (e.getValue() instanceof ConfigBooleanEntry ne) { + ConfigBooleanEntry ol = (ConfigBooleanEntry)entries.get(e.getKey()); + if (ne.value != null) + ol.value = ne.value; + } + else if (e.getValue() instanceof ConfigNumericEntry ne) { + ConfigNumericEntry ol = (ConfigNumericEntry)entries.get(e.getKey()); + if (ne.value != null) + ol.value = ne.value; + if (ne.min != null) + ol.min = ne.min; + if (ne.max != null) + ol.max = ne.max; + } + else if (e.getValue() instanceof ConfigBranch ne) { + ConfigBranch ol = (ConfigBranch)entries.get(e.getKey()); + ol.loadValues(ne, false); + } + else { + throw new SyntaxError("Invalid type"); + } + } + } + } + + public , T2> T add(String name, T val) { + val.name = name; + val.defaultValue = val.value; + entries.put(name, val); + return val; + } + + public Entry get(String key) { + return entries.get(key); + } + + public boolean has(String key) { + return entries.containsKey(key); + } + + public Set>> getEntries() { + return entries.entrySet(); + } + + public void buildShader(StringBuilder sb, String valuePrefix) throws SyntaxError { + for (Map.Entry> e : entries.entrySet()) { + if (e.getValue() instanceof ConfigNumericEntry n) { + sb.append("\n#define "); + sb.append(valuePrefix); + sb.append(e.getKey()); + sb.append(' '); + sb.append(n.value.toString()); + } + else if (e.getValue() instanceof ConfigBooleanEntry n) { + if (n.value) { + sb.append("\n#define "); + sb.append(valuePrefix); + sb.append(e.getKey()); + } + } + else if (e.getValue() instanceof ConfigEnumEntry n) { + sb.append("\n#define "); + sb.append(valuePrefix); + sb.append(e.getKey()); + sb.append(' '); + sb.append(n.value.toString()); + for (Map.Entry e2 : n.values.entrySet()) { + sb.append("\n#define "); + sb.append(valuePrefix); + sb.append(e.getKey()); + sb.append('_'); + sb.append(e2.getKey()); + sb.append(' '); + sb.append(e2.getValue().toString()); + } + } + else if (e.getValue() instanceof ConfigBranch n) { + n.buildShader(sb, valuePrefix + e.getKey() + "_"); + } + else { + throw new SyntaxError("Invalid type"); + } + } + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigEnumEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigEnumEntry.java new file mode 100644 index 0000000..4d43136 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigEnumEntry.java @@ -0,0 +1,12 @@ +package io.gitlab.jfronny.respackopts.data; + +import java.util.HashMap; +import java.util.Map; + +public class ConfigEnumEntry extends Entry { + public Map values = new HashMap<>(); + + public ConfigEnumEntry() { + value = 0; + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigNumericEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigNumericEntry.java new file mode 100644 index 0000000..d3869ef --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/ConfigNumericEntry.java @@ -0,0 +1,10 @@ +package io.gitlab.jfronny.respackopts.data; + +public class ConfigNumericEntry extends Entry { + public Double min; + public Double max; + + public ConfigNumericEntry() { + value = 0d; + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/Entry.java b/src/main/java/io/gitlab/jfronny/respackopts/data/Entry.java new file mode 100644 index 0000000..d9f9120 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/Entry.java @@ -0,0 +1,7 @@ +package io.gitlab.jfronny.respackopts.data; + +public abstract class Entry { + public String name; + public T defaultValue; + public T value; +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/Respackmeta.java b/src/main/java/io/gitlab/jfronny/respackopts/data/Respackmeta.java deleted file mode 100644 index a54dddd..0000000 --- a/src/main/java/io/gitlab/jfronny/respackopts/data/Respackmeta.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.gitlab.jfronny.respackopts.data; - -import com.google.gson.JsonObject; - -public class Respackmeta { - public JsonObject conf; - public String id; - public Integer version; -} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/in/LegacyConfig.java b/src/main/java/io/gitlab/jfronny/respackopts/data/in/LegacyConfig.java new file mode 100644 index 0000000..362c3af --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/in/LegacyConfig.java @@ -0,0 +1,8 @@ +package io.gitlab.jfronny.respackopts.data.in; + +import java.util.HashMap; + +public class LegacyConfig { + public HashMap doubles = new HashMap<>(); + public HashMap bools = new HashMap<>(); +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/in/Respackmeta.java b/src/main/java/io/gitlab/jfronny/respackopts/data/in/Respackmeta.java new file mode 100644 index 0000000..17f6203 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/in/Respackmeta.java @@ -0,0 +1,9 @@ +package io.gitlab.jfronny.respackopts.data.in; + +import io.gitlab.jfronny.respackopts.data.ConfigBranch; + +public class Respackmeta { + public ConfigBranch conf; + public String id; + public Integer version; +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/data/Rpo.java b/src/main/java/io/gitlab/jfronny/respackopts/data/in/Rpo.java similarity index 76% rename from src/main/java/io/gitlab/jfronny/respackopts/data/Rpo.java rename to src/main/java/io/gitlab/jfronny/respackopts/data/in/Rpo.java index c197cd2..85f7a02 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/data/Rpo.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/data/in/Rpo.java @@ -1,4 +1,4 @@ -package io.gitlab.jfronny.respackopts.data; +package io.gitlab.jfronny.respackopts.data.in; import com.google.gson.JsonArray; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ConditionEvaluator.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ConditionEvaluator.java index 61a4deb..9dbc5a8 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ConditionEvaluator.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ConditionEvaluator.java @@ -2,15 +2,15 @@ package io.gitlab.jfronny.respackopts.filters.conditions; import com.google.gson.JsonElement; import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.respackopts.data.in.Respackmeta; import java.util.LinkedHashSet; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; public class ConditionEvaluator { - private static Set conditions; + private static final Set conditions; static { conditions = new LinkedHashSet<>(); conditions.add(new AndCondition()); @@ -50,19 +50,14 @@ public class ConditionEvaluator { if (!condition.contains(":")) { throw new SyntaxError("You must include you resource pack ID in conditions (format: pack:some.key)"); } - AtomicBoolean found = new AtomicBoolean(false); - AtomicBoolean output = new AtomicBoolean(false); - Respackopts.resPackMetas.forEach((r, v) -> { - String sourcePack = condition.split(":")[0]; - String name = condition.substring(condition.indexOf(':') + 1); - if (Objects.equals(v.id, sourcePack)) { - found.set(true); - output.set(Respackopts.boolVals.get(sourcePack).get(name)); + + String sourcePack = condition.split(":")[0]; + String name = condition.substring(condition.indexOf(':') + 1); + for (Map.Entry e : Respackopts.resPackMetas.entrySet()) { + if (Objects.equals(e.getValue().id, sourcePack)) { + return Respackopts.CONFIG_BRANCH.get(sourcePack).getBoolean(name); } - }); - if (!found.get()) { - throw new SyntaxError("Could not find pack with specified ID"); } - return output.get(); + throw new SyntaxError("Could not find pack with specified ID"); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ResourcePackFilter.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ResourcePackFilter.java index 9344756..f000b1b 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ResourcePackFilter.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/conditions/ResourcePackFilter.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.respackopts.filters.conditions; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.abstractions.FileOpenProvider; -import io.gitlab.jfronny.respackopts.data.Rpo; +import io.gitlab.jfronny.respackopts.data.in.Rpo; import java.io.InputStream; import java.io.InputStreamReader; @@ -18,18 +18,18 @@ public class ResourcePackFilter { } public boolean fileHidden(String name) { - if (name.endsWith(Respackopts.fileExtension)) + if (name.endsWith(Respackopts.FILE_EXTENSION)) return false; - if (!containsFileBase.test(name + Respackopts.fileExtension)) + if (!containsFileBase.test(name + Respackopts.FILE_EXTENSION)) return false; - try (InputStream stream = openFileBase.open(name + Respackopts.fileExtension); Reader w = new InputStreamReader(stream)) { - Rpo rpo = Respackopts.g.fromJson(w, Rpo.class); + try (InputStream stream = openFileBase.open(name + Respackopts.FILE_EXTENSION); Reader w = new InputStreamReader(stream)) { + Rpo rpo = Respackopts.GSON.fromJson(w, Rpo.class); if (rpo.conditions == null) return false; return !ConditionEvaluator.evaluate(rpo.conditions); } catch (Throwable e) { - e.printStackTrace(); + Respackopts.LOGGER.error(e); return false; } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/filters/fallback/FallbackFilter.java b/src/main/java/io/gitlab/jfronny/respackopts/filters/fallback/FallbackFilter.java index 7345502..79b3e91 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/filters/fallback/FallbackFilter.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/filters/fallback/FallbackFilter.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.respackopts.filters.fallback; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.abstractions.FileOpenProvider; -import io.gitlab.jfronny.respackopts.data.Rpo; +import io.gitlab.jfronny.respackopts.data.in.Rpo; import net.minecraft.resource.ResourceNotFoundException; import net.minecraft.util.Identifier; @@ -23,13 +23,13 @@ public class FallbackFilter { } public boolean fileVisible(String name) { - if (name.endsWith(Respackopts.fileExtension)) + if (name.endsWith(Respackopts.FILE_EXTENSION)) return false; - String fbt = name + Respackopts.fileExtension; + String fbt = name + Respackopts.FILE_EXTENSION; if (containsFileBase.test(fbt)) { System.out.println(fbt); try (InputStream stream = openFileBase.open(fbt); Reader w = new InputStreamReader(stream)) { - Rpo rpo = Respackopts.g.fromJson(w, Rpo.class); + Rpo rpo = Respackopts.GSON.fromJson(w, Rpo.class); if (rpo.fallbacks != null) { List arr = rpo.fallbacks; for (String s : arr) { @@ -39,16 +39,16 @@ public class FallbackFilter { } } catch (IOException e) { - e.printStackTrace(); + Respackopts.LOGGER.error(e); } } return false; } public InputStream getReplacement(String name, ResourceNotFoundException ex) throws ResourceNotFoundException { - String fbt = name + Respackopts.fileExtension; + String fbt = name + Respackopts.FILE_EXTENSION; try (InputStream stream = openFileBase.open(fbt); Reader w = new InputStreamReader(stream)) { - Rpo rpo = Respackopts.g.fromJson(w, Rpo.class); + Rpo rpo = Respackopts.GSON.fromJson(w, Rpo.class); if (rpo.fallbacks != null) { List arr = rpo.fallbacks; for (String s : arr) { @@ -58,7 +58,7 @@ public class FallbackFilter { } } catch (IOException e) { - e.printStackTrace(); + Respackopts.LOGGER.error(e); } throw ex; } @@ -66,8 +66,8 @@ public class FallbackFilter { public void addFallbackResources(Collection ret, String namespace) { for (Identifier identifier : ret) { String path = identifier.getPath(); - if (path.endsWith(Respackopts.fileExtension)) { - String expectedTarget = path.substring(0, path.length() - Respackopts.fileExtension.length()); + if (path.endsWith(Respackopts.FILE_EXTENSION)) { + String expectedTarget = path.substring(0, path.length() - Respackopts.FILE_EXTENSION.length()); System.out.println(expectedTarget); if (ret.stream().noneMatch(s -> s.getPath().equals(expectedTarget)) && fileVisible(expectedTarget)) { ret.add(new Identifier(namespace, expectedTarget)); diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/BooleanEntrySerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/BooleanEntrySerializer.java new file mode 100644 index 0000000..190e295 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/BooleanEntrySerializer.java @@ -0,0 +1,18 @@ +package io.gitlab.jfronny.respackopts.gson; + +import com.google.gson.*; +import io.gitlab.jfronny.respackopts.data.ConfigBooleanEntry; + +import java.lang.reflect.Type; + +public class BooleanEntrySerializer implements JsonSerializer, JsonDeserializer { + @Override + public ConfigBooleanEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + return new ConfigBooleanEntry(json.getAsBoolean()); + } + + @Override + public JsonElement serialize(ConfigBooleanEntry src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.value); + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigBranchSerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigBranchSerializer.java new file mode 100644 index 0000000..edde167 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigBranchSerializer.java @@ -0,0 +1,54 @@ +package io.gitlab.jfronny.respackopts.gson; + +import com.google.gson.*; +import io.gitlab.jfronny.respackopts.data.*; + +import java.lang.reflect.Type; +import java.util.Map; + +public class ConfigBranchSerializer implements JsonSerializer, JsonDeserializer { + @Override + public JsonElement serialize(ConfigBranch src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject o = new JsonObject(); + for (Map.Entry> entry : src.getEntries()) { + o.add(entry.getKey(), context.serialize(entry.getValue())); + } + return o; + } + + @Override + public ConfigBranch deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + if (!json.isJsonObject()) + throw new JsonSyntaxException("ConfigBranch is not an object"); + JsonObject o = json.getAsJsonObject(); + if (o.entrySet().stream().allMatch(s -> "bools".equals(s.getKey()) || "doubles".equals(s.getKey()) || "strings".equals(s.getKey()))) { + return LegacyConfigDeserializer.deserialize(json, context); + } + ConfigBranch cbNew = new ConfigBranch(); + for (Map.Entry e : o.entrySet()) { + JsonElement j = e.getValue(); + String s = e.getKey(); + if (NumericEntrySerializer.isSlider(j)) + cbNew.add(s, context.deserialize(j, ConfigNumericEntry.class)); + else if (j.isJsonPrimitive()) { + JsonPrimitive p = j.getAsJsonPrimitive(); + if (p.isBoolean()) + cbNew.add(s, new ConfigBooleanEntry(p.getAsBoolean())); + else if (p.isNumber()) { + //TODO identify saved enum values - use string? + cbNew.add(s, context.deserialize(j, ConfigNumericEntry.class)); + } else if (p.isString()) + throw new JsonSyntaxException("String primitives are not currently supported"); + } + else if (j.isJsonArray()) + cbNew.add(s, context.deserialize(j, ConfigEnumEntry.class)); + else if (j.isJsonObject()) + cbNew.add(s, context.deserialize(j, ConfigBranch.class)); + else if (j.isJsonNull()) + throw new JsonSyntaxException("Unexpected json null"); + else + throw new JsonSyntaxException("Unexpected json object type"); + } + return cbNew; + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/EnumEntrySerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/EnumEntrySerializer.java new file mode 100644 index 0000000..f333cb6 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/EnumEntrySerializer.java @@ -0,0 +1,43 @@ +package io.gitlab.jfronny.respackopts.gson; + +import com.google.gson.*; +import io.gitlab.jfronny.respackopts.data.ConfigEnumEntry; + +import java.lang.reflect.Type; +import java.util.HashMap; + +public class EnumEntrySerializer implements JsonSerializer, JsonDeserializer { + @Override + public JsonElement serialize(ConfigEnumEntry src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.value == null ? 0 : src.value); + } + + @Override + public ConfigEnumEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + ConfigEnumEntry result = new ConfigEnumEntry(); + if (json.isJsonPrimitive()) { + JsonPrimitive jp = json.getAsJsonPrimitive(); + if (jp.isNumber()) { + result.value = jp.getAsInt(); + return result; + } + else + throw new JsonSyntaxException("Expected primitive numeric key for enum"); + } + else if (json.isJsonArray()) { + result.values = new HashMap<>(); + int i = 0; + for (JsonElement e : json.getAsJsonArray()) { + if (e.isJsonPrimitive() && e.getAsJsonPrimitive().isString()) { + result.values.put(e.getAsString(), i); + } + else + throw new JsonSyntaxException("Expected string entry in enum"); + i++; + } + return result; + } + else + throw new JsonSyntaxException("Expected primitive numeric key for enum"); + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/LegacyConfigDeserializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/LegacyConfigDeserializer.java new file mode 100644 index 0000000..f831d9c --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/LegacyConfigDeserializer.java @@ -0,0 +1,49 @@ +package io.gitlab.jfronny.respackopts.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import io.gitlab.jfronny.respackopts.data.ConfigBooleanEntry; +import io.gitlab.jfronny.respackopts.data.ConfigBranch; +import io.gitlab.jfronny.respackopts.data.ConfigNumericEntry; +import io.gitlab.jfronny.respackopts.data.Entry; +import io.gitlab.jfronny.respackopts.data.in.LegacyConfig; + +import java.util.Map; + +public class LegacyConfigDeserializer { + public static ConfigBranch deserialize(JsonElement json, JsonDeserializationContext context) throws JsonParseException { + ConfigBranch cb = new ConfigBranch(); + LegacyConfig lc = context.deserialize(json, LegacyConfig.class); + for (Map.Entry e : lc.bools.entrySet()) { + ConfigBooleanEntry c = new ConfigBooleanEntry(e.getValue()); + int i = e.getKey().lastIndexOf('.'); + if (i == -1) + cb.add(e.getKey(), c); + else { + cb = getBranch(e.getKey().substring(0, i), cb); + String n = e.getKey().substring(i + 1); + cb.add(n, c); + } + } + for (Map.Entry e : lc.doubles.entrySet()) { + ConfigNumericEntry ne = new ConfigNumericEntry(); + ne.value = e.getValue(); + int i = e.getKey().lastIndexOf('.'); + if (i == -1) + cb.add(e.getKey(), ne); + else + getBranch(e.getKey().substring(0, i), cb).add(e.getKey().substring(i + 1), ne); + } + return cb; + } + + private static ConfigBranch getBranch(String name, ConfigBranch base) { + int i = name.indexOf('.'); + String keyNext = i == -1 ? name : name.substring(0, i); + if (!base.has(keyNext)) + base.add(keyNext, new ConfigBranch()); + ConfigBranch c = (ConfigBranch)base.get(keyNext); + return i == -1 ? c : getBranch(name.substring(i + 1), c); + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/NumericEntrySerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/NumericEntrySerializer.java new file mode 100644 index 0000000..2e32f51 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/NumericEntrySerializer.java @@ -0,0 +1,54 @@ +package io.gitlab.jfronny.respackopts.gson; + +import com.google.gson.*; +import io.gitlab.jfronny.respackopts.data.ConfigNumericEntry; + +import java.lang.reflect.Type; + +public class NumericEntrySerializer implements JsonSerializer, JsonDeserializer { + @Override + public JsonElement serialize(ConfigNumericEntry src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.value); + } + @Override + public ConfigNumericEntry deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + ConfigNumericEntry result = new ConfigNumericEntry(); + if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isNumber()) { + result.value = json.getAsDouble(); + return result; + } + else if (isSlider(json)) { + JsonObject o = json.getAsJsonObject(); + JsonElement def = o.get("default"); + JsonElement min = o.get("min"); + JsonElement max = o.get("max"); + if (def.isJsonPrimitive() && def.getAsJsonPrimitive().isNumber() + && min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber() + && max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) { + double defV = def.getAsNumber().doubleValue(); + double minV = min.getAsNumber().doubleValue(); + double maxV = max.getAsNumber().doubleValue(); + if (defV < minV || defV > maxV) { + throw new JsonSyntaxException("Default value out of range in slider definition"); + } + if (isWhole(defV) && isWhole(minV) && isWhole(maxV)) { + result.value = defV; + result.min = minV; + result.max = maxV; + return result; + } + throw new JsonSyntaxException("Expected whole number in slider definition"); + } + throw new JsonSyntaxException("Expected numeric values in slider definition"); + } + throw new JsonSyntaxException("Could not deserialize numeric entry"); + } + + public static boolean isSlider(JsonElement element) { + return element.isJsonObject() && element.getAsJsonObject().entrySet().stream().allMatch(s -> "default".equals(s.getKey()) || "min".equals(s.getKey()) || "max".equals(s.getKey())); + } + + private boolean isWhole(double v) { + return v == Math.floor(v) && !Double.isInfinite(v); + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/integration/FrexCompat.java b/src/main/java/io/gitlab/jfronny/respackopts/integration/FrexCompat.java index d34b8f6..3aee3e6 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/integration/FrexCompat.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/integration/FrexCompat.java @@ -3,9 +3,11 @@ package io.gitlab.jfronny.respackopts.integration; import grondag.frex.FrexInitializer; import grondag.frex.api.config.ShaderConfig; import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.respackopts.data.ConfigBranch; +import io.gitlab.jfronny.respackopts.filters.conditions.SyntaxError; import net.minecraft.util.Identifier; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Map; public class FrexCompat implements FrexInitializer { boolean initial = true; @@ -13,53 +15,25 @@ public class FrexCompat implements FrexInitializer { public void onInitalizeFrex() { ShaderConfig.registerShaderConfigSupplier(new Identifier(Respackopts.ID, "config_supplier"), () -> { StringBuilder sb = new StringBuilder(); - Respackopts.numVals.forEach((s, v) -> v.forEach((s1, v1) -> { - sb.append("\n"); - sb.append("#define "); - sb.append(s.replace('.', '_')); - sb.append("_"); - sb.append(s1.replace('.', '_')); - sb.append(" "); - String tmp = v1.toString(); - if (tmp.endsWith(".0")) - tmp = tmp.substring(0, tmp.length() - 2); - sb.append(tmp); - })); - Respackopts.boolVals.forEach((s, v) -> v.forEach((s1, v1) -> { - if (v1) { - sb.append("\n"); - sb.append("#define "); - sb.append(s.replace('.', '_')); - sb.append("_"); - sb.append(s1.replace('.', '_')); + for (Map.Entry e : Respackopts.CONFIG_BRANCH.entrySet()) { + try { + e.getValue().buildShader(sb, e.getKey() + "_"); + } catch (SyntaxError syntaxError) { + Respackopts.LOGGER.error(syntaxError); } - })); - Respackopts.enumKeys.forEach((s, v) -> v.forEach((s1, v1) -> { - AtomicInteger i = new AtomicInteger(0); - v1.forEach((s2) -> { - sb.append("\n"); - sb.append("#define "); - sb.append(s.replace('.', '_')); - sb.append("_"); - sb.append(s1.replace('.', '_')); - sb.append("_"); - sb.append(s2.replace('.', '_')); - sb.append(" "); - sb.append(i.getAndIncrement()); - }); - })); + } sb.append("\n#define respackopts_loaded"); return sb.toString(); }); - Respackopts.logger.info("enabled frex/canvas support"); - Respackopts.saveActions.add(() -> { + Respackopts.LOGGER.info("enabled frex/canvas support"); + Respackopts.SAVE_ACTIONS.add(() -> { try { if (!initial) ShaderConfig.invalidateShaderConfig(); initial = false; } catch (Throwable e) { - e.printStackTrace(); + Respackopts.LOGGER.error(e); } }); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java b/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java index d792021..dfb2e1f 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/integration/ModMenuCompat.java @@ -9,7 +9,6 @@ import me.shedaniel.clothconfig2.api.ConfigCategory; import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.FatalErrorScreen; -import net.minecraft.text.LiteralText; import net.minecraft.text.TranslatableText; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java index be31040..349ba14 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackEntryMixin.java @@ -2,7 +2,7 @@ package io.gitlab.jfronny.respackopts.mixin; import com.mojang.blaze3d.systems.RenderSystem; import io.gitlab.jfronny.respackopts.Respackopts; -import io.gitlab.jfronny.respackopts.data.Respackmeta; +import io.gitlab.jfronny.respackopts.data.in.Respackmeta; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawableHelper; import net.minecraft.client.gui.screen.pack.PackListWidget; @@ -25,7 +25,7 @@ public abstract class ResourcePackEntryMixin extends AlwaysSelectedEntryListWidg @Shadow protected abstract boolean isSelectable(); @Shadow @Final private ResourcePackOrganizer.Pack pack; - boolean respackopts$selected; + boolean rpo$selected; @Inject(at = @At("TAIL"), method = "render(Lnet/minecraft/client/util/math/MatrixStack;IIIIIIIZF)V") private void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta, CallbackInfo info) { @@ -34,8 +34,8 @@ public abstract class ResourcePackEntryMixin extends AlwaysSelectedEntryListWidg int d = mouseX - x; d = widget.getRowWidth() - d; int e = mouseY - y; - respackopts$selected = d <= 32 && d >= 12 && e <= entryHeight / 2 + 10 && e >= entryHeight / 2 - 10; - respackopts$renderButton(matrices, respackopts$selected, new Identifier("modmenu", "textures/gui/configure_button.png"), x + entryWidth - 30, y + entryHeight / 2 - 10, 20, 20, 0, 0, 32, 64); + rpo$selected = d <= 32 && d >= 12 && e <= entryHeight / 2 + 10 && e >= entryHeight / 2 - 10; + rpo$renderButton(matrices, rpo$selected, new Identifier("modmenu", "textures/gui/configure_button.png"), x + entryWidth - 30, y + entryHeight / 2 - 10); } } @@ -44,7 +44,7 @@ public abstract class ResourcePackEntryMixin extends AlwaysSelectedEntryListWidg if (!info.getReturnValue()) { if (this.isSelectable()) { String k = pack.getDisplayName().asString(); - if (Respackopts.resPackMetas.containsKey(k) && respackopts$selected) { + if (Respackopts.resPackMetas.containsKey(k) && rpo$selected) { info.setReturnValue(true); Respackmeta meta = Respackopts.resPackMetas.get(k); MinecraftClient c = MinecraftClient.getInstance(); @@ -54,16 +54,11 @@ public abstract class ResourcePackEntryMixin extends AlwaysSelectedEntryListWidg } } - private void respackopts$renderButton(MatrixStack matrices, boolean hovered, Identifier texture, int x, int y, int width, int height, int u, int v, int uWidth, int vHeight) { + private void rpo$renderButton(MatrixStack matrices, boolean hovered, Identifier texture, int x, int y) { RenderSystem.setShaderColor(1, 1, 1, 1f); RenderSystem.setShaderTexture(0, texture); RenderSystem.disableDepthTest(); - int adjustedV = v; - if (hovered) { - adjustedV += height; - } - - DrawableHelper.drawTexture(matrices, x, y, u, adjustedV, width, height, uWidth, vHeight); + DrawableHelper.drawTexture(matrices, x, y, 0, hovered ? 20 : 0, 20, 20, 32, 64); RenderSystem.enableDepthTest(); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java index 05ea6e0..1eac00d 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/ResourcePackManagerMixin.java @@ -2,11 +2,11 @@ package io.gitlab.jfronny.respackopts.mixin; import com.google.gson.*; import io.gitlab.jfronny.respackopts.Respackopts; -import io.gitlab.jfronny.respackopts.data.Respackmeta; +import io.gitlab.jfronny.respackopts.data.ConfigBranch; +import io.gitlab.jfronny.respackopts.data.in.Respackmeta; import net.minecraft.resource.ResourcePackManager; import net.minecraft.resource.ResourcePackProfile; import net.minecraft.resource.ResourceType; -import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -16,7 +16,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -27,126 +26,32 @@ public class ResourcePackManagerMixin { @Inject(at = @At("TAIL"), method = "scanPacks()V") private void scanPacks(CallbackInfo info) { profiles.forEach((s, v) -> { - if (respackopts$hasMetadata(v, "conf.json")) { + if (rpo$hasMetadata(v)) { try { - Respackmeta conf = Respackopts.g.fromJson(respackopts$readMetadata(v, "conf.json", Respackopts.g), Respackmeta.class); - if (!Respackopts.metaVersion.equals(conf.version)) { - Respackopts.logger.error(s + " was not loaded as it specifies a different respackopts version than is installed"); + Respackmeta conf = Respackopts.GSON.fromJson(rpo$readMetadata(v, Respackopts.GSON), Respackmeta.class); + if (!Respackopts.META_VERSION.equals(conf.version)) { + Respackopts.LOGGER.error(s + " was not loaded as it specifies a different respackopts version than is installed"); return; } - if (!Respackopts.boolVals.containsKey(conf.id)) - Respackopts.boolVals.put(conf.id, new HashMap<>()); - if (!Respackopts.numVals.containsKey(conf.id)) - Respackopts.numVals.put(conf.id, new HashMap<>()); - if (!Respackopts.strVals.containsKey(conf.id)) - Respackopts.strVals.put(conf.id, new HashMap<>()); - if (!Respackopts.enumKeys.containsKey(conf.id)) - Respackopts.enumKeys.put(conf.id, new HashMap<>()); + if (!Respackopts.CONFIG_BRANCH.containsKey(conf.id)) + Respackopts.CONFIG_BRANCH.put(conf.id, conf.conf); + else + Respackopts.CONFIG_BRANCH.get(conf.id).loadValues(conf.conf, true); Respackopts.resPackMetas.put(v.getDisplayName().asString(), conf); - respackopts$registerFields(conf.conf, conf.id, ""); Respackopts.load(conf.id); } catch (Throwable e) { - e.printStackTrace(); + Respackopts.LOGGER.error(e); } } }); } - private void respackopts$registerFields(JsonObject data, String id, String keyPrefix) { - //Slider - if (data.entrySet().stream().allMatch(s -> "default".equals(s.getKey()) || "min".equals(s.getKey()) || "max".equals(s.getKey()))) - { - JsonElement def = data.get("default"); - JsonElement min = data.get("min"); - JsonElement max = data.get("max"); - if (def.isJsonPrimitive() && def.getAsJsonPrimitive().isNumber() - && min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber() - && max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) { - double defV = def.getAsNumber().doubleValue(); - double minV = min.getAsNumber().doubleValue(); - double maxV = max.getAsNumber().doubleValue(); - if (defV < minV || defV > maxV) { - Respackopts.logger.error("Default value out of range in slider definition " + id); - } - else if (respackopts$isWhole(defV) && respackopts$isWhole(minV) && respackopts$isWhole(maxV)) { - Respackopts.numVals.get(id).put(keyPrefix, defV); - } - else { - Respackopts.logger.error("Expected whole number in slider definition " + id); - } - } - else { - Respackopts.logger.error("Expected numeric values in slider definition " + id); - } - return; - } - //Normal object - for (Map.Entry entry : data.entrySet()) { - String n = ("".equals(keyPrefix) ? "" : keyPrefix + ".") + entry.getKey(); - JsonElement e = entry.getValue(); - if (e.isJsonPrimitive()) { - JsonPrimitive p = e.getAsJsonPrimitive(); - if (p.isBoolean()) { - if (!Respackopts.boolVals.get(id).containsKey(n)) - Respackopts.boolVals.get(id).put(n, p.getAsBoolean()); - } - else if (p.isNumber()) { - if (!Respackopts.numVals.get(id).containsKey(n)) - Respackopts.numVals.get(id).put(n, p.getAsDouble()); - } - else if (p.isString()) { - if (!Respackopts.strVals.get(id).containsKey(n)) - Respackopts.strVals.get(id).put(n, p.getAsString()); - } - } - else if (e.isJsonArray()) { - JsonArray a = e.getAsJsonArray(); - for (JsonElement element : a) { - if (!element.isJsonPrimitive()) { - Respackopts.logger.error("Unsupported non-primitive datatype in enum definition"); - continue; - } - if (!Respackopts.enumKeys.get(id).containsKey(n)) { - Respackopts.enumKeys.get(id).put(n, new LinkedHashSet<>()); - } - JsonPrimitive p = element.getAsJsonPrimitive(); - if (!p.isString()) { - Respackopts.logger.error("Unsupported non-string enum key"); - continue; - } - String b = p.getAsString(); - if (b.contains(":") || b.contains(".") || b.contains("_")) { - Respackopts.logger.error(b + " contains invalid characters"); - continue; - } - Respackopts.enumKeys.get(id).get(n).add(b); - } - if (!Respackopts.numVals.get(id).containsKey(n)) { - Respackopts.numVals.get(id).put(n, 0d); - } - } - else if (e.isJsonNull()) { - Respackopts.logger.error("Config definition contains null, skipping that entry"); - } - else if (e.isJsonObject()) { - respackopts$registerFields(e.getAsJsonObject(), id, n); - } - else { - Respackopts.logger.error("Unsupported non-primitive datatype"); - } - } + private boolean rpo$hasMetadata(ResourcePackProfile v) { + return v.createResourcePack().contains(ResourceType.CLIENT_RESOURCES, Respackopts.CONF_ID); } - private boolean respackopts$isWhole(double v) { - return v == Math.floor(v) && !Double.isInfinite(v); - } - - private boolean respackopts$hasMetadata(ResourcePackProfile v, String fname) { - return v.createResourcePack().contains(ResourceType.CLIENT_RESOURCES, new Identifier(Respackopts.ID, fname)); - } - - private JsonObject respackopts$readMetadata(ResourcePackProfile v, String fname, Gson g) throws IOException { - InputStream is = v.createResourcePack().open(ResourceType.CLIENT_RESOURCES, new Identifier(Respackopts.ID, fname)); + private JsonObject rpo$readMetadata(ResourcePackProfile v, Gson g) throws IOException { + InputStream is = v.createResourcePack().open(ResourceType.CLIENT_RESOURCES, Respackopts.CONF_ID); ByteArrayOutputStream bais = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/DirectoryResourcePackMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/DirectoryResourcePackMixin.java index 2d9611c..4f1676c 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/DirectoryResourcePackMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/DirectoryResourcePackMixin.java @@ -28,20 +28,20 @@ public abstract class DirectoryResourcePackMixin extends AbstractFileResourcePac @Shadow protected abstract InputStream openFile(String name) throws IOException; - FilterProvider filter = new FilterProvider(this::containsFile, this::openFile); + FilterProvider rpo$filter = new FilterProvider(this::containsFile, this::openFile); @Inject(at = @At("HEAD"), method = "openFile(Ljava/lang/String;)Ljava/io/InputStream;", cancellable = true) protected void openFile(String name, CallbackInfoReturnable info) throws IOException { - filter.openFile(name, base, info); + rpo$filter.openFile(name, base, info); } @Inject(at = @At("TAIL"), method = "containsFile(Ljava/lang/String;)Z", cancellable = true) protected void containsFile(String name, CallbackInfoReturnable info) { - filter.containsFile(name, info); + rpo$filter.containsFile(name, info); } @Inject(at = @At("TAIL"), method = "findResources(Lnet/minecraft/resource/ResourceType;Ljava/lang/String;Ljava/lang/String;ILjava/util/function/Predicate;)Ljava/util/Collection;") private void findResources(ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter, CallbackInfoReturnable> info) { - filter.findResources(type, namespace, prefix, maxDepth, pathFilter, info); + rpo$filter.findResources(type, namespace, prefix, maxDepth, pathFilter, info); } } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/ZipResourcePackMixin.java b/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/ZipResourcePackMixin.java index 5e1515d..5a3620b 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/ZipResourcePackMixin.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/mixin/conditions/ZipResourcePackMixin.java @@ -28,20 +28,20 @@ public abstract class ZipResourcePackMixin extends AbstractFileResourcePack { @Shadow protected abstract InputStream openFile(String name) throws IOException; - FilterProvider filter = new FilterProvider(this::containsFile, this::openFile); + FilterProvider rpo$filter = new FilterProvider(this::containsFile, this::openFile); @Inject(at = @At("HEAD"), method = "openFile(Ljava/lang/String;)Ljava/io/InputStream;", cancellable = true) protected void openFile(String name, CallbackInfoReturnable info) throws IOException { - filter.openFile(name, base, info); + rpo$filter.openFile(name, base, info); } @Inject(at = @At("TAIL"), method = "containsFile(Ljava/lang/String;)Z", cancellable = true) protected void containsFile(String name, CallbackInfoReturnable info) { - filter.containsFile(name, info); + rpo$filter.containsFile(name, info); } @Inject(at = @At("TAIL"), method = "findResources(Lnet/minecraft/resource/ResourceType;Ljava/lang/String;Ljava/lang/String;ILjava/util/function/Predicate;)Ljava/util/Collection;") private void findResources(ResourceType type, String namespace, String prefix, int maxDepth, Predicate pathFilter, CallbackInfoReturnable> info) { - filter.findResources(type, namespace, prefix, maxDepth, pathFilter, info); + rpo$filter.findResources(type, namespace, prefix, maxDepth, pathFilter, info); } }