nageyqma·git
HTTPS https://git.nageyqma.icu/nageyqma/odin_next.git SSH git@git.nageyqma.icu:nageyqma/odin_next.git

HTTPS 链接可直接 git clone;推送代码请使用 SSH。

6.8 KB · 182 行raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
package com.odtheking.odin.config

import com.google.gson.*
import com.google.gson.reflect.TypeToken
import com.odtheking.odin.OdinMod
import com.odtheking.odin.features.impl.dungeon.dungeonwaypoints.DungeonWaypoints
import com.odtheking.odin.features.impl.dungeon.dungeonwaypoints.DungeonWaypoints.DungeonWaypoint
import com.odtheking.odin.utils.Color
import net.minecraft.core.BlockPos
import net.minecraft.world.phys.AABB
import java.io.ByteArrayOutputStream
import java.lang.reflect.Type
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
import kotlin.io.encoding.Base64

object DungeonWaypointConfig {
    val gson: Gson = GsonBuilder()
        .registerTypeAdapter(AABB::class.java, AABBSerializer())
        .registerTypeAdapter(DungeonWaypoint::class.java, DungeonWaypointDeserializer())
        .registerTypeAdapter(BlockPos::class.java, BlockPosSerializer())
        .setPrettyPrinting().create()

    fun encodeWaypoints(waypointsMap: MutableMap<String, MutableList<DungeonWaypoint>>): String? {
        return try {
            Base64.encode(compress(gson.toJson(waypointsMap)))
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }

    private fun compress(input: String): ByteArray {
        ByteArrayOutputStream().use { byteArrayOutputStream ->
            GZIPOutputStream(byteArrayOutputStream).use { gzipOutputStream ->
                gzipOutputStream.write(input.toByteArray())
            }
            return byteArrayOutputStream.toByteArray()
        }
    }

    fun decodeWaypoints(input: String): MutableMap<String, MutableList<DungeonWaypoint>>? {
        return try {
            gson.fromJson(
                if (input.startsWith("{")) input else decompress(Base64.decode(input)),
                object : TypeToken<MutableMap<String, MutableList<DungeonWaypoint>>>() {}.type
            )
        } catch (_: Exception) {
            null
        }
    }

    private fun decompress(compressed: ByteArray): String {
        GZIPInputStream(compressed.inputStream()).use { gzipInputStream ->
            return gzipInputStream.bufferedReader().use { it.readText() }
        }
    }

    internal class DungeonWaypointDeserializer : JsonDeserializer<DungeonWaypoint> {
        override fun deserialize(json: JsonElement, type: Type, context: JsonDeserializationContext): DungeonWaypoint {
            val jsonObj = json.asJsonObject

            val blockPos = if (jsonObj.has("blockPos")) context.deserialize(jsonObj["blockPos"], BlockPos::class.java)
            else BlockPos(jsonObj["x"].asInt, jsonObj["y"].asInt, jsonObj["z"].asInt)

            val color = context.deserialize<Color>(jsonObj["color"], Color::class.java)

            val filled = jsonObj["filled"].asBoolean
            val depth = jsonObj["depth"].asBoolean

            val aabb = context.deserialize<AABB>(jsonObj["aabb"], AABB::class.java)

            val title = jsonObj["title"]?.asString?.ifBlank { null }
            val waypointType = jsonObj["type"]?.asString?.let {
                runCatching { DungeonWaypoints.WaypointType.valueOf(it) }.getOrNull()
            }

            val waypoint = DungeonWaypoint(blockPos, color, filled, depth, aabb, title, type = waypointType)

            if (waypointType == null && jsonObj.has("secret") && jsonObj["secret"]?.asBoolean == true)
                waypoint.type = DungeonWaypoints.WaypointType.SECRET

            return waypoint
        }
    }

    internal class AABBSerializer : JsonSerializer<AABB>, JsonDeserializer<AABB> {
        override fun deserialize(json: JsonElement, type: Type, context: JsonDeserializationContext): AABB {
            val jsonObj = json.asJsonObject

            if (jsonObj.has("minX")) {
                val minX = jsonObj["minX"].asDouble
                val minY = jsonObj["minY"].asDouble
                val minZ = jsonObj["minZ"].asDouble
                val maxX = jsonObj["maxX"].asDouble
                val maxY = jsonObj["maxY"].asDouble
                val maxZ = jsonObj["maxZ"].asDouble

                return AABB(minX, minY, minZ, maxX, maxY, maxZ)
            }

            if (jsonObj.has("field_1323")) {
                val minX = jsonObj["field_1323"].asDouble
                val minY = jsonObj["field_1322"].asDouble
                val minZ = jsonObj["field_1321"].asDouble
                val maxX = jsonObj["field_1320"].asDouble
                val maxY = jsonObj["field_1325"].asDouble
                val maxZ = jsonObj["field_1324"].asDouble

                return AABB(minX, minY, minZ, maxX, maxY, maxZ)
            }

            if (jsonObj.has("field_72340_a")) {
                val minX = jsonObj["field_72340_a"].asDouble
                val minY = jsonObj["field_72338_b"].asDouble
                val minZ = jsonObj["field_72339_c"].asDouble
                val maxX = jsonObj["field_72336_d"].asDouble
                val maxY = jsonObj["field_72337_e"].asDouble
                val maxZ = jsonObj["field_72334_f"].asDouble

                return AABB(minX, minY, minZ, maxX, maxY, maxZ)
            }

            return AABB(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
        }

        override fun serialize(src: AABB, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement {
            val jsonObject = JsonObject()
            jsonObject.addProperty("minX", src.minX)
            jsonObject.addProperty("minY", src.minY)
            jsonObject.addProperty("minZ", src.minZ)
            jsonObject.addProperty("maxX", src.maxX)
            jsonObject.addProperty("maxY", src.maxY)
            jsonObject.addProperty("maxZ", src.maxZ)

            return jsonObject
        }
    }

    internal class BlockPosSerializer : JsonSerializer<BlockPos>, JsonDeserializer<BlockPos> {
        override fun serialize(
            src: BlockPos,
            typeOfSrc: Type,
            context: JsonSerializationContext
        ): JsonElement {
            val obj = JsonObject()
            obj.addProperty("x", src.x)
            obj.addProperty("y", src.y)
            obj.addProperty("z", src.z)

            return obj
        }

        override fun deserialize(
            json: JsonElement,
            typeOfT: Type,
            context: JsonDeserializationContext
        ): BlockPos {
            val obj = json.asJsonObject

            if (obj.has("field_11173")) {
                val x = obj["field_11175"].asInt
                val y = obj["field_11174"].asInt
                val z = obj["field_11173"].asInt
                return BlockPos(x, y, z)
            }

            if (obj.has("x")) {
                val x = obj["x"].asInt
                val y = obj["y"].asInt
                val z = obj["z"].asInt
                return BlockPos(x, y, z)
            }

            OdinMod.logger.debug("Failed to deserialize BlockPos\n$json")
            return BlockPos(0, 0, 0)
        }

    }
}