All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jglrxavpok.hephaistos.json.NBTGsonReader.kt Maven / Gradle / Ivy

The newest version!
package org.jglrxavpok.hephaistos.json

import com.google.gson.Gson
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import org.jglrxavpok.hephaistos.nbt.*
import java.io.Closeable
import java.io.Reader

class NBTGsonReader(private val reader: Reader): AutoCloseable, Closeable {

    private companion object {
        val GsonInstance = Gson()

        /**
         * If nbtType is TAG_List, this method will attempt to guess the type of the list elements.
         * The guess is done by getting the first element and guessing its type via #guessType.
         * If the list is empty, this method will always guess that the subtype is TAG_String
         */
        @JvmStatic
        fun  parse(nbtType: NBTType, element: JsonElement): Tag {
            try {
                val result = when (nbtType) {
                    NBTType.TAG_End -> NBTEnd
                    NBTType.TAG_Byte -> NBT.Byte(element.asByte)
                    NBTType.TAG_Short -> NBT.Short(element.asShort)
                    NBTType.TAG_Int -> NBT.Int(element.asInt)
                    NBTType.TAG_Long -> NBT.Long(element.asLong)
                    NBTType.TAG_Float -> NBT.Float(element.asFloat)
                    NBTType.TAG_Double -> NBT.Double(element.asDouble)
                    NBTType.TAG_Byte_Array -> NBT.ByteArray(*element.asJsonArray.map { it.asByte }.toByteArray())
                    NBTType.TAG_String -> if(element.isJsonNull) NBT.String("") else NBT.String(element.asString)

                    NBTType.TAG_Compound -> toCompound(element.asJsonObject)

                    NBTType.TAG_Int_Array -> NBT.IntArray(*element.asJsonArray.map { it.asInt }.toIntArray())
                    NBTType.TAG_Long_Array -> NBT.LongArray(*element.asJsonArray.map { it.asLong }.toLongArray())

                    NBTType.TAG_List -> {
                        if (!element.isJsonArray)
                            throw NBTException("Expected a list, but was: $element")
                        val elements = element.asJsonArray

                        if (elements.size() == 0) { // guess strings
                            NBT.List(NBTType.TAG_String)
                        } else {
                            val firstElement = parse(guessType(elements[0]), elements[0])
                            val list = NBT.List(firstElement.ID, elements.map { parse(firstElement.ID, it) })
                            list
                        }
                    }

                    else -> throw IllegalArgumentException("$nbtType is not a valid/supported NBT type")
                }
                return result as Tag
            } catch (e: IllegalStateException) {
                throw NBTException("Failed to load NBT from json", e)
            }
        }

        @JvmStatic
        private fun toCompound(jsonObject: JsonObject) = NBT.Kompound {
            for((key, value) in jsonObject.entrySet()) {
                val nbt = parse(guessType(value), value)
                this[key] = nbt
            }
        }

        @JvmStatic
        private fun guessType(element: JsonElement): NBTType {
            return when {
                element.isJsonObject -> NBTType.TAG_Compound
                element.isJsonNull -> NBTType.TAG_String
                element.isJsonPrimitive -> {
                    val primitive = element.asJsonPrimitive
                    when {
                        primitive.isBoolean -> NBTType.TAG_Byte
                        primitive.isString -> NBTType.TAG_String
                        primitive.isNumber ->
                            if(primitive.asLong.toDouble() == primitive.asDouble) {
                                if('.' in primitive.asString) {
                                    NBTType.TAG_Double
                                } else {
                                    NBTType.TAG_Long
                                }
                            } else {
                                NBTType.TAG_Double
                            }
                        else -> error("Primitive that is neither a boolean, a string, nor a number?")
                    }
                }

                element.isJsonArray -> {
                    val array = element.asJsonArray
                    if(array.size() == 0) {
                        NBTType.TAG_List
                    } else {
                        val firstElement = element.asJsonArray.get(0)
                        val guessedType = guessType(firstElement)
                        when(guessedType) {
                            NBTType.TAG_Long -> NBTType.TAG_Long_Array
                            NBTType.TAG_Byte -> NBTType.TAG_Byte_Array
                            NBTType.TAG_Int -> NBTType.TAG_Int_Array

                            else -> NBTType.TAG_List
                        }
                    }
                }

                else -> error("Unknown json element type $element")
            }
        }
    }

    inline fun  read(): Tag {
        return read(NBTType.byClass() ?: error("Invalid NBTType: ${Tag::class.qualifiedName}")) as Tag
    }

    fun  read(nbtClass: Class): Tag = read(NBTType.byClass(nbtClass) ?: error("Invalid NBTType: ${nbtClass.canonicalName}")) as Tag


    fun read(nbtType: NBTType): NBT {
        return parse(nbtType, GsonInstance.fromJson(reader, JsonElement::class.java))
    }

    fun readWithGuess(): NBT {
        val element = GsonInstance.fromJson(reader, JsonElement::class.java)
        return parse(guessType(element), element)
    }

    override fun close() {
        reader.close()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy