Proper conditions
This commit is contained in:
parent
b07e0a0671
commit
f825b73e38
|
@ -46,6 +46,7 @@ There have been issues with LibCD in development, so it might be smart not to us
|
||||||
Respackopts allows creating conditional resources by creating a file named `{targetFile}.rpo`.\
|
Respackopts allows creating conditional resources by creating a file named `{targetFile}.rpo`.\
|
||||||
This file is a json file that contains an array named "conditions". The resource will be ignored if any of the conditions are not met.\
|
This file is a json file that contains an array named "conditions". The resource will be ignored if any of the conditions are not met.\
|
||||||
This allows (for example) overrides for textures to only be loaded if the user enables them through the config.\
|
This allows (for example) overrides for textures to only be loaded if the user enables them through the config.\
|
||||||
|
It also allows the following operations: `and`, `equal`, `nor`/`not`, `or`, `xor`
|
||||||
As an example can be seen [here](https://gitlab.com/JFronny/respackopts/-/tree/master/run/resourcepacks/lumi/assets/minecraft/lang)
|
As an example can be seen [here](https://gitlab.com/JFronny/respackopts/-/tree/master/run/resourcepacks/lumi/assets/minecraft/lang)
|
||||||
## Mod developers
|
## Mod developers
|
||||||
All data is available in static HashMaps in `io.gitlab.jfronny.respackopts.Respackopts`.\
|
All data is available in static HashMaps in `io.gitlab.jfronny.respackopts.Respackopts`.\
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
{
|
{
|
||||||
"conditions": [
|
"conditions": [
|
||||||
"lumi:subcategoryTest.enableLang"
|
"lumi:subcategoryTest.enableLang",
|
||||||
|
{
|
||||||
|
"not": [
|
||||||
|
"lumi:subcategoryTest.enableLangForceDisable"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -31,7 +31,8 @@
|
||||||
"default": 16,
|
"default": 16,
|
||||||
"max": 20
|
"max": 20
|
||||||
},
|
},
|
||||||
"enableLang": true
|
"enableLang": true,
|
||||||
|
"enableLangForceDisable": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,27 +134,4 @@ public class Respackopts implements ClientModInitializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean matchStringCondition(String condition) throws SyntaxError {
|
|
||||||
if (condition == null) {
|
|
||||||
throw new SyntaxError("Condition must not be null");
|
|
||||||
}
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!found.get()) {
|
|
||||||
throw new SyntaxError("Could not find pack with specified ID");
|
|
||||||
}
|
|
||||||
return output.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class AndCondition implements Condition {
|
||||||
|
@Override
|
||||||
|
public boolean evaluate(JsonElement node) throws SyntaxError {
|
||||||
|
if (!node.isJsonArray())
|
||||||
|
throw new SyntaxError("\"and\" condition requires an array of conditions");
|
||||||
|
for (JsonElement jsonElement : node.getAsJsonArray()) {
|
||||||
|
if (!ConditionEvaluator.evaluate(jsonElement))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
Set<String> strings = new LinkedHashSet<>();
|
||||||
|
strings.add("add");
|
||||||
|
strings.add("&");
|
||||||
|
strings.add("conditions"); // This is also the root condition
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface Condition {
|
||||||
|
boolean evaluate(JsonElement node) throws SyntaxError;
|
||||||
|
Set<String> getKeys();
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||||
|
|
||||||
|
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<Condition> conditions;
|
||||||
|
static {
|
||||||
|
conditions = new LinkedHashSet<>();
|
||||||
|
conditions.add(new AndCondition());
|
||||||
|
conditions.add(new OrCondition());
|
||||||
|
conditions.add(new XorCondition());
|
||||||
|
conditions.add(new EqualityCondition());
|
||||||
|
conditions.add(new NorCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean evaluate(JsonElement condition) throws SyntaxError {
|
||||||
|
if (condition.isJsonPrimitive() && condition.getAsJsonPrimitive().isString())
|
||||||
|
return evaluate(condition.getAsString());
|
||||||
|
if (condition.isJsonObject() && condition.getAsJsonObject().size() == 1) {
|
||||||
|
for (Map.Entry<String, JsonElement> entry : condition.getAsJsonObject().entrySet()) {
|
||||||
|
for (Condition c : conditions) {
|
||||||
|
if (c.getKeys().contains(entry.getKey())) {
|
||||||
|
return c.evaluate(entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new SyntaxError("Could not find condition: " + entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new SyntaxError("Condition entries may only be json objects containing one key and one value or strings");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean evaluate(String condition) throws SyntaxError {
|
||||||
|
if (condition == null) {
|
||||||
|
throw new SyntaxError("Condition must not be null");
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!found.get()) {
|
||||||
|
throw new SyntaxError("Could not find pack with specified ID");
|
||||||
|
}
|
||||||
|
return output.get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
//TODO implement equality checking for string/number variables
|
||||||
|
public class EqualityCondition implements Condition {
|
||||||
|
@Override
|
||||||
|
public boolean evaluate(JsonElement node) throws SyntaxError {
|
||||||
|
if (!node.isJsonArray())
|
||||||
|
throw new SyntaxError("\"equal\" condition requires an array of conditions");
|
||||||
|
Optional<Boolean> v = Optional.empty();
|
||||||
|
for (JsonElement jsonElement : node.getAsJsonArray()) {
|
||||||
|
boolean current = ConditionEvaluator.evaluate(jsonElement);
|
||||||
|
if (!v.isPresent())
|
||||||
|
v = Optional.of(current);
|
||||||
|
if (current != v.get())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
Set<String> strings = new LinkedHashSet<>();
|
||||||
|
strings.add("==");
|
||||||
|
strings.add("=");
|
||||||
|
strings.add("equal");
|
||||||
|
strings.add("eq");
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class NorCondition implements Condition {
|
||||||
|
@Override
|
||||||
|
public boolean evaluate(JsonElement node) throws SyntaxError {
|
||||||
|
if (!node.isJsonArray())
|
||||||
|
throw new SyntaxError("\"not\"/\"nor\" condition requires an array of conditions");
|
||||||
|
for (JsonElement jsonElement : node.getAsJsonArray()) {
|
||||||
|
if (ConditionEvaluator.evaluate(jsonElement))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
Set<String> strings = new LinkedHashSet<>();
|
||||||
|
strings.add("not");
|
||||||
|
strings.add("nor");
|
||||||
|
strings.add("!");
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class OrCondition implements Condition {
|
||||||
|
@Override
|
||||||
|
public boolean evaluate(JsonElement node) throws SyntaxError {
|
||||||
|
if (!node.isJsonArray())
|
||||||
|
throw new SyntaxError("\"or\" condition requires an array of conditions");
|
||||||
|
for (JsonElement jsonElement : node.getAsJsonArray()) {
|
||||||
|
if (ConditionEvaluator.evaluate(jsonElement))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
Set<String> strings = new LinkedHashSet<>();
|
||||||
|
strings.add("or");
|
||||||
|
strings.add("|");
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package io.gitlab.jfronny.respackopts.conditions;
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||||
import io.gitlab.jfronny.respackopts.data.RpoResourceEntry;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
@ -23,18 +23,7 @@ public class ResourcePackFilter {
|
||||||
if (!containsFileBase.test(name + Respackopts.fileExtension))
|
if (!containsFileBase.test(name + Respackopts.fileExtension))
|
||||||
return true;
|
return true;
|
||||||
try (InputStream stream = openFileBase.apply(name + Respackopts.fileExtension); Reader w = new InputStreamReader(stream)) {
|
try (InputStream stream = openFileBase.apply(name + Respackopts.fileExtension); Reader w = new InputStreamReader(stream)) {
|
||||||
RpoResourceEntry entry = Respackopts.g.fromJson(w, RpoResourceEntry.class);
|
return ConditionEvaluator.evaluate(Respackopts.g.fromJson(w, JsonElement.class));
|
||||||
if (entry.conditions != null) {
|
|
||||||
for (String condition : entry.conditions) {
|
|
||||||
if (!Respackopts.matchStringCondition(condition))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Respackopts.logger.error("Conditions null for " + name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package io.gitlab.jfronny.respackopts.conditions;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class XorCondition implements Condition {
|
||||||
|
@Override
|
||||||
|
public boolean evaluate(JsonElement node) throws SyntaxError {
|
||||||
|
if (!node.isJsonArray())
|
||||||
|
throw new SyntaxError("\"xor\" condition requires an array of conditions");
|
||||||
|
boolean bl = false;
|
||||||
|
for (JsonElement jsonElement : node.getAsJsonArray()) {
|
||||||
|
if (ConditionEvaluator.evaluate(jsonElement))
|
||||||
|
bl = !bl;
|
||||||
|
}
|
||||||
|
return bl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
Set<String> strings = new LinkedHashSet<>();
|
||||||
|
strings.add("^");
|
||||||
|
strings.add("xor");
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
package io.gitlab.jfronny.respackopts.data;
|
|
||||||
|
|
||||||
public class RpoResourceEntry {
|
|
||||||
public String[] conditions;
|
|
||||||
}
|
|
|
@ -1,9 +1,11 @@
|
||||||
package io.gitlab.jfronny.respackopts.integration;
|
package io.gitlab.jfronny.respackopts.integration;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
import io.github.cottonmc.libcd.api.CDSyntaxError;
|
import io.github.cottonmc.libcd.api.CDSyntaxError;
|
||||||
import io.github.cottonmc.libcd.api.condition.ConditionManager;
|
import io.github.cottonmc.libcd.api.condition.ConditionManager;
|
||||||
import io.github.cottonmc.libcd.api.init.ConditionInitializer;
|
import io.github.cottonmc.libcd.api.init.ConditionInitializer;
|
||||||
import io.gitlab.jfronny.respackopts.Respackopts;
|
import io.gitlab.jfronny.respackopts.Respackopts;
|
||||||
|
import io.gitlab.jfronny.respackopts.conditions.ConditionEvaluator;
|
||||||
import io.gitlab.jfronny.respackopts.conditions.SyntaxError;
|
import io.gitlab.jfronny.respackopts.conditions.SyntaxError;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
@ -11,15 +13,22 @@ public class LibCDCompat implements ConditionInitializer {
|
||||||
@Override
|
@Override
|
||||||
public void initConditions(ConditionManager conditionManager) {
|
public void initConditions(ConditionManager conditionManager) {
|
||||||
conditionManager.registerCondition(new Identifier(Respackopts.ID, "cfg"), q -> {
|
conditionManager.registerCondition(new Identifier(Respackopts.ID, "cfg"), q -> {
|
||||||
if (!(q instanceof String)) {
|
if (q instanceof String) {
|
||||||
throw new CDSyntaxError("Expected string");
|
|
||||||
}
|
|
||||||
String s = (String) q;
|
|
||||||
try {
|
try {
|
||||||
return Respackopts.matchStringCondition(s);
|
return ConditionEvaluator.evaluate((String) q);
|
||||||
} catch (SyntaxError syntaxError) {
|
} catch (Throwable error) {
|
||||||
throw new CDSyntaxError(syntaxError.getMessage());
|
throw new CDSyntaxError(error.getMessage());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (q instanceof JsonElement) {
|
||||||
|
try {
|
||||||
|
return ConditionEvaluator.evaluate((JsonElement) q);
|
||||||
|
} catch (Throwable error) {
|
||||||
|
throw new CDSyntaxError(error.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new CDSyntaxError("Expected Json element or string for rpo libcd conditions");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user