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
This commit is contained in:
parent
e989d25a3c
commit
8f9ebdb1e1
13 changed files with 396 additions and 67 deletions
|
|
@ -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[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<FactorioEventUpdateType> = values().toList()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
object JsonSerializer : JsonContentPolymorphicSerializer<FactorioEventUpdate>(
|
||||
FactorioEventUpdate::class
|
||||
) {
|
||||
private val key = FactorioEventUpdate::updateType.name
|
||||
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<out FactorioEventUpdate> {
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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<ObjectName> = values().toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object FactorioObjectDataJsonSerializer : JsonContentPolymorphicSerializer<FactorioObjectData>(
|
||||
FactorioObjectData::class
|
||||
) {
|
||||
|
|
@ -56,7 +63,7 @@ object FactorioObjectDataJsonSerializer : JsonContentPolymorphicSerializer<Facto
|
|||
?.jsonPrimitive
|
||||
?.contentOrNull
|
||||
?.let { json ->
|
||||
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<Facto
|
|||
}
|
||||
|
||||
|
||||
/** [`LuaControl`](https://lua-api.factorio.com/latest/LuaControl.html) */
|
||||
interface FactorioLuaControl {
|
||||
val position: MapEntityPosition
|
||||
val surface: SurfaceIndex
|
||||
val force: ForceIndex
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class PlayerData(
|
||||
// @Serializable(with = FactorioJsonListSerializer::class)
|
||||
override val force: ForceIndex,
|
||||
override val position: MapEntityPosition,
|
||||
override val surface: SurfaceIndex,
|
||||
@Contextual
|
||||
val associatedCharactersUnitNumbers: List<UInt>,
|
||||
val characterUnitNumber: UInt?,
|
||||
val name: String,
|
||||
val position: MapEntityPosition,
|
||||
val colour: Colour,
|
||||
val associatedCharactersUnitNumbers: List<UnitNumber>,
|
||||
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<MapTile>,
|
||||
) : FactorioObjectData() {
|
||||
@EncodeDefault
|
||||
override val objectName = ObjectName.LuaTiles
|
||||
}
|
||||
|
||||
|
||||
@Serializable
|
||||
data class ConsoleChatMessage(
|
||||
val authorPlayerIndex: UInt?,
|
||||
val authorPlayerIndex: PlayerIndex?,
|
||||
val content: String,
|
||||
) : FactorioObjectData() {
|
||||
@EncodeDefault
|
||||
|
|
|
|||
|
|
@ -28,7 +28,12 @@ sealed class FactorioPrototype {
|
|||
abstract val prototypeObjectName: PrototypeObjectName
|
||||
|
||||
enum class PrototypeObjectName {
|
||||
LuaTilePrototype
|
||||
LuaTilePrototype,
|
||||
;
|
||||
|
||||
companion object {
|
||||
val values: List<PrototypeObjectName> = values().toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +50,7 @@ object FactorioPrototypeJsonSerializer : JsonContentPolymorphicSerializer<Factor
|
|||
?.jsonPrimitive
|
||||
?.contentOrNull
|
||||
?.let { json ->
|
||||
PrototypeObjectName.values().firstOrNull { it.name == json }
|
||||
PrototypeObjectName.values.firstOrNull { it.name == json }
|
||||
}
|
||||
|
||||
requireNotNull(type) { "Unknown FactorioPrototype ${key}: $element" }
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ sealed class KafkatorioPacket {
|
|||
EVENT,
|
||||
CONFIG,
|
||||
PROTOTYPES,
|
||||
;
|
||||
|
||||
companion object {
|
||||
val values: List<PacketType> = values().toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +42,7 @@ object KafkatorioPacketJsonSerializer : JsonContentPolymorphicSerializer<Kafkato
|
|||
?.jsonPrimitive
|
||||
?.contentOrNull
|
||||
?.let { json ->
|
||||
KafkatorioPacket.PacketType.values().firstOrNull { it.name == json }
|
||||
KafkatorioPacket.PacketType.values.firstOrNull { it.name == json }
|
||||
}
|
||||
|
||||
requireNotNull(type) { "Unknown KafkatorioPacket ${key}: $element" }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<KClass<*>>()
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ fun main(args: Array<String>) {
|
|||
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<String>) {
|
|||
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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue