KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/defs/PhysicsForceRegion.kt

148 lines
4.8 KiB
Kotlin

package ru.dbotthepony.kstarbound.defs
import com.google.gson.reflect.TypeToken
import ru.dbotthepony.kstarbound.io.readDouble
import ru.dbotthepony.kstarbound.io.readNullableDouble
import ru.dbotthepony.kstarbound.io.readVector2d
import ru.dbotthepony.kstarbound.io.writeDouble
import ru.dbotthepony.kstarbound.io.writeNullableDouble
import ru.dbotthepony.kstarbound.io.writeStruct2d
import ru.dbotthepony.kstarbound.json.builder.DispatchingAdapter
import ru.dbotthepony.kstarbound.json.builder.IStringSerializable
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.json.builder.JsonFlat
import ru.dbotthepony.kstarbound.math.Line2d
import ru.dbotthepony.kstarbound.math.vector.Vector2d
import ru.dbotthepony.kstarbound.network.syncher.legacyCodec
import ru.dbotthepony.kstarbound.network.syncher.nativeCodec
import ru.dbotthepony.kstarbound.world.physics.Poly
import java.io.DataInputStream
import java.io.DataOutputStream
sealed class PhysicsForceRegion {
// ephemeral property from json
abstract val enabled: Boolean
abstract val filter: PhysicsCategoryFilter
abstract fun write(stream: DataOutputStream, isLegacy: Boolean)
abstract val type: Type
enum class Type(override val jsonName: String, val token: TypeToken<out PhysicsForceRegion>) : IStringSerializable {
DIRECTIONAL("DirectionalForceRegion", TypeToken.get(Directional::class.java)),
RADIAL("RadialForceRegion", TypeToken.get(Radial::class.java)),
GRADIENT("GradientForceRegion", TypeToken.get(Gradient::class.java))
}
@JsonFactory
data class Directional(
val region: Poly,
val xTargetVelocity: Double?,
val yTargetVelocity: Double?,
val controlForce: Double,
@JsonFlat
override val filter: PhysicsCategoryFilter,
override val enabled: Boolean = true
) : PhysicsForceRegion() {
constructor(stream: DataInputStream, isLegacy: Boolean) : this(
Poly.read(stream, isLegacy),
stream.readNullableDouble(isLegacy),
stream.readNullableDouble(isLegacy),
stream.readDouble(isLegacy),
PhysicsCategoryFilter(stream, isLegacy)
)
override val type: Type
get() = Type.DIRECTIONAL
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
stream.writeByte(0)
region.write(stream, isLegacy)
stream.writeNullableDouble(xTargetVelocity, isLegacy)
stream.writeNullableDouble(yTargetVelocity, isLegacy)
stream.writeDouble(controlForce, isLegacy)
filter.write(stream, isLegacy)
}
}
@JsonFactory
data class Radial(
val center: Vector2d = Vector2d.ZERO,
val outerRadius: Double,
val innerRadius: Double,
val targetRadialVelocity: Double,
val controlForce: Double,
@JsonFlat
override val filter: PhysicsCategoryFilter,
override val enabled: Boolean = true
) : PhysicsForceRegion() {
constructor(stream: DataInputStream, isLegacy: Boolean) : this(
stream.readVector2d(isLegacy),
stream.readDouble(isLegacy),
stream.readDouble(isLegacy),
stream.readDouble(isLegacy),
stream.readDouble(isLegacy),
PhysicsCategoryFilter(stream, isLegacy)
)
override val type: Type
get() = Type.RADIAL
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
stream.writeByte(1)
stream.writeStruct2d(center, isLegacy)
stream.writeDouble(outerRadius, isLegacy)
stream.writeDouble(innerRadius, isLegacy)
stream.writeDouble(targetRadialVelocity, isLegacy)
stream.writeDouble(controlForce, isLegacy)
filter.write(stream, isLegacy)
}
}
@JsonFactory
data class Gradient(
val region: Poly,
val gradient: Line2d,
val baseTargetVelocity: Double,
val baseControlForce: Double,
@JsonFlat
override val filter: PhysicsCategoryFilter,
override val enabled: Boolean = true
) : PhysicsForceRegion() {
constructor(stream: DataInputStream, isLegacy: Boolean) : this(
Poly.read(stream, isLegacy),
Line2d(stream, isLegacy),
stream.readDouble(isLegacy),
stream.readDouble(isLegacy),
PhysicsCategoryFilter(stream, isLegacy)
)
override val type: Type
get() = Type.GRADIENT
override fun write(stream: DataOutputStream, isLegacy: Boolean) {
stream.writeByte(2)
region.write(stream, isLegacy)
gradient.write(stream, isLegacy)
stream.writeDouble(baseTargetVelocity, isLegacy)
stream.writeDouble(baseControlForce, isLegacy)
filter.write(stream, isLegacy)
}
}
companion object {
val CODEC = nativeCodec(::read, PhysicsForceRegion::write)
val LEGACY_CODEC = legacyCodec(::read, PhysicsForceRegion::write)
val ADAPTER = DispatchingAdapter("type", { type }, { token }, Type.entries)
fun read(stream: DataInputStream, isLegacy: Boolean): PhysicsForceRegion {
return when (val type = stream.readUnsignedByte()) {
0 -> Directional(stream, isLegacy)
1 -> Radial(stream, isLegacy)
2 -> Gradient(stream, isLegacy)
else -> throw IllegalArgumentException("Unknown force region type $type!")
}
}
}
}