diff --git a/docs/setup/AdvancedConfig.md b/docs/setup/AdvancedConfig.md index d7e5afa..7d024c2 100644 --- a/docs/setup/AdvancedConfig.md +++ b/docs/setup/AdvancedConfig.md @@ -10,6 +10,12 @@ Every entry can contain the following properties, regardless of its type: | default | yes | The default value for this entry. This is what you would specify in a normal config entry (except for enums, where this is just the default entries name) | | reloadType | no | `"Resource"` or `"Simple"`, specifies whether resources have to be reloaded if this is changed. Frex shaders will be reloaded anyways | +## Strings +These entries will be displayed as text boxes. They can be used to drive any in-game text you might want to make configurable. +Their type is `string` or `text`. +They are most useful in combination with [Resource Expansion](../additional/ResourceExpansion.md), but you can also access them in your conditions. +See the muScript standard library documentation for more info on how to use and manipulate them. + ## Numbers There are two ways to display numbers: input boxes and sliders. Any number input that provides a minimum and maximum value will be displayed as a slider instead of a box. diff --git a/run/resourcepacks/testpack/assets/minecraft/langer/en_us.json.rpo b/run/resourcepacks/testpack/assets/minecraft/langer/en_us.json.rpo index 7ce1bca..16c3209 100644 --- a/run/resourcepacks/testpack/assets/minecraft/langer/en_us.json.rpo +++ b/run/resourcepacks/testpack/assets/minecraft/langer/en_us.json.rpo @@ -2,7 +2,7 @@ "conditions": "lumi.subcategoryTest.enableLang & (!subcategoryTest.enableLangForceDisable) & version('respackopts', '*')", "fallback": "assets/minecraft/lang/en_us_joke.json", "expansions": { - "Lights": "lumi.subcategoryTest.enableLang", + "Lights": "lumi.subcategoryTest.enableLang || lumi.someString", "Mode": "lumi.debugMode", "Normal": "lumi.numTest * lumi.subcategoryTest.numberInSub", "Lumi": "'model'", diff --git a/run/resourcepacks/testpack/respackopts.json5 b/run/resourcepacks/testpack/respackopts.json5 index 8f39c10..372d004 100644 --- a/run/resourcepacks/testpack/respackopts.json5 +++ b/run/resourcepacks/testpack/respackopts.json5 @@ -18,6 +18,10 @@ "normal", "viewDir" ], + someString: { + type: "string", + default: "This is a Value?" + }, waterVertexWavy: false, numTest: 15.4, oakFence: { diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigEntryTypeAdapter.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigEntryTypeAdapter.java index 0608a3c..33926ee 100644 --- a/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigEntryTypeAdapter.java +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/ConfigEntryTypeAdapter.java @@ -12,6 +12,7 @@ import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.gson.entry.BooleanEntrySerializer; import io.gitlab.jfronny.respackopts.gson.entry.EnumEntrySerializer; import io.gitlab.jfronny.respackopts.gson.entry.NumericEntrySerializer; +import io.gitlab.jfronny.respackopts.gson.entry.StringEntrySerializer; import io.gitlab.jfronny.respackopts.model.tree.*; @SerializerFor(targets = ConfigEntry.class) @@ -23,6 +24,7 @@ public class ConfigEntryTypeAdapter extends TypeAdapter> { case ConfigNumericEntry num -> GC_ConfigNumericEntry.serialize(num, writer); case ConfigEnumEntry en -> GC_ConfigEnumEntry.serialize(en, writer); case ConfigBranch br -> GC_ConfigBranch.serialize(br, writer); + case ConfigStringEntry str -> GC_ConfigStringEntry.serialize(str, writer); default -> throw new MalformedDataException("Unknown entry type: " + entry.getClass().getName()); } } @@ -58,6 +60,8 @@ public class ConfigEntryTypeAdapter extends TypeAdapter> { entry = NumericEntrySerializer.INT_TYPES.contains(type) ? e.asInteger() : e; } else if (EnumEntrySerializer.TYPES.contains(type)) { entry = GC_ConfigEnumEntry.deserialize(new EmulatedReader(de)); + } else if (StringEntrySerializer.TYPES.contains(type)) { + entry = GC_ConfigStringEntry.deserialize(new EmulatedReader(de)); } else { throw new MalformedDataException("Invalid type for entry: " + type); } diff --git a/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/StringEntrySerializer.java b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/StringEntrySerializer.java new file mode 100644 index 0000000..6de3f20 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/gson/entry/StringEntrySerializer.java @@ -0,0 +1,53 @@ +package io.gitlab.jfronny.respackopts.gson.entry; + +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; +import io.gitlab.jfronny.commons.serialize.Token; +import io.gitlab.jfronny.commons.serialize.databind.api.SerializerFor; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeAdapter; +import io.gitlab.jfronny.respackopts.model.enums.PackReloadType; +import io.gitlab.jfronny.respackopts.model.tree.ConfigBooleanEntry; +import io.gitlab.jfronny.respackopts.model.tree.ConfigEntry; +import io.gitlab.jfronny.respackopts.model.tree.ConfigStringEntry; + +import java.util.Set; + +@SerializerFor(targets = ConfigBooleanEntry.class) +public class StringEntrySerializer extends TypeAdapter { + public static final Set TYPES = Set.of("string", "text"); + + @Override + public > void serialize(ConfigStringEntry configBooleanEntry, Writer writer) throws TEx, MalformedDataException { + writer.value(configBooleanEntry.getValue()); + } + + @Override + public > ConfigStringEntry deserialize(Reader reader) throws TEx, MalformedDataException { + if (reader.peek() == Token.BEGIN_OBJECT) { + reader.beginObject(); + ConfigStringEntry result = new ConfigStringEntry(""); + while (reader.hasNext()) { + String key = reader.nextName(); + switch (key) { + case "type" -> { + if (!TYPES.contains(reader.nextString())) { + throw new MalformedDataException("Invalid type for string entry"); + } + } + case "default" -> { + String value = reader.nextString(); + result.setDefault(value); + result.setValue(value); + } + case "reloadType" -> result.setReloadType(PackReloadType.valueOf(reader.nextString())); + default -> throw new MalformedDataException("Unknown key in string entry: " + key); + }; + } + reader.endObject(); + return result; + } else { + throw new MalformedDataException("Invalid data type for string entry"); + } + } +} diff --git a/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigStringEntry.java b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigStringEntry.java new file mode 100644 index 0000000..5829094 --- /dev/null +++ b/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigStringEntry.java @@ -0,0 +1,51 @@ +package io.gitlab.jfronny.respackopts.model.tree; + +import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter; +import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; +import io.gitlab.jfronny.muscript.data.dynamic.DString; +import io.gitlab.jfronny.respackopts.Respackopts; +import io.gitlab.jfronny.respackopts.RespackoptsConfig; +import io.gitlab.jfronny.respackopts.gson.entry.StringEntrySerializer; + +import java.util.Objects; + +@SerializeWithAdapter(adapter = StringEntrySerializer.class) +public class ConfigStringEntry extends ConfigEntry implements DString { + public ConfigStringEntry(String v) { + super(String.class); + setValue(v); + setDefault(v); + } + + @Override + public ConfigEntry clone() { + ConfigStringEntry be = new ConfigStringEntry(getValue()); + be.setDefault(getDefault()); + return be; + } + + @Override + public void buildShader(StringBuilder sb, String valueName) { + } + + @Override + public CategoryBuilder buildEntry(GuiEntryBuilderParam args) { + return args.builder().value(args.name(), getDefault(), this::getValue, v -> { + if (!Objects.equals(getValue(), v)) { + if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("ConfigStringEntry SaveCallback"); + args.saveCallback(); + } + setValue(v); + }); + } + + @Override + public boolean equals(Object o) { + return super.equals(o) && o instanceof ConfigStringEntry cb && getValue().equals(cb.getValue()) && getDefault().equals(cb.getDefault()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), getValue(), getDefault()); + } +}