Relax conditions syntax via enhanced TypeAdapterFactory for Sets

This commit is contained in:
JFronny 2021-09-16 08:35:26 +02:00
parent bc8512e098
commit 18886c6635
No known key found for this signature in database
GPG Key ID: BEC5ACBBD4EE17E5
9 changed files with 132 additions and 67 deletions

View File

@ -2,14 +2,10 @@
"conditions": [ "conditions": [
"lumi:subcategoryTest.enableLang", "lumi:subcategoryTest.enableLang",
{ {
"not": [ "not": "subcategoryTest.enableLangForceDisable"
"subcategoryTest.enableLangForceDisable"
]
} }
], ],
"fallbacks": [ "fallback": "assets/minecraft/lang/en_us_joke.json",
"assets/minecraft/lang/en_us_joke.json"
],
"expansions": { "expansions": {
"Lights": "{lumi.subcategoryTest.enableLang}", "Lights": "{lumi.subcategoryTest.enableLang}",
"Mode": "{lumi.debugMode}", "Mode": "{lumi.debugMode}",

View File

@ -34,9 +34,10 @@ public class RpoModInfo {
.registerTypeAdapter(ConfigBooleanEntry.class, new BooleanEntrySerializer()) .registerTypeAdapter(ConfigBooleanEntry.class, new BooleanEntrySerializer())
.registerTypeAdapter(ConfigBranch.class, new ConfigBranchSerializer()) .registerTypeAdapter(ConfigBranch.class, new ConfigBranchSerializer())
.registerTypeAdapter(Script.class, new ScriptDeserializer()) .registerTypeAdapter(Script.class, new ScriptDeserializer())
.registerTypeAdapter(FileRpo.class, new RpoDeserializer()) .registerTypeAdapter(FileRpo.class, new FileRpoDeserializer())
.registerTypeAdapter(DirRpo.class, new DirRpoDeserializer()) .registerTypeAdapter(DirRpo.class, new DirRpoDeserializer())
.registerTypeAdapter(Condition.class, new ConditionDeserializer()) .registerTypeAdapter(Condition.class, new ConditionDeserializer())
.registerTypeAdapterFactory(new SingleElementSetTypeAdapterFactory())
.setPrettyPrinting() .setPrettyPrinting()
.create(); .create();
try { try {

View File

@ -3,11 +3,11 @@ package io.gitlab.jfronny.respackopts.data;
import io.gitlab.jfronny.respackopts.data.condition.Condition; import io.gitlab.jfronny.respackopts.data.condition.Condition;
import meteordevelopment.starscript.Script; import meteordevelopment.starscript.Script;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
public class FileRpo { public class FileRpo {
public Condition conditions; public Condition conditions;
public List<String> fallbacks; public Set<String> fallbacks;
public Map<String, Script> expansions; public Map<String, Script> expansions;
} }

View File

@ -8,14 +8,12 @@ import net.minecraft.util.Identifier;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
import java.util.List;
public class FileFallbackProvider { public class FileFallbackProvider {
public static boolean fileVisible(WrappedPack pack, String name) { public static boolean fileVisible(WrappedPack pack, String name) {
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> { return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
if (rpo.fallbacks != null) { if (rpo.fallbacks != null) {
List<String> arr = rpo.fallbacks; for (String s : rpo.fallbacks) {
for (String s : arr) {
ResourcePath tmp = new ResourcePath(s); ResourcePath tmp = new ResourcePath(s);
if (pack.contains(tmp.getType(), tmp.getId())) if (pack.contains(tmp.getType(), tmp.getId()))
return true; return true;
@ -29,8 +27,7 @@ public class FileFallbackProvider {
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> { return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
try { try {
if (rpo.fallbacks != null) { if (rpo.fallbacks != null) {
List<String> arr = rpo.fallbacks; for (String s : rpo.fallbacks) {
for (String s : arr) {
ResourcePath tmp = new ResourcePath(s); ResourcePath tmp = new ResourcePath(s);
if (pack.contains(tmp.getType(), tmp.getId())) if (pack.contains(tmp.getType(), tmp.getId()))
return pack.open(tmp.getType(), tmp.getId()); return pack.open(tmp.getType(), tmp.getId());

View File

@ -15,19 +15,15 @@ public class DirRpoDeserializer implements JsonDeserializer<DirRpo> {
DirRpo rpo = new DirRpo(); DirRpo rpo = new DirRpo();
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) { for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
switch (entry.getKey()) { switch (entry.getKey()) {
case "conditions": case "conditions", "condition" -> rpo.conditions = context.deserialize(entry.getValue(), Condition.class);
case "condition": case "fallbacks", "fallback" -> {
rpo.conditions = context.deserialize(entry.getValue(), Condition.class);
break;
case "fallbacks":
case "fallback":
if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isString()) { if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isString()) {
rpo.fallback = entry.getValue().getAsString(); rpo.fallback = entry.getValue().getAsString();
} }
else { else {
throw new JsonParseException("Directory .rpos only support a single fallback"); throw new JsonParseException("Directory .rpos only support a single fallback");
} }
break; }
} }
} }
return rpo; return rpo;

View File

@ -0,0 +1,30 @@
package io.gitlab.jfronny.respackopts.gson;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.respackopts.data.FileRpo;
import io.gitlab.jfronny.respackopts.data.condition.Condition;
import meteordevelopment.starscript.Script;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
public class FileRpoDeserializer implements JsonDeserializer<FileRpo> {
private static final Type stringScriptMapType = new TypeToken<Map<String, Script>>(){}.getType();
private static final Type stringSetType = new TypeToken<Set<String>>(){}.getType();
@Override
public FileRpo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (!json.isJsonObject())
throw new JsonParseException("Rpo must be a json object");
FileRpo rpo = new FileRpo();
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
switch (entry.getKey()) {
case "conditions", "condition" -> rpo.conditions = context.deserialize(entry.getValue(), Condition.class);
case "fallbacks", "fallback" -> rpo.fallbacks = context.deserialize(entry.getValue(), stringSetType);
case "expansions", "expansion" -> rpo.expansions = context.deserialize(entry.getValue(), stringScriptMapType);
}
}
return rpo;
}
}

View File

@ -1,46 +0,0 @@
package io.gitlab.jfronny.respackopts.gson;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.respackopts.data.FileRpo;
import io.gitlab.jfronny.respackopts.data.condition.Condition;
import meteordevelopment.starscript.Script;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RpoDeserializer implements JsonDeserializer<FileRpo> {
@Override
public FileRpo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (!json.isJsonObject())
throw new JsonParseException("Rpo must be a json object");
FileRpo rpo = new FileRpo();
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
switch (entry.getKey()) {
case "conditions":
case "condition":
rpo.conditions = context.deserialize(entry.getValue(), Condition.class);
break;
case "fallbacks":
case "fallback":
if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isString()) {
rpo.fallbacks = new ArrayList<>();
rpo.fallbacks.add(entry.getValue().getAsString());
}
else {
Type listType = new TypeToken<List<String>>(){}.getType();
rpo.fallbacks = context.deserialize(entry.getValue(), listType);
}
break;
case "expansions":
case "expansion":
Type listType = new TypeToken<Map<String, Script>>(){}.getType();
rpo.expansions = context.deserialize(entry.getValue(), listType);
break;
}
}
return rpo;
}
}

View File

@ -0,0 +1,66 @@
package io.gitlab.jfronny.respackopts.gson;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import io.gitlab.jfronny.respackopts.RpoModInfo;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedHashSet;
import java.util.Set;
public class SingleElementSetTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
if (typeToken.getRawType() != Set.class
|| !(type instanceof ParameterizedType pt))
return null;
if (RpoModInfo.CONFIG.debugLogs)
RpoModInfo.LOGGER.info("Using SingleElementSetTypeAdapter for " + typeToken.toString());
Type elementType = pt.getActualTypeArguments()[0];
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
return (TypeAdapter<T>) createAdapter(elementAdapter);
}
private <T> TypeAdapter<Set<T>> createAdapter(final TypeAdapter<T> elementAdapter) {
return new TypeAdapter<>() {
@Override
public void write(JsonWriter out, Set<T> value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginArray();
for (T entry : value) {
elementAdapter.write(out, entry);
}
out.endArray();
}
@Override
public Set<T> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
Set<T> list = new LinkedHashSet<>();
if (in.peek() == JsonToken.BEGIN_ARRAY) {
in.beginArray();
while (in.hasNext()) {
list.add(elementAdapter.read(in));
}
in.endArray();
}
else list.add(elementAdapter.read(in));
return list;
}
};
}
}

View File

@ -1,5 +1,7 @@
package io.gitlab.jfronny.respackopts; package io.gitlab.jfronny.respackopts;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.respackopts.data.ConfigFile;
import io.gitlab.jfronny.respackopts.data.entry.*; import io.gitlab.jfronny.respackopts.data.entry.*;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -8,6 +10,7 @@ import org.junit.jupiter.api.Test;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Set;
import static io.gitlab.jfronny.respackopts.Respackopts.*; import static io.gitlab.jfronny.respackopts.Respackopts.*;
import static io.gitlab.jfronny.respackopts.RpoModInfo.*; import static io.gitlab.jfronny.respackopts.RpoModInfo.*;
@ -22,6 +25,7 @@ class RespackoptsTest {
static void initialize() { static void initialize() {
LOGGER.info("Expected error end"); LOGGER.info("Expected error end");
CONF_DIR = Paths.get("./test"); CONF_DIR = Paths.get("./test");
CONFIG = new ConfigFile();
assertDoesNotThrow(() -> Files.deleteIfExists(CONF_DIR.resolve(testEntry1Name + ".json"))); assertDoesNotThrow(() -> Files.deleteIfExists(CONF_DIR.resolve(testEntry1Name + ".json")));
assertDoesNotThrow(() -> Files.createDirectories(CONF_DIR)); assertDoesNotThrow(() -> Files.createDirectories(CONF_DIR));
SAVE_ACTIONS.add(() -> LOGGER.info("Save")); SAVE_ACTIONS.add(() -> LOGGER.info("Save"));
@ -94,4 +98,25 @@ class RespackoptsTest {
cbNew.add(testEntryName, new ConfigBooleanEntry(true)); cbNew.add(testEntryName, new ConfigBooleanEntry(true));
cbNew.sync(cb, SyncMode.RESPACK_LOAD); cbNew.sync(cb, SyncMode.RESPACK_LOAD);
} }
@Test
void gsonSetOrder() {
String[] expected = new String[] {"one", "two", "three", "zero", "76"};
String gson = "[\"one\", \"two\", \"three\", \"zero\", \"76\"]";
Set<String> parsed = GSON.fromJson(gson, new TypeToken<Set<String>>(){}.getType());
int i = 0;
for (String s : parsed) {
assertEquals(s, expected[i++]);
}
}
@Test
void gsonSingleEntrySet() {
String gson = "\"someText\"";
Set<String> parsed = GSON.fromJson(gson, new TypeToken<Set<String>>(){}.getType());
assertEquals(parsed.size(), 1);
for (String s : parsed) {
assertEquals(s, "someText");
}
}
} }