Skip to content

Commit

Permalink
feat(nbt): add serializers for tags and item stack
Browse files Browse the repository at this point in the history
TODO: add unit tests for serializers
  • Loading branch information
SettingDust committed Sep 27, 2022
1 parent cd09ebb commit 26f2f3a
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 0 deletions.
4 changes: 4 additions & 0 deletions silk-nbt/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ plugins {
kotlin("plugin.serialization")
}

dependencies {
api(modProject(":${rootProject.name}-core"))
}

val modName by extra("$projectTitle NBT")
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.silkmc.silk.nbt.serialization.serializer

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.element
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import net.minecraft.nbt.CompoundTag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import net.silkmc.silk.core.serialization.SilkSerializer

// TODO: Unit test
@ExperimentalSerializationApi
object ItemStackSerializer : SilkSerializer<ItemStack>() {
override val descriptor = buildClassSerialDescriptor(descriptorName) {
element<ResourceLocation>("id")
element<Int>("Count")
element<CompoundTag>("tag")
}

override fun deserialize(decoder: Decoder) =
run { ItemStack.of(decoder.decodeSerializableValue(CompoundTagSerializer))!! }

override fun serialize(encoder: Encoder, value: ItemStack) =
encoder.encodeSerializableValue(CompoundTagSerializer, CompoundTag().also(value::save))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package net.silkmc.silk.nbt.serialization.serializer

import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.listSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import net.minecraft.nbt.*
import net.silkmc.silk.core.serialization.SilkSerializer

// TODO: Unit test
@ExperimentalSerializationApi
abstract class TagSerializer<T : Tag>(
primitiveKind: PrimitiveKind = PrimitiveKind.STRING
) : SilkSerializer<T>(primitiveKind)

@ExperimentalSerializationApi
object BaseTagSerializer : TagSerializer<Tag>() {
private val serializer = PolymorphicSerializer(Tag::class)
override val descriptor = serializer.descriptor
override fun deserialize(decoder: Decoder) = serializer.deserialize(decoder)
override fun serialize(encoder: Encoder, value: Tag) = serializer.serialize(encoder, value)
}

@ExperimentalSerializationApi
object CompoundTagSerializer : TagSerializer<CompoundTag>() {
private val serializer = MapSerializer(String.serializer(), BaseTagSerializer)
override val descriptor = serializer.descriptor
override fun deserialize(decoder: Decoder) = CompoundTag().apply { serializer.deserialize(decoder).forEach(::put) }
override fun serialize(encoder: Encoder, value: CompoundTag) =
serializer.serialize(encoder, value.allKeys.map { it to value[it]!! }.toMap())
}

@ExperimentalSerializationApi
object EndTagSerializer : TagSerializer<EndTag>(PrimitiveKind.BYTE) {
override fun deserialize(decoder: Decoder) = EndTag.INSTANCE.also { decoder.decodeByte() }
override fun serialize(encoder: Encoder, value: EndTag) = encoder.encodeByte(0)
}

@ExperimentalSerializationApi
object StringTagSerializer : TagSerializer<StringTag>(PrimitiveKind.STRING) {
override fun deserialize(decoder: Decoder) = StringTag.valueOf(decoder.decodeString())!!
override fun serialize(encoder: Encoder, value: StringTag) = encoder.encodeString(value.asString)
}

/**
* NumericTag
*/
@ExperimentalSerializationApi
object ByteTagSerializer : TagSerializer<ByteTag>(PrimitiveKind.BYTE) {
override fun deserialize(decoder: Decoder) = ByteTag.valueOf(decoder.decodeByte())!!
override fun serialize(encoder: Encoder, value: ByteTag) = encoder.encodeByte(value.asByte)
}

@ExperimentalSerializationApi
object DoubleTagSerializer : TagSerializer<DoubleTag>(PrimitiveKind.DOUBLE) {
override fun deserialize(decoder: Decoder) = DoubleTag.valueOf(decoder.decodeDouble())!!
override fun serialize(encoder: Encoder, value: DoubleTag) = encoder.encodeDouble(value.asDouble)
}

@ExperimentalSerializationApi
object FloatTagSerializer : TagSerializer<FloatTag>(PrimitiveKind.FLOAT) {
override fun deserialize(decoder: Decoder) = FloatTag.valueOf(decoder.decodeFloat())!!
override fun serialize(encoder: Encoder, value: FloatTag) = encoder.encodeFloat(value.asFloat)
}

@ExperimentalSerializationApi
object IntTagSerializer : TagSerializer<IntTag>(PrimitiveKind.INT) {
override fun deserialize(decoder: Decoder) = IntTag.valueOf(decoder.decodeInt())!!
override fun serialize(encoder: Encoder, value: IntTag) = encoder.encodeInt(value.asInt)
}

@ExperimentalSerializationApi
object LongTagSerializer : TagSerializer<LongTag>(PrimitiveKind.LONG) {
override fun deserialize(decoder: Decoder) = LongTag.valueOf(decoder.decodeLong())!!
override fun serialize(encoder: Encoder, value: LongTag) = encoder.encodeLong(value.asLong)
}

@ExperimentalSerializationApi
object ShortTagSerializer : TagSerializer<ShortTag>(PrimitiveKind.SHORT) {
override fun deserialize(decoder: Decoder) = ShortTag.valueOf(decoder.decodeShort())!!
override fun serialize(encoder: Encoder, value: ShortTag) = encoder.encodeShort(value.asShort)
}

/**
* CollectionTag
*/
@ExperimentalSerializationApi
open class CollectionTagSerializer<U : Tag, T : CollectionTag<U>>(
private val tag: TagSerializer<U>,
private val constructor: (List<U>) -> T
) : TagSerializer<T>() {
override val descriptor = listSerialDescriptor(tag.descriptor)
override fun deserialize(decoder: Decoder) = constructor(ListSerializer(tag).deserialize(decoder))
override fun serialize(encoder: Encoder, value: T) = ListSerializer(tag).serialize(encoder, value)
}

@ExperimentalSerializationApi
object ListTagSerializer :
CollectionTagSerializer<Tag, ListTag>(BaseTagSerializer, {
ListTag().apply {
addAll(it)
}
})

@ExperimentalSerializationApi
object ByteArrayTagSerializer :
CollectionTagSerializer<ByteTag, ByteArrayTag>(ByteTagSerializer, { list -> ByteArrayTag(list.map { it.asByte }) })

@ExperimentalSerializationApi
object IntArrayTagSerializer :
CollectionTagSerializer<IntTag, IntArrayTag>(IntTagSerializer, { list -> IntArrayTag(list.map { it.asInt }) })

@ExperimentalSerializationApi
object LongArrayTagSerializer :
CollectionTagSerializer<LongTag, LongArrayTag>(LongTagSerializer, { list -> LongArrayTag(list.map { it.asLong }) })

0 comments on commit 26f2f3a

Please sign in to comment.