This library enables you to work with NBT using standard Kotlin types.
Note:
- NBT doesn't know
null
- Compound =
Map<String, Any>
- List =
List<E>
Basic operations
Read
val dataInputStream: DataInputStream
// Read a byte
val nbt: Byte = dataInputStream.readNBT()
// Read a named compound
val (name, compound) = dataInputStream.readNamedNBTCompound()
val compound = dataInputStream.readNamedNBTCompound("name")
Write
val dataOutputStream: DataOutputStream
// Write a byte
val byte: Byte
dataOutputStream.writeNBT(byte)
// Write a named compound
val name: String
val compound: Map<String, Any>
dataOutputStream.writeNamedNBTCompound(name, compound)
Stringify
val nbt: Any
val output: String = nbt.toSNBT()
Example
Input:
val nbt: Map<String, Any> = mapOf(
"foo" to listOf("bar", "x"),
"answer" to 42.0,
"baz" to mapOf(
"pi" to intArrayOf(3, 1, 4, 1)
)
)
println(nbt.toSNBT())
Output:
{
"foo": [
"bar",
"x"
],
"answer": 42.0D,
"baz": {
"pi": [3, 1, 4, 1]
}
}
Advanced
Compression
Currently not supported. See this issue.
Merging
Map-only merging
You can use NBT.mergeMaps(a, b)
to merge two compounds into one, deeply.
Lists will not be merged.
Algorithm:
val c = a
for (key in b) {
if (key in a && a[key] is Map && b[key] is Map) {
c[key] = mergeMaps(a[key], b[key])
} else {
c[key] = b[key]
}
}
Demonstration
{ { {
"foo": 0, "foo": 10, "foo": 10,
"bar": { "bar": { "bar": {
"baz": 1, "baz": 11, "baz": 11,
"qux": 2 + => "qux": 2,
"abc": 3 "abc": 3
}, }, },
"xyz": 4, "xyz": 4,
"list": [ "list": [ "list": [
"!", "," ","
"/"
] ] ]
} } }
List-only merging
You can use NBT.mergeLists(a, b)
to merge two lists into one, deeply.
Compounds will not be merged.
Algorithm:
val c = a
for (index in b) {
if (index in a && a[index] is List && b[index] is List) {
c[index] = mergeLists(a[index], b[index])
} else {
c[index] = b[index]
}
}
Demonstration
[ [ [
[ [ [
0, 10, 10,
1, 11, 11,
2 12, 12,
5 5
], + ], => ],
[ [ [
{"x": 3}, {} {},
{"y": 4} {"y": 4}
] ], ],
[] []
] ] ]
List-concatenating map merging
You can use NBT.mergeMapsAdding(a, b)
to merge two compounds into one, deeply.
Lists that are present in both a
and b
will be concatenated.
Algorithm:
val c = a
for (key in b) {
if (key in a) {
if (a[key] is Map && b[key] is Map) {
c[key] = merge(a[key], b[key])
}
else if (a[key] is List && b[key] is List) {
c[key] = a[key] + b[key]
}
else {
c[key] = b[key]
}
} else {
c[key] = b[key]
}
}
Demonstration
{ { {
"foo": 0, "foo": 10, "foo": 10,
"bar": { "bar": { "bar": {
"baz": 1, "baz": 11, "baz": 11,
"qux": 2 + => "qux": 2,
"abc": 3 "abc": 3
}, }, },
"xyz": 4, "xyz": 4,
"list": [ "list": [ "list": [
"!", "!",
"/" "/",
"," ","
] ] ]
} } }
Map merging
You can use NBT.merge(a, b)
to merge two compounds into one, deeply.
Lists will be merged too.
Algorithm:
val c = a
for (key in b) {
if (key in a) {
if (a[key] is Map && b[key] is Map) {
c[key] = merge(a[key], b[key])
}
else if (a[key] is List && b[key] is List) {
c[key] = merge(a[key], b[key])
}
else {
c[key] = b[key]
}
} else {
c[key] = b[key]
}
}
Demonstration
{ { {
"foo": 0, "foo": 10, "foo": 10,
"bar": { "bar": { "bar": {
"baz": 1, "baz": 11, "baz": 11,
"qux": 2 + => "qux": 2,
"abc": 3 "abc": 3
}, }, },
"xyz": 4, "xyz": 4,
"list": [ "list": [ "list": [
{ { {
"x": "!" "x": "!",
"y": ",", "y": ",",
"z": "%" "z": "%"
}, } },
{ "y": "/" } { "y": "/" }
] ] ]
} } }
List merging
You can use NBT.merge(a, b)
to merge two lists into one, deeply.
Compounds will be merged too.
Algorithm:
val c = a
for (index in b) {
if (index in a) {
if (a[index] is Map && b[index] is Map) {
c[index] = merge(a[index], b[index])
}
else if (a[index] is List && b[index] is List) {
c[index] = merge(a[index], b[index])
}
else {
c[index] = b[index]
}
} else {
c[index] = b[index]
}
}
Demonstration
[ [ [
[ [ [
0, 10, 10,
1, 11, 11,
2 12, 12,
5 5
], + ], => ],
[ [ [
{ { {
"x": 3 "x": 3,
"z": 7 "z": 7
}, } },
{ {
"y": 4 "y": 4
} }
] ], ],
[] []
] ] ]
Paths
Additional Information
Type map:
Byte
: TAG_ByteShort
: TAG_ShortInt
: TAG_IntLong
: TAG_LongFloat
: TAG_FloatDouble
: TAG_DoubleByteArray
: TAG_Byte_ArrayString
: Tag_StringList
: TAG_List, values must be of a single valid NBT typeMap
: TAG_Compound, keys must be strings, values must be valid NBT typesIntArray
: TAG_Int_ArrayLongArray
: TAG_Long_Array
For more detail, see NBT Specification.