KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/world/UniversePos.kt

134 lines
3.6 KiB
Kotlin

package ru.dbotthepony.kstarbound.world
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kommons.gson.get
import ru.dbotthepony.kommons.vector.Vector3i
import ru.dbotthepony.kommons.gson.consumeNull
data class UniversePos(val location: Vector3i = Vector3i.ZERO, val planetOrbit: Int = 0, val satelliteOrbit: Int = 0) {
val isSystem: Boolean
get() = planetOrbit == 0
val isPlanet: Boolean
get() = planetOrbit != 0 && satelliteOrbit == 0
val isSatellite: Boolean
get() = planetOrbit != 0 && satelliteOrbit == 0
val orbitNumber: Int
get() = if (isSatellite) satelliteOrbit else if (isPlanet) planetOrbit else 0
fun system(): UniversePos {
if (planetOrbit == 0 && satelliteOrbit == 0)
return this
return UniversePos(location)
}
fun planet(): UniversePos {
if (satelliteOrbit == 0)
return this
return UniversePos(location, planetOrbit)
}
fun satellite(): UniversePos {
return this
}
fun parent(): UniversePos {
if (isSatellite)
return planet()
else if (isPlanet)
return system()
else
return this
}
companion object : TypeAdapterFactory {
private val splitter = Regex("[ _:]")
val ZERO = UniversePos()
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.rawType == UniversePos::class.java) {
val vectors = gson.getAdapter(Vector3i::class.java)
val objects = gson.getAdapter(JsonObject::class.java)
return object : TypeAdapter<UniversePos>() {
override fun write(out: JsonWriter, value: UniversePos?) {
if (value == null)
out.nullValue()
else {
out.beginObject()
out.name("location")
vectors.write(out, value.location)
out.name("planet")
out.value(value.planetOrbit)
out.name("satellite")
out.value(value.satelliteOrbit)
out.endObject()
}
}
override fun read(`in`: JsonReader): UniversePos? {
if (`in`.consumeNull())
return null
if (`in`.peek() == JsonToken.BEGIN_OBJECT) {
val values = objects.read(`in`)!!
val location = values.get("location", vectors)
val planet = values.get("planet", 0)
val orbit = values.get("orbit", 0)
return UniversePos(location, planet, orbit)
}
if (`in`.peek() == JsonToken.STRING) {
val read = `in`.nextString().trim()
if (read == "" || read.lowercase() == "")
return ZERO
else {
try {
val split = read.split(splitter)
val x = split[0].toInt()
val y = split[1].toInt()
val z = split[2].toInt()
val planet = if (split.size > 3) split[3].toInt() else 0
val orbit = if (split.size > 4) split[4].toInt() else 0
if (planet <= 0) // TODO: ??? Determine, if this is a bug in original code
throw IndexOutOfBoundsException("Planetary orbit: $planet")
if (orbit < 0)
throw IndexOutOfBoundsException("Satellite orbit: $orbit")
return UniversePos(Vector3i(x, y, z), planet, orbit)
} catch (err: Throwable) {
throw JsonSyntaxException("Error parsing UniversePos from string", err)
}
}
}
throw JsonSyntaxException("Invalid data type for UniversePos: ${`in`.peek()}")
}
} as TypeAdapter<T>
}
return null
}
}
}