Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/mojang/minecraft-creator-tools/llms.txt

Use this file to discover all available pages before exploring further.

The NbtBinary class provides functionality for reading and writing NBT (Named Binary Tag) format, which is used throughout Minecraft for structured data storage.

Overview

NBT is a binary format used in:
  • level.dat - World settings and metadata
  • Block actors (tile entities) - Chests, signs, spawners, etc.
  • Entities - Mobs, items, armor stands
  • Structure files - .mcstructure files
  • Player data

Constructor

const nbt = new NbtBinary();
nbt.context = 'level.dat'; // Optional context for error messages

Loading NBT Data

fromBinary
(data: Uint8Array, littleEndian: boolean, isVarint: boolean, skipBytes?: number, stringsAreASCII?: boolean, processAsList?: boolean) => number
Parses NBT binary data.Parameters:
  • data - Binary data to parse
  • littleEndian - Use little-endian byte order (true for Bedrock)
  • isVarint - Use varint encoding for lengths
  • skipBytes - Number of bytes to skip at start (e.g., 8 for level.dat)
  • stringsAreASCII - Optimize for ASCII strings
  • processAsList - Parse as list of multiple root tags
Returns: Number of bytes read
const nbt = new NbtBinary();
const bytesRead = nbt.fromBinary(
  fileBytes,
  true,  // littleEndian for Bedrock
  false, // no varint
  8      // skip 8-byte header in level.dat
);

Writing NBT Data

toBinary
() => Uint8Array | undefined
Serializes the NBT structure to binary format.
const bytes = nbt.toBinary();
if (bytes) {
  await file.setContent(bytes);
}

Accessing Data

roots
NbtBinaryTag[] | null
Array of root tags. Most files have a single root.
if (nbt.roots && nbt.roots.length > 0) {
  const root = nbt.roots[0];
}
singleRoot
NbtBinaryTag | null
Convenience getter for the first root tag.
const root = nbt.singleRoot;
if (root) {
  const levelName = root.find('LevelName');
  console.log(levelName?.valueAsString);
}

Creating NBT Structure

ensureSingleRoot
() => NbtBinaryTag
Creates or returns the single root compound tag.
const root = nbt.ensureSingleRoot();
root.ensureTag('LevelName', NbtTagType.string).value = 'My World';
root.ensureTag('SpawnX', NbtTagType.int).value = 0;
root.ensureTag('SpawnY', NbtTagType.int).value = 100;
root.ensureTag('SpawnZ', NbtTagType.int).value = 0;

JSON Conversion

getJson
() => INbtTag
Converts NBT structure to JSON object.
const json = nbt.getJson();
console.log(JSON.stringify(json, null, 2));
getJsonString
() => string
Converts NBT structure to JSON string.
const jsonStr = nbt.getJsonString();

NbtBinaryTag

Individual NBT tags are represented by NbtBinaryTag:

Properties

type
NbtTagType
Tag type (compound, list, int, string, etc.).
name
string
Tag name (empty for list children).
value
string | number | bigint | bigint[] | number[] | boolean | null
Tag value (type depends on tag type).

Methods

find
(name: string) => NbtBinaryTag | null
Recursively searches for a tag by name.
const tag = root.find('LevelName');
if (tag) {
  console.log(tag.valueAsString);
}
child
(name: string) => NbtBinaryTag | null
Gets a direct child tag by name.
const abilities = root.child('abilities');
const mayFly = abilities?.child('mayfly');
ensureTag
(tagName: string, tagType: NbtTagType) => NbtBinaryTag
Gets or creates a tag.
const levelName = root.ensureTag('LevelName', NbtTagType.string);
levelName.value = 'New Name';
addTag
(tagType: NbtTagType, tagName?: string) => NbtBinaryTag
Adds a new tag.
const newTag = root.addTag(NbtTagType.int, 'MyValue');
newTag.value = 42;
removeTag
(tagName: string) => boolean
Removes a tag by name.
root.removeTag('oldProperty');
getTagChildren
() => NbtBinaryTag[]
Gets all child tags (excludes end tag).
for (const child of root.getTagChildren()) {
  console.log(`${child.name}: ${child.valueAsString}`);
}

Value Accessors

valueAsString
string
Gets value as string.
const name = tag.valueAsString;
valueAsInt
number
Gets value as integer.
const x = tag.valueAsInt;
valueAsFloat
number
Gets value as float.
valueAsBigInt
bigint
Gets value as bigint.
const time = tag.valueAsBigInt;
valueAsBoolean
boolean
Gets value as boolean.
const enabled = tag.valueAsBoolean;
valueAsNumericArray
number[]
Gets list children as numeric array.
const version = tag.valueAsNumericArray; // [1, 20, 0]
valueAsJSONObject
any
Parses string value as JSON.
const layers = tag.valueAsJSONObject;

NBT Tag Types

enum NbtTagType {
  end = 0,        // End of compound
  byte = 1,       // 8-bit signed integer
  short = 2,      // 16-bit signed integer
  int = 3,        // 32-bit signed integer
  long = 4,       // 64-bit signed integer
  float = 5,      // 32-bit float
  double = 6,     // 64-bit float
  byteArray = 7,  // Array of bytes
  string = 8,     // UTF-8 string
  list = 9,       // List of tags (same type)
  compound = 10,  // Named tags
  intArray = 11,  // Array of ints
  longArray = 12  // Array of longs
}

Example: Reading level.dat

