Usage

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_Byte
  • Short: TAG_Short
  • Int: TAG_Int
  • Long: TAG_Long
  • Float: TAG_Float
  • Double: TAG_Double
  • ByteArray: TAG_Byte_Array
  • String: Tag_String
  • List: TAG_List, values must be of a single valid NBT type
  • Map: TAG_Compound, keys must be strings, values must be valid NBT types
  • IntArray: TAG_Int_Array
  • LongArray: TAG_Long_Array

For more detail, see NBT Specification.