Set value type of ConfigEnumEntry to String and simplify shader API

This commit is contained in:
JFronny 2021-06-14 16:33:15 +02:00
parent 3389db278d
commit 68cdc81c27
No known key found for this signature in database
GPG Key ID: BEC5ACBBD4EE17E5
17 changed files with 206 additions and 125 deletions

2
.gitignore vendored
View File

@ -117,7 +117,7 @@ gradle-app.setting
!/run/resourcepacks
/run/resourcepacks/*
!/run/resourcepacks/lumi
test/
/test/
logs/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)

View File

@ -6,7 +6,7 @@ minecraft_version=1.17
yarn_mappings=build.1
loader_version=0.11.3
# Mod Properties
mod_version=2.0.0
mod_version=2.1.0
maven_group=io.gitlab.jfronny
archives_base_name=respackopts

View File

@ -54,7 +54,7 @@ public class Respackopts implements ClientModInitializer {
try {
CONF_DIR = FabricLoader.getInstance().getConfigDir().resolve(ID);
} catch (Throwable e) {
LOGGER.error(e);
LOGGER.error("Could not resolve config directory", e);
}
}
@ -63,7 +63,7 @@ public class Respackopts implements ClientModInitializer {
try {
Files.createDirectories(CONF_DIR);
} catch (IOException e) {
Respackopts.LOGGER.error(e);
Respackopts.LOGGER.error("Could not initialize config directory", e);
}
if (FabricLoader.getInstance().isDevelopmentEnvironment())
SAVE_ACTIONS.add(() -> LOGGER.info("Save"));
@ -75,7 +75,7 @@ public class Respackopts implements ClientModInitializer {
GSON.toJson(e.getValue(), writer);
writer.flush();
} catch (IOException ex) {
Respackopts.LOGGER.error(ex);
Respackopts.LOGGER.error("Could not save config", ex);
}
}
for (Runnable action : SAVE_ACTIONS) {

View File

@ -1,17 +1,17 @@
package io.gitlab.jfronny.respackopts.data.entry;
public class ConfigBooleanEntry extends Entry<Boolean> {
public class ConfigBooleanEntry extends ConfigEntry<Boolean> {
public ConfigBooleanEntry(boolean v) {
setValue(v);
}
@Override
public boolean typeMatches(Entry<?> val) {
public boolean typeMatches(ConfigEntry<?> val) {
return val instanceof ConfigBooleanEntry;
}
@Override
public Entry<Boolean> clone() {
public ConfigEntry<Boolean> clone() {
ConfigBooleanEntry be = new ConfigBooleanEntry(getValue());
be.setDefault(getDefault());
return be;

View File

@ -7,7 +7,7 @@ import io.gitlab.jfronny.respackopts.data.RpoError;
import java.util.HashMap;
import java.util.Map;
public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> {
public ConfigBranch() {
setValue(new HashMap<>());
}
@ -16,16 +16,16 @@ public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
String[] sp = name.split("\\.");
if (!super.getValue().containsKey(sp[0]))
throw new RpoError("Invalid path to key");
Entry<?> e = super.getValue().get(sp[0]);
ConfigEntry<?> e = super.getValue().get(sp[0]);
if (sp.length == 1) {
if (e instanceof ConfigBooleanEntry b)
return b.getValue();
throw new RpoError("Not a boolean");
}
if (sp.length == 2 && e instanceof ConfigEnumEntry en) {
for (Map.Entry<String, Integer> entry : en.values.entrySet()) {
if (entry.getKey().equals(sp[1]))
return entry.getValue().equals(en.getValue());
for (String entry : en.values) {
if (entry.equals(sp[1]))
return entry.equals(en.getValue());
}
throw new RpoError("Could not find enum entry");
}
@ -35,15 +35,15 @@ public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
}
@Override
public void sync(Entry<Map<String, Entry<?>>> source, SyncMode mode) {
for (Map.Entry<String, Entry<?>> e : source.getValue().entrySet()) {
public void sync(ConfigEntry<Map<String, ConfigEntry<?>>> source, SyncMode mode) {
for (Map.Entry<String, ConfigEntry<?>> e : source.getValue().entrySet()) {
if (!has(e.getKey())) {
if (mode.isAdd())
if (mode == SyncMode.RESPACK_LOAD)
add(e.getKey(), e.getValue().clone());
} else {
Entry<?> current = get(e.getKey());
ConfigEntry<?> current = get(e.getKey());
if (e.getValue().typeMatches(current)) {
syncSub(current, (Entry)e.getValue(), mode);
syncSub(current, (ConfigEntry)e.getValue(), mode);
}
else {
Respackopts.LOGGER.warn("Type mismatch in config, ignoring");
@ -53,20 +53,19 @@ public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
}
@Override
public boolean typeMatches(Entry<?> val) {
public boolean typeMatches(ConfigEntry<?> val) {
return val instanceof ConfigBranch;
}
private <T> void syncSub(Entry<T> current, Entry<T> next, SyncMode mode) {
private <T> void syncSub(ConfigEntry<T> current, ConfigEntry<T> next, SyncMode mode) {
current.sync(next, mode);
}
public <T> void add(String name, Entry<T> val) {
val.setDefault(val.getValue());
public <T> void add(String name, ConfigEntry<T> val) {
super.getValue().put(name, val);
}
public Entry<?> get(String key) {
public ConfigEntry<?> get(String key) {
return super.getValue().get(key);
}
@ -75,12 +74,12 @@ public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
}
@Override
public Map<String, Entry<?>> getValue() {
public Map<String, ConfigEntry<?>> getValue() {
return ImmutableMap.copyOf(super.getValue());
}
public void buildShader(StringBuilder sb, String valuePrefix) throws RpoError {
for (Map.Entry<String, Entry<?>> e : super.getValue().entrySet()) {
for (Map.Entry<String, ConfigEntry<?>> e : super.getValue().entrySet()) {
if (e.getValue() instanceof ConfigNumericEntry n) {
sb.append("\n#define ");
sb.append(valuePrefix);
@ -99,16 +98,14 @@ public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
sb.append("\n#define ");
sb.append(valuePrefix);
sb.append(e.getKey());
sb.append(' ');
sb.append(n.getValue().toString());
for (Map.Entry<String, Integer> 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());
for (String e2 : n.values) {
if (e2.equals(n.getValue())) {
sb.append("\n#define ");
sb.append(valuePrefix);
sb.append(e.getKey());
sb.append('_');
sb.append(e2);
}
}
}
else if (e.getValue() instanceof ConfigBranch n) {
@ -122,7 +119,7 @@ public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
@Override
public void appendString(StringBuilder sb) {
for (Map.Entry<String, Entry<?>> e : getValue().entrySet()) {
for (Map.Entry<String, ConfigEntry<?>> e : getValue().entrySet()) {
sb.append("\n");
sb.append(e.getKey());
sb.append(": ");
@ -131,9 +128,9 @@ public class ConfigBranch extends Entry<Map<String, Entry<?>>> {
}
@Override
public Entry<Map<String, Entry<?>>> clone() {
public ConfigEntry<Map<String, ConfigEntry<?>>> clone() {
ConfigBranch branch = new ConfigBranch();
for (Map.Entry<String, Entry<?>> e : getValue().entrySet()) {
for (Map.Entry<String, ConfigEntry<?>> e : getValue().entrySet()) {
branch.add(e.getKey(), e.getValue().clone());
}
return branch;

View File

@ -1,10 +1,12 @@
package io.gitlab.jfronny.respackopts.data.entry;
public abstract class Entry<T> {
public abstract class ConfigEntry<T> {
private T defaultValue;
private T value;
public T getValue() {
if (value == null)
value = defaultValue;
return value;
}
@ -14,6 +16,8 @@ public abstract class Entry<T> {
}
public T getDefault() {
if (defaultValue == null)
defaultValue = value;
return defaultValue;
}
@ -22,14 +26,14 @@ public abstract class Entry<T> {
defaultValue = value;
}
public void sync(Entry<T> source, SyncMode mode) {
if (mode.modifyDefault())
public void sync(ConfigEntry<T> source, SyncMode mode) {
if (mode == SyncMode.RESPACK_LOAD)
setDefault(source.getDefault());
if (mode.modifyValue())
if (mode == SyncMode.CONF_LOAD)
setValue(source.getValue());
}
public abstract boolean typeMatches(Entry<?> val);
public abstract boolean typeMatches(ConfigEntry<?> val);
public void appendString(StringBuilder sb) {
sb.append(value).append(" (").append(defaultValue).append(")");
@ -42,5 +46,5 @@ public abstract class Entry<T> {
return log.toString();
}
public abstract Entry<T> clone();
public abstract ConfigEntry<T> clone();
}

View File

@ -1,82 +1,84 @@
package io.gitlab.jfronny.respackopts.data.entry;
import com.ibm.icu.impl.locale.XCldrStub;
import io.gitlab.jfronny.respackopts.Respackopts;
import java.util.HashMap;
import java.util.Map;
import java.util.ArrayList;
import java.util.List;
public class ConfigEnumEntry extends Entry<Integer> {
public Map<String, Integer> values = new HashMap<>();
private String fieldName;
public ConfigEnumEntry() {
setValue(0);
public class ConfigEnumEntry extends ConfigEntry<String> {
public List<String> values = new ArrayList<>();
private Integer nextValue;
public void setNextValue(int v) {
nextValue = v;
}
@Override
public Integer getValue() {
Integer v = super.getValue();
if (v == null)
throw new NullPointerException();
public String getValue() {
String v = super.getValue();
if (v == null) {
if (nextValue != null && nextValue >= 0 && nextValue < values.size()) {
v = values.get(nextValue);
setValue(v);
}
else {
throw new NullPointerException("Could not get value");
}
}
return v;
}
@Override
public void sync(Entry<Integer> source, SyncMode mode) {
public String getDefault() {
String v = super.getDefault();
if (v == null) {
if (values.size() == 0)
throw new NullPointerException("Could not get default entry as the entry array is empty");
else
v = values.get(0);
}
return v;
}
@Override
public void sync(ConfigEntry<String> source, SyncMode mode) {
super.sync(source, mode);
ConfigEnumEntry n = (ConfigEnumEntry) source;
if (mode.modifyDefault()) {
if (mode == SyncMode.RESPACK_LOAD) {
if (n.values != null && !n.values.isEmpty())
values = n.values;
}
if (mode.modifyValue()) {
if (n.fieldName != null)
setValue(values.get(n.fieldName));
if (getValue() == null && nextValue != null) {
if (n.nextValue >= 0 && n.nextValue < values.size()) {
setValue(values.get(n.nextValue));
}
else {
Respackopts.LOGGER.error("Could not load default value for enum");
}
}
}
@Override
public boolean typeMatches(Entry<?> val) {
public boolean typeMatches(ConfigEntry<?> val) {
return val instanceof ConfigEnumEntry;
}
@Override
public void appendString(StringBuilder sb) {
sb.append(getValueName()).append('/').append(getValue()).append(" (").append(getDefaultName()).append('/').append(getDefault()).append(" of:");
for (Map.Entry<String, Integer> e : values.entrySet()) {
sb.append(' ').append(e.getKey()).append('/').append(e.getValue());
sb.append(getValue()).append('/').append(getValue()).append(" (").append(getDefault()).append('/').append(getDefault()).append(" of:");
for (String e : values) {
sb.append(' ').append(e);
}
sb.append(')');
}
@Override
public Entry<Integer> clone() {
public ConfigEntry<String> clone() {
ConfigEnumEntry e = new ConfigEnumEntry();
e.fieldName = fieldName;
e.values = XCldrStub.ImmutableMap.copyOf(values);
e.nextValue = nextValue;
e.values = List.copyOf(values);
e.setValue(getValue());
e.setDefault(getDefault());
return e;
}
public void setFieldName(String s) {
if (s != null)
fieldName = s;
}
public String getValueName() {
for (Map.Entry<String, Integer> en : values.entrySet()) {
if (en.getValue().equals(getValue()))
return en.getKey();
}
return getDefaultName();
}
public String getDefaultName() {
for (Map.Entry<String, Integer> en : values.entrySet()) {
if (en.getValue().equals(getDefault()))
return en.getKey();
}
throw new NullPointerException();
}
}

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.respackopts.data.entry;
public class ConfigNumericEntry extends Entry<Double> {
public class ConfigNumericEntry extends ConfigEntry<Double> {
public Double min;
public Double max;
@ -9,10 +9,10 @@ public class ConfigNumericEntry extends Entry<Double> {
}
@Override
public void sync(Entry<Double> source, SyncMode mode) {
public void sync(ConfigEntry<Double> source, SyncMode mode) {
super.sync(source, mode);
ConfigNumericEntry n = (ConfigNumericEntry) source;
if (mode.modifyDefault()) {
if (mode == SyncMode.RESPACK_LOAD) {
if (n.min != null)
min = n.min;
if (n.max != null)
@ -21,7 +21,7 @@ public class ConfigNumericEntry extends Entry<Double> {
}
@Override
public boolean typeMatches(Entry<?> val) {
public boolean typeMatches(ConfigEntry<?> val) {
return val instanceof ConfigNumericEntry;
}
@ -38,7 +38,7 @@ public class ConfigNumericEntry extends Entry<Double> {
}
@Override
public Entry<Double> clone() {
public ConfigEntry<Double> clone() {
ConfigNumericEntry ce = new ConfigNumericEntry();
ce.max = max;
ce.min = min;

View File

@ -1,7 +1,5 @@
package io.gitlab.jfronny.respackopts.data.entry;
public record SyncMode(boolean modifyValue, boolean modifyDefault, boolean isAdd) {
public static final SyncMode RESPACK_LOAD = new SyncMode(false, true, true);
public static final SyncMode CONF_LOAD = new SyncMode(true, false, false);
public enum SyncMode {
RESPACK_LOAD, CONF_LOAD
}

View File

@ -29,7 +29,7 @@ public class ResourcePackFilter {
return !ConditionEvaluator.evaluate(rpo.conditions);
}
catch (Throwable e) {
Respackopts.LOGGER.error(e);
Respackopts.LOGGER.error("Could not load RPO file " + name, e);
return false;
}
}

View File

@ -39,7 +39,7 @@ public class FallbackFilter {
}
}
catch (IOException e) {
Respackopts.LOGGER.error(e);
Respackopts.LOGGER.error("Could not determine visibility of " + name + e);
}
}
return false;
@ -58,7 +58,7 @@ public class FallbackFilter {
}
}
catch (IOException e) {
Respackopts.LOGGER.error(e);
Respackopts.LOGGER.error("Could not determine replacement for " + name, e);
}
throw ex;
}

View File

@ -10,7 +10,7 @@ public class ConfigBranchSerializer implements JsonSerializer<ConfigBranch>, Jso
@Override
public JsonElement serialize(ConfigBranch src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject o = new JsonObject();
for (Map.Entry<String, Entry<?>> entry : src.getValue().entrySet()) {
for (Map.Entry<String, ConfigEntry<?>> entry : src.getValue().entrySet()) {
o.add(entry.getKey(), context.serialize(entry.getValue()));
}
return o;

View File

@ -4,12 +4,11 @@ import com.google.gson.*;
import io.gitlab.jfronny.respackopts.data.entry.ConfigEnumEntry;
import java.lang.reflect.Type;
import java.util.HashMap;
public class EnumEntrySerializer implements JsonSerializer<ConfigEnumEntry>, JsonDeserializer<ConfigEnumEntry> {
@Override
public JsonElement serialize(ConfigEnumEntry src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.getValueName());
return new JsonPrimitive(src.getValue());
}
@Override
@ -17,32 +16,29 @@ public class EnumEntrySerializer implements JsonSerializer<ConfigEnumEntry>, Jso
ConfigEnumEntry result = new ConfigEnumEntry();
if (json.isJsonPrimitive()) {
JsonPrimitive jp = json.getAsJsonPrimitive();
if (jp.isNumber()) {
result.setValue(jp.getAsInt());
result.setDefault(jp.getAsInt());
if (jp.isString()) {
result.setValue(jp.getAsString());
return result;
}
else if (jp.isString()) {
result.setFieldName(jp.getAsString());
else if (jp.isNumber()) {
result.setNextValue(jp.getAsInt());
return result;
}
else
throw new JsonSyntaxException("Expected primitive numeric key for enum");
throw new JsonSyntaxException("Expected primitive string key for enum");
}
else if (json.isJsonArray()) {
result.values = new HashMap<>();
int i = 0;
result.values.clear();
for (JsonElement e : json.getAsJsonArray()) {
if (e.isJsonPrimitive() && e.getAsJsonPrimitive().isString()) {
result.values.put(e.getAsString(), i);
result.values.add(e.getAsString());
}
else
throw new JsonSyntaxException("Expected string entry in enum");
i++;
}
return result;
}
else
throw new JsonSyntaxException("Expected primitive numeric key for enum");
throw new JsonSyntaxException("Expected primitive string key or string array for enum");
}
}

View File

@ -24,8 +24,8 @@ import java.util.Optional;
public class GuiFactory {
public void buildCategory(ConfigBranch source, String screenId, JfConfigCategory config, ConfigEntryBuilder entryBuilder, String namePrefix) {
String b = "respackopts.field." + screenId;
for (Map.Entry<String, Entry<?>> in : source.getValue().entrySet()) {
Entry<?> entry = in.getValue();
for (Map.Entry<String, ConfigEntry<?>> in : source.getValue().entrySet()) {
ConfigEntry<?> entry = in.getValue();
String n = ("".equals(namePrefix) ? "" : namePrefix + ".") + in.getKey();
if (entry instanceof ConfigBranch e) {
SubCategoryBuilder sc = entryBuilder.startSubCategory(getText(n, "respackopts.title." + screenId));
@ -42,12 +42,12 @@ public class GuiFactory {
}
else if (entry instanceof ConfigEnumEntry e) {
config.addEntry(entryBuilder.startDropdownMenu(getText(n, b),
DropdownMenuBuilder.TopCellElementBuilder.of(e.getValueName(), s -> s, LiteralText::new),
DropdownMenuBuilder.TopCellElementBuilder.of(e.getValue(), s -> s, LiteralText::new),
new DropdownBoxEntry.DefaultSelectionCellCreator<>())
.setSuggestionMode(false)
.setDefaultValue(e.getDefaultName())
.setSelections(() -> e.values.keySet().iterator())
.setSaveConsumer(v -> e.setValue(e.values.get(v)))
.setDefaultValue(e.getDefault())
.setSelections(() -> e.values.iterator())
.setSaveConsumer(e::setValue)
.setTooltipSupplier(() -> getTooltip(n, screenId))
.build());
}

View File

@ -19,7 +19,7 @@ public class FrexCompat implements FrexInitializer {
try {
e.getValue().buildShader(sb, e.getKey() + "_");
} catch (RpoError rpoError) {
Respackopts.LOGGER.error(rpoError);
Respackopts.LOGGER.error("Could not build shader", rpoError);
}
}
sb.append("\n#define respackopts_loaded");
@ -33,7 +33,7 @@ public class FrexCompat implements FrexInitializer {
initial = false;
}
catch (Throwable e) {
Respackopts.LOGGER.error(e);
Respackopts.LOGGER.error("Could not reload shader config", e);
}
});
}

View File

@ -42,7 +42,7 @@ public class ResourcePackManagerMixin {
Respackopts.NAME_LOOKUP.put(v.getDisplayName().asString(), conf.id);
Respackopts.load(conf.id);
} catch (Throwable e) {
Respackopts.LOGGER.error(e);
Respackopts.LOGGER.error("Could not initialize pack meta for " + s, e);
}
}
});

View File

@ -0,0 +1,84 @@
package io.gitlab.jfronny.respackopts;
import io.gitlab.jfronny.respackopts.data.entry.ConfigBooleanEntry;
import io.gitlab.jfronny.respackopts.data.entry.ConfigBranch;
import io.gitlab.jfronny.respackopts.data.entry.SyncMode;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.nio.file.Files;
import java.nio.file.Paths;
import static io.gitlab.jfronny.respackopts.Respackopts.*;
import static io.gitlab.jfronny.respackopts.Respackopts.CONFIG_BRANCH;
import static org.junit.jupiter.api.Assertions.*;
class RespackoptsTest {
private static final String testEntryName = "test";
private static final String testEntry1Name = "test1";
@BeforeAll
static void initialize() {
CONF_DIR = Paths.get("./test");
assertDoesNotThrow(() -> Files.deleteIfExists(CONF_DIR.resolve(testEntry1Name + ".json")));
assertDoesNotThrow(() -> Files.createDirectories(CONF_DIR));
SAVE_ACTIONS.add(() -> LOGGER.info("Save"));
LOGGER.info(CONF_DIR);
}
@AfterEach
void reset() {
CONFIG_BRANCH.clear();
save();
assertEquals(CONFIG_BRANCH.keySet().size(), 0);
}
@BeforeEach
void initSingle() {
CONFIG_BRANCH.put(testEntryName, new ConfigBranch());
assertEquals(CONFIG_BRANCH.keySet().size(), 1);
}
@Test
void saveLoadSimple() {
CONFIG_BRANCH.get(testEntryName).add(testEntry1Name, new ConfigBooleanEntry(false));
assertTrue(CONFIG_BRANCH.get(testEntryName).has(testEntry1Name));
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
save();
CONFIG_BRANCH.remove(testEntryName);
assertEquals(CONFIG_BRANCH.keySet().size(), 0);
CONFIG_BRANCH.put(testEntryName, new ConfigBranch());
CONFIG_BRANCH.get(testEntryName).add(testEntry1Name, new ConfigBooleanEntry(false));
load(testEntryName);
assertEquals(CONFIG_BRANCH.keySet().size(), 1);
assertTrue(CONFIG_BRANCH.get(testEntryName).has(testEntry1Name));
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
}
@Test
void syncSimple() {
ConfigBranch test = new ConfigBranch();
test.add(testEntry1Name, new ConfigBooleanEntry(false));
CONFIG_BRANCH.get(testEntryName).sync(test, SyncMode.RESPACK_LOAD);
save();
load(testEntryName);
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
assertEquals(CONFIG_BRANCH.keySet().size(), 1);
assertEquals(test.getValue().size(), 1);
assertNotNull(CONFIG_BRANCH.get(testEntryName));
ConfigBooleanEntry be;
assertTrue(test.get(testEntry1Name) instanceof ConfigBooleanEntry);
be = (ConfigBooleanEntry)test.get(testEntry1Name);
be.setValue(true);
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
LOGGER.info("E");
CONFIG_BRANCH.get(testEntryName).sync(test, SyncMode.RESPACK_LOAD);
assertFalse((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
CONFIG_BRANCH.get(testEntryName).sync(test, SyncMode.CONF_LOAD);
save();
load(testEntryName);
assertTrue((Boolean) CONFIG_BRANCH.get(testEntryName).get(testEntry1Name).getValue());
}
}