import { NbtBinary, NbtTagType } from '@minecraft/creator-tools';

async function readLevelDat(file: IFile) {
  await file.loadContent();
  const bytes = file.content as Uint8Array;
  
  const nbt = new NbtBinary();
  nbt.context = 'level.dat';
  
  // level.dat has 8-byte header before NBT data
  nbt.fromBinary(bytes, true, false, 8);
  
  const root = nbt.singleRoot;
  if (!root) {
    console.error('No root tag found');
    return;
  }
  
  // Read basic properties
  const levelName = root.find('LevelName')?.valueAsString;
  const spawnX = root.find('SpawnX')?.valueAsInt;
  const spawnY = root.find('SpawnY')?.valueAsInt;
  const spawnZ = root.find('SpawnZ')?.valueAsInt;
  const gameType = root.find('GameType')?.valueAsInt;
  
  console.log(`World: ${levelName}`);
  console.log(`Spawn: (${spawnX}, ${spawnY}, ${spawnZ})`);
  console.log(`Game Type: ${gameType}`);
  
  // Read experiments
  const experiments = root.find('experiments');
  if (experiments) {
    const betaApis = experiments.child('gametest')?.valueAsBoolean;
    console.log(`Beta APIs: ${betaApis}`);
  }
}

Example: Modifying NBT

async function modifyLevelDat(file: IFile) {
  await file.loadContent();
  const bytes = file.content as Uint8Array;
  
  const nbt = new NbtBinary();
  nbt.fromBinary(bytes, true, false, 8);
  
  const root = nbt.ensureSingleRoot();
  
  // Modify properties
  root.ensureTag('LevelName', NbtTagType.string).value = 'Modified World';
  root.ensureTag('commandsEnabled', NbtTagType.byte).value = 1;
  root.ensureTag('showcoordinates', NbtTagType.byte).value = 1;
  
  // Enable experiment
  const experiments = root.ensureTag('experiments', NbtTagType.compound);
  experiments.ensureTag('gametest', NbtTagType.byte).value = 1;
  
  // Save with 8-byte header
  const nbtBytes = nbt.toBinary();
  if (nbtBytes) {
    const fullBytes = new Uint8Array(nbtBytes.length + 8);
    fullBytes.set(nbtBytes, 8);
    
    // Write header (version 10, length)
    fullBytes[0] = 10; fullBytes[1] = 0; fullBytes[2] = 0; fullBytes[3] = 0;
    fullBytes[4] = nbtBytes.length & 0xFF;
    fullBytes[5] = (nbtBytes.length >> 8) & 0xFF;
    fullBytes[6] = (nbtBytes.length >> 16) & 0xFF;
    fullBytes[7] = (nbtBytes.length >> 24) & 0xFF;
    
    file.setContent(fullBytes);
    await file.saveContent();
  }
}

Example: Reading Block Actor Data

function parseChestData(nbtBytes: Uint8Array) {
  const nbt = new NbtBinary();
  nbt.context = 'Chest';
  nbt.fromBinary(nbtBytes, true, false, 0, true);
  
  const root = nbt.singleRoot;
  if (!root) return;
  
  // Get chest position
  const x = root.find('x')?.valueAsInt;
  const y = root.find('y')?.valueAsInt;
  const z = root.find('z')?.valueAsInt;
  
  console.log(`Chest at (${x}, ${y}, ${z})`);
  
  // Get items
  const items = root.find('Items');
  if (items) {
    const itemList = items.getTagChildren();
    console.log(`Contains ${itemList.length} items:`);
    
    for (const item of itemList) {
      const name = item.find('Name')?.valueAsString;
      const count = item.find('Count')?.valueAsInt;
      const slot = item.find('Slot')?.valueAsInt;
      console.log(`  Slot ${slot}: ${name} x${count}`);
    }
  }
}

Example: Creating NBT Structure

function createStructure() {
  const nbt = new NbtBinary();
  const root = nbt.ensureSingleRoot();
  
  // Add basic types
  root.ensureTag('name', NbtTagType.string).value = 'My Structure';
  root.ensureTag('version', NbtTagType.int).value = 1;
  root.ensureTag('size', NbtTagType.list).setListFromArray([16, 16, 16]);
  
  // Add compound
  const metadata = root.ensureTag('metadata', NbtTagType.compound);
  metadata.ensureTag('author', NbtTagType.string).value = 'Player';
  metadata.ensureTag('created', NbtTagType.long).value = BigInt(Date.now());
  
  // Add list of compounds
  const blocks = root.ensureTag('blocks', NbtTagType.list);
  blocks.childTagType = NbtTagType.compound;
  
  for (let i = 0; i < 10; i++) {
    const block = blocks.addTag(NbtTagType.compound);
    block.ensureTag('pos', NbtTagType.list).setListFromArray([i, 0, 0]);
    block.ensureTag('state', NbtTagType.int).value = 0;
  }
  
  // Serialize
  const bytes = nbt.toBinary();
  return bytes;
}

Error Handling

The NBT classes implement IErrorable:
const nbt = new NbtBinary();
nbt.fromBinary(bytes, true, false, 8);

if (nbt.isInErrorState) {
  console.error('NBT parsing errors:');
  for (const error of nbt.errorMessages || []) {
    console.error(`  ${error.message}`);
    if (error.context) {
      console.error(`    Context: ${error.context}`);
    }
  }
}

Build docs developers (and LLMs) love