Named Binary Tags (NBT)
Read and write the tag data Bedrock stores on items.
NBT (Named Binary Tag) is the key/value format Bedrock uses to store structured data - on items, blocks, and entities. Endstone exposes it through the tag types in endstone/nbt, so you read and edit it without touching the binary format. The examples alias the namespace with namespace es = endstone;.
Tag types
Every value is a typed tag. Scalars expose .value(); the container tags nest other tags:
| Tag | Holds |
|---|---|
ByteTag, ShortTag, IntTag, LongTag | an integer |
FloatTag, DoubleTag | a float |
StringTag | a string |
ByteArrayTag, IntArrayTag | an array of integers |
ListTag | a sequence of tags (all the same type) |
CompoundTag | a map of named tags |
CompoundTag indexes by key with operator[] and iterates as {key, tag} pairs; a Tag extracted from it is read back with get<T>() (throws on a type mismatch) or get_if<T>() (returns a pointer, or nullptr).
Read an item's NBT
ItemStack::getNbt() returns a CompoundTag. Iterate it, or pull a scalar out with get_if:
#include <endstone/endstone.hpp>
namespace es = endstone;
// `player` is an endstone::Player
auto item = player.getInventory().getItemInMainHand();
if (!item) {
return;
}
es::CompoundTag tag = item->getNbt();
for (const auto &[key, value] : tag) {
getLogger().info("{}", key);
}
if (auto *level = tag["my_plugin:level"].get_if<es::IntTag>()) {
int value = level->value();
}Write NBT
Edit the CompoundTag and hand it back with setNbt. Wrap raw values in the matching tag type:
es::CompoundTag tag = item->getNbt();
tag["my_plugin:level"] = es::IntTag(5);
tag["my_plugin:owner"] = es::StringTag("Steve");
item->setNbt(tag);Namespace your keys (my_plugin:level, not level) so they can't collide with the vanilla data Bedrock keeps on the same item.
Build nested structures
CompoundTag and ListTag nest, so you can build whatever shape you need. CompoundTag also takes an initializer list of key/tag pairs:
es::CompoundTag stats{{"kills", es::IntTag(10)}};
es::ListTag lore;
lore.emplace_back(es::StringTag("Forged in fire"));
stats["lore"] = lore;Serialize and load
To persist NBT or move it between systems, nbt::dump() writes the binary form and nbt::load() reads it back. Bedrock uses little-endian byte order, which is the default:
std::string data = es::nbt::dump(tag); // little-endian
es::Tag restored = es::nbt::load(data);Pass std::endian::big for Java-style NBT, or network=true for Bedrock's network varint encoding.