fix polymorphic serialization, and update the names of some schema objects

This commit is contained in:
Adam 2022-01-09 12:37:26 +01:00
parent e5feabf7eb
commit 2208c91652
11 changed files with 109 additions and 55 deletions

View file

@ -1,6 +1,6 @@
// Generated by TypeScriptGenerator - do not edit this file manually
type ObjectName = "LuaPlayer" | "LuaEntity" | "LuaSurface" | "FactorioMapChunk" | "LuaTile" | "ConsoleChatMessage";
type ObjectName = "LuaPlayer" | "LuaEntity" | "LuaSurface" | "MapChunk" | "LuaTile" | "ConsoleChatMessage";
interface FactorioObjectData {
objectName: ObjectName;
@ -45,16 +45,16 @@ interface SurfaceData extends FactorioObjectData {
objectName: ObjectName;
}
interface FactorioMapTile extends FactorioObjectData {
interface MapTile extends FactorioObjectData {
objectName: ObjectName;
position: PositionData;
prototypeName: string;
surfaceIndex: int;
}
interface FactorioMapChunk extends FactorioObjectData {
interface MapChunk extends FactorioObjectData {
objectName: ObjectName;
tiles: FactorioMapTile[];
tiles: MapTile[];
}
interface ConsoleChatMessage extends FactorioObjectData {

View file

@ -83,7 +83,7 @@ export namespace Converters {
}
}
export function convertTile(tile: LuaTile): FactorioMapTile {
export function convertTile(tile: LuaTile): MapTile {
return {
objectName: tile.object_name,

View file

@ -70,12 +70,12 @@ export function handleChunkUpdate(
}
) ?? []
let convertedTiles: FactorioMapTile[] = tiles.map((tile: LuaTile) => {
let convertedTiles: MapTile[] = tiles.map((tile: LuaTile) => {
return Converters.convertTile(tile)
})
let mapChunk: FactorioMapChunk = {
objectName: "FactorioMapChunk",
let mapChunk: MapChunk = {
objectName: "MapChunk",
tiles: convertedTiles,
}

View file

@ -1,17 +1,17 @@
package dev.adamko.kafkatorio.events.schema
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
@Serializable
@SerialName("CONFIG")
data class FactorioConfigurationUpdate(
override val modVersion: String,
val factorioData: FactorioGameDataUpdate,
val allMods: List<FactorioModInfo>,
val prototypes: List<FactorioPrototype>,
) : KafkatorioPacket() {
@Transient
override val packetType = PacketType.CONFIG
}

View file

@ -1,11 +1,20 @@
package dev.adamko.kafkatorio.events.schema
import dev.adamko.kafkatorio.events.schema.FactorioObjectData.ObjectName
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonContentPolymorphicSerializer
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.modules.SerializersModule
@Serializable
@SerialName("EVENT")
data class FactorioEvent<out T : FactorioObjectData>(
override val modVersion: String,
/** the initial Factorio event (`defines.events`) trigger */
@ -14,6 +23,40 @@ data class FactorioEvent<out T : FactorioObjectData>(
val tick: UInt,
val data: T,
) : KafkatorioPacket() {
@Transient
override val packetType: PacketType = PacketType.EVENT
companion object {
val kxsModule = SerializersModule {
contextual(FactorioEvent::class) { types -> serializer(types[0]) }
}
}
}
object FactorioEventSerializer : JsonContentPolymorphicSerializer<FactorioEvent<*>>(
FactorioEvent::class
) {
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<out FactorioEvent<*>> {
val objectName: ObjectName? = element
.jsonObject[FactorioEvent<*>::data.name]
?.jsonObject
?.get(FactorioObjectData.discriminatorKey)
?.jsonPrimitive
?.contentOrNull
?.let(ObjectName::valueOf)
val sub = when (objectName) {
ObjectName.LuaPlayer -> PlayerData.serializer()
ObjectName.LuaEntity -> EntityData.serializer()
ObjectName.LuaSurface -> SurfaceData.serializer()
ObjectName.MapChunk -> MapChunk.serializer()
ObjectName.LuaTile -> MapTile.serializer()
ObjectName.ConsoleChatMessage -> ConsoleChatMessage.serializer()
null -> throw IllegalStateException("unknown type $objectName")
}
return FactorioEvent.serializer(sub)
}
}

View file

@ -2,7 +2,6 @@ package dev.adamko.kafkatorio.events.schema
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonClassDiscriminator
@Serializable
@ -33,7 +32,7 @@ sealed class FactorioObjectData {
LuaPlayer,
LuaEntity,
LuaSurface,
FactorioMapChunk,
MapChunk,
LuaTile,
ConsoleChatMessage,
}
@ -57,7 +56,6 @@ data class PlayerData(
val chatColour: Colour,
val lastOnline: UInt,
) : FactorioObjectData() {
@Transient
override val objectName = ObjectName.LuaPlayer
}
@ -74,7 +72,6 @@ data class EntityData(
val unitNumber: UInt? = null,
val playerIndex: UInt? = null,
) : FactorioObjectData() {
@Transient
override val objectName = ObjectName.LuaEntity
}
@ -85,36 +82,33 @@ data class SurfaceData(
val index: UInt,
val name: String,
) : FactorioObjectData() {
@Transient
override val objectName = ObjectName.LuaSurface
}
/** Quasi-object. This isn't a Factorio Lua type, but a helpful collection of [FactorioMapTile]s */
/** Quasi-object. This isn't a Factorio Lua type, but a helpful collection of [MapTile]s */
@Serializable
@SerialName("FactorioMapChunk")
data class FactorioMapChunk(
val tiles: List<FactorioMapTile>,
@SerialName("MapChunk")
data class MapChunk(
val tiles: List<MapTile>,
) : FactorioObjectData() {
@Transient
override val objectName = ObjectName.FactorioMapChunk
override val objectName = ObjectName.MapChunk
}
@Serializable
@SerialName("LuaTile")
data class FactorioMapTile(
data class MapTile(
val prototypeName: String,
val position: PositionData,
val surfaceIndex: Int,
) : FactorioObjectData() {
@Transient
override val objectName = ObjectName.LuaTile
}
@Serializable
@SerialName("ConsoleChatMessage")
data class ConsoleChatMessage(
val authorPlayerIndex: UInt?,
val content: String,
) : FactorioObjectData() {
@Transient
override val objectName = ObjectName.ConsoleChatMessage
}

View file

@ -9,7 +9,6 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonTransformingSerializer
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.modules.SerializersModule
/** Factorio outputs lists as Json objects - this serializer converts an object back to a list. */
@ -27,8 +26,10 @@ internal class ListAsObjectSerializer<T>(dataSerializer: KSerializer<T>) :
)
}
internal val jsonMapper = Json {
val jsonMapperKafkatorio = Json {
prettyPrint = true
prettyPrintIndent = " "
serializersModule = SerializersModule { }
serializersModule = FactorioEvent.kxsModule
// serializersModule = KafkatorioPacket.kxsModule + FactorioEvent.kxsModule
// serializersModule = SerializersModule { }
}

View file

@ -1,29 +1,45 @@
package dev.adamko.kafkatorio.events.schema;
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonClassDiscriminator
import kotlinx.serialization.json.JsonContentPolymorphicSerializer
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
@Serializable
@JsonClassDiscriminator("packetType")
@Serializable(with = KafkatorioPacketSerializer::class)
sealed class KafkatorioPacket {
/** Schema versioning */
abstract val modVersion: String
abstract val packetType: PacketType
enum class PacketType {
EVENT, CONFIG,
EVENT,
CONFIG,
}
}
//@Serializable
//@JsonClassDiscriminator(KafkatorioPacketData.discriminatorKey)
//sealed class KafkatorioPacketData(
// @SerialName(discriminatorKey)
// val dataType: PacketDataType
//) {
// companion object {
// const val discriminatorKey: String = "dataType"
// }
//}
object KafkatorioPacketSerializer : JsonContentPolymorphicSerializer<KafkatorioPacket>(
KafkatorioPacket::class
) {
private const val key = "packetType"
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<out KafkatorioPacket> {
val type = element
.jsonObject[key]
?.jsonPrimitive
?.contentOrNull
?.let(KafkatorioPacket.PacketType::valueOf)
return when (type) {
KafkatorioPacket.PacketType.EVENT -> FactorioEventSerializer
KafkatorioPacket.PacketType.CONFIG -> FactorioConfigurationUpdate.serializer()
else ->
throw Exception("Unknown Packet: key '$key' ")
}
}
}

View file

@ -45,7 +45,7 @@ class FactorioEventTest : BehaviorSpec({
""".trimIndent()
Then("parse") {
val actual: KafkatorioPacket = jsonMapper.decodeFromString(KafkatorioPacket.serializer(), json)
val actual: KafkatorioPacket = jsonMapperKafkatorio.decodeFromString(json)
val expected = FactorioEvent(
data = PlayerData(
@ -99,7 +99,7 @@ class FactorioEventTest : BehaviorSpec({
}
""".trimIndent()
Then("parse") {
val actual: KafkatorioPacket = jsonMapper.decodeFromString(json)
val actual: KafkatorioPacket = jsonMapperKafkatorio.decodeFromString(json)
val expected = FactorioEvent(
data = SurfaceData(
@ -144,7 +144,7 @@ class FactorioEventTest : BehaviorSpec({
}
""".trimIndent()
Then("parse") {
val actual: KafkatorioPacket = jsonMapper.decodeFromString(json)
val actual: KafkatorioPacket = jsonMapperKafkatorio.decodeFromString(json)
val expected = FactorioEvent(
data = EntityData(

View file

@ -1,10 +1,10 @@
package dev.adamko.kafkatorio.processor
import dev.adamko.kafkatorio.events.schema.KafkatorioPacket
import dev.adamko.kafkatorio.events.schema.jsonMapperKafkatorio
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import org.apache.kafka.common.serialization.Deserializer
import org.apache.kafka.common.serialization.Serde
import org.apache.kafka.common.serialization.Serializer
@ -26,7 +26,7 @@ object KafkatorioPacketSerde : Serde<KafkatorioPacket> {
val jsonMapper = Json {
prettyPrint = true
prettyPrintIndent = " "
serializersModule = SerializersModule { }
serializersModule = jsonMapperKafkatorio.serializersModule
}
object KXS : ConfigurableKotlinxSerialization({
@ -34,5 +34,5 @@ object KXS : ConfigurableKotlinxSerialization({
prettyPrint = true
prettyPrintIndent = " "
asConfigurable().withStandardMappings().done()
serializersModule = SerializersModule { }
serializersModule = jsonMapperKafkatorio.serializersModule
})

View file

@ -4,8 +4,8 @@ import dev.adamko.kafkatorio.events.schema.ConsoleChatMessage
import dev.adamko.kafkatorio.events.schema.EntityData
import dev.adamko.kafkatorio.events.schema.FactorioConfigurationUpdate
import dev.adamko.kafkatorio.events.schema.FactorioEvent
import dev.adamko.kafkatorio.events.schema.FactorioMapChunk
import dev.adamko.kafkatorio.events.schema.FactorioMapTile
import dev.adamko.kafkatorio.events.schema.MapChunk
import dev.adamko.kafkatorio.events.schema.MapTile
import dev.adamko.kafkatorio.events.schema.KafkatorioPacket
import dev.adamko.kafkatorio.events.schema.PlayerData
import dev.adamko.kafkatorio.events.schema.SurfaceData
@ -42,10 +42,10 @@ class WebsocketService(
is PlayerData ->
reduxStore.dispatch(FactorioUpdate.PlayerUpdate(event, eventData))
is ConsoleChatMessage -> {}
is EntityData -> {}
is FactorioMapChunk -> {}
is FactorioMapTile -> {}
is SurfaceData -> {}
is EntityData -> {}
is MapChunk -> {}
is MapTile -> {}
is SurfaceData -> {}
}
}
is FactorioConfigurationUpdate -> {}