From 8f9ebdb1e1d8194ad6b7494a5441cbcf407f7187 Mon Sep 17 00:00:00 2001 From: Adam <897017+aSemy@users.noreply.github.com> Date: Sun, 20 Feb 2022 12:29:34 +0100 Subject: [PATCH] update events schema - unwrap value classes when generating TS - add value classes for some data types - add FactorioEventUpdates (for new incremental event updates) - use static lists for enum values (better performance) - add LuaControl for sharing Player/Entity fields --- .../kafkatorio-schema/object-data.d.ts | 26 +--- .../kafkatorio-schema/prototype.d.ts | 2 +- .../generated/kafkatorio-schema/schema.d.ts | 89 ++++++++++++- .../events/schema/factorioCommonData.kt | 13 +- .../events/schema/factorioEventUpdates.kt | 124 ++++++++++++++++++ .../events/schema/factorioEvents.kt | 2 +- .../kafkatorio/events/schema/factorioIds.kt | 36 +++++ .../events/schema/factorioLuaObjects.kt | 56 +++++--- .../events/schema/factorioPrototypes.kt | 9 +- .../events/schema/kafkatorioPacket.kt | 7 +- .../events/schema/FactorioEventTest.kt | 23 ++-- .../events/schema/ValueClassTransformer.kt | 67 ++++++++++ .../adamko/kafkatorio/events/schema/kt2ts.kt | 9 +- 13 files changed, 396 insertions(+), 67 deletions(-) create mode 100644 modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt create mode 100644 modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioIds.kt create mode 100644 modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt diff --git a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts index 4585cfa..9313d83 100644 --- a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts +++ b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/object-data.d.ts @@ -6,30 +6,6 @@ interface FactorioObjectData { objectName: ObjectName; } -interface PlayerData extends FactorioObjectData { - associatedCharactersUnitNumbers: uint[]; - characterUnitNumber: uint | null; - chatColour: Colour; - colour: Colour; - lastOnline: uint; - name: string; - objectName: ObjectName; - position: MapEntityPosition; -} - -interface EntityData extends FactorioObjectData { - active: boolean; - health: double | null; - healthRatio: double; - name: string; - objectName: ObjectName; - playerIndex: uint | null; - position: MapEntityPosition; - surfaceIndex: int; - type: string; - unitNumber: uint | null; -} - interface SurfaceData extends FactorioObjectData { daytime: double; index: uint; @@ -39,7 +15,7 @@ interface SurfaceData extends FactorioObjectData { interface MapTiles extends FactorioObjectData { objectName: ObjectName; - surfaceIndex: int; + surfaceIndex: uint; tiles: MapTile[]; } diff --git a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/prototype.d.ts b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/prototype.d.ts index 01d4958..9021c35 100644 --- a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/prototype.d.ts +++ b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/prototype.d.ts @@ -15,7 +15,7 @@ interface FactorioPrototypes extends KafkatorioPacket { interface MapTilePrototype extends FactorioPrototype { canBeMined: boolean; collisionMasks: string[]; - layer: uint; + layer: int; mapColour: Colour; name: string; order: string; diff --git a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts index f1caf5a..3ba828d 100644 --- a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts +++ b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema/schema.d.ts @@ -15,6 +15,17 @@ interface FactorioEvent extends KafkatorioPacket { tick: uint; } +interface MapEntityPosition { + x: double; + y: double; +} + +interface FactorioLuaControl { + force: uint; + position: MapEntityPosition; + surface: uint; +} + interface Colour { alpha: float; blue: float; @@ -22,9 +33,31 @@ interface Colour { red: float; } -interface MapEntityPosition { - x: double; - y: double; +interface PlayerData extends FactorioObjectData, FactorioLuaControl { + associatedCharactersUnitNumbers: uint[]; + characterUnitNumber: uint | null; + chatColour: Colour; + colour: Colour; + force: uint; + lastOnline: uint; + name: string; + objectName: ObjectName; + position: MapEntityPosition; + surface: uint; +} + +interface EntityData extends FactorioObjectData, FactorioLuaControl { + active: boolean; + force: uint; + health: double | null; + healthRatio: double; + name: string; + objectName: ObjectName; + playerIndex: uint | null; + position: MapEntityPosition; + surface: uint; + type: string; + unitNumber: uint | null; } interface MapTilePosition { @@ -46,3 +79,53 @@ interface MapTile { position: MapTilePosition; prototypeName: string; } + +type FactorioEventUpdateType = "PLAYER" | "MAP_CHUNK" | "ENTITY"; + +interface FactorioEventUpdate { + updateType: FactorioEventUpdateType; +} + +interface PlayerUpdate extends FactorioEventUpdate { + characterUnitNumber: uint | null; + chatColour: Colour | null; + colour: Colour | null; + disconnectReason: string | null; + forceIndex: uint | null; + index: uint; + isAdmin: boolean | null; + isConnected: boolean | null; + isShowOnMap: boolean | null; + isSpectator: boolean | null; + lastOnline: uint | null; + name: string | null; + onlineTime: uint | null; + position: MapEntityPosition | null; + surfaceIndex: uint | null; + tag: string | null; + updateType: FactorioEventUpdateType; +} + +interface EntityUpdate extends FactorioEventUpdate { + chunkPosition: MapChunkPosition | null; + graphicsVariation: number | null; + health: float | null; + isActive: boolean | null; + isRotatable: boolean | null; + lastUser: int | null; + localisedDescription: string | null; + localisedName: string | null; + name: string | null; + prototype: string | null; + type: string | null; + unitNumber: uint; + updateType: FactorioEventUpdateType; +} + +interface MapChunkUpdate extends FactorioEventUpdate { + chunkPosition: MapChunkPosition; + isDeleted: boolean | null; + surfaceIndex: uint; + tiles: MapTiles | null; + updateType: FactorioEventUpdateType; +} diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioCommonData.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioCommonData.kt index f08eb79..f5cdf9c 100644 --- a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioCommonData.kt +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioCommonData.kt @@ -1,11 +1,18 @@ package dev.adamko.kafkatorio.events.schema +import kotlin.jvm.JvmInline import kotlinx.serialization.EncodeDefault import kotlinx.serialization.Serializable const val MAP_CHUNK_SIZE = 32 + +@Serializable +@JvmInline +value class Tick(val value: UInt) + + /** * Coordinates of a [EntityData] on a map. * @@ -60,7 +67,7 @@ data class MapBoundingBox( */ @Serializable data class Colour( - @EncodeDefault + @EncodeDefault // remove encode default? val red: Float = 0f, @EncodeDefault val green: Float = 0f, @@ -74,7 +81,7 @@ data class Colour( /** Size-efficient version of [Colour] (`4*4` bytes vs `4*1` bytes) */ @Serializable data class ColourHex( - @EncodeDefault + @EncodeDefault // remove encode default? val red: UByte = UByte.MIN_VALUE, @EncodeDefault val green: UByte = UByte.MIN_VALUE, @@ -91,6 +98,6 @@ data class ColourHex( @Serializable data class MapTile( - val prototypeName: String, + val prototypeName: PrototypeName, val position: MapTilePosition, ) diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt new file mode 100644 index 0000000..a109ca7 --- /dev/null +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEventUpdates.kt @@ -0,0 +1,124 @@ +package dev.adamko.kafkatorio.events.schema + +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.EncodeDefault +import kotlinx.serialization.Serializable +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(with = FactorioEventUpdate.Companion.JsonSerializer::class) +sealed class FactorioEventUpdate { + + @EncodeDefault + abstract val updateType: FactorioEventUpdateType + + @Serializable + enum class FactorioEventUpdateType { + PLAYER, + MAP_CHUNK, + ENTITY, + ; + + companion object { + val values: List = values().toList() + } + } + + companion object { + + object JsonSerializer : JsonContentPolymorphicSerializer( + FactorioEventUpdate::class + ) { + private val key = FactorioEventUpdate::updateType.name + + override fun selectDeserializer(element: JsonElement): DeserializationStrategy { + + val type = element + .jsonObject[key] + ?.jsonPrimitive + ?.contentOrNull + ?.let { json -> + FactorioEventUpdateType.values.firstOrNull { it.name == json } + } + + requireNotNull(type) { "Unknown FactorioEventUpdate $key: $element" } + + return when (type) { + FactorioEventUpdateType.PLAYER -> PlayerUpdate.serializer() + FactorioEventUpdateType.MAP_CHUNK -> TODO() + FactorioEventUpdateType.ENTITY -> EntityUpdate.serializer() + } + } + } + + } +} + + +@Serializable +data class PlayerUpdate( + val index: PlayerIndex, + + val characterUnitNumber: UnitNumber? = null, + val chatColour: Colour? = null, + val colour: Colour? = null, + val name: String? = null, + + val disconnectReason: String? = null, + val forceIndex: ForceIndex? = null, + val isAdmin: Boolean? = null, + val isConnected: Boolean? = null, + val isShowOnMap: Boolean? = null, + val isSpectator: Boolean? = null, + val lastOnline: Tick? = null, + val onlineTime: Tick? = null, + val position: MapEntityPosition? = null, + val surfaceIndex: SurfaceIndex? = null, + val tag: String? = null, +) : FactorioEventUpdate() { + @EncodeDefault + override val updateType: FactorioEventUpdateType = FactorioEventUpdateType.PLAYER +} + + +@Serializable +data class EntityUpdate( + /** + * A [unitNumber] is required for caching, else the Entity Update should be emitted without + * debouncing/throttling + */ + val unitNumber: UnitNumber, + + val name: String? = null, + val type: String? = null, + val chunkPosition: MapChunkPosition? = null, + val graphicsVariation: UShort? = null, + val health: Float? = null, + val isActive: Boolean? = null, + val isRotatable: Boolean? = null, + val lastUser: UInt? = null, + val localisedDescription: String? = null, + val localisedName: String? = null, + val prototype: PrototypeName? = null, +) : FactorioEventUpdate() { + @EncodeDefault + override val updateType: FactorioEventUpdateType = FactorioEventUpdateType.ENTITY +} + + +@Serializable +data class MapChunkUpdate( + val chunkPosition: MapChunkPosition, + val surfaceIndex: SurfaceIndex, + + /** Might be a partial list of updated tiles */ + val tiles: MapTiles? = null, + val isDeleted: Boolean? = null, +) : FactorioEventUpdate() { + @EncodeDefault + override val updateType: FactorioEventUpdateType = FactorioEventUpdateType.MAP_CHUNK +} diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEvents.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEvents.kt index 9477af1..0cb882e 100644 --- a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEvents.kt +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioEvents.kt @@ -10,7 +10,7 @@ data class FactorioEvent( /** the initial Factorio event (`defines.events`) trigger */ val eventType: String, /** game time */ - val tick: UInt, + val tick: Tick, val data: FactorioObjectData, ) : KafkatorioPacket() { @EncodeDefault diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioIds.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioIds.kt new file mode 100644 index 0000000..525ada3 --- /dev/null +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioIds.kt @@ -0,0 +1,36 @@ +package dev.adamko.kafkatorio.events.schema + +import kotlin.jvm.JvmInline +import kotlinx.serialization.Serializable + + +/** + * Unique ID associated with this surface + * + * See [`LuaSurface.index`](https://lua-api.factorio.com/latest/LuaSurface.html#LuaSurface.index) + */ +@Serializable +@JvmInline +value class SurfaceIndex(val value: UInt) + + +@Serializable +@JvmInline +value class ForceIndex(val value: UInt) + + +/** The player's index in `LuaGameScript::players` */ +@Serializable +@JvmInline +value class PlayerIndex(val value: UInt) + + +/** This is universally unique for every entity that has one, for the lifetime of a whole game. */ +@Serializable +@JvmInline +value class UnitNumber(val value: UInt) + + +@Serializable +@JvmInline +value class PrototypeName(val value: String) diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioLuaObjects.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioLuaObjects.kt index b6e2d09..796914d 100644 --- a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioLuaObjects.kt +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioLuaObjects.kt @@ -10,6 +10,7 @@ import kotlinx.serialization.json.contentOrNull import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive + @Serializable(with = FactorioObjectDataJsonSerializer::class) sealed class FactorioObjectData { @@ -41,9 +42,15 @@ sealed class FactorioObjectData { // LuaTile, LuaTiles, ConsoleChatMessage, + ; + + companion object { + val values: List = values().toList() + } } } + object FactorioObjectDataJsonSerializer : JsonContentPolymorphicSerializer( FactorioObjectData::class ) { @@ -56,7 +63,7 @@ object FactorioObjectDataJsonSerializer : JsonContentPolymorphicSerializer - FactorioObjectData.ObjectName.values().firstOrNull { it.name == json } + FactorioObjectData.ObjectName.values.firstOrNull { it.name == json } } requireNotNull(type) { "Unknown FactorioObjectData $key: $element" } @@ -74,48 +81,61 @@ object FactorioObjectDataJsonSerializer : JsonContentPolymorphicSerializer, - val characterUnitNumber: UInt?, - val name: String, - val position: MapEntityPosition, - val colour: Colour, + val associatedCharactersUnitNumbers: List, + val characterUnitNumber: UnitNumber?, val chatColour: Colour, - val lastOnline: UInt, -) : FactorioObjectData() { + val colour: Colour, + val lastOnline: Tick, + val name: String, +) : FactorioObjectData(), FactorioLuaControl { @EncodeDefault override val objectName = ObjectName.LuaPlayer } + @Serializable data class EntityData( + override val force: ForceIndex, + override val position: MapEntityPosition, + override val surface: SurfaceIndex, val active: Boolean, val health: Double?, val healthRatio: Double, val name: String, - val position: MapEntityPosition, - val surfaceIndex: Int, + val playerIndex: PlayerIndex? = null, val type: String, - val unitNumber: UInt? = null, - val playerIndex: UInt? = null, -) : FactorioObjectData() { + val unitNumber: UnitNumber? = null, +) : FactorioObjectData(), FactorioLuaControl { @EncodeDefault override val objectName = ObjectName.LuaEntity } + @Serializable data class SurfaceData( val daytime: Double, - val index: UInt, + val index: SurfaceIndex, val name: String, ) : FactorioObjectData() { @EncodeDefault override val objectName = ObjectName.LuaSurface } + /** This isn't a Factorio Lua type, but a helpful collection of Chunk info */ @Serializable data class MapChunk( @@ -127,19 +147,21 @@ data class MapChunk( override val objectName = ObjectName.MapChunk } + /** This isn't a Factorio Lua type, but a helpful collection of [MapTile]s */ @Serializable data class MapTiles( - val surfaceIndex: Int, + val surfaceIndex: SurfaceIndex, val tiles: List, ) : FactorioObjectData() { @EncodeDefault override val objectName = ObjectName.LuaTiles } + @Serializable data class ConsoleChatMessage( - val authorPlayerIndex: UInt?, + val authorPlayerIndex: PlayerIndex?, val content: String, ) : FactorioObjectData() { @EncodeDefault diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioPrototypes.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioPrototypes.kt index 8fc42ea..0cce79d 100644 --- a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioPrototypes.kt +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/factorioPrototypes.kt @@ -28,7 +28,12 @@ sealed class FactorioPrototype { abstract val prototypeObjectName: PrototypeObjectName enum class PrototypeObjectName { - LuaTilePrototype + LuaTilePrototype, + ; + + companion object { + val values: List = values().toList() + } } } @@ -45,7 +50,7 @@ object FactorioPrototypeJsonSerializer : JsonContentPolymorphicSerializer - PrototypeObjectName.values().firstOrNull { it.name == json } + PrototypeObjectName.values.firstOrNull { it.name == json } } requireNotNull(type) { "Unknown FactorioPrototype ${key}: $element" } diff --git a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/kafkatorioPacket.kt b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/kafkatorioPacket.kt index cb98d95..fd59bc2 100644 --- a/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/kafkatorioPacket.kt +++ b/modules/events-schema/src/commonMain/kotlin/dev/adamko/kafkatorio/events/schema/kafkatorioPacket.kt @@ -21,6 +21,11 @@ sealed class KafkatorioPacket { EVENT, CONFIG, PROTOTYPES, + ; + + companion object { + val values: List = values().toList() + } } } @@ -37,7 +42,7 @@ object KafkatorioPacketJsonSerializer : JsonContentPolymorphicSerializer - KafkatorioPacket.PacketType.values().firstOrNull { it.name == json } + KafkatorioPacket.PacketType.values.firstOrNull { it.name == json } } requireNotNull(type) { "Unknown KafkatorioPacket ${key}: $element" } diff --git a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/FactorioEventTest.kt b/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/FactorioEventTest.kt index ce7c8a8..400b8bf 100644 --- a/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/FactorioEventTest.kt +++ b/modules/events-schema/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/FactorioEventTest.kt @@ -50,7 +50,9 @@ class FactorioEventTest : FunSpec({ val expected = FactorioEvent( data = PlayerData( name = "fredthedeadhead", - characterUnitNumber = 1u, + surface = SurfaceIndex(1u), + force = ForceIndex(1u), + characterUnitNumber = UnitNumber(1u), associatedCharactersUnitNumbers = emptyList(), position = MapEntityPosition( x = 30.6, @@ -68,11 +70,11 @@ class FactorioEventTest : FunSpec({ blue = 0.25f, alpha = 1f ), - lastOnline = 2287061u + lastOnline = Tick(2287061u) ), eventType = "on_player_joined_game", modVersion = "0.2.1", - tick = 2287072u + tick = Tick(2287072u) ) actual shouldBe expected @@ -112,12 +114,12 @@ class FactorioEventTest : FunSpec({ val expected = FactorioEvent( data = SurfaceData( name = "nauvis", - index = 1u, + index = SurfaceIndex(1u), daytime = 0.745 ), eventType = "on_tick", modVersion = "0.2.1", - tick = 2301240u + tick = Tick(2301240u) ) actual shouldBe expected @@ -168,8 +170,9 @@ class FactorioEventTest : FunSpec({ active = true, health = 250.0, healthRatio = 1.0, - surfaceIndex = 1, - unitNumber = 1u, + surface = SurfaceIndex(1u), + unitNumber = UnitNumber(1u), + force = ForceIndex(1u), playerIndex = null, position = MapEntityPosition( x = 37.5, @@ -178,7 +181,7 @@ class FactorioEventTest : FunSpec({ ), eventType = "on_player_changed_position", modVersion = "0.2.1", - tick = 2301231u + tick = Tick(2301231u) ) actual shouldBe expected @@ -245,7 +248,7 @@ class FactorioEventTest : FunSpec({ val expected = FactorioEvent( data = MapTiles( - surfaceIndex = 1, + surfaceIndex = SurfaceIndex(1u), tiles = listOf( MapTile( prototypeName = "refined-concrete", @@ -267,7 +270,7 @@ class FactorioEventTest : FunSpec({ ), eventType = "on_player_built_tile", modVersion = "0.2.2", - tick = 2429929u + tick = Tick(2429929u) ) actual shouldBe expected diff --git a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt b/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt new file mode 100644 index 0000000..bdc9747 --- /dev/null +++ b/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/ValueClassTransformer.kt @@ -0,0 +1,67 @@ +package dev.adamko.kafkatorio.events.schema + +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.KType +import kotlin.reflect.KTypeProjection +import kotlin.reflect.full.createType +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.withNullability +import me.ntrrgc.tsGenerator.ClassTransformer + +/** + * 'Unwrap' value classes + */ +object ValueClassTransformer : ClassTransformer { + + override fun transformPropertyType(type: KType, property: KProperty<*>, klass: KClass<*>): KType { + + val classifier = type.classifier ?: return super.transformPropertyType(type, property, klass) + + val valueClassType = unwrapValueClassType(type) + + if (valueClassType != null) { + println("$klass has a value class $type -> $valueClassType") + return valueClassType + } + + val hasValueClassTypeParameters = type.arguments + .mapNotNull { it.type?.classifier } + .filterIsInstance>() + .any { it.isValue } + + if (hasValueClassTypeParameters) { + + val args = type.arguments.map { arg -> + when (val vct = unwrapValueClassType(arg.type)) { + null -> arg + else -> KTypeProjection(arg.variance, vct.withNullability(arg.type!!.isMarkedNullable)) + } + } + + println("$klass has a prop with value class type parameters ${type.arguments} -> $args") + + return classifier.createType( + arguments = args, + nullable = type.isMarkedNullable, + annotations = type.annotations, + ) + } + + return super.transformPropertyType(type, property, klass) + } + + private fun unwrapValueClassType(type: KType?): KType? { + val klass = type?.classifier as? KClass<*> ?: return null + + return when { + klass.isValue -> klass + .declaredMemberProperties + .first() + .returnType + .withNullability(type.isMarkedNullable) + + else -> null + } + } +} diff --git a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt b/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt index 705b607..6d6e492 100644 --- a/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt +++ b/modules/events-schema/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts.kt @@ -18,6 +18,7 @@ fun main(args: Array) { addAll(FactorioPrototype::class.sealedSubclasses) add(FactorioPrototypes::class) add(FactorioConfigurationUpdate::class) + addAll(FactorioEventUpdate::class.sealedSubclasses) }, mappings = mapOf( // builtin Factorio numeric types > `typed-factorio/generated/builtin-types.d.ts` @@ -31,16 +32,16 @@ fun main(args: Array) { ULong::class to "uint64", ), classTransformers = listOf( + ValueClassTransformer, // PropertyNameTransformer, - ) + ), +// voidType = VoidType.UNDEFINED, ) val definitions = gen.definitionsText when (val filename = args.firstOrNull()) { - null -> { - println(definitions) - } + null -> println(definitions) else -> { val outPath = Path(filename) outPath.createDirectories()