BetterNBT

A lightweight (under 250 lines of code) Kotlin library for Fabric 1.18.x that allows intuitively working
with Minecraft NBT by reading & writing to a custom data structure.

Install

Step 1: put this into your gradle.properties:

better_nbt_version=v1.0.0

Step 2: put this into your build.gradle:

repositories {
    maven {
        url = "https://redgrapefruit09.github.io/maven"
        content {
            includeGroup "com.redgrapefruit.betternbt"
        }
    }
}

Step 3: put this in your dependencies block in the build.gradle after the last line:

modImplementation "com.redgrapefruit.betternbt:betternbt:${project.better_nbt_version}"
include "com.redgrapefruit.betternbt:betternbt:${project.better_nbt_version}"

Step 4: refresh your Gradle project.

Usage guide

In this tutorial we’ll be creating a simple counter item that:

  • Stores an integer counter in its NBT
  • Increments that counter every tick
  • Displays the counter in its tooltip

First, we need to create the class, from which a schema can be generated.
A schema is a description of all nodes (regular fields) and sub-schemas (nested compounds) in the structure of an NBT.
The schema will be created from a class’s set of mutable properties, and if a property has a node serializer,
it’s a node, else it will be interpreted as a sub-schema.

Our class only holds the integer property, so it’ll look like this:

class CounterItemData {
    var counter: Int = 0
    
    companion object {
        // Store the schema for this class, use the T::class.schema() method to get
        // a schema for your structure class
        val SCHEMA = CounterItemData::class.schema()
    }
}

Now we’ll have to create our Item class, from which we’ll make useNbt calls to work with our data
and increment the counter & display it in the tooltip:

class CounterItem : Item(Settings().group(ItemGroup.MISC)) {
    override fun inventoryTick(stack: ItemStack, world: World, entity: Entity, slot: Int, selected: Boolean) {
        useNbt<CounterItemData /* the serialized structure */>(
            stack.orCreateNbt /* the NBT tag */,
            CounterItemData.SCHEMA /* the schema */) { data /* the instance of your structure, which has the data read
            in and, if you mutate it, will be saved back to the given NBT tag */ ->

            data.counter++ // increment the counter
        }
    }

    override fun appendTooltip(
        stack: ItemStack,
        world: World?,
        tooltip: MutableList<Text>,
        context: TooltipContext
    ) {
        // repeat the call from above
        useNbt<CounterItemData>(stack.orCreateNbt, CounterItemData.SCHEMA) { data ->
            tooltip += LiteralText(data.counter.toString()) // add a literal text with the counter to the item's tooltip
        }
    }
}

Now register your item into the game (see this tutorial if you don’t know how
to do it) and you’ll see a saved counter item working just fine!

GitHub

View Github