Skip to content

Instantly share code, notes, and snippets.

@tox1cozZ
Created April 22, 2024 10:02
Show Gist options
  • Save tox1cozZ/74f5b9f1d0c4216f2c3867a573ff63cf to your computer and use it in GitHub Desktop.
Save tox1cozZ/74f5b9f1d0c4216f2c3867a573ff63cf to your computer and use it in GitHub Desktop.
Minecraft ItemStack Jackson adapter
package io.github.tox1cozz.externalengine.util.json.deserializer
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.node.ObjectNode
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
object JsonItemStackDeserializer : JsonDeserializer<ItemStack>() {
override fun deserialize(parser: JsonParser, ctx: DeserializationContext): ItemStack {
val json = parser.readValueAsTree<ObjectNode>()
val id = json["id"].asText()
check(Item.itemRegistry.containsKey(id)) {
"Item with id '$id' doesn't exists"
}
return ItemStack(
Item.itemRegistry.getObject(id) as Item,
json["count"]?.intValue() ?: 1,
json["metadata"]?.intValue() ?: 0
).apply {
json["tag"]?.also {
tagCompound = parser.codec.treeToValue(it, NBTTagCompound::class.java)
}
}
}
}
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import io.github.tox1cozz.externalengine.util.game.stringId
import net.minecraft.item.ItemStack
object JsonItemStackSerializer : JsonSerializer<ItemStack>() {
override fun serialize(itemStack: ItemStack, json: JsonGenerator, provider: SerializerProvider) {
json.writeStartObject()
json.writeStringField("id", itemStack.stringId)
json.writeNumberField("count", itemStack.stackSize)
json.writeNumberField("metadata", itemStack.itemDamage)
if (itemStack.hasTagCompound()) {
provider.defaultSerializeField("tag", itemStack.tagCompound, json)
}
json.writeEndObject()
}
}
package io.github.tox1cozz.externalengine.util.json.deserializer
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import net.minecraft.nbt.*
import net.minecraftforge.common.util.Constants.NBT
class JsonNBTDeserializer(private val typeInNameDelimiter: Char? = '$') : JsonDeserializer<NBTTagCompound>() {
override fun deserialize(parser: JsonParser, ctx: DeserializationContext): NBTTagCompound {
return deserializeCompoundNBT(parser.readValueAsTree())
}
private fun deserializeNBT(key: String?, data: JsonNode, id: Int): NBTBase {
var type = id
var value = data
if (id == -1) {
if (typeInNameDelimiter != null) {
type = key!!.substringAfterLast(typeInNameDelimiter).toInt()
} else {
type = data["type"].asInt()
value = data["value"]
}
}
return when (type) {
NBT.TAG_END -> NBTTagEnd()
NBT.TAG_BYTE -> NBTTagByte(value.asInt().toByte())
NBT.TAG_SHORT -> NBTTagShort(value.asInt().toShort())
NBT.TAG_INT -> NBTTagInt(value.asInt())
NBT.TAG_LONG -> NBTTagLong(value.asLong())
NBT.TAG_FLOAT -> NBTTagFloat(value.asDouble().toFloat())
NBT.TAG_DOUBLE -> NBTTagDouble(value.asDouble())
NBT.TAG_ANY_NUMERIC -> deserializeNBT(key, data, NBT.TAG_LONG)
NBT.TAG_STRING -> NBTTagString(value.asText())
NBT.TAG_COMPOUND -> deserializeCompoundNBT(value)
NBT.TAG_LIST -> {
NBTTagList().apply {
val tagType = value["tagType"].asInt()
value["value"].forEach { tag ->
appendTag(deserializeNBT(null, tag, tagType))
}
}
}
NBT.TAG_BYTE_ARRAY -> NBTTagByteArray(value.map { it.asInt().toByte() }.toByteArray())
NBT.TAG_INT_ARRAY -> NBTTagIntArray(value.map { it.asInt() }.toIntArray())
else -> throw IllegalArgumentException("Unknown nbt type")
}
}
private fun deserializeCompoundNBT(json: JsonNode): NBTTagCompound {
val nbt = NBTTagCompound()
json.fields().forEach { (key, value) ->
val nbtKey = if (typeInNameDelimiter != null) key.substringBeforeLast(typeInNameDelimiter) else key
nbt.setTag(nbtKey, deserializeNBT(key, value, -1))
}
return nbt
}
}
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import io.github.tox1cozz.externalengine.util.game.tags
import net.minecraft.nbt.*
class JsonNBTSerializer(private val typeInNameDelimiter: Char? = '$') : JsonSerializer<NBTTagCompound>() {
override fun serialize(nbt: NBTTagCompound, json: JsonGenerator, provider: SerializerProvider) {
serializeCompoundNBT(json, nbt)
}
private fun serializeCompoundNBT(json: JsonGenerator, nbt: NBTTagCompound) {
json.writeStartObject()
nbt.tags.forEach { (key, tag) ->
if (tag is NBTTagEnd) return@forEach
if (typeInNameDelimiter != null) {
json.writeFieldName(key + typeInNameDelimiter + tag.id)
serializeNBT(json, tag)
} else {
json.writeObjectFieldStart(key)
json.writeFieldName("value")
serializeNBT(json, tag)
json.writeNumberField("type", tag.id.toShort())
json.writeEndObject()
}
}
json.writeEndObject()
}
private fun serializeNBT(json: JsonGenerator, tag: NBTBase) {
when (tag) {
is NBTTagByte -> json.writeNumber(tag.func_150290_f().toShort())
is NBTTagShort -> json.writeNumber(tag.func_150289_e())
is NBTTagInt -> json.writeNumber(tag.func_150287_d())
is NBTTagLong -> json.writeNumber(tag.func_150291_c())
is NBTTagFloat -> json.writeNumber(tag.func_150288_h())
is NBTTagDouble -> json.writeNumber(tag.func_150286_g())
is NBTTagString -> json.writeString(tag.func_150285_a_())
is NBTTagCompound -> serializeCompoundNBT(json, tag)
is NBTTagList -> {
json.writeStartObject()
json.writeArrayFieldStart("value")
tag.tags.forEach {
serializeNBT(json, it)
}
json.writeEndArray()
json.writeNumberField("tagType", tag.func_150303_d())
json.writeEndObject()
}
is NBTTagByteArray -> {
json.writeStartArray()
tag.func_150292_c().forEach {
json.writeNumber(it.toShort())
}
json.writeEndArray()
}
is NBTTagIntArray -> {
json.writeStartArray()
tag.func_150302_c().forEach {
json.writeNumber(it)
}
json.writeEndArray()
}
else -> throw IllegalArgumentException("Unsupported nbt tag: " + tag.javaClass.name)
}
}
}
ObjectMapper#registerModule(
SimpleModule().addSerializer(ItemStack::class.java, JsonItemStackSerializer)
.addDeserializer(ItemStack::class.java, JsonItemStackDeserializer)
.addSerializer(NBTTagCompound::class.java, JsonNBTSerializer())
.addDeserializer(NBTTagCompound::class.java, JsonNBTDeserializer())
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment