Skip to content

Serialization

Archie provides a multi-layered serialization stack built on top of kotlinx.serialization and Mojang's Codec system.


NBT helpers (serialization/NBT.kt)

NBT object

A pre-configured Nbt instance (Java variant, no compression):

NBT.encodeToNbtTag(MyData.serializer(), myData)
NBT.decodeFromNbtTag(MyData.serializer(), tag)

Builder functions

val tag: CompoundTag = buildCompoundTag {
    put("count", NbtInt(42))
    put("label", NbtString("hello"))
}

val listTag: ListTag = buildListTag<NbtInt> {
    add(NbtInt(1)); add(NbtInt(2))
}

mergeToCompoundTag(existingTag) { put("extra", NbtString("value")) }

forEachTag(listTag) { nbt -> println(nbt) }

Extension conversions

// knbt ↔ Minecraft Tag
val mcTag: Tag = myNbtTag.toMinecraft
val knbtTag: NbtTag? = mcTag.fromMinecraft

// Compound round-trip
val compound: CompoundTag = nbtCompound.toMinecraft
val back: NbtCompound = compound.fromMinecraft

NBTHolder

NBTHolder is an interface that lets you declare NBT-backed fields via Kotlin property delegation.

class MyBlockEntity(pos, state) : NBTBlockEntity(TYPE, pos, state) {
    var count  by nbt.intField()
    var label  by nbt.stringField { "default" }
    val items  by nbt.itemField(9)  // 9-slot inventory

    // Generic field with custom serializer
    var pos    by nbt.field(BlockPos.CODEC.serializer()) { BlockPos.ZERO }
}

Available field types: boolean, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, string, item, plus a generic field(serializer, default).


Codec ↔ KSerializer bridge

Codec<T>.serializer() / CodecSerializer

Convert a Mojang Codec into a KSerializer so it can be used with kotlinx.serialization:

@Serializable
data class MyData(
    val biome: @Serializable(with = BiomeCodecSerializer::class) ResourceKey<Biome>,
)

object BiomeCodecSerializer : CodecSerializer<ResourceKey<Biome>>(Biome.CODEC)
// or simply:
val ser: KSerializer<ResourceKey<Biome>> = Biome.CODEC.serializer()

KSerializer<T>.codec() / SerializerCodec

Convert a KSerializer into a Mojang Codec:

@Serializable
data class Config(val value: Int, val name: String)

val CONFIG_CODEC: Codec<Config> = Config.serializer().codec()
// Equivalent to RecordCodecBuilder.create { ... } but derived from @Serializable

KSerializer<T>.getStreamCodec()

Produces a StreamCodec<RegistryFriendlyByteBuf, T> backed by CBOR:

val STREAM_CODEC = MyPacket.serializer().getStreamCodec()

KOps

KOps provides DynamicOps implementations for kotlinx.serialization's JsonElement, Toml's TomlElement, and knbt's NbtTag. These are used internally by SerializerCodec and CodecSerializer for Codec interop.


Minecraft type serializers

Register contextual serializers for common Minecraft types by including MinecraftSerializersModule:

Type Alias
BlockPos SBlockPos
ChunkPos SChunkPos
GlobalPos SGlobalPos
Vec3 SVec3
Vec3i SVec3i
BlockHitResult SBlockHitResult
ResourceLocation SerializableResourceLocation
FriendlyByteBuf SFriendlyByteBuf

Usage:

@Serializable
data class MyPacket(
    val pos: @Contextual BlockPos,
    val dir: String,
)

Sync

Archie's Sync utility enables automatic client–server synchronization of @Serializable data classes attached to block entities, using the NBTHolder system under the hood.