161 lines
4.4 KiB
Kotlin
161 lines
4.4 KiB
Kotlin
package ru.dbotthepony.kstarbound.defs
|
|
|
|
import com.google.gson.Gson
|
|
import com.google.gson.TypeAdapter
|
|
import com.google.gson.annotations.JsonAdapter
|
|
import com.google.gson.stream.JsonReader
|
|
import com.google.gson.stream.JsonWriter
|
|
import ru.dbotthepony.kommons.io.readUUID
|
|
import ru.dbotthepony.kommons.io.writeBinaryString
|
|
import ru.dbotthepony.kommons.io.writeUUID
|
|
import ru.dbotthepony.kstarbound.io.readInternedString
|
|
import ru.dbotthepony.kstarbound.network.syncher.legacyCodec
|
|
import ru.dbotthepony.kstarbound.network.syncher.nativeCodec
|
|
import ru.dbotthepony.kstarbound.util.toStarboundString
|
|
import ru.dbotthepony.kstarbound.util.uuidFromStarboundString
|
|
import ru.dbotthepony.kstarbound.world.UniversePos
|
|
import java.io.DataInputStream
|
|
import java.io.DataOutputStream
|
|
import java.util.UUID
|
|
|
|
@JsonAdapter(WorldID.Adapter::class)
|
|
sealed class WorldID {
|
|
abstract fun write(stream: DataOutputStream, isLegacy: Boolean)
|
|
val isLimbo: Boolean get() = this is Limbo
|
|
|
|
object Limbo : WorldID() {
|
|
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
|
|
stream.writeByte(0)
|
|
}
|
|
|
|
override fun toString(): String {
|
|
return "Nowhere"
|
|
}
|
|
}
|
|
|
|
data class Celestial(val pos: UniversePos) : WorldID() {
|
|
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
|
|
stream.writeByte(1)
|
|
pos.write(stream, isLegacy)
|
|
}
|
|
|
|
override fun toString(): String {
|
|
return "CelestialWorld:$pos"
|
|
}
|
|
}
|
|
|
|
data class ShipWorld(val uuid: UUID) : WorldID() {
|
|
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
|
|
stream.writeByte(2)
|
|
stream.writeUUID(uuid)
|
|
}
|
|
|
|
override fun toString(): String {
|
|
return "ClientShipWorld:${uuid.toStarboundString()}"
|
|
}
|
|
}
|
|
|
|
data class Instance(val name: String, val uuid: UUID? = null, val threatLevel: Double? = null) : WorldID() {
|
|
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
|
|
stream.writeByte(3)
|
|
stream.writeBinaryString(name)
|
|
|
|
stream.writeBoolean(uuid != null)
|
|
if (uuid != null) stream.writeUUID(uuid)
|
|
|
|
stream.writeBoolean(threatLevel != null)
|
|
if (threatLevel != null) {
|
|
if (isLegacy) {
|
|
stream.writeFloat(threatLevel.toFloat())
|
|
} else {
|
|
stream.writeDouble(threatLevel)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun toString(): String {
|
|
return "InstanceWorld:$name:${uuid?.toStarboundString() ?: "-"}:${threatLevel ?: "-"}"
|
|
}
|
|
}
|
|
|
|
class Adapter(gson: Gson) : TypeAdapter<WorldID>() {
|
|
override fun write(out: JsonWriter, value: WorldID) {
|
|
out.value(value.toString())
|
|
}
|
|
|
|
override fun read(`in`: JsonReader): WorldID {
|
|
return parse(`in`.nextString())
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
val CODEC = nativeCodec(::read, WorldID::write)
|
|
val LEGACY_CODEC = legacyCodec(::read, WorldID::write)
|
|
|
|
fun parse(value: String): WorldID {
|
|
if (value.isBlank())
|
|
return Limbo
|
|
|
|
val parts = value.split(':')
|
|
|
|
return when (val type = parts[0].lowercase()) {
|
|
"nowhere" -> Limbo
|
|
"instanceworld" -> {
|
|
val rest = parts[1].split(':')
|
|
|
|
if (rest.isEmpty() || rest.size > 3) {
|
|
throw IllegalArgumentException("Malformed InstanceWorld string: $value")
|
|
}
|
|
|
|
val name = rest[0]
|
|
var uuid: UUID? = null
|
|
var threatLevel: Double? = null
|
|
|
|
if (rest.size > 1) {
|
|
uuid = if (rest[1] == "-") null else uuidFromStarboundString(rest[1])
|
|
|
|
if (rest.size > 2) {
|
|
threatLevel = if (rest[2] == "-") null else rest[2].toDouble()
|
|
|
|
if (threatLevel != null && threatLevel < 0.0)
|
|
throw IllegalArgumentException("InstanceWorld threat level is negative: $value")
|
|
}
|
|
}
|
|
|
|
Instance(name, uuid, threatLevel)
|
|
}
|
|
|
|
"celestialworld" -> Celestial(UniversePos.parse(parts[1]))
|
|
"clientshipworld" -> ShipWorld(uuidFromStarboundString(parts[1]))
|
|
else -> throw IllegalArgumentException("Invalid WorldID type: $type (input: $value)")
|
|
}
|
|
}
|
|
|
|
fun read(stream: DataInputStream, isLegacy: Boolean): WorldID {
|
|
return when (val type = stream.readUnsignedByte()) {
|
|
0 -> Limbo
|
|
1 -> Celestial(UniversePos(stream, isLegacy))
|
|
2 -> ShipWorld(stream.readUUID())
|
|
3 -> {
|
|
val name = stream.readInternedString()
|
|
val uuid = if (stream.readBoolean()) stream.readUUID() else null
|
|
val level: Double?
|
|
|
|
if (stream.readBoolean()) {
|
|
if (isLegacy) {
|
|
level = stream.readFloat().toDouble()
|
|
} else {
|
|
level = stream.readDouble()
|
|
}
|
|
} else {
|
|
level = null
|
|
}
|
|
|
|
Instance(name, uuid, level)
|
|
}
|
|
else -> throw IllegalArgumentException("Unknown WorldID type $type!")
|
|
}
|
|
}
|
|
}
|
|
}
|