make the data being output by the events-mod more generalised, to include more than just events (mod config, prototypes)

This commit is contained in:
Adam 2022-01-08 13:11:51 +01:00
parent 58233c9343
commit ed4d42a2ef
26 changed files with 524 additions and 379 deletions

View file

@ -10,7 +10,7 @@ import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
plugins {
idea
id("dev.adamko.kafkatorio.lang.node")
dev.adamko.kafkatorio.lang.node
distribution
}
@ -60,7 +60,7 @@ val typescriptToLua by tasks.registering(NpmTask::class) {
description = "Convert Typescript To Lua"
group = project.name
dependsOn(tasks.npmInstall, installEventsTsSchema)
dependsOn(tasks.npmInstall, installEventsTsSchema, tasks.updatePackageJson)
execOverrides { standardOutput = System.out }
@ -214,5 +214,3 @@ tasks.assemble { dependsOn(installEventsTsSchema, tasks.updatePackageJson) }
// }
// }
// }
tasks.npmInstall

View file

@ -1,8 +1,5 @@
import {emitTiles} from "./prototypes/emitPrototypes";
import {handleConfigurationUpdate} from "./main/config-update/handleConfigurationUpdate";
require("events")
// on startup, push out prototypes
script.on_configuration_changed((e: ConfigurationChangedData) => {
emitTiles()
})
script.on_configuration_changed(handleConfigurationUpdate)

View file

@ -9,9 +9,8 @@ export function emitEvent<T extends FactorioObjectData>(eventData: T, tick: uint
let event: FactorioEvent<T> = {
data: eventData,
event_type: eventType,
mod_version: MOD_VERSION,
factorio_version: FACTORIO_VERSION,
eventType: eventType,
modVersion: MOD_VERSION,
tick: tick
}

View file

@ -50,10 +50,12 @@ export function handleConsoleChat(
const CHUNK_SIZE = 32
export function handleChunkUpdate(tick: uint,
eventType: string,
surfaceIndex: uint,
position: ChunkPosition) {
export function handleChunkUpdate(
tick: uint,
eventType: string,
surfaceIndex: uint,
position: ChunkPosition
) {
let surface = game.get_surface(surfaceIndex)
@ -69,14 +71,13 @@ export function handleChunkUpdate(tick: uint,
let tilePositionMap = new Map<PositionData, FactorioTile>();
for (let tile of tiles) {
let position = Serdes.positionTableToTable(tile.position)
let position = Serdes.convertMapPosition(tile.position)
tilePositionMap.set(position, Serdes.convertTile(tile))
}
let mapChunk: FactorioTilesMap = {
object_name: "FactorioTilesMap",
objectName: "FactorioTilesMap",
tiles: tilePositionMap,
}
emitEvent(mapChunk, tick, eventType)
}

View file

@ -3,15 +3,15 @@ export namespace Serdes {
export function playerToTable(player: LuaPlayer): PlayerData {
let charIds = entitiesToUnitNumbers(player.get_associated_characters())
return {
object_name: player.object_name,
objectName: player.object_name,
name: player.name,
character_unit_number: player.character?.unit_number ?? null,
associated_characters_unit_numbers: charIds,
position: positionTableToTable(player.position),
characterUnitNumber: player.character?.unit_number ?? null,
associatedCharactersUnitNumbers: charIds,
position: convertMapPosition(player.position),
colour: mapColour(player.color),
chat_colour: mapColour(player.chat_color),
last_online: player.last_online
chatColour: mapColour(player.chat_color),
lastOnline: player.last_online
}
}
@ -20,20 +20,20 @@ export namespace Serdes {
let player: LuaPlayer | null = entity.is_player() ? entity.player!! : null
return {
object_name: entity.object_name,
objectName: entity.object_name,
// entity data
name: entity.name,
type: entity.type,
active: entity.active,
health: entity.health ?? null,
health_ratio: entity.get_health_ratio(),
surface_index: entity.surface.index,
unit_number: entity.unit_number ?? null,
position: positionTableToTable(entity.position),
healthRatio: entity.get_health_ratio(),
surfaceIndex: entity.surface.index,
unitNumber: entity.unit_number ?? null,
position: convertMapPosition(entity.position),
// player data
player_index: player?.index ?? null
playerIndex: player?.index ?? null
}
}
@ -49,7 +49,7 @@ export namespace Serdes {
export function surfaceToTable(surface: LuaSurface): SurfaceData {
return {
object_name: surface.object_name,
objectName: surface.object_name,
name: surface.name,
index: surface.index,
@ -57,10 +57,11 @@ export namespace Serdes {
}
}
export function positionTableToTable(positionTable: PositionTable): PositionData {
export function convertMapPosition(mapPos: MapPositionTable): PositionData {
return {
x: positionTable.x,
y: positionTable.y,
type: "MAP",
x: mapPos.x,
y: mapPos.y,
}
}
@ -75,20 +76,20 @@ export namespace Serdes {
export function consoleChat(content: string, playerIndex?: uint): ConsoleChatMessage {
return {
object_name: "ConsoleChatMessage",
objectName: "ConsoleChatMessage",
author_player_index: playerIndex ?? null,
authorPlayerIndex: playerIndex ?? null,
content: content
}
}
export function convertTile(tile: LuaTile): FactorioTile {
return {
object_name: tile.object_name,
objectName: tile.object_name,
position: tile.position,
prototype_name: tile.prototype.name,
surface_index: tile.surface.index
position: convertMapPosition(tile.position),
prototypeName: tile.prototype.name,
surfaceIndex: tile.surface.index
}
}

View file

@ -0,0 +1,43 @@
import {emitPacket} from "../emitKafkatorioPacket";
import {convertPrototypes} from "../../prototypes/emitPrototypes";
export function handleConfigurationUpdate(changeData: ConfigurationChangedData) {
emitPacket<FactorioConfigurationUpdate>({
modVersion: global.MOD_VERSION,
allMods: allMods(changeData),
factorioData: factorioData(changeData),
prototypes: convertPrototypes()
})
}
function factorioData(changeData: ConfigurationChangedData): FactorioGameDataUpdate {
return {
oldVersion: changeData.old_version ?? null,
newVersion: changeData.new_version ?? null,
}
}
function allMods(e: ConfigurationChangedData): FactorioModInfo[] {
let namesOfChangedMods: string[] = Object.keys(e.mod_changes)
let namesOfCurrentMods: string[] = Object.keys(script.active_mods)
let modNames = [...new Set<string>(
namesOfChangedMods.concat(namesOfCurrentMods)
)]
return modNames.map((modName) => {
let currentVer = script.active_mods[modName] ?? e.mod_changes[modName].new_version
let previousVer = e.mod_changes[modName].old_version
return <FactorioModInfo>{
modName: modName,
currentVersion: currentVer,
previousVersion: previousVer,
}
})
}

View file

@ -0,0 +1,4 @@
export function updateGlobal() {
global.MOD_VERSION = script.active_mods[script.mod_name][1]
global.FACTORIO_VERSION = script.active_mods["base"][1]
}

View file

@ -0,0 +1,6 @@
/** Emit a serialised KafkatorioPacket */
export function emitPacket<T extends KafkatorioPacket>(packet: T) {
let data = game.table_to_json(packet)
localised_print(`KafkatorioPacket: ${data}`)
// rcon.print(`KafkatorioPacket: ${data}`)
}

View file

@ -0,0 +1,4 @@
declare const global: {
MOD_VERSION: string
FACTORIO_VERSION: string
}

View file

@ -1,6 +1,6 @@
{
"name": "kafkatorio-events-mod",
"version": "0.1.7",
"version": "0.2.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "kafkatorio-events-mod",
"version": "0.1.7",
"version": "0.2.0",
"private": true,
"scripts": {
"build": "tstl",

View file

@ -1,42 +1,36 @@
import {Serdes} from "../events/serdes";
export function emitTiles() {
export function convertPrototypes (): FactorioPrototype[] {
let prototypes = new Array<FactorioPrototype>()
let tilePrototypes = new LuaTable<string, FactorioMapTilePrototype>()
prototypes.push(...getMapTilePrototypes())
for (const [_, tile] of pairs(game.tile_prototypes)) {
// let ttttt = game.tile_prototypes[tileName]
tilePrototypes.set(tile.name, mapTilePrototype(tile))
return prototypes
}
function getMapTilePrototypes(): FactorioMapTilePrototype[] {
let tiles: FactorioMapTilePrototype[] = []
for (let [_, tile] of pairs(game.tile_prototypes)) {
tiles.push(
<FactorioMapTilePrototype>{
objectName: tile.object_name,
name: tile.name,
order: tile.order,
layer: tile.layer,
collisionMasks: convertCollisionMaskToNames(tile.collision_mask),
mapColor: Serdes.mapColour(tile.map_color),
canBeMined: tile.mineable_properties.minable,
}
)
}
// for (let tileName in game.tile_prototypes) {
// const tile = game.tile_prototypes[tileName]
// tilePrototypes.set(tileName, mapTilePrototype(tile))
// }
// for (const [id, player] of pairs(game.players)) {
// const num: number = id
// const p: LuaPlayer = player
// }
emitPrototypes(tilePrototypes)
return tiles
}
function mapTilePrototype(tile: LuaTilePrototype): FactorioMapTilePrototype {
return {
object_name: tile.object_name,
name: tile.name,
order: tile.order,
layer: tile.layer,
collision_masks: [],
map_color: Serdes.mapColour(tile.map_color),
can_be_mined: tile.mineable_properties.minable,
function convertCollisionMaskToNames(cm: CollisionMask): string[] {
let masks: string[] = []
for (let [name, _] of pairs(cm)) {
masks.push(name)
}
}
function emitPrototypes<T extends FactorioPrototype>(prototypes: LuaTable<string, T>) {
let data = game.table_to_json(prototypes)
localised_print(`FactorioPrototype: ${data}`)
return masks
}

View file

@ -0,0 +1,19 @@
// Generated by TypeScriptGenerator - do not edit this file manually
interface FactorioModInfo {
currentVersion: string | null;
modName: string;
previousVersion: string | null;
}
interface FactorioGameDataUpdate {
newVersion: string | null;
oldVersion: string | null;
}
interface FactorioConfigurationUpdate extends KafkatorioPacket {
allMods: FactorioModInfo[];
factorioData: FactorioGameDataUpdate;
modVersion: string;
prototypes: FactorioPrototype[];
}

View file

@ -1,92 +0,0 @@
// Generated by TypeScriptGenerator - do not edit this file manually
interface FactorioObjectData {
object_name: string;
}
interface FactorioEvent<T extends FactorioObjectData> {
data: T;
event_type: string;
factorio_version: string;
mod_version: string;
tick: uint;
}
interface Colour {
alpha: float;
blue: float;
green: float;
red: float;
}
interface PositionData {
x: double;
y: double;
}
interface PlayerData extends FactorioObjectData {
associated_characters_unit_numbers: uint[];
character_unit_number: uint | null;
chat_colour: Colour;
colour: Colour;
last_online: uint;
name: string;
object_name: string;
position: PositionData;
}
interface EntityData extends FactorioObjectData {
active: boolean;
health: double | null;
health_ratio: double;
name: string;
object_name: string;
player_index: uint | null;
position: PositionData;
surface_index: int;
type: string;
unit_number: uint | null;
}
interface SurfaceData extends FactorioObjectData {
daytime: double;
index: uint;
name: string;
object_name: string;
}
interface ConsoleChatMessage extends FactorioObjectData {
author_player_index: uint | null;
content: string;
object_name: string;
}
interface FactorioTile extends FactorioObjectData {
object_name: string;
position: PositionData;
prototype_name: string;
surface_index: int;
}
interface FactorioTilesMap extends FactorioObjectData {
object_name: string;
tiles: Map<PositionData, FactorioTile>;
}
interface FactorioTiles extends FactorioObjectData {
object_name: string;
tiles: FactorioTile[];
}
interface FactorioPrototype {
object_name: string;
}
interface FactorioMapTilePrototype extends FactorioPrototype {
can_be_mined: boolean;
collision_masks: string[];
layer: uint;
map_color: Colour;
name: string;
object_name: string;
order: string;
}

View file

@ -0,0 +1,61 @@
// Generated by TypeScriptGenerator - do not edit this file manually
interface FactorioObjectData {
objectName: string;
}
interface FactorioEvent<T extends FactorioObjectData> extends KafkatorioPacket {
data: T;
eventType: string;
modVersion: string;
tick: uint;
}
interface PlayerData extends FactorioObjectData {
associatedCharactersUnitNumbers: uint[];
characterUnitNumber: uint | null;
chatColour: Colour;
colour: Colour;
lastOnline: uint;
name: string;
objectName: string;
position: PositionData;
}
interface EntityData extends FactorioObjectData {
active: boolean;
health: double | null;
healthRatio: double;
name: string;
objectName: string;
playerIndex: uint | null;
position: PositionData;
surfaceIndex: int;
type: string;
unitNumber: uint | null;
}
interface SurfaceData extends FactorioObjectData {
daytime: double;
index: uint;
name: string;
objectName: string;
}
interface FactorioTile extends FactorioObjectData {
objectName: string;
position: PositionData;
prototypeName: string;
surfaceIndex: int;
}
interface FactorioTilesMap extends FactorioObjectData {
objectName: string;
tiles: Map<PositionData, FactorioTile>;
}
interface ConsoleChatMessage extends FactorioObjectData {
authorPlayerIndex: uint | null;
content: string;
objectName: string;
}

View file

@ -0,0 +1,20 @@
// Generated by TypeScriptGenerator - do not edit this file manually
interface FactorioPrototype {
objectName: string;
}
interface FactorioPrototypes<T extends FactorioPrototype> extends KafkatorioPacket {
modVersion: string;
prototypes: T[];
}
interface FactorioMapTilePrototype extends FactorioPrototype {
canBeMined: boolean;
collisionMasks: string[];
layer: uint;
mapColor: Colour;
name: string;
objectName: string;
order: string;
}

View file

@ -0,0 +1,20 @@
// Generated by TypeScriptGenerator - do not edit this file manually
interface KafkatorioPacket {
modVersion: string;
}
interface Colour {
alpha: float;
blue: float;
green: float;
red: float;
}
type PositionType = "MAP" | "CHUNK" | "TILE";
interface PositionData {
type: PositionType | null;
x: double;
y: double;
}

View file

@ -80,8 +80,8 @@ val generateTypescript by tasks.registering(JavaExec::class) {
mainClass.set("dev.adamko.kafkatorio.events.schema.Kt2tsKt")
val generatedFile = file("$temporaryDir/${project.name}.ts")
args(generatedFile)
val tempOutputDirectory = file("$temporaryDir")
args(tempOutputDirectory)
val buildOutput = layout.buildDirectory.dir("generated/typescript")
outputs.dir(buildOutput)

View file

@ -0,0 +1,50 @@
package dev.adamko.kafkatorio.events.schema
import kotlinx.serialization.Serializable
@Serializable
data class PositionData(
val x: Double,
val y: Double,
val type: PositionType?,
)
@Serializable
enum class PositionType {
MAP, CHUNK, TILE,
}
/**
* Red, green, blue and alpha values, all in range `[0, 1]` or all in range `[0, 255]` if any
* value is > 1.
*
* All values here are optional. Color channels default to 0, the alpha channel defaults to 1.
*/
@Serializable
data class Colour(
val red: Float = 0f,
val green: Float = 0f,
val blue: Float = 0f,
val alpha: Float = 1f,
) {
/** True if any value is greater than 1, so the values are hexadecimal. */
fun isDecimal(): Boolean {
return red > 1f
|| green > 1f
|| blue > 1f
|| alpha > 1f
}
/** True if all values are between `[0..1]`. */
fun isPercentage(): Boolean = !isDecimal()
}
//@Serializable
//@SerialName("FactorioTiles")
//data class FactorioTiles(
// val tiles: List<FactorioTile>,
//) : FactorioObjectData() {
// @Transient
// override val objectName: String = "FactorioTiles"
//}

View file

@ -0,0 +1,25 @@
package dev.adamko.kafkatorio.events.schema
import kotlinx.serialization.Serializable
@Serializable
data class FactorioConfigurationUpdate(
override val modVersion: String,
val factorioData: FactorioGameDataUpdate,
val allMods: List<FactorioModInfo>,
val prototypes: List<FactorioPrototype>,
) : KafkatorioPacket
@Serializable
data class FactorioGameDataUpdate(
val oldVersion: String?,
val newVersion: String?,
)
@Serializable
data class FactorioModInfo(
val modName: String,
val currentVersion: String?,
val previousVersion: String?,
)

View file

@ -1,192 +1,16 @@
package dev.adamko.kafkatorio.events.schema
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonClassDiscriminator
//@Serializable(with = FactorioEventSerializer::class)
@Serializable
data class FactorioEvent<out T : FactorioObjectData>(
override val modVersion: String,
/** the initial Factorio event ({defines.events}) trigger */
@SerialName("event_type")
val eventType: String,
/** Schema versioning */
@SerialName("mod_version")
val modVersion: String,
@SerialName("factorio_version")
val factorioVersion: String,
/** game time */
@SerialName("tick")
val tick: UInt,
@SerialName("data")
val data: T
)
/** The [JsonClassDiscriminator] for [FactorioEvent] */
const val FactorioObjectDataDiscriminatorKey: String = "object_name"
@Serializable
@JsonClassDiscriminator(FactorioObjectDataDiscriminatorKey)
sealed class FactorioObjectData {
abstract val objectName: String
// workaround - https://github.com/Kotlin/kotlinx.serialization/issues/1664
// val objectName: String by lazy {
// serializer().descriptor.serialName
// }
// val objectName: String by lazy {
// kotlinx.serialization.serializer(this::class.starProjectedType).descriptor.serialName
// }
// alternative: find the @SerialName annotation
// Again it must be delegated so there's no backing field and kxs ignores it
// val objectName: String by lazy {
// requireNotNull(this::class.findAnnotation<SerialName>()?.value) {
// "Couldn't find @SerialName for ${this::class}!"
// }
// }
}
@Serializable
@SerialName("LuaPlayer")
data class PlayerData(
@Serializable(with = ListAsObjectSerializer::class)
@SerialName("associated_characters_unit_numbers")
val associatedCharactersUnitNumbers: List<UInt>,
@SerialName("character_unit_number")
val characterUnitNumber: UInt?,
@SerialName("name")
val name: String,
@SerialName("position")
val position: PositionData,
@SerialName("colour")
val colour: Colour,
@SerialName("chat_colour")
val chatColour: Colour,
@SerialName("last_online")
val lastOnline: UInt,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaPlayer"
}
@Serializable
@SerialName("LuaEntity")
data class EntityData(
@SerialName("active")
val active: Boolean,
@SerialName("health")
val health: Double?,
@SerialName("health_ratio")
val healthRatio: Double,
@SerialName("name")
val name: String,
@SerialName("position")
val position: PositionData,
@SerialName("surface_index")
val surfaceIndex: Int,
@SerialName("type")
val type: String,
@SerialName("unit_number")
val unitNumber: UInt? = null,
@SerialName("player_index")
val playerIndex: UInt? = null,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaEntity"
}
@Serializable
@SerialName("LuaSurface")
data class SurfaceData(
@SerialName("daytime")
val daytime: Double,
@SerialName("index")
val index: UInt,
@SerialName("name")
val name: String,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaSurface"
}
@Serializable
data class PositionData(
val x: Double,
val y: Double,
)
/**
* Red, green, blue and alpha values, all in range `[0, 1]` or all in range `[0, 255]` if any
* value is > 1.
*
* All values here are optional. Color channels default to 0, the alpha channel defaults to 1.
*/
@Serializable
data class Colour(
val red: Float = 0f,
val green: Float = 0f,
val blue: Float = 0f,
val alpha: Float = 1f,
) {
/** True if any value is greater than 1, so the values are hexadecimal. */
fun isDecimal(): Boolean {
return red > 1f
|| green > 1f
|| blue > 1f
|| alpha > 1f
}
/** True if all values are between `[0..1]`. */
fun isPercentage(): Boolean = !isDecimal()
}
@Serializable
data class ConsoleChatMessage(
@SerialName("author_player_index")
val authorPlayerIndex: UInt?,
val content: String,
) : FactorioObjectData() {
@Transient
override val objectName: String = "ConsoleChatMessage"
}
@Serializable
@SerialName("FactorioTilesMap")
data class FactorioTilesMap(
val tiles: Map<PositionData, FactorioTile>,
) : FactorioObjectData() {
@Transient
override val objectName: String = "FactorioTilesMap"
}
@Serializable
@SerialName("FactorioTiles")
data class FactorioTiles(
val tiles: List<FactorioTile>,
) : FactorioObjectData() {
@Transient
override val objectName: String = "FactorioTiles"
}
@Serializable
@SerialName("LuaTile")
data class FactorioTile(
val prototypeName: String,
val position: PositionData,
val surfaceIndex: Int,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaTile"
}
val data: T,
) : KafkatorioPacket

View file

@ -0,0 +1,108 @@
package dev.adamko.kafkatorio.events.schema
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonClassDiscriminator
@Serializable
@JsonClassDiscriminator(FactorioObjectData.discriminatorKey)
sealed class FactorioObjectData {
abstract val objectName: String
// workaround - https://github.com/Kotlin/kotlinx.serialization/issues/1664
// val objectName: String by lazy {
// serializer().descriptor.serialName
// }
// val objectName: String by lazy {
// kotlinx.serialization.serializer(this::class.starProjectedType).descriptor.serialName
// }
// alternative: find the @SerialName annotation
// Again it must be delegated so there's no backing field and kxs ignores it
// val objectName: String by lazy {
// requireNotNull(this::class.findAnnotation<SerialName>()?.value) {
// "Couldn't find @SerialName for ${this::class}!"
// }
// }
companion object {
/** The [JsonClassDiscriminator] for [FactorioEvent] */
const val discriminatorKey: String = "objectName"
}
}
@Serializable
@SerialName("LuaPlayer")
data class PlayerData(
@Serializable(with = ListAsObjectSerializer::class)
val associatedCharactersUnitNumbers: List<UInt>,
val characterUnitNumber: UInt?,
val name: String,
val position: PositionData,
val colour: Colour,
val chatColour: Colour,
val lastOnline: UInt,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaPlayer"
}
@Serializable
@SerialName("LuaEntity")
data class EntityData(
val active: Boolean,
val health: Double?,
val healthRatio: Double,
val name: String,
val position: PositionData,
val surfaceIndex: Int,
val type: String,
val unitNumber: UInt? = null,
val playerIndex: UInt? = null,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaEntity"
}
@Serializable
@SerialName("LuaSurface")
data class SurfaceData(
val daytime: Double,
val index: UInt,
val name: String,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaSurface"
}
@Serializable
@SerialName("FactorioTilesMap")
data class FactorioTilesMap(
val tiles: Map<PositionData, FactorioTile>,
) : FactorioObjectData() {
@Transient
override val objectName: String = "FactorioTilesMap"
}
@Serializable
@SerialName("LuaTile")
data class FactorioTile(
val prototypeName: String,
val position: PositionData,
val surfaceIndex: Int,
) : FactorioObjectData() {
@Transient
override val objectName: String = "LuaTile"
}
@Serializable
data class ConsoleChatMessage(
val authorPlayerIndex: UInt?,
val content: String,
) : FactorioObjectData() {
@Transient
override val objectName: String = "ConsoleChatMessage"
}

View file

@ -6,9 +6,19 @@ import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonClassDiscriminator
@Serializable
@JsonClassDiscriminator(FactorioObjectDataDiscriminatorKey)
class FactorioPrototypes<T : FactorioPrototype>(
override val modVersion: String,
val prototypes: List<T>,
) : KafkatorioPacket
@Serializable
@JsonClassDiscriminator(FactorioPrototype.discriminatorKey)
sealed class FactorioPrototype {
abstract val objectName: String
companion object {
const val discriminatorKey: String = "objectName"
}
}
@Serializable
@ -20,7 +30,7 @@ data class FactorioMapTilePrototype(
val collisionMasks: List<String>,
val order: String,
/** Is this tile mineable at all? */
/** Can the tile be mined for resources? */
val canBeMined: Boolean,
) : FactorioPrototype() {
@Transient

View file

@ -0,0 +1,26 @@
package dev.adamko.kafkatorio.events.schema;
//@Serializable
sealed interface KafkatorioPacket {
/** Schema versioning */
val modVersion: String
}
//enum class PacketDataType {
// EVENT, PROTOTYPE, CONFIG_DATA,
// ;
//}
//@Serializable
//@JsonClassDiscriminator(KafkatorioPacketData.discriminatorKey)
//sealed class KafkatorioPacketData(
// @SerialName(discriminatorKey)
// val dataType: PacketDataType
//) {
// companion object {
// const val discriminatorKey: String = "dataType"
// }
//}

View file

@ -1,11 +1,8 @@
package dev.adamko.kafkatorio.events.schema
import java.io.File
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import me.ntrrgc.tsGenerator.ClassTransformer
import kotlin.io.path.Path
import kotlin.io.path.createDirectories
import me.ntrrgc.tsGenerator.TypeScriptGenerator
import me.ntrrgc.tsGenerator.camelCaseToSnakeCase
import org.intellij.lang.annotations.Language
/**
@ -15,9 +12,8 @@ fun main(args: Array<String>) {
val gen =
TypeScriptGenerator(
rootClasses =
buildSet {
add(FactorioEvent::class)
rootClasses = buildSet {
addAll(KafkatorioPacket::class.sealedSubclasses)
addAll(FactorioObjectData::class.sealedSubclasses)
addAll(FactorioPrototype::class.sealedSubclasses)
},
@ -33,7 +29,7 @@ fun main(args: Array<String>) {
ULong::class to "uint64",
),
classTransformers = listOf(
PropertyNameTransformer,
// PropertyNameTransformer,
)
)
@ -44,29 +40,60 @@ fun main(args: Array<String>) {
println(definitions)
}
else -> {
val out = File(filename)
out.parentFile.mkdirs()
out.printWriter().use {
it.print(header)
it.print(definitions)
}
println("Generated file: $out")
val outPath = Path(filename)
outPath.createDirectories()
splitDefinitions(definitions)
.forEach { (defFile, def) ->
val outFile = outPath.resolve(defFile).toFile()
outFile.printWriter().use {
it.print(header)
it.print(def)
}
println("Generated file: $outFile")
}
}
}
}
/** Split the TypeScript interfaces into different files */
private fun splitDefinitions(definitions: String): Map<String, String> {
return definitions
.split("\n\n")
.groupBy { def ->
when {
"extends FactorioObjectData" in def ||
"interface FactorioObjectData" in def -> "object-data.d.ts"
"extends FactorioPrototype" in def ||
"interface FactorioPrototype" in def -> "prototype.d.ts"
"extends FactorioConfigurationUpdate" in def ||
"interface FactorioConfigurationUpdate" in def ||
"FactorioGameDataUpdate" in def ||
"FactorioModInfo" in def -> "config-update.d.ts"
else -> "schema.d.ts"
}
}
.mapValues { (_, def) ->
def
.joinToString("\n\n", postfix = "\n")
.replace(" ", " ")
}
}
@Language("TypeScript")
val header = """
|// Generated by TypeScriptGenerator - do not edit this file manually
|
""".trimMargin()
""".trimMargin() + "\n"
object PropertyNameTransformer : ClassTransformer {
override fun transformPropertyName(
propertyName: String,
property: KProperty<*>,
klass: KClass<*>
): String {
return camelCaseToSnakeCase(propertyName)
}
}
//object PropertyNameTransformer : ClassTransformer {
// override fun transformPropertyName(
// propertyName: String,
// property: KProperty<*>,
// klass: KClass<*>
// ): String {
// return camelCaseToSnakeCase(propertyName)
// }
//}