project re-organisation, and rename
This commit is contained in:
parent
53862ef1b5
commit
633e898f3c
52 changed files with 525 additions and 387 deletions
43
modules/events-schema/build.gradle.kts
Normal file
43
modules/events-schema/build.gradle.kts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import dev.adamko.factoriowebmap.configurations.asProvider
|
||||
import dev.adamko.factoriowebmap.configurations.typescriptAttributes
|
||||
|
||||
plugins {
|
||||
id("dev.adamko.factoriowebmap.archetype.kotlin-jvm")
|
||||
kotlin("plugin.serialization")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform(libs.kotlinx.serialization.bom))
|
||||
implementation(libs.kotlinx.serialization.core)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
|
||||
implementation("com.github.ntrrgc:ts-generator:1.1.2")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
}
|
||||
|
||||
val generateTypescript by tasks.registering(JavaExec::class) {
|
||||
group = project.name
|
||||
|
||||
val generatedFileName = "$temporaryDir/data-model.ts"
|
||||
inputs.property("generatedFileName", generatedFileName)
|
||||
outputs.file(generatedFileName)
|
||||
|
||||
classpath(sourceSets.main.map { it.runtimeClasspath })
|
||||
mainClass.set("dev.adamko.factorioevents.model.Kt2tsKt")
|
||||
args(generatedFileName)
|
||||
|
||||
doFirst {
|
||||
delete(temporaryDir)
|
||||
mkdir(temporaryDir)
|
||||
}
|
||||
}
|
||||
|
||||
val typescriptModelGenerated by configurations.registering {
|
||||
asProvider()
|
||||
typescriptAttributes(objects)
|
||||
outgoing.artifact(
|
||||
generateTypescript.map {
|
||||
it.outputs.files.singleFile
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
@file:Suppress("ClassName")
|
||||
|
||||
package dev.adamko.factorioevents.model
|
||||
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
|
||||
/*
|
||||
* The basic types used in the Factorio API. While Lua only supports the `boolean`, `number`,
|
||||
* `string`, and `table` types (as they relate to the types listed below), the API docs will
|
||||
* specify what C++ types these are converted to or from internally.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Tables are enclosed in curly brackets, like this `{}`
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#table)
|
||||
*/
|
||||
typealias F_table = MutableMap<Any, Any>
|
||||
|
||||
sealed interface FBuiltInType {
|
||||
|
||||
sealed interface FNumber {
|
||||
/**
|
||||
* A floating-point number. This is a single-precision floating point number. Whilst Lua only uses double-precision
|
||||
* numbers, when a function takes a float, the game engine will immediately convert the double-precision number to
|
||||
* single-precision.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#float)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_float(val float: Float) : FNumber
|
||||
/**
|
||||
* A double-precision floating-point number. This is the same data type as all Lua numbers use.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#double)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_double(val double: Double) : FNumber
|
||||
|
||||
/**
|
||||
* 32-bit signed integer. Possible values are -2,147,483,648 to 2,147,483,647.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#int)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_int(val int: Int) : FNumber
|
||||
/**
|
||||
* 8-bit signed integer. Possible values are -128 to 127.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#int8)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_int8(val int8: Byte) : FNumber
|
||||
|
||||
/**
|
||||
* 32-bit unsigned integer. Possible values are 0 to 4,294,967,295.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#uint)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_uint(val uint: UInt) : FNumber
|
||||
/**
|
||||
* 8-bit unsigned integer. Possible values are 0 to 255.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#uint8)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_uint8(val uint8: UByte) : FNumber
|
||||
/**
|
||||
* 16-bit unsigned integer. Possible values are 0 to 65535.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#uint16)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_uint16(val uint16: UShort) : FNumber
|
||||
/**
|
||||
* 64-bit unsigned integer. Possible values are 0 to 18,446,744,073,709,551,615.
|
||||
*
|
||||
* [View documentation](https://lua-api.factorio.com/next/Builtin-Types.html#uint64)
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class F_uint64(val uint64: ULong) : FNumber
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package dev.adamko.factorioevents.model
|
||||
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonClassDiscriminator
|
||||
|
||||
|
||||
//@Serializable(with = FactorioEventSerializer::class)
|
||||
@Serializable
|
||||
data class FactorioEvent<out T : FactorioObjectData>(
|
||||
/** the initial Factorio event ({defines.events}) trigger */
|
||||
@SerialName("event_type")
|
||||
val eventType: String,
|
||||
/** Schema versioning */
|
||||
@SerialName("mod_version")
|
||||
val modVersion: 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 {
|
||||
@SerialName(FactorioObjectDataDiscriminatorKey)
|
||||
abstract val objectName: String
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("LuaPlayer")
|
||||
data class PlayerData(
|
||||
@SerialName(FactorioObjectDataDiscriminatorKey)
|
||||
override val objectName: String,
|
||||
|
||||
@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,
|
||||
) : FactorioObjectData()
|
||||
|
||||
@Serializable
|
||||
@SerialName("LuaEntity")
|
||||
data class EntityData(
|
||||
@SerialName(FactorioObjectDataDiscriminatorKey)
|
||||
override val objectName: String,
|
||||
|
||||
@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?,
|
||||
|
||||
@SerialName("player_index")
|
||||
val playerIndex: UInt? = null,
|
||||
) : FactorioObjectData()
|
||||
|
||||
@Serializable
|
||||
@SerialName("LuaSurface")
|
||||
data class SurfaceData(
|
||||
@SerialName(FactorioObjectDataDiscriminatorKey)
|
||||
override val objectName: String,
|
||||
|
||||
@SerialName("daytime")
|
||||
val daytime: Double,
|
||||
@SerialName("index")
|
||||
val index: UInt,
|
||||
@SerialName("name")
|
||||
val name: String,
|
||||
) : FactorioObjectData()
|
||||
|
||||
@Serializable
|
||||
data class PositionData(
|
||||
@SerialName("x")
|
||||
val x: Double,
|
||||
@SerialName("y")
|
||||
val y: Double,
|
||||
)
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package dev.adamko.factorioevents.model
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
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. */
|
||||
class ListAsObjectSerializer<T>(dataSerializer: KSerializer<T>) :
|
||||
JsonTransformingSerializer<List<T>>(ListSerializer(dataSerializer)) {
|
||||
|
||||
override fun transformDeserialize(element: JsonElement): JsonElement =
|
||||
JsonArray(
|
||||
element.jsonObject.values.toList()
|
||||
)
|
||||
|
||||
override fun transformSerialize(element: JsonElement): JsonElement =
|
||||
JsonObject(
|
||||
element.jsonArray.mapIndexed { index, jsonElement -> "$index" to jsonElement }.toMap()
|
||||
)
|
||||
}
|
||||
|
||||
val jsonMapper = Json {
|
||||
prettyPrint = true
|
||||
prettyPrintIndent = " "
|
||||
serializersModule = SerializersModule { }
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package dev.adamko.factorioevents.model
|
||||
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import me.ntrrgc.tsGenerator.ClassTransformer
|
||||
import me.ntrrgc.tsGenerator.TypeScriptGenerator
|
||||
import me.ntrrgc.tsGenerator.camelCaseToSnakeCase
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
val gen =
|
||||
TypeScriptGenerator(
|
||||
rootClasses =
|
||||
buildSet {
|
||||
add(FactorioEvent::class)
|
||||
addAll(FactorioObjectData::class.sealedSubclasses)
|
||||
},
|
||||
mappings = mapOf(
|
||||
// builtin Factorio numeric types > `typed-factorio/generated/builtin-types.d.ts`
|
||||
Float::class to "float",
|
||||
Double::class to "double",
|
||||
Int::class to "int",
|
||||
Byte::class to "int8",
|
||||
UInt::class to "uint",
|
||||
UByte::class to "uint8",
|
||||
UShort::class to "uint16",
|
||||
ULong::class to "uint64",
|
||||
),
|
||||
classTransformers = listOf(
|
||||
PropertyNameTransformer,
|
||||
)
|
||||
)
|
||||
|
||||
val definitions = gen.definitionsText
|
||||
|
||||
when (val filename = args.firstOrNull()) {
|
||||
null -> {
|
||||
println(definitions)
|
||||
}
|
||||
else -> {
|
||||
val out = File(filename)
|
||||
out.parentFile.mkdirs()
|
||||
out.printWriter().use {
|
||||
it.print(header)
|
||||
it.print(definitions)
|
||||
}
|
||||
println("Generated file: $out")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Language("TypeScript")
|
||||
val header = """
|
||||
|
||||
// Generated code - do edit this file manually
|
||||
|
||||
|
||||
""".trimIndent()
|
||||
|
||||
object PropertyNameTransformer : ClassTransformer {
|
||||
override fun transformPropertyName(
|
||||
propertyName: String,
|
||||
property: KProperty<*>,
|
||||
klass: KClass<*>
|
||||
): String {
|
||||
return camelCaseToSnakeCase(propertyName)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package dev.adamko.factorioevents.model
|
||||
|
||||
import io.kotest.core.spec.style.BehaviorSpec
|
||||
import io.kotest.matchers.equality.shouldBeEqualToComparingFields
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import org.intellij.lang.annotations.Language
|
||||
|
||||
class FactorioEventTest : BehaviorSpec({
|
||||
|
||||
Given("json on_player_joined_game") {
|
||||
|
||||
@Language("JSON")
|
||||
val json = """
|
||||
{
|
||||
"data": {
|
||||
"object_name": "LuaPlayer",
|
||||
"name": "fredthedeadhead",
|
||||
"character_unit_number": 1,
|
||||
"associated_characters_unit_numbers": {},
|
||||
"position": {
|
||||
"x": -3.5703125,
|
||||
"y": 29.75
|
||||
}
|
||||
},
|
||||
"event_type": "on_player_joined_game",
|
||||
"mod_version": "0.0.4",
|
||||
"tick": 1278458
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
Then("parse") {
|
||||
val actual: FactorioEvent<FactorioObjectData> = jsonMapper.decodeFromString(json)
|
||||
|
||||
val expected = FactorioEvent(
|
||||
data = PlayerData(
|
||||
objectName = "LuaPlayer",
|
||||
name = "fredthedeadhead",
|
||||
characterUnitNumber = 1u,
|
||||
associatedCharactersUnitNumbers = emptyList(),
|
||||
position = PositionData(
|
||||
x = -3.5703125,
|
||||
y = 29.75
|
||||
)
|
||||
),
|
||||
eventType = "on_player_joined_game",
|
||||
modVersion = "0.0.4",
|
||||
tick = 1278458u
|
||||
)
|
||||
|
||||
actual shouldBeEqualToComparingFields expected
|
||||
}
|
||||
}
|
||||
|
||||
Given("json surface") {
|
||||
@Language("JSON")
|
||||
val json = """
|
||||
{
|
||||
"data": {
|
||||
"object_name": "LuaSurface",
|
||||
"name": "nauvis",
|
||||
"index": 1,
|
||||
"daytime": 0.8390800000511436707029133685864508152008056640625
|
||||
},
|
||||
"event_type": "on_tick",
|
||||
"mod_version": "0.0.4",
|
||||
"tick": 1278480
|
||||
}
|
||||
""".trimIndent()
|
||||
Then("parse") {
|
||||
val actual: FactorioEvent<FactorioObjectData> = jsonMapper.decodeFromString(json)
|
||||
|
||||
val expected = FactorioEvent(
|
||||
data = SurfaceData(
|
||||
objectName = "LuaSurface",
|
||||
name = "nauvis",
|
||||
index = 1u,
|
||||
daytime = 0.8390800000511436707029133685864508152008056640625
|
||||
),
|
||||
eventType = "on_tick",
|
||||
modVersion = "0.0.4",
|
||||
tick = 1278480u
|
||||
)
|
||||
|
||||
actual shouldBeEqualToComparingFields expected
|
||||
}
|
||||
}
|
||||
|
||||
Given("json entity") {
|
||||
@Language("JSON")
|
||||
val json = """
|
||||
{
|
||||
"data": {
|
||||
"object_name": "LuaEntity",
|
||||
"name": "character",
|
||||
"type": "character",
|
||||
"active": true,
|
||||
"health": 250,
|
||||
"health_ratio": 1,
|
||||
"surface_index": 1,
|
||||
"unit_number": 1,
|
||||
"position": {
|
||||
"x": -0.25,
|
||||
"y": 30.09375
|
||||
}
|
||||
},
|
||||
"event_type": "on_player_changed_position",
|
||||
"mod_version": "0.0.6",
|
||||
"tick": 1384507
|
||||
}
|
||||
""".trimIndent()
|
||||
Then("parse") {
|
||||
val actual: FactorioEvent<FactorioObjectData> = jsonMapper.decodeFromString(json)
|
||||
|
||||
val expected = FactorioEvent(
|
||||
data = EntityData(
|
||||
objectName = "LuaEntity",
|
||||
name = "character",
|
||||
type = "character",
|
||||
active = true,
|
||||
health = 250.0,
|
||||
healthRatio = 1.0,
|
||||
surfaceIndex = 1,
|
||||
unitNumber = 1u,
|
||||
playerIndex = null,
|
||||
position = PositionData(
|
||||
x = -0.25,
|
||||
y = 30.09375,
|
||||
)
|
||||
),
|
||||
eventType = "on_player_changed_position",
|
||||
modVersion = "0.0.6",
|
||||
tick = 1384507u
|
||||
)
|
||||
|
||||
actual shouldBeEqualToComparingFields expected
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue