Skip to content

NBTBlockEntity

abstract class NBTBlockEntity(
    type: BlockEntityType<*>, 
    pos: BlockPos, 
    blockState: BlockState
) : BlockEntity, NBTHolder

A BlockEntity base class that automatically persists fields declared with NBTHolder delegates to and from the block entity's CompoundTag.

Subclass this and declare fields using the NBTHolder delegation API:

class MyBlockEntity(pos: BlockPos, state: BlockState)
    : NBTBlockEntity(MY_TYPE, pos, state) {

    var energy by nbt.intField()
    var label  by nbt.stringField { "default" }
    val items  by nbt.itemField(9)
}

Saving and loading are handled automatically via saveAdditional and loadAdditional. Call BlockEntity.setChanged to push the block entity state to tracking clients.

Constructors

NBTBlockEntity

constructor(
    type: BlockEntityType<*>, 
    pos: BlockPos, 
    blockState: BlockState
)

Properties

blockPos

open val blockPos: BlockPos?

blockState

open var blockState: BlockState?

isRemoved

open val isRemoved: Boolean

level

@get:



Nullable



open var level: Level?

modelData

open val modelData: ModelData?

persistentData

open val persistentData: CompoundTag?

type

open val type: BlockEntityType<*>?

updatePacket

open override val updatePacket: Packet<ClientGamePacketListener>?

Functions

applyComponents

fun applyComponents(components: DataComponentMap?, patch: DataComponentPatch?)

applyComponentsFromItemStack

fun applyComponentsFromItemStack(stack: ItemStack?)

booleanField

open override fun booleanField(default: () -> Boolean): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, Boolean>>

byteField

open override fun byteField(default: () -> Byte): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, Byte>>

clearRemoved

open fun clearRemoved()

collectComponents

fun collectComponents(): DataComponentMap?

components

open fun components(): DataComponentMap?

doubleField

open override fun doubleField(default: () -> Double): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, Double>>

energyField

open override fun energyField(capacity: Long, onUpdate: () -> Unit?): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ArchieEnergyStorage>>

Declares an ArchieEnergyStorage field capped at capacity, keyed by the delegated property's name. See itemField for onUpdate's semantics.

energyListField

Declares an ArchieStorageList of ArchieEnergyStorages, each capped at capacity, keyed by the delegated property's name. See itemMapField for onUpdate's semantics.

energyMapField

Declares an ArchieStorageMap of ArchieEnergyStorages, each capped at capacity, keyed by the delegated property's name. See itemMapField for onUpdate's semantics.

field

open override fun <T> field(serializer: KSerializer<T>, default: () -> T): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, T>>

Declares a read-write field backed by serializer, keyed by the delegated property's name. default supplies the value used before the field has been loaded/set.

field

inline fun <T> NBTHolder.field(noinline default: () -> T): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, T>>

Reified variant of NBTHolder.field that resolves the KSerializer for T automatically.

fillCrashReportCategory

open fun fillCrashReportCategory(reportCategory: CrashReportCategory?)

floatField

open override fun floatField(default: () -> Float): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, Float>>

fluidField

open override fun fluidField(
    limit: Long, 
    size: Int, 
    filter: Predicate<FluidResource>, 
    onUpdate: () -> Unit?
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ArchieFluidStorage>>

Declares an ArchieFluidStorage field with size tank slots each capped at limit, keyed by the delegated property's name. See itemField for onUpdate's semantics.

fluidListField

open override fun fluidListField(
    limit: Long, 
    size: Int, 
    filter: Predicate<FluidResource>, 
    onUpdate: () -> Unit?
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ArchieStorageList<ArchieFluidStorage>>>

Declares an ArchieStorageList of ArchieFluidStorages, each with size tank slots capped at limit, keyed by the delegated property's name. See itemMapField for onUpdate's semantics.

fluidMapField

open override fun fluidMapField(
    limit: Long, 
    size: Int, 
    filter: Predicate<FluidResource>, 
    onUpdate: () -> Unit?
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ArchieStorageMap<ArchieFluidStorage>>>

Declares an ArchieStorageMap of ArchieFluidStorages, each with size tank slots capped at limit, keyed by the delegated property's name. See itemMapField for onUpdate's semantics.

getData

open fun <T : Any?> getData(type: Supplier<AttachmentType<T?>?>?): T?
fun <T : Any?> getData(type: AttachmentType<T?>?): T?

getExistingData

open fun <T : Any?> getExistingData(type: Supplier<AttachmentType<T?>?>?): Optional<T?>?
open fun <T : Any?> getExistingData(type: AttachmentType<T?>?): Optional<T?>?

getStateContainer

Convenience extension to get or create a state container for a block entity.

getSyncTag

open override fun getSyncTag(): CompoundTag

Builds a CompoundTag suitable for sending to the client to sync current field values.

getUpdatePacket

open override fun getUpdatePacket(): Packet<ClientGamePacketListener>?

Builds the block entity update packet carrying getUpdateTag's data.

getUpdateTag

open override fun getUpdateTag(provider: HolderLookup.Provider): CompoundTag

Returns the NBTHolder sync tag sent to tracking clients; see NBTHolder.getSyncTag.

handleUpdateTag

open fun handleUpdateTag(tag: CompoundTag?, lookupProvider: HolderLookup.Provider?)

hasAttachments

hasCustomOutlineRendering

open fun hasCustomOutlineRendering(player: Player?): Boolean

hasData

open fun <T : Any?> hasData(type: Supplier<AttachmentType<T?>?>?): Boolean
fun hasData(type: AttachmentType<*>?): Boolean

hasLevel

open fun hasLevel(): Boolean

intField

open override fun intField(default: () -> Int): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, Int>>

invalidateCapabilities

@ApiStatus.NonExtendable



open fun invalidateCapabilities()

isValidBlockState

open fun isValidBlockState(arg: BlockState?): Boolean

itemField

open override fun itemField(
    size: Int, 
    filter: Predicate<ItemResource>, 
    onUpdate: () -> Unit?
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ArchieItemStorage>>

Declares an ArchieItemStorage field with size slots, keyed by the delegated property's name. onUpdate, if given, runs in addition to (not instead of) this holder's own internal bookkeeping (persistence, @Sync propagation, BlockEntity.setChanged, ...) every time ArchieItemStorage.update fires for this specific field - a caller-supplied "something in this inventory changed" hook, without needing to poll it or re-derive the same notification some other way.

itemListField

open override fun itemListField(
    size: Int, 
    filter: Predicate<ItemResource>, 
    onUpdate: () -> Unit?
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ArchieStorageList<ArchieItemStorage>>>

Declares an ArchieStorageList of ArchieItemStorages, each with size slots, keyed by the delegated property's name. See itemMapField for onUpdate's semantics.

itemMapField

open override fun itemMapField(
    size: Int, 
    filter: Predicate<ItemResource>, 
    onUpdate: () -> Unit?
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ArchieStorageMap<ArchieItemStorage>>>

Declares an ArchieStorageMap of ArchieItemStorages, each with size slots, keyed by the delegated property's name. onUpdate, if given, runs whenever the map's own structure changes (an entry added/removed/cleared) or any individual entry's own contents change - every entry the map creates is wired with the map's own persistence trigger as well, so a mutation deep inside one entry is never silently unpersisted.

listField

open override fun <T> listField(serializer: KSerializer<T>, default: () -> List<T>): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, ObservableList<T>>>

Declares a mutable-list field backed by serializer, keyed by the delegated property's name.

listField

inline fun <T> NBTHolder.listField(noinline default: () -> List<T>): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, MutableList<T>>>

Reified variant of NBTHolder.listField that resolves the KSerializer for T automatically.

loadCustomOnly

fun loadCustomOnly(tag: CompoundTag?, registries: HolderLookup.Provider?)

loadFromTag

open override fun loadFromTag(compoundTag: CompoundTag)

Loads every declared field's value from compoundTag, overwriting current values.

loadWithComponents

fun loadWithComponents(tag: CompoundTag?, registries: HolderLookup.Provider?)

longField

open override fun longField(default: () -> Long): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, Long>>

mapField

open override fun <T> mapField(serializer: KSerializer<T>, default: () -> Map<String, T>): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, MutableMap<String, T>>>

Declares a mutable-map (keyed by String) field backed by serializer, keyed by the delegated property's name.

mapField

inline fun <T> NBTHolder.mapField(noinline default: () -> Map<String, T>): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, MutableMap<String, T>>>

Reified variant of NBTHolder.mapField that resolves the KSerializer for T automatically.

nestedField

open override fun <T : NBTHolder> nestedField(factory: (CompoundTag) -> T?): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, NestedNBTHolder<T>>>

Declares a single nested NBTHolder field, keyed by the delegated property's name and built once via factory - the scalar counterpart to nestedMapField/nestedListField. Unlike those, there's exactly one fixed-type entry, so no per-entry type discrimination is needed: factory takes no tag to inspect.

nestedListField

open override fun <T : NBTHolder> nestedListField(factory: (CompoundTag) -> T?): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, NestedNBTHolderList<T>>>

Declares a NestedNBTHolderList field, keyed by the delegated property's name - the index-ordered counterpart to nestedMapField; see its KDoc for factory's role and T's.

nestedMapField

open override fun <T : NBTHolder> nestedMapField(factory: (CompoundTag) -> T?): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, NestedNBTHolderMap<T>>>

Declares a NestedNBTHolderMap field, keyed by the delegated property's name. Unlike mapField, entries aren't one fixed kotlinx.serialization-compatible value type - each is its own self-contained NBTHolder, built fresh via factory either when first inserted (NestedNBTHolderMap.getOrPut) or, when loading a previously-saved entry back, from that entry's own raw sub-CompoundTag (so factory can inspect it - e.g. a stored "kind" field - to decide which concrete nested holder type to reconstruct). T is factory's return type - the common upper bound every entry shares, letting a caller declare e.g. NestedNBTHolderMap<HookHolderState> instead of always getting back the base NBTHolder type and having to cast every entry manually.

onChunkUnloaded

open fun onChunkUnloaded()

onDataPacket

open fun onDataPacket(
    net: Connection?, 
    pkt: ClientboundBlockEntityDataPacket?, 
    lookupProvider: HolderLookup.Provider?
)

onLoad

open fun onLoad()

onlyOpCanSetNbt

open fun onlyOpCanSetNbt(): Boolean

removeComponentsFromTag

open fun removeComponentsFromTag(tag: CompoundTag?)

removeData

@Nullable



open fun <T : Any?> removeData(type: Supplier<AttachmentType<T?>?>?): @Nullable



 T?
@Nullable



fun <T : Any?> removeData(type: AttachmentType<T?>?): T?

requestModelDataUpdate

saveCustomAndMetadata

fun saveCustomAndMetadata(registries: HolderLookup.Provider?): CompoundTag?

saveCustomOnly

fun saveCustomOnly(registries: HolderLookup.Provider?): CompoundTag?

saveToItem

open fun saveToItem(stack: ItemStack?, registries: HolderLookup.Provider?)

saveToTag

open override fun saveToTag(compoundTag: CompoundTag)

Writes every declared field's current value into compoundTag.

saveWithFullMetadata

fun saveWithFullMetadata(registries: HolderLookup.Provider?): CompoundTag?

saveWithId

fun saveWithId(registries: HolderLookup.Provider?): CompoundTag?

saveWithoutMetadata

fun saveWithoutMetadata(registries: HolderLookup.Provider?): CompoundTag?

serializeAttachments

@Nullable



fun serializeAttachments(provider: HolderLookup.Provider?): @Nullable



 CompoundTag?

setChanged

open fun setChanged()

setComponents

open fun setComponents(components: DataComponentMap?)

setData

@Nullable



open fun <T : Any?> setData(type: Supplier<AttachmentType<T?>?>?, data: T?): @Nullable



 T?
@Nullable



fun <T : Any?> setData(type: AttachmentType<T?>?, data: T?): T?

setRemoved

open fun setRemoved()

shortField

open override fun shortField(default: () -> Short): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, Short>>

stringField

open override fun stringField(default: () -> String): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, String>>

triggerEvent

open fun triggerEvent(id: Int, type: Int): Boolean

ubyteField

open override fun ubyteField(default: () -> UByte): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, UByte>>

uintField

open override fun uintField(default: () -> UInt): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, UInt>>

ulongField

open override fun ulongField(default: () -> ULong): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, ULong>>

updateProperty

open override fun <T> updateProperty(
    propertyName: String, 
    serializer: KSerializer<T>, 
    value: T
)

Updates a single field, identified by propertyName, from a client sync payload.

ushortField

open override fun ushortField(default: () -> UShort): PropertyDelegateProvider<Any?, ReadWriteProperty<Any?, UShort>>