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": [
"lumi:subcategoryTest.enableLang",
{
"not": [
"subcategoryTest.enableLangForceDisable"
]
"not": "subcategoryTest.enableLangForceDisable"
}
],
"fallbacks": [
"assets/minecraft/lang/en_us_joke.json"
],
"fallback": "assets/minecraft/lang/en_us_joke.json",
"expansions": {
"Lights": "{lumi.subcategoryTest.enableLang}",
"Mode": "{lumi.debugMode}",

View File

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

View File

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

View File

@ -8,14 +8,12 @@ import net.minecraft.util.Identifier;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
public class FileFallbackProvider {
public static boolean fileVisible(WrappedPack pack, String name) {
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
if (rpo.fallbacks != null) {
List<String> arr = rpo.fallbacks;
for (String s : arr) {
for (String s : rpo.fallbacks) {
ResourcePath tmp = new ResourcePath(s);
if (pack.contains(tmp.getType(), tmp.getId()))
return true;
@ -29,8 +27,7 @@ public class FileFallbackProvider {
return FileRpoSearchProvider.modifyWithRpo(name, pack, rpo -> {
try {
if (rpo.fallbacks != null) {
List<String> arr = rpo.fallbacks;
for (String s : arr) {
for (String s : rpo.fallbacks) {
ResourcePath tmp = new ResourcePath(s);
if (pack.contains(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();
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":
case "conditions", "condition" -> rpo.conditions = context.deserialize(entry.getValue(), Condition.class);
case "fallbacks", "fallback" -> {
if (entry.getValue().isJsonPrimitive() && entry.getValue().getAsJsonPrimitive().isString()) {
rpo.fallback = entry.getValue().getAsString();
}
else {
throw new JsonParseException("Directory .rpos only support a single fallback");
}
break;
}
}
}
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;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.respackopts.data.ConfigFile;
import io.gitlab.jfronny.respackopts.data.entry.*;
import org.junit.jupiter.api.AfterEach;
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.Paths;
import java.util.Set;
import static io.gitlab.jfronny.respackopts.Respackopts.*;
import static io.gitlab.jfronny.respackopts.RpoModInfo.*;
@ -22,6 +25,7 @@ class RespackoptsTest {
static void initialize() {
LOGGER.info("Expected error end");
CONF_DIR = Paths.get("./test");
CONFIG = new ConfigFile();
assertDoesNotThrow(() -> Files.deleteIfExists(CONF_DIR.resolve(testEntry1Name + ".json")));
assertDoesNotThrow(() -> Files.createDirectories(CONF_DIR));
SAVE_ACTIONS.add(() -> LOGGER.info("Save"));
@ -94,4 +98,25 @@ class RespackoptsTest {
cbNew.add(testEntryName, new ConfigBooleanEntry(true));
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");
}
}
}