feat: Add *base64 and *json nbt path matchers
This commit is contained in:
@@ -1,7 +1,14 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.util
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
import java.util.Base64
|
||||||
|
|
||||||
object Base64Util {
|
object Base64Util {
|
||||||
|
fun decodeString(str: String): String {
|
||||||
|
return Base64.getDecoder().decode(str.padToValidBase64())
|
||||||
|
.decodeToString()
|
||||||
|
}
|
||||||
|
|
||||||
fun String.padToValidBase64(): String {
|
fun String.padToValidBase64(): String {
|
||||||
val align = this.length % 4
|
val align = this.length % 4
|
||||||
if (align == 0) return this
|
if (align == 0) return this
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.features.texturepack.predicates
|
package moe.nea.firmament.features.texturepack.predicates
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonPrimitive
|
import com.google.gson.JsonPrimitive
|
||||||
|
import com.mojang.serialization.JsonOps
|
||||||
|
import kotlin.jvm.optionals.getOrDefault
|
||||||
import moe.nea.firmament.features.texturepack.FirmamentModelPredicate
|
import moe.nea.firmament.features.texturepack.FirmamentModelPredicate
|
||||||
import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser
|
import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser
|
||||||
import moe.nea.firmament.features.texturepack.StringMatcher
|
import moe.nea.firmament.features.texturepack.StringMatcher
|
||||||
@@ -17,8 +19,10 @@ import net.minecraft.nbt.NbtFloat
|
|||||||
import net.minecraft.nbt.NbtInt
|
import net.minecraft.nbt.NbtInt
|
||||||
import net.minecraft.nbt.NbtList
|
import net.minecraft.nbt.NbtList
|
||||||
import net.minecraft.nbt.NbtLong
|
import net.minecraft.nbt.NbtLong
|
||||||
|
import net.minecraft.nbt.NbtOps
|
||||||
import net.minecraft.nbt.NbtShort
|
import net.minecraft.nbt.NbtShort
|
||||||
import net.minecraft.nbt.NbtString
|
import net.minecraft.nbt.NbtString
|
||||||
|
import moe.nea.firmament.util.Base64Util
|
||||||
import moe.nea.firmament.util.extraAttributes
|
import moe.nea.firmament.util.extraAttributes
|
||||||
|
|
||||||
fun interface NbtMatcher {
|
fun interface NbtMatcher {
|
||||||
@@ -261,6 +265,20 @@ class NbtPrism(val path: List<String>) {
|
|||||||
var switch = mutableListOf<NbtElement>()
|
var switch = mutableListOf<NbtElement>()
|
||||||
for (pathSegment in path) {
|
for (pathSegment in path) {
|
||||||
if (pathSegment == ".") continue
|
if (pathSegment == ".") continue
|
||||||
|
if (pathSegment != "*" && pathSegment.startsWith("*")) {
|
||||||
|
if (pathSegment == "*json") {
|
||||||
|
for (element in rootSet) {
|
||||||
|
val eString = element.asString() ?: continue
|
||||||
|
val element = Gson().fromJson(eString, JsonElement::class.java)
|
||||||
|
switch.add(JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, element))
|
||||||
|
}
|
||||||
|
} else if (pathSegment == "*base64") {
|
||||||
|
for (element in rootSet) {
|
||||||
|
val string = element.asString() ?: continue
|
||||||
|
switch.add(NbtString.of(Base64Util.decodeString(string)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for (element in rootSet) {
|
for (element in rootSet) {
|
||||||
if (element is NbtList) {
|
if (element is NbtList) {
|
||||||
if (pathSegment == "*")
|
if (pathSegment == "*")
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ Filter by item type:
|
|||||||
|
|
||||||
Filter by extra attribute NBT data:
|
Filter by extra attribute NBT data:
|
||||||
|
|
||||||
Specify a `path` to look at, separating sub elements with a `.`. You can use a `*` to check any child.
|
Specify a `path` (using an [nbt prism](#nbt-prism)) to look at, separating sub elements with a `.`. You can use a `*` to check any child.
|
||||||
|
|
||||||
Then either specify a `match` sub-object or directly inline that object in the format of an [nbt matcher](#nbt-matcher).
|
Then either specify a `match` sub-object or directly inline that object in the format of an [nbt matcher](#nbt-matcher).
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ Sub object match:
|
|||||||
You can match generic components similarly to [extra attributes](#extra-attributes). If you want to match an extra
|
You can match generic components similarly to [extra attributes](#extra-attributes). If you want to match an extra
|
||||||
attribute match directly using that, for better performance.
|
attribute match directly using that, for better performance.
|
||||||
|
|
||||||
You can specify a `path` and match similar to extra attributes, but in addition you can also specify a `component`. This
|
You can specify a `path` (using an [nbt prism](#nbt-prism)) and match similar to extra attributes, but in addition you can also specify a `component`. This
|
||||||
variable is the identifier of a component type that will then be encoded to nbt and matched according to the `match`
|
variable is the identifier of a component type that will then be encoded to nbt and matched according to the `match`
|
||||||
using a [nbt matcher](#nbt-matcher).
|
using a [nbt matcher](#nbt-matcher).
|
||||||
|
|
||||||
@@ -336,6 +336,58 @@ compare your number:
|
|||||||
This example would match if the level is less than fifty. The available operators are `<`, `>`, `<=` and `>=`. The
|
This example would match if the level is less than fifty. The available operators are `<`, `>`, `<=` and `>=`. The
|
||||||
operator needs to be specified on the left. The versions of the operator with `=` also allow the number to be equal.
|
operator needs to be specified on the left. The versions of the operator with `=` also allow the number to be equal.
|
||||||
|
|
||||||
|
### Nbt Prism
|
||||||
|
|
||||||
|
An nbt prism (or path) is used to specify where in a complex nbt construct to look for a value. A basic prism just looks
|
||||||
|
like a dot-separated path (`parent.child.grandchild`), but more complex paths can be constructed.
|
||||||
|
|
||||||
|
First the specified path is split into dot separated chunks: `"a.b.c"` -> `["a", "b", "c"]`. You can also directly
|
||||||
|
specify the list if you would like. Any entry in that list not starting with a `*` ist treated as an attribute name or
|
||||||
|
an index:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"propA": {
|
||||||
|
"propB": {
|
||||||
|
"propC": 100,
|
||||||
|
"propD": 1000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"someOtherProp": "hello",
|
||||||
|
"someThirdProp": "{\"innerProp\": true}",
|
||||||
|
"someFourthProp": "aGlkZGVuIHZhbHVl"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example json (which is supposed to represent a corresponding nbt object), you can use a path like
|
||||||
|
`propA.propB.propC` to directly extract the value `100`.
|
||||||
|
|
||||||
|
If you want to extract all of the innermost values of `propB`
|
||||||
|
(for example if `propB` was an array instead), you could use `propA.propB.*`. You can use the `*` at any level:
|
||||||
|
`*.*.*` for example extracts all properties that are exactly at the third level. In that case you would try to match any
|
||||||
|
of the values of `[100, 1000]` to your match object.
|
||||||
|
|
||||||
|
Sometimes values are encoded in a non-nbt format inside a string. For those you can use other star based directives like
|
||||||
|
`*base64` or `*json` to decode those entries.
|
||||||
|
|
||||||
|
`*base64` turns a base64 encoded string into the base64 decoded counterpart. `*.json` decodes a string into the json
|
||||||
|
object represented by that string. Note that json to nbt conversion isn't always straightforwards and the types can
|
||||||
|
end up being mangled (for example what could have been a byte ends up an int).
|
||||||
|
|
||||||
|
| Path | Result |
|
||||||
|
|---------------------------------|---------------------------------|
|
||||||
|
| `propA.propB` | `{"propC": 100, "propD": 1000}` |
|
||||||
|
| `propA.propB.propC` | `100` |
|
||||||
|
| `propA.*.propC` | `100` |
|
||||||
|
| `propA.propB.*` | `100`, `1000` |
|
||||||
|
| `someOtherProp` | `"hello"` |
|
||||||
|
| `someThirdProp` | "{\"innerProp\": true}" |
|
||||||
|
| `someThirdProp.*json` | {"innerProp": true} |
|
||||||
|
| `someThirdProp.*json.innerProp` | true |
|
||||||
|
| `someFourthProp` | `"aGlkZGVuIHZhbHVl"` |
|
||||||
|
| `someFourthProp.*base64` | `"hidden value"` |
|
||||||
|
|
||||||
|
|
||||||
### Nbt Matcher
|
### Nbt Matcher
|
||||||
|
|
||||||
This matches a single nbt element.
|
This matches a single nbt element.
|
||||||
|
|||||||
Reference in New Issue
Block a user