massive refactor to export entities (buildings and resources)

- minor version bumps
- new Factorio version
- use both prototype name and type to identify a prototype
- kxs-ts-gen: use BrandTyping, but exclude some identifiers
- kxs-ts-gen: manually create zip dist, so it can run after the project compiles
- mod: use typed-factorio strict types
- mod: refactor event handlers to be a little more consistent and object-oriented
This commit is contained in:
Adam 2022-07-05 23:44:23 +02:00
parent 88982d818a
commit 90dc520d22
62 changed files with 2629 additions and 713 deletions

View file

@ -18,12 +18,14 @@ fun Configuration.asProvider() {
isCanBeConsumed = true isCanBeConsumed = true
} }
fun Configuration.asConsumer() { fun Configuration.asConsumer() {
isVisible = false isVisible = false
isCanBeResolved = true isCanBeResolved = true
isCanBeConsumed = false isCanBeConsumed = false
} }
fun Configuration.factorioModAttributes(objects: ObjectFactory): Configuration = fun Configuration.factorioModAttributes(objects: ObjectFactory): Configuration =
attributes { attributes {
attribute(USAGE_ATTRIBUTE, objects.named("factorio")) attribute(USAGE_ATTRIBUTE, objects.named("factorio"))
@ -32,6 +34,7 @@ fun Configuration.factorioModAttributes(objects: ObjectFactory): Configuration =
attribute(BUNDLING_ATTRIBUTE, objects.named(Bundling.EMBEDDED)) attribute(BUNDLING_ATTRIBUTE, objects.named(Bundling.EMBEDDED))
} }
fun Configuration.typescriptAttributes(objects: ObjectFactory): Configuration = fun Configuration.typescriptAttributes(objects: ObjectFactory): Configuration =
attributes { attributes {
attribute(USAGE_ATTRIBUTE, objects.named("typescript")) attribute(USAGE_ATTRIBUTE, objects.named("typescript"))

View file

@ -6,8 +6,10 @@ import org.gradle.api.file.FileSystemOperations
import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
import org.gradle.work.DisableCachingByDefault
@DisableCachingByDefault(because = "caching makes regenerating more difficult")
abstract class GenerateTypeScriptTask @Inject constructor( abstract class GenerateTypeScriptTask @Inject constructor(
private val fileOps: FileSystemOperations, private val fileOps: FileSystemOperations,
) : JavaExec() { ) : JavaExec() {

View file

@ -16,20 +16,22 @@ kvision = "5.11.0"
log4j2 = "2.17.2" log4j2 = "2.17.2"
qosLogback = "1.2.11" qosLogback = "1.2.11"
slf4j = "1.7.36" slf4j = "1.7.36"
okio = "3.1.0" okio = "3.2.0"
scrimage = "4.0.31" scrimage = "4.0.31"
semver = "1.2.0" semver = "1.2.0"
kotlinx-serialization = "1.3.3" kotlinx-serialization = "1.3.3"
kxs-charleskornKaml = "0.44.0" kxs-charleskornKaml = "0.44.0"
kxs-mamoeYamlkt = "0.12.0" kxs-mamoeYamlkt = "0.12.0"
kxs-kxsTsGen = "0.2.1"
kotlinJsWrappers = "1.0.0-pre.346" kotlinJsWrappers = "1.0.0-pre.349" # https://search.maven.org/artifact/org.jetbrains.kotlin-wrappers/kotlin-wrappers-bom
kotlinx-cli = "0.3.4"
kotlinx-coroutines = "1.6.3"
kotlinx-datetime = "0.3.3"
kotlinx-html = "0.7.5" kotlinx-html = "0.7.5"
kotlinx-nodejs = "0.0.7" kotlinx-nodejs = "0.0.7"
kotlinx-coroutines = "1.6.1"
kotlinx-cli = "0.3.4"
kotlinx-datetime = "0.3.3"
ktor = "2.0.3" ktor = "2.0.3"
@ -39,20 +41,24 @@ simpleSyslogParser = "0.0.6"
kotkaStreams = "dev-SNAPSHOT" kotkaStreams = "dev-SNAPSHOT"
## test ## ## test ##
junit = "5.8.2" junit = "5.8.2"
kotest = "5.3.1" kotest = "5.3.1"
mockk = "1.12.4" mockk = "1.12.4"
## infra ## ## infra ##
factorio = "1.1.59" factorio = "1.1.61"
confluent-kafkaConnect = "7.0.1" confluent-kafkaConnect = "7.0.1"
grafana = "8.5.0" grafana = "8.5.0"
prometheus = "v2.34.0" prometheus = "v2.34.0"
## gradle plugins ## ## gradle plugins ##
gradleNodePlugin = "3.3.0" # https://github.com/node-gradle/gradle-node-plugin/releases gradleNodePlugin = "3.3.0" # https://github.com/node-gradle/gradle-node-plugin/releases
######### #########
[plugins] [plugins]
######### #########
@ -89,8 +95,10 @@ kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "ko
kotlinx-serialization-properties = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-properties" } kotlinx-serialization-properties = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-properties" }
kotlinx-serialization-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf" } kotlinx-serialization-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf" }
kxs-charleskornKaml = { group = "com.charleskorn.kaml", name = "kaml", version.ref = "kxs-charleskornKaml" } kxs-charleskornKaml = { group = "com.charleskorn.kaml", name = "kaml", version.ref = "kxs-charleskornKaml" }
kxs-mamoeYamlkt = { group = "net.mamoe.yamlkt", name = "yamlkt", version.ref = "kxs-mamoeYamlkt" } kxs-mamoeYamlkt = { group = "net.mamoe.yamlkt", name = "yamlkt", version.ref = "kxs-mamoeYamlkt" }
#kxs-kxsTsGen = { group = "dev.adamko.kxstsgen", name = "kxs-ts-gen-core", version.ref = "kxs-kxsTsGen" }
kxs-kxsTsGen = { group = "com.github.adamko-dev.kotlinx-serialization-typescript-generator", name = "kxs-ts-gen-core", version.ref = "kxs-kxsTsGen" }
kotlinx-coroutines-bom = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-bom", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-bom = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-bom", version.ref = "kotlinx-coroutines" }

View file

@ -1,6 +1,9 @@
import dev.adamko.kafkatorio.gradle.asProvider import dev.adamko.kafkatorio.gradle.asProvider
import dev.adamko.kafkatorio.gradle.typescriptAttributes import dev.adamko.kafkatorio.gradle.typescriptAttributes
import dev.adamko.kafkatorio.task.GenerateTypeScriptTask import dev.adamko.kafkatorio.task.GenerateTypeScriptTask
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
@ -36,6 +39,7 @@ kotlin {
all { all {
languageSettings.apply { languageSettings.apply {
optIn("kotlin.ExperimentalStdlibApi") optIn("kotlin.ExperimentalStdlibApi")
optIn("kotlin.ExperimentalUnsignedTypes")
optIn("kotlin.RequiresOptIn") optIn("kotlin.RequiresOptIn")
optIn("kotlin.js.ExperimentalJsExport") optIn("kotlin.js.ExperimentalJsExport")
optIn("kotlin.time.ExperimentalTime") optIn("kotlin.time.ExperimentalTime")
@ -51,7 +55,7 @@ kotlin {
implementation(project.dependencies.platform(libs.kotlinx.serialization.bom)) implementation(project.dependencies.platform(libs.kotlinx.serialization.bom))
implementation(libs.kotlinx.serialization.core) implementation(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json)
api("dev.adamko.kxstsgen:kxs-ts-gen-core:0.1.3") api(libs.kxs.kxsTsGen)
implementation(dependencies.platform(libs.okio.bom)) implementation(dependencies.platform(libs.okio.bom))
implementation(libs.okio.core) implementation(libs.okio.core)
@ -96,16 +100,34 @@ kotlin {
} }
val kotlinJvmMainCompilation: NamedDomainObjectProvider<KotlinJvmCompilation> =
kotlin.jvm().compilations.named(KotlinCompilation.MAIN_COMPILATION_NAME)
val jvmJar: TaskProvider<Jar> = tasks.named<Jar>(kotlin.jvm().artifactsTaskName) val jvmJar: TaskProvider<Jar> = tasks.named<Jar>(kotlin.jvm().artifactsTaskName)
val mainCompilation: Provider<FileCollection> =
kotlin.jvm().compilations.named("main").map { it.runtimeDependencyFiles } val kotlinMainRuntimeDependencies: Provider<FileCollection> =
kotlinJvmMainCompilation.map { it.runtimeDependencyFiles }
val kotlinMainCompileDependencies: Provider<FileCollection> =
kotlinJvmMainCompilation.map { it.compileDependencyFiles }
val kotlinMainCompileTask: Provider<KotlinCompile> =
kotlinJvmMainCompilation.map { it.compileKotlinTask }
val generateTypeScript by tasks.registering(GenerateTypeScriptTask::class) { val generateTypeScript by tasks.registering(GenerateTypeScriptTask::class) {
dependsOn(jvmJar) dependsOn(jvmJar)
// dependsOn(kotlinMainCompileTask)
// inputs.files(jvmJar.map { it.outputs.files })
// inputs.files(kotlinMainCompileTask.map { it.javaSources })
classpath( classpath(
jvmJar, jvmJar,
mainCompilation, kotlinMainRuntimeDependencies,
// kotlinMainCompileTask.map { it.libraries }
// kotlinMainDependencies,
) )
output.set(layout.buildDirectory.dir("generated/typescript")) output.set(layout.buildDirectory.dir("generated/typescript"))
mainClass.set("dev.adamko.kafkatorio.events.schema.Kt2ts2Kt") mainClass.set("dev.adamko.kafkatorio.events.schema.Kt2ts2Kt")
@ -122,16 +144,26 @@ val generateTypeScriptOutputFiles: Provider<FileTree> =
generateTypeScript.map { it.outputs.files.asFileTree } generateTypeScript.map { it.outputs.files.asFileTree }
val schemaTs by distributions.registering { //val schemaTs by distributions.registering {
distributionBaseName.set(schemaTsDistributionName) // distributionBaseName.set(schemaTsDistributionName)
contents { // contents {
from(generateTypeScriptOutputFiles) // from(generateTypeScriptOutputFiles)
} // }
//}
//val schemaTsZipTask: TaskProvider<Zip> = tasks.named<Zip>("${schemaTs.name}DistZip")
//val schemaTsZipTaskArchiveFile: Provider<RegularFile> = schemaTsZipTask.flatMap { it.archiveFile }
val schemaTsZip by tasks.registering(Zip::class) {
group = "kt2ts"
archiveBaseName.set("schema-ts")
from(generateTypeScriptOutputFiles)
destinationDirectory.set(layout.buildDirectory.dir("distributions/kt2ts"))
} }
val schemaTsZipTaskArchiveFile: Provider<RegularFile> = schemaTsZip.flatMap { it.archiveFile }
val schemaTsZipTask: TaskProvider<Zip> = tasks.named<Zip>("${schemaTs.name}DistZip")
val schemaTsZipTaskArchiveFile: Provider<RegularFile> = schemaTsZipTask.flatMap { it.archiveFile }
val typeScriptModelGenerated: Configuration by configurations.creating { val typeScriptModelGenerated: Configuration by configurations.creating {
@ -139,4 +171,5 @@ val typeScriptModelGenerated: Configuration by configurations.creating {
typescriptAttributes(objects) typescriptAttributes(objects)
outgoing.artifact(schemaTsZipTaskArchiveFile) outgoing.artifact(schemaTsZipTaskArchiveFile)
// outgoing.artifact(schemaTsZipTaskArchiveFile)
} }

View file

@ -5,6 +5,7 @@ import kotlin.math.roundToInt
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
/** /**
* Red, green, blue and alpha values, all in range `[0, 1]` or all in range `[0, 255]` if any * Red, green, blue and alpha values, all in range `[0, 1]` or all in range `[0, 255]` if any
* value is > 1. * value is > 1.

View file

@ -0,0 +1,191 @@
package dev.adamko.kafkatorio.schema.common
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@SerialName("kafkatorio.entity.FactorioEntityData")
sealed interface FactorioEntityData {
val protoId: PrototypeId
val status: Status?
val position: MapEntityPosition
/** Non-specific entity data */
@Serializable
@SerialName("kafkatorio.entity.FactorioEntityData.Standard")
data class Standard(
override val protoId: PrototypeId,
override val status: Status? = null,
override val position: MapEntityPosition,
val graphicsVariation: UByte? = 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,
) : FactorioEntityData
@Serializable
@SerialName("kafkatorio.entity.FactorioEntityData.Resource")
data class Resource(
override val protoId: PrototypeId,
override val status: Status? = null,
override val position: MapEntityPosition,
val amount: UInt,
/** Count of initial resource units contained. `null` if resource is not infinite. */
val initialAmount: UInt? = null,
) : FactorioEntityData
@Serializable
@SerialName("kafkatorio.entity.FactorioEntityData.EntityStatus")
enum class Status {
CANT_DIVIDE_SEGMENTS,
CHARGING,
CLOSED_BY_CIRCUIT_NETWORK,
DISABLED,
DISABLED_BY_CONTROL_BEHAVIOR,
DISABLED_BY_SCRIPT,
DISCHARGING,
FLUID_INGREDIENT_SHORTAGE,
FULLY_CHARGED,
FULL_OUTPUT,
ITEM_INGREDIENT_SHORTAGE,
LAUNCHING_ROCKET,
LOW_INPUT_FLUID,
LOW_POWER,
LOW_TEMPERATURE,
MARKED_FOR_DECONSTRUCTION,
MISSING_REQUIRED_FLUID,
MISSING_SCIENCE_PACKS,
NETWORKS_CONNECTED,
NETWORKS_DISCONNECTED,
NORMAL,
NOT_CONNECTED_TO_RAIL,
NOT_PLUGGED_IN_ELECTRIC_NETWORK,
NO_AMMO,
NO_FUEL,
NO_INGREDIENTS,
NO_INPUT_FLUID,
NO_MINABLE_RESOURCES,
NO_MODULES_TO_TRANSMIT,
NO_POWER,
NO_RECIPE,
NO_RESEARCH_IN_PROGRESS,
OPENED_BY_CIRCUIT_NETWORK,
OUT_OF_LOGISTIC_NETWORK,
PREPARING_ROCKET_FOR_LAUNCH,
RECHARGING_AFTER_POWER_OUTAGE,
TURNED_OFF_DURING_DAYTIME,
WAITING_FOR_SOURCE_ITEMS,
WAITING_FOR_SPACE_IN_DESTINATION,
WAITING_FOR_TARGET_TO_BE_BUILT,
WAITING_FOR_TRAIN,
WAITING_TO_LAUNCH_ROCKET,
WORKING,
}
}
/*
enum entity_status {
working,
normal,
no_power,
low_power,
no_fuel,
disabled_by_control_behavior,
opened_by_circuit_network,
closed_by_circuit_network,
disabled_by_script,
marked_for_deconstruction,
not_plugged_in_electric_network,
networks_connected,
networks_disconnected,
charging,
discharging,
fully_charged,
out_of_logistic_network,
no_recipe,
no_ingredients,
no_input_fluid,
no_research_in_progress,
no_minable_resources,
low_input_fluid,
fluid_ingredient_shortage,
full_output,
item_ingredient_shortage,
missing_required_fluid,
missing_science_packs,
waiting_for_source_items,
waiting_for_space_in_destination,
preparing_rocket_for_launch,
waiting_to_launch_rocket,
launching_rocket,
no_modules_to_transmit,
recharging_after_power_outage,
waiting_for_target_to_be_built,
waiting_for_train,
no_ammo,
low_temperature,
disabled,
turned_off_during_daytime,
not_connected_to_rail,
cant_divide_segments,
}
*/
/*
AssemblingMachine
Beam
Car
Character
CharacterCorpse
CraftingMachine
ElectricEnergyInterface
ElectricPole
EntityGhost
EntityWithHealth
EntityWithOwner
FlyingText
Furnace
Gate
Generator
Ghost
HeatInterface
HighlightBox
InfinityContainer
InfinityPipe
Inserter
ItemEntity
LandMine
LinkedBelt
Loader
Market
MiningDrill
ProgrammableSpeaker
Pump
Radar
Rail
RailChainSignal
RailSignal
Reactor
ResourceEntity
RocketSilo
SmokeWithTrigger
SpiderVehicle
Splitter
TrainStop
TransportBeltConnectable
TransportBeltToGround
Turret
Unit
Vehicle
*/

View file

@ -1,10 +1,12 @@
package dev.adamko.kafkatorio.schema.common package dev.adamko.kafkatorio.schema.common
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("kafkatorio.id.Tick")
@JvmInline @JvmInline
value class Tick(val value: UInt) value class Tick(val value: UInt)
@ -17,6 +19,7 @@ val UInt.tick
* See [`LuaSurface.index`](https://lua-api.factorio.com/latest/LuaSurface.html#LuaSurface.index) * See [`LuaSurface.index`](https://lua-api.factorio.com/latest/LuaSurface.html#LuaSurface.index)
*/ */
@Serializable @Serializable
@SerialName("kafkatorio.id.SurfaceIndex")
@JvmInline @JvmInline
value class SurfaceIndex(private val id: UInt) { value class SurfaceIndex(private val id: UInt) {
override fun toString(): String = "$id" override fun toString(): String = "$id"
@ -24,6 +27,7 @@ value class SurfaceIndex(private val id: UInt) {
@Serializable @Serializable
@SerialName("kafkatorio.id.ForceIndex")
@JvmInline @JvmInline
value class ForceIndex(private val id: UInt) { value class ForceIndex(private val id: UInt) {
override fun toString(): String = "$id" override fun toString(): String = "$id"
@ -32,6 +36,7 @@ value class ForceIndex(private val id: UInt) {
/** The player's index in `LuaGameScript::players` */ /** The player's index in `LuaGameScript::players` */
@Serializable @Serializable
@SerialName("kafkatorio.id.PlayerIndex")
@JvmInline @JvmInline
value class PlayerIndex(private val id: UInt) { value class PlayerIndex(private val id: UInt) {
override fun toString(): String = "$id" override fun toString(): String = "$id"
@ -40,6 +45,7 @@ value class PlayerIndex(private val id: UInt) {
/** > This is universally unique for every entity that has one, for the lifetime of a whole game. */ /** > This is universally unique for every entity that has one, for the lifetime of a whole game. */
@Serializable @Serializable
@SerialName("kafkatorio.id.UnitNumber")
@JvmInline @JvmInline
value class UnitNumber(private val id: UInt) { value class UnitNumber(private val id: UInt) {
override fun toString(): String = "$id" override fun toString(): String = "$id"
@ -47,13 +53,7 @@ value class UnitNumber(private val id: UInt) {
@Serializable @Serializable
@JvmInline @SerialName("kafkatorio.id.EventName")
value class PrototypeName(private val id: String) {
override fun toString(): String = id
}
@Serializable
@JvmInline @JvmInline
value class EventName(private val name: String) { value class EventName(private val name: String) {
override fun toString(): String = name override fun toString(): String = name
@ -62,23 +62,23 @@ value class EventName(private val name: String) {
interface EntityIdentifiers { interface EntityIdentifiers {
val unitNumber: UnitNumber? val unitNumber: UnitNumber?
val name: String /** The 'prototype type' and 'prototype name' of the entity. */
/** The prototype-type of the entity. */ val protoId: PrototypeId
val protoType: String
} }
// instant of EntityIdentifiers, because kxs needs a concrete instance // instant of EntityIdentifiers, because kxs needs a concrete instance
@Serializable @Serializable
@SerialName("kafkatorio.id.EntityIdentifiersData")
data class EntityIdentifiersData( data class EntityIdentifiersData(
override val unitNumber: UnitNumber? = null, override val unitNumber: UnitNumber? = null,
override val name: String, override val protoId: PrototypeId,
override val protoType: String,
) : EntityIdentifiers ) : EntityIdentifiers
@JvmInline
@Serializable @Serializable
@SerialName("kafkatorio.id.FactorioServerId")
@JvmInline
value class FactorioServerId(private val id: String) { value class FactorioServerId(private val id: String) {
override fun toString() = id override fun toString() = id
} }

View file

@ -8,13 +8,14 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("kafkatorio.prototype.FactorioPrototype") @SerialName("kafkatorio.prototype.FactorioPrototype")
sealed interface FactorioPrototype { sealed interface FactorioPrototype {
val name: PrototypeName val protoId: PrototypeId
val mapColour: Colour val mapColour: Colour
@SerialName("kafkatorio.prototype.MapTile") @SerialName("kafkatorio.prototype.MapTile")
@Serializable @Serializable
data class MapTile( data class MapTile(
override val name: PrototypeName, override val protoId: PrototypeId,
override val mapColour: Colour, override val mapColour: Colour,
val layer: UInt, val layer: UInt,
@ -29,7 +30,7 @@ sealed interface FactorioPrototype {
@SerialName("kafkatorio.prototype.Entity") @SerialName("kafkatorio.prototype.Entity")
@Serializable @Serializable
data class Entity( data class Entity(
override val name: PrototypeName, override val protoId: PrototypeId,
override val mapColour: Colour, override val mapColour: Colour,
val protoType: String, val protoType: String,

View file

@ -12,16 +12,16 @@ const val MAP_CHUNK_SIZE = 32
data class MapTile( data class MapTile(
val x: Int, val x: Int,
val y: Int, val y: Int,
val proto: PrototypeName, val protoId: PrototypeId,
) )
/** /**
* 2D map of x/y tile positions and prototype-name, optimised for JSON size. * 2D map of x/y tile positions and prototype-name, optimised for JSON size.
* *
* [protos] is a one-to-one map between a [PrototypeName] and [PrototypeKey]. * [protos] is a one-to-one map between a prototype[PrototypeId] and [PrototypeKey].
* *
* [PrototypeKey] is an arbitrary integer value, which maps to one [PrototypeName] only for a * [PrototypeKey] is an arbitrary integer value, which maps to one [PrototypeId] only for a
* specific instance of [MapTileDictionary]. * specific instance of [MapTileDictionary].
* *
* Each X/Y coordinate in [tilesXY] maps to a [PrototypeKey]. * Each X/Y coordinate in [tilesXY] maps to a [PrototypeKey].
@ -30,9 +30,10 @@ data class MapTile(
data class MapTileDictionary( data class MapTileDictionary(
/** Map an X,Y coordinate a prototype name */ /** Map an X,Y coordinate a prototype name */
val tilesXY: Map<String, Map<String, PrototypeKey>>, val tilesXY: Map<String, Map<String, PrototypeKey>>,
val protos: Map<PrototypeName, PrototypeKey>, val protos: Map<PrototypeId, PrototypeKey>,
) { ) {
private val protosIndexToName: Map<PrototypeKey, PrototypeName> by lazy {
private val protosIndexToId: Map<PrototypeKey, PrototypeId> by lazy {
protos.entries.associate { (name, key) -> key to name } protos.entries.associate { (name, key) -> key to name }
} }
@ -41,11 +42,11 @@ data class MapTileDictionary(
row.forEach { (yString, protoIndex) -> row.forEach { (yString, protoIndex) ->
val x = xString.toIntOrNull() val x = xString.toIntOrNull()
val y = yString.toIntOrNull() val y = yString.toIntOrNull()
val protoName = protosIndexToName[protoIndex] val protoName = protosIndexToId[protoIndex]
if (x != null && y != null && protoName != null) { if (x != null && y != null && protoName != null) {
add(MapTile(x, y, protoName)) add(MapTile(x, y, protoName))
} else if (protoName == null) { } else if (protoName == null) {
println("warning: no prototype name found for index:$protoIndex. $protosIndexToName") println("warning: no prototype name found for index:$protoIndex. $protosIndexToId")
} }
} }
} }

View file

@ -0,0 +1,817 @@
package dev.adamko.kafkatorio.schema.common
import kotlin.jvm.JvmInline
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Both a [name] and [type] are required to unique identify a [prototype][FactorioPrototype].
*
*
* @property[name] The name of the prototype, which is unique per specific Prototype [type]
*/
// * Each subclass of [PrototypeId] is equivalent to a Prototype `type`.
//sealed interface PrototypeId {
//
// val name: String
//
// @Serializable
// @JvmInline
// @SerialName("kafkatorio.prototype.id.PrototypeIdMapTile")
// value class MapTile(override val name: String) : PrototypeId {
// override fun toString(): String = name
// }
//
// @Serializable
// @JvmInline
// @SerialName("kafkatorio.prototype.id.PrototypeIdEntity")
// value class Entity(override val name: String) : PrototypeId {
// override fun toString(): String = name
// }
//
// @Serializable
// @JvmInline
// @SerialName("kafkatorio.prototype.id.PrototypeIdResourceEntity")
// value class ResourceEntity(override val name: String) : PrototypeId {
// override fun toString(): String = name
// }
//
// @Serializable
// @JvmInline
// @SerialName("kafkatorio.prototype.id.PrototypeIdFluid")
// value class Fluid(override val name: String) : PrototypeId {
// override fun toString(): String = name
// }
//
// @Serializable
// @JvmInline
// @SerialName("kafkatorio.prototype.id.PrototypeIdItem")
// value class Item(override val name: String) : PrototypeId {
// override fun toString(): String = name
// }
//
//}
@Serializable
@JvmInline
@SerialName("kafkatorio.id.PrototypeId")
value class PrototypeId private constructor(
private val typeNameConcat: String,
) {
val type: Type get() = Type(typeNameConcat.substringBefore(delim, ""))
val name: Name get() = Name(typeNameConcat.substringAfter(delim, ""))
operator fun component1(): Type = type
operator fun component2(): Name = name
constructor(
type: String,
name: String,
) : this("${type}${delim}${name}")
/** Denotes the class of the Prototype */
@Serializable
@JvmInline
@SerialName("kafkatorio.id.PrototypeIdType")
value class Type(private val id: String) {
override fun toString(): String = id
}
/** A specific implementation of a [type]. Unique per prototype 'super class' */
@Serializable
@JvmInline
@SerialName("kafkatorio.id.PrototypeIdName")
value class Name(private val name: String) {
override fun toString(): String = name
}
companion object {
private const val delim = '/'
}
}
//@Suppress("unused")
//enum class PrototypeTypeId(
// val id: String
//) {
// AmbientSound("ambient-sound"),
// Animation("animation"),
// EditorController("editor-controller"),
// Font("font"),
// GodController("god-controller"),
// MapGenPresets("map-gen-presets"),
// MapSettings("map-settings"),
// MouseCursor("mouse-cursor"),
// Sound("sound"),
// SpectatorController("spectator-controller"),
// Sprite("sprite"),
// TileEffect("tile-effect"),
// TipsAndTricksItemCategory("tips-and-tricks-item-category"),
// TriggerTargetType("trigger-target-type"),
// WindSound("wind-sound"),
// Achievement("achievement"),
// BuildEntityAchievement("build-entity-achievement"),
// CombatRobotCountAchievement("combat-robot-count"),
// ConstructWithRobotsAchievement("construct-with-robots-achievement"),
// DeconstructWithRobotsAchievement("deconstruct-with-robots-achievement"),
// DeliverByRobotsAchievement("deliver-by-robots-achievement"),
// DontBuildEntityAchievement("dont-build-entity-achievement"),
// DontCraftManuallyAchievement("dont-craft-manually-achievement"),
// DontUseEntityInEnergyProductionAchievement("dont-use-entity-in-energy-production-achievement"),
// FinishTheGameAchievement("finish-the-game-achievement"),
// GroupAttackAchievement("group-attack-achievement"),
// KillAchievement("kill-achievement"),
// PlayerDamagedAchievement("player-damaged-achievement"),
// ProduceAchievement("produce-achievement"),
// ProducePerHourAchievement("produce-per-hour-achievement"),
// ResearchAchievement("research-achievement"),
// TrainPathAchievement("train-path-achievement"),
// AmmoCategory("ammo-category"),
// AutoplaceControl("autoplace-control"),
// CustomInput("custom-input"),
// DamageType("damage-type"),
// Decorative("optimized-decorative"),
// Entity("<abstract>"),
// Arrow("arrow"),
// ArtilleryFlare("artillery-flare"),
// ArtilleryProjectile("artillery-projectile"),
// Beam("beam"),
// CharacterCorpse("character-corpse"),
// Cliff("cliff"),
// Corpse("corpse"),
// RailRemnants("rail-remnants"),
// DeconstructibleTileProxy("deconstructible-tile-proxy"),
// EntityGhost("entity-ghost"),
// /** for migration, cannot be used */
// EntityParticle("particle"),
// /** for migration, cannot be used */
// LeafParticle("leaf-particle"),
// EntityWithHealth("<abstract>"),
// EntityWithOwner("<abstract>"),
// Accumulator("accumulator"),
// ArtilleryTurret("artillery-turret"),
// Beacon("beacon"),
// Boiler("boiler"),
// BurnerGenerator("burner-generator"),
// Character("character"),
// Combinator("<abstract>"),
// ArithmeticCombinator("arithmetic-combinator"),
// DeciderCombinator("decider-combinator"),
// ConstantCombinator("constant-combinator"),
// Container("container"),
// LogisticContainer("logistic-container"),
// InfinityContainer("infinity-container"),
// CraftingMachine("<abstract>"),
// AssemblingMachine("assembling-machine"),
// RocketSilo("rocket-silo"),
// Furnace("furnace"),
// ElectricEnergyInterface("electric-energy-interface"),
// ElectricPole("electric-pole"),
// EnemySpawner("unit-spawner"),
// FlyingRobot("<abstract>"),
// CombatRobot("combat-robot"),
// RobotWithLogisticInterface("<abstract>"),
// ConstructionRobot("construction-robot"),
// LogisticRobot("logistic-robot"),
// Gate("gate"),
// Generator("generator"),
// HeatInterface("heat-interface"),
// HeatPipe("heat-pipe"),
// Inserter("inserter"),
// Lab("lab"),
// Lamp("lamp"),
// LandMine("land-mine"),
// LinkedContainer("linked-container"),
// Market("market"),
// MiningDrill("mining-drill"),
// OffshorePump("offshore-pump"),
// Pipe("pipe"),
// InfinityPipe("infinity-pipe"),
// PipeToGround("pipe-to-ground"),
// PlayerPort("player-port"),
// PowerSwitch("power-switch"),
// ProgrammableSpeaker("programmable-speaker"),
// Pump("pump"),
// Radar("radar"),
// Rail("<abstract>"),
// CurvedRail("curved-rail"),
// StraightRail("straight-rail"),
// RailSignalBase("<abstract>"),
// RailChainSignal("rail-chain-signal"),
// RailSignal("rail-signal"),
// Reactor("reactor"),
// Roboport("roboport"),
// SimpleEntityWithOwner("simple-entity-with-owner"),
// SimpleEntityWithForce("simple-entity-with-force"),
// SolarPanel("solar-panel"),
// StorageTank("storage-tank"),
// TrainStop("train-stop"),
// TransportBeltConnectable("<abstract>"),
// LinkedBelt("linked-belt"),
// Loader1x1("loader-1x1"),
// Loader1x2("loader"),
// Splitter("splitter"),
// TransportBelt("transport-belt"),
// UndergroundBelt("underground-belt"),
// Turret("turret"),
// AmmoTurret("ammo-turret"),
// ElectricTurret("electric-turret"),
// FluidTurret("fluid-turret"),
// Unit("unit"),
// Vehicle("<abstract>"),
// Car("car"),
// RollingStock("<abstract>"),
// ArtilleryWagon("artillery-wagon"),
// CargoWagon("cargo-wagon"),
// FluidWagon("fluid-wagon"),
// Locomotive("locomotive"),
// SpiderVehicle("spider-vehicle"),
// Wall("wall"),
// Fish("fish"),
// SimpleEntity("simple-entity"),
// SpiderLeg("spider-leg"),
// Tree("tree"),
// Explosion("explosion"),
// FlameThrowerExplosion("flame-thrower-explosion"),
// FireFlame("fire"),
// FluidStream("stream"),
// FlyingText("flying-text"),
// HighlightBoxEntity("highlight-box"),
// ItemEntity("item-entity"),
// ItemRequestProxy("item-request-proxy"),
// ParticleSource("particle-source"),
// Projectile("projectile"),
// ResourceEntity("resource"),
// RocketSiloRocket("rocket-silo-rocket"),
// RocketSiloRocketShadow("rocket-silo-rocket-shadow"),
// Smoke("<abstract>"),
// /** for migration, cannot be used */
// SimpleSmoke("smoke"),
// SmokeWithTrigger("smoke-with-trigger"),
// SpeechBubble("speech-bubble"),
// Sticker("sticker"),
// TileGhost("tile-ghost"),
// Equipment("<abstract>"),
// ActiveDefenseEquipment("active-defense-equipment"),
// BatteryEquipment("battery-equipment"),
// BeltImmunityEquipment("belt-immunity-equipment"),
// EnergyShieldEquipment("energy-shield-equipment"),
// GeneratorEquipment("generator-equipment"),
// MovementBonusEquipment("movement-bonus-equipment"),
// NightVisionEquipment("night-vision-equipment"),
// RoboportEquipment("roboport-equipment"),
// SolarPanelEquipment("solar-panel-equipment"),
// EquipmentCategory("equipment-category"),
// EquipmentGrid("equipment-grid"),
// Fluid("fluid"),
// FuelCategory("fuel-category"),
// GuiStyle("gui-style"),
// Item("item"),
// AmmoItem("ammo"),
// Capsule("capsule"),
// Gun("gun"),
// ItemWithEntityData("item-with-entity-data"),
// ItemWithLabel("item-with-label"),
// ItemWithInventory("item-with-inventory"),
// BlueprintBook("blueprint-book"),
// ItemWithTags("item-with-tags"),
// SelectionTool("selection-tool"),
// BlueprintItem("blueprint"),
// CopyPasteTool("copy-paste-tool"),
// DeconstructionItem("deconstruction-item"),
// UpgradeItem("upgrade-item"),
// Module("module"),
// RailPlanner("rail-planner"),
// SpidertronRemote("spidertron-remote"),
// Tool("tool"),
// Armor("armor"),
// /** for migration, cannot be used */
// MiningTool("mining-tool"),
// RepairTool("repair-tool"),
// ItemGroup("item-group"),
// ItemSubGroup("item-subgroup"),
// ModuleCategory("module-category"),
// NamedNoiseExpression("noise-expression"),
// NoiseLayer("noise-layer"),
// Particle("optimized-particle"),
// Recipe("recipe"),
// RecipeCategory("recipe-category"),
// ResourceCategory("resource-category"),
// Shortcut("shortcut"),
// Technology("technology"),
// Tile("tile"),
// TipsAndTricksItem("tips-and-tricks-item"),
// TrivialSmoke("trivial-smoke"),
// Tutorial("tutorial"),
// UtilityConstants("utility-constants"),
// UtilitySounds("utility-sounds"),
// UtilitySprites("utility-sprites"),
// VirtualSignal("virtual-signal"),
// ;
//
// fun named(protoName: String): PrototypeId = PrototypeId(this, protoName)
//
// companion object {
// val entries: Set<PrototypeTypeId> = values().toSet()
// }
//
//}
//@Suppress("unused")
//sealed class PrototypeType(
// val id: String
//) {
//
// object AmbientSound : PrototypeType("ambient-sound")
// object Animation : PrototypeType("animation")
// object EditorController : PrototypeType("editor-controller")
// object Font : PrototypeType("font")
// object GodController : PrototypeType("god-controller")
// object MapGenPresets : PrototypeType("map-gen-presets")
// object MapSettings : PrototypeType("map-settings")
// object MouseCursor : PrototypeType("mouse-cursor")
// object Sound : PrototypeType("sound")
// object SpectatorController : PrototypeType("spectator-controller")
// object Sprite : PrototypeType("sprite")
// object TileEffect : PrototypeType("tile-effect")
// object TipsAndTricksItemCategory : PrototypeType("tips-and-tricks-item-category")
// object TriggerTargetType : PrototypeType("trigger-target-type")
// object WindSound : PrototypeType("wind-sound")
//
//
// object Achievement : PrototypeType("achievement")
// object BuildEntityAchievement : PrototypeType("build-entity-achievement")
// object CombatRobotCountAchievement : PrototypeType("combat-robot-count")
// object ConstructWithRobotsAchievement : PrototypeType("construct-with-robots-achievement")
// object DeconstructWithRobotsAchievement : PrototypeType("deconstruct-with-robots-achievement")
// object DeliverByRobotsAchievement : PrototypeType("deliver-by-robots-achievement")
// object DontBuildEntityAchievement : PrototypeType("dont-build-entity-achievement")
// object DontCraftManuallyAchievement : PrototypeType("dont-craft-manually-achievement")
// object DontUseEntityInEnergyProductionAchievement : PrototypeType("dont-use-entity-in-energy-production-achievement")
//
//
// object FinishTheGameAchievement : PrototypeType("finish-the-game-achievement")
// object GroupAttackAchievement : PrototypeType("group-attack-achievement")
// object KillAchievement : PrototypeType("kill-achievement")
// object PlayerDamagedAchievement : PrototypeType("player-damaged-achievement")
// object ProduceAchievement : PrototypeType("produce-achievement")
// object ProducePerHourAchievement : PrototypeType("produce-per-hour-achievement")
// object ResearchAchievement : PrototypeType("research-achievement")
// object TrainPathAchievement : PrototypeType("train-path-achievement")
// object AmmoCategory : PrototypeType("ammo-category")
// object AutoplaceControl : PrototypeType("autoplace-control")
// object CustomInput : PrototypeType("custom-input")
// object DamageType : PrototypeType("damage-type")
// object Decorative : PrototypeType("optimized-decorative")
//
//
// object Entity : PrototypeType("stract>")
// object Arrow : PrototypeType("arrow")
// object ArtilleryFlare : PrototypeType("artillery-flare")
// object ArtilleryProjectile : PrototypeType("artillery-projectile")
// object Beam : PrototypeType("beam")
// object CharacterCorpse : PrototypeType("character-corpse")
// object Cliff : PrototypeType("cliff")
// object Corpse : PrototypeType("corpse")
// object RailRemnants : PrototypeType("rail-remnants")
// object DeconstructibleTileProxy : PrototypeType("deconstructible-tile-proxy")
// object EntityGhost : PrototypeType("entity-ghost")
// /** for migration, cannot be used */
// object EntityParticle : PrototypeType("particle")
// /** for migration, cannot be used */
// object LeafParticle : PrototypeType("leaf-particle")
//
//
// object EntityWithOwner : PrototypeType("stract>")
// object Accumulator : PrototypeType("accumulator")
// object ArtilleryTurret : PrototypeType("artillery-turret")
// object Beacon : PrototypeType("beacon")
// object Boiler : PrototypeType("boiler")
// object BurnerGenerator : PrototypeType("burner-generator")
// object Character : PrototypeType("character")
//
//
// object Combinator : PrototypeType("stract>")
// object ArithmeticCombinator : PrototypeType("arithmetic-combinator")
// object DeciderCombinator : PrototypeType("decider-combinator")
// object ConstantCombinator : PrototypeType("constant-combinator")
// object Container : PrototypeType("container")
// object LogisticContainer : PrototypeType("logistic-container")
// object InfinityContainer : PrototypeType("infinity-container")
//
//
// object CraftingMachine : PrototypeType("stract>")
// object AssemblingMachine : PrototypeType("assembling-machine")
// object RocketSilo : PrototypeType("rocket-silo")
// object Furnace : PrototypeType("furnace")
// object ElectricEnergyInterface : PrototypeType("electric-energy-interface")
// object ElectricPole : PrototypeType("electric-pole")
// object EnemySpawner : PrototypeType("unit-spawner")
//
//
// object FlyingRobot : PrototypeType("stract>")
// object CombatRobot : PrototypeType("combat-robot") , PrototypeAbstract.FlyingRobot
//
//
// object RobotWithLogisticInterface : PrototypeType("stract>")
// object ConstructionRobot : PrototypeType("construction-robot")
// object LogisticRobot : PrototypeType("logistic-robot")
// object Gate : PrototypeType("gate")
// object Generator : PrototypeType("generator")
// object HeatInterface : PrototypeType("heat-interface")
// object HeatPipe : PrototypeType("heat-pipe")
// object Inserter : PrototypeType("inserter")
// object Lab : PrototypeType("lab")
// object Lamp : PrototypeType("lamp")
// object LandMine : PrototypeType("land-mine")
// object LinkedContainer : PrototypeType("linked-container")
// object Market : PrototypeType("market")
// object MiningDrill : PrototypeType("mining-drill")
// object OffshorePump : PrototypeType("offshore-pump")
// object Pipe : PrototypeType("pipe")
// object InfinityPipe : PrototypeType("infinity-pipe")
// object PipeToGround : PrototypeType("pipe-to-ground")
// object PlayerPort : PrototypeType("player-port")
// object PowerSwitch : PrototypeType("power-switch")
// object ProgrammableSpeaker : PrototypeType("programmable-speaker")
// object Pump : PrototypeType("pump")
// object Radar : PrototypeType("radar")
//
// object CurvedRail : PrototypeType("curved-rail"), PrototypeAbstract.Rail
// object StraightRail : PrototypeType("straight-rail"), PrototypeAbstract.Rail
//
// object RailSignalBase : PrototypeType("stract>")
// object RailChainSignal : PrototypeType("rail-chain-signal")
// object RailSignal : PrototypeType("rail-signal")
// object Reactor : PrototypeType("reactor")
// object Roboport : PrototypeType("roboport")
// object SimpleEntityWithOwner : PrototypeType("simple-entity-with-owner")
// object SimpleEntityWithForce : PrototypeType("simple-entity-with-force")
// object SolarPanel : PrototypeType("solar-panel")
// object StorageTank : PrototypeType("storage-tank")
// object TrainStop : PrototypeType("train-stop")
//
//
// object TransportBeltConnectable : PrototypeType("stract>")
// object LinkedBelt : PrototypeType("linked-belt")
// object Loader1x1 : PrototypeType("loader-1x1")
// object Loader1x2 : PrototypeType("loader")
// object Splitter : PrototypeType("splitter")
// object TransportBelt : PrototypeType("transport-belt")
// object UndergroundBelt : PrototypeType("underground-belt")
// object Turret : PrototypeType("turret")
// object AmmoTurret : PrototypeType("ammo-turret")
// object ElectricTurret : PrototypeType("electric-turret")
// object FluidTurret : PrototypeType("fluid-turret")
// object Unit : PrototypeType("unit")
//
//
// object Car : PrototypeType("car>"), PrototypeAbstract.Vehicle
// object SpiderVehicle : PrototypeType("spider-vehicle"), PrototypeAbstract.Vehicle
//
//
// object ArtilleryWagon : PrototypeType("artillery-wagon"), PrototypeAbstract.RollingStock
// object CargoWagon : PrototypeType("cargo-wagon"), PrototypeAbstract.RollingStock
// object FluidWagon : PrototypeType("fluid-wagon"), PrototypeAbstract.RollingStock
// object Locomotive : PrototypeType("locomotive"), PrototypeAbstract.RollingStock
//
// object Wall : PrototypeType("wall")
//
//
// object Fish : PrototypeType("fish"), PrototypeAbstract.EntityWithHealth
// object SimpleEntity : PrototypeType("simple-entity"), PrototypeAbstract.EntityWithHealth
// object SpiderLeg : PrototypeType("spider-leg"), PrototypeAbstract.EntityWithHealth
// object Tree : PrototypeType("tree"), PrototypeAbstract.EntityWithHealth
//
//
// object Explosion : PrototypeType("explosion"),
// object FlameThrowerExplosion : PrototypeType("flame-thrower-explosion"),
// object FireFlame : PrototypeType("fire"),
// object FluidStream : PrototypeType("stream"),
// object FlyingText : PrototypeType("flying-text"),
// object HighlightBoxEntity : PrototypeType("highlight-box"),
// object ItemEntity : PrototypeType("item-entity"),
// object ItemRequestProxy : PrototypeType("item-request-proxy"),
// object ParticleSource : PrototypeType("particle-source"),
// object Projectile : PrototypeType("projectile"),
// object ResourceEntity : PrototypeType("resource"),
// object RocketSiloRocket : PrototypeType("rocket-silo-rocket"),
// object RocketSiloRocketShadow : PrototypeType("rocket-silo-rocket-shadow"),
//
// /** for migration, cannot be used */
// object SimpleSmoke : PrototypeType("smoke"), PrototypeAbstract.Smoke
// object SmokeWithTrigger : PrototypeType("smoke-with-trigger"), PrototypeAbstract.Smoke
// object SpeechBubble : PrototypeType("speech-bubble"), PrototypeAbstract.Smoke
// object Sticker : PrototypeType("sticker"), PrototypeAbstract.Smoke
// object TileGhost : PrototypeType("tile-ghost"), PrototypeAbstract.Smoke
//
// object Equipment : PrototypeType("abstract>")
// object ActiveDefenseEquipment : PrototypeType("active-defense-equipment")
// object BatteryEquipment : PrototypeType("battery-equipment")
// object BeltImmunityEquipment : PrototypeType("belt-immunity-equipment")
// object EnergyShieldEquipment : PrototypeType("energy-shield-equipment")
// object GeneratorEquipment : PrototypeType("generator-equipment")
// object MovementBonusEquipment : PrototypeType("movement-bonus-equipment")
// object NightVisionEquipment : PrototypeType("night-vision-equipment")
// object RoboportEquipment : PrototypeType("roboport-equipment")
// object SolarPanelEquipment : PrototypeType("solar-panel-equipment")
// object EquipmentCategory : PrototypeType("equipment-category")
// object EquipmentGrid : PrototypeType("equipment-grid")
// object Fluid : PrototypeType("fluid")
// object FuelCategory : PrototypeType("fuel-category")
// object GuiStyle : PrototypeType("gui-style")
// object Item : PrototypeType("item")
// object AmmoItem : PrototypeType("ammo")
// object Capsule : PrototypeType("capsule")
// object Gun : PrototypeType("gun")
// object ItemWithEntityData : PrototypeType("item-with-entity-data")
// object ItemWithLabel : PrototypeType("item-with-label")
// object ItemWithInventory : PrototypeType("item-with-inventory")
// object BlueprintBook : PrototypeType("blueprint-book")
// object ItemWithTags : PrototypeType("item-with-tags")
// object SelectionTool : PrototypeType("selection-tool")
// object BlueprintItem : PrototypeType("blueprint")
// object CopyPasteTool : PrototypeType("copy-paste-tool")
// object DeconstructionItem : PrototypeType("deconstruction-item")
// object UpgradeItem : PrototypeType("upgrade-item")
// object Module : PrototypeType("module")
// object RailPlanner : PrototypeType("rail-planner")
// object SpidertronRemote : PrototypeType("spidertron-remote")
// object Tool : PrototypeType("tool")
// object Armor : PrototypeType("armor")
// /** for migration, cannot be used */
// object MiningTool : PrototypeType("mining-tool")
// object RepairTool : PrototypeType("repair-tool")
// object ItemGroup : PrototypeType("item-group")
// object ItemSubGroup : PrototypeType("item-subgroup")
// object ModuleCategory : PrototypeType("module-category")
// object NamedNoiseExpression : PrototypeType("noise-expression")
// object NoiseLayer : PrototypeType("noise-layer")
// object Particle : PrototypeType("optimized-particle")
// object Recipe : PrototypeType("recipe")
// object RecipeCategory : PrototypeType("recipe-category")
// object ResourceCategory : PrototypeType("resource-category")
// object Shortcut : PrototypeType("shortcut")
// object Technology : PrototypeType("technology")
// object Tile : PrototypeType("tile")
// object TipsAndTricksItem : PrototypeType("tips-and-tricks-item")
// object TrivialSmoke : PrototypeType("trivial-smoke")
// object Tutorial : PrototypeType("tutorial")
// object UtilityConstants : PrototypeType("utility-constants")
// object UtilitySounds : PrototypeType("utility-sounds")
// object UtilitySprites : PrototypeType("utility-sprites")
// object VirtualSignal : PrototypeType("virtual-signal")
//
//}
//
//@Suppress("unused")
//sealed interface PrototypeAbstract {
// //@formatter:off
// sealed interface PrototypeBase : PrototypeAbstract
// sealed interface Entity : PrototypeAbstract
// sealed interface EntityWithHealth : Entity
//
// sealed interface EntityWithOwner : EntityWithHealth
//
// sealed interface Combinator : EntityWithOwner
// sealed interface CraftingMachine : EntityWithOwner
// sealed interface FlyingRobot : EntityWithOwner
//
// sealed interface RobotWithLogisticInterface : FlyingRobot
//
// sealed interface Rail : EntityWithOwner
//
// sealed interface RailSignalBase : EntityWithOwner
// sealed interface TransportBeltConnectable : EntityWithOwner
// sealed interface Vehicle : EntityWithOwner
// sealed interface RollingStock : Vehicle
// sealed interface Smoke : Entity
// sealed interface Equipment : PrototypeAbstract
// //@formatter:on
//}
/*
* [[Prototype/AmbientSound]] '''ambient-sound'''
* [[Prototype/Animation]] '''animation'''
* [[Prototype/EditorController]] '''editor-controller'''
* [[Prototype/Font]] '''font'''
* [[Prototype/GodController]] '''god-controller'''
* [[Prototype/MapGenPresets]] '''map-gen-presets'''
* [[Prototype/MapSettings]] '''map-settings'''
* [[Prototype/MouseCursor]] '''mouse-cursor'''
* [[Prototype/Sound]] '''sound'''
* [[Prototype/SpectatorController]] '''spectator-controller'''
* [[Prototype/Sprite]] '''sprite'''
* [[Prototype/TileEffect]] '''tile-effect'''
* [[Prototype/TipsAndTricksItemCategory]] '''tips-and-tricks-item-category'''
* [[Prototype/TriggerTargetType]] '''trigger-target-type'''
* [[Prototype/WindSound]] '''wind-sound'''
* [[PrototypeBase]] <abstract>
</div><div class="prototype-tree">
* [[Prototype/Achievement]] '''achievement'''
** [[Prototype/BuildEntityAchievement]] '''build-entity-achievement'''
** [[Prototype/CombatRobotCountAchievement]] '''combat-robot-count'''
** [[Prototype/ConstructWithRobotsAchievement]] '''construct-with-robots-achievement'''
** [[Prototype/DeconstructWithRobotsAchievement]] '''deconstruct-with-robots-achievement'''
** [[Prototype/DeliverByRobotsAchievement]] '''deliver-by-robots-achievement'''
** [[Prototype/DontBuildEntityAchievement]] '''dont-build-entity-achievement'''
** [[Prototype/DontCraftManuallyAchievement]] '''dont-craft-manually-achievement'''
** [[Prototype/DontUseEntityInEnergyProductionAchievement]] '''dont-use-entity-in-energy-production-achievement'''
** [[Prototype/FinishTheGameAchievement]] '''finish-the-game-achievement'''
** [[Prototype/GroupAttackAchievement]] '''group-attack-achievement'''
** [[Prototype/KillAchievement]] '''kill-achievement'''
** [[Prototype/PlayerDamagedAchievement]] '''player-damaged-achievement'''
** [[Prototype/ProduceAchievement]] '''produce-achievement'''
** [[Prototype/ProducePerHourAchievement]] '''produce-per-hour-achievement'''
** [[Prototype/ResearchAchievement]] '''research-achievement'''
** [[Prototype/TrainPathAchievement]] '''train-path-achievement'''
* [[Prototype/AmmoCategory]] '''ammo-category'''
* [[Prototype/AutoplaceControl]] '''autoplace-control'''
* [[Prototype/CustomInput]] '''custom-input'''
* [[Prototype/DamageType]] '''damage-type'''
* [[Prototype/Decorative]] '''optimized-decorative'''
* [[Prototype/Entity]] <abstract>
** [[Prototype/Arrow]] '''arrow'''
** [[Prototype/ArtilleryFlare]] '''artillery-flare'''
** [[Prototype/ArtilleryProjectile]] '''artillery-projectile'''
** [[Prototype/Beam]] '''beam'''
** [[Prototype/CharacterCorpse]] '''character-corpse'''
** [[Prototype/Cliff]] '''cliff'''
** [[Prototype/Corpse]] '''corpse'''
*** [[Prototype/RailRemnants]] '''rail-remnants'''
** [[Prototype/DeconstructibleTileProxy]] '''deconstructible-tile-proxy'''
** [[Prototype/EntityGhost]] '''entity-ghost'''
** [[Prototype/EntityParticle]] '''particle''' (for migration, cannot be used)
*** [[Prototype/LeafParticle]] '''leaf-particle''' (for migration, cannot be used)
** [[Prototype/EntityWithHealth]] <abstract>
*** [[Prototype/EntityWithOwner]] <abstract>
**** [[Prototype/Accumulator]] '''accumulator'''
**** [[Prototype/ArtilleryTurret]] '''artillery-turret'''
**** [[Prototype/Beacon]] '''beacon'''
**** [[Prototype/Boiler]] '''boiler'''
**** [[Prototype/BurnerGenerator]] '''burner-generator'''
**** [[Prototype/Character]] '''character'''
**** [[Prototype/Combinator]] <abstract>
***** [[Prototype/ArithmeticCombinator]] '''arithmetic-combinator'''
***** [[Prototype/DeciderCombinator]] '''decider-combinator'''
**** [[Prototype/ConstantCombinator]] '''constant-combinator'''
**** [[Prototype/Container]] '''container'''
***** [[Prototype/LogisticContainer]] '''logistic-container'''
****** [[Prototype/InfinityContainer]] '''infinity-container'''
**** [[Prototype/CraftingMachine]] <abstract>
***** [[Prototype/AssemblingMachine]] '''assembling-machine'''
****** [[Prototype/RocketSilo]] '''rocket-silo'''
***** [[Prototype/Furnace]] '''furnace'''
**** [[Prototype/ElectricEnergyInterface]] '''electric-energy-interface'''
**** [[Prototype/ElectricPole]] '''electric-pole'''
**** [[Prototype/EnemySpawner]] '''unit-spawner'''
**** [[Prototype/FlyingRobot]] <abstract>
***** [[Prototype/CombatRobot]] '''combat-robot'''
***** [[Prototype/RobotWithLogisticInterface]] <abstract>
****** [[Prototype/ConstructionRobot]] '''construction-robot'''
****** [[Prototype/LogisticRobot]] '''logistic-robot'''
**** [[Prototype/Gate]] '''gate'''
**** [[Prototype/Generator]] '''generator'''
**** [[Prototype/HeatInterface]] '''heat-interface'''
**** [[Prototype/HeatPipe]] '''heat-pipe'''
**** [[Prototype/Inserter]] '''inserter'''
**** [[Prototype/Lab]] '''lab'''
**** [[Prototype/Lamp]] '''lamp'''
**** [[Prototype/LandMine]] '''land-mine'''
**** [[Prototype/LinkedContainer]] '''linked-container'''
**** [[Prototype/Market]] '''market'''
**** [[Prototype/MiningDrill]] '''mining-drill'''
**** [[Prototype/OffshorePump]] '''offshore-pump'''
**** [[Prototype/Pipe]] '''pipe'''
***** [[Prototype/InfinityPipe]] '''infinity-pipe'''
**** [[Prototype/PipeToGround]] '''pipe-to-ground'''
**** [[Prototype/PlayerPort]] '''player-port'''
**** [[Prototype/PowerSwitch]] '''power-switch'''
**** [[Prototype/ProgrammableSpeaker]] '''programmable-speaker'''
**** [[Prototype/Pump]] '''pump'''
**** [[Prototype/Radar]] '''radar'''
**** [[Prototype/Rail]] <abstract>
***** [[Prototype/CurvedRail]] '''curved-rail'''
***** [[Prototype/StraightRail]] '''straight-rail'''
**** [[Prototype/RailSignalBase]] <abstract>
***** [[Prototype/RailChainSignal]] '''rail-chain-signal'''
***** [[Prototype/RailSignal]] '''rail-signal'''
**** [[Prototype/Reactor]] '''reactor'''
**** [[Prototype/Roboport]] '''roboport'''
**** [[Prototype/SimpleEntityWithOwner]] '''simple-entity-with-owner'''
***** [[Prototype/SimpleEntityWithForce]] '''simple-entity-with-force'''
**** [[Prototype/SolarPanel]] '''solar-panel'''
**** [[Prototype/StorageTank]] '''storage-tank'''
**** [[Prototype/TrainStop]] '''train-stop'''
**** [[Prototype/TransportBeltConnectable]] <abstract>
***** [[Prototype/LinkedBelt]] '''linked-belt'''
***** [[Prototype/Loader1x1]] '''loader-1x1'''
***** [[Prototype/Loader1x2]] '''loader'''
***** [[Prototype/Splitter]] '''splitter'''
***** [[Prototype/TransportBelt]] '''transport-belt'''
***** [[Prototype/UndergroundBelt]] '''underground-belt'''
**** [[Prototype/Turret]] '''turret'''
***** [[Prototype/AmmoTurret]] '''ammo-turret'''
***** [[Prototype/ElectricTurret]] '''electric-turret'''
***** [[Prototype/FluidTurret]] '''fluid-turret'''
**** [[Prototype/Unit]] '''unit'''
**** [[Prototype/Vehicle]] <abstract>
***** [[Prototype/Car]] '''car'''
***** [[Prototype/RollingStock]] <abstract>
****** [[Prototype/ArtilleryWagon]] '''artillery-wagon'''
****** [[Prototype/CargoWagon]] '''cargo-wagon'''
****** [[Prototype/FluidWagon]] '''fluid-wagon'''
****** [[Prototype/Locomotive]] '''locomotive'''
***** [[Prototype/SpiderVehicle]] '''spider-vehicle'''
**** [[Prototype/Wall]] '''wall'''
*** [[Prototype/Fish]] '''fish'''
*** [[Prototype/SimpleEntity]] '''simple-entity'''
*** [[Prototype/SpiderLeg]] '''spider-leg'''
*** [[Prototype/Tree]] '''tree'''
** [[Prototype/Explosion]] '''explosion'''
*** [[Prototype/FlameThrowerExplosion]] '''flame-thrower-explosion'''
** [[Prototype/FireFlame]] '''fire'''
** [[Prototype/FluidStream]] '''stream'''
** [[Prototype/FlyingText]] '''flying-text'''
** [[Prototype/HighlightBoxEntity]] '''highlight-box'''
** [[Prototype/ItemEntity]] '''item-entity'''
** [[Prototype/ItemRequestProxy]] '''item-request-proxy'''
** [[Prototype/ParticleSource]] '''particle-source'''
** [[Prototype/Projectile]] '''projectile'''
** [[Prototype/ResourceEntity]] '''resource'''
** [[Prototype/RocketSiloRocket]] '''rocket-silo-rocket'''
** [[Prototype/RocketSiloRocketShadow]] '''rocket-silo-rocket-shadow'''
** [[Prototype/Smoke]] <abstract>
*** [[Prototype/SimpleSmoke]] '''smoke''' (for migration, cannot be used)
*** [[Prototype/SmokeWithTrigger]] '''smoke-with-trigger'''
** [[Prototype/SpeechBubble]] '''speech-bubble'''
** [[Prototype/Sticker]] '''sticker'''
** [[Prototype/TileGhost]] '''tile-ghost'''
* [[Prototype/Equipment]] <abstract>
** [[Prototype/ActiveDefenseEquipment]] '''active-defense-equipment'''
** [[Prototype/BatteryEquipment]] '''battery-equipment'''
** [[Prototype/BeltImmunityEquipment]] '''belt-immunity-equipment'''
** [[Prototype/EnergyShieldEquipment]] '''energy-shield-equipment'''
** [[Prototype/GeneratorEquipment]] '''generator-equipment'''
** [[Prototype/MovementBonusEquipment]] '''movement-bonus-equipment'''
** [[Prototype/NightVisionEquipment]] '''night-vision-equipment'''
** [[Prototype/RoboportEquipment]] '''roboport-equipment'''
** [[Prototype/SolarPanelEquipment]] '''solar-panel-equipment'''
* [[Prototype/EquipmentCategory]] '''equipment-category'''
* [[Prototype/EquipmentGrid]] '''equipment-grid'''
* [[Prototype/Fluid]] '''fluid'''
* [[Prototype/FuelCategory]] '''fuel-category'''
* [[Prototype/GuiStyle]] '''gui-style'''
* [[Prototype/Item]] '''item'''
** [[Prototype/AmmoItem]] '''ammo'''
** [[Prototype/Capsule]] '''capsule'''
** [[Prototype/Gun]] '''gun'''
** [[Prototype/ItemWithEntityData]] '''item-with-entity-data'''
** [[Prototype/ItemWithLabel]] '''item-with-label'''
*** [[Prototype/ItemWithInventory]] '''item-with-inventory'''
**** [[Prototype/BlueprintBook]] '''blueprint-book'''
*** [[Prototype/ItemWithTags]] '''item-with-tags'''
*** [[Prototype/SelectionTool]] '''selection-tool'''
**** [[Prototype/BlueprintItem]] '''blueprint'''
**** [[Prototype/CopyPasteTool]] '''copy-paste-tool'''
**** [[Prototype/DeconstructionItem]] '''deconstruction-item'''
**** [[Prototype/UpgradeItem]] '''upgrade-item'''
** [[Prototype/Module]] '''module'''
** [[Prototype/RailPlanner]] '''rail-planner'''
** [[Prototype/SpidertronRemote]] '''spidertron-remote'''
** [[Prototype/Tool]] '''tool'''
*** [[Prototype/Armor]] '''armor'''
*** [[Prototype/MiningTool]] '''mining-tool''' (for migration, cannot be used)
*** [[Prototype/RepairTool]] '''repair-tool'''
* [[Prototype/ItemGroup]] '''item-group'''
* [[Prototype/ItemSubGroup]] '''item-subgroup'''
* [[Prototype/ModuleCategory]] '''module-category'''
* [[Prototype/NamedNoiseExpression]] '''noise-expression'''
* [[Prototype/NoiseLayer]] '''noise-layer'''
* [[Prototype/Particle]] '''optimized-particle'''
* [[Prototype/Recipe]] '''recipe'''
* [[Prototype/RecipeCategory]] '''recipe-category'''
* [[Prototype/ResourceCategory]] '''resource-category'''
* [[Prototype/Shortcut]] '''shortcut'''
* [[Prototype/Technology]] '''technology'''
* [[Prototype/Tile]] '''tile'''
* [[Prototype/TipsAndTricksItem]] '''tips-and-tricks-item'''
* [[Prototype/TrivialSmoke]] '''trivial-smoke'''
* [[Prototype/Tutorial]] '''tutorial'''
* [[Prototype/UtilityConstants]] '''utility-constants'''
* [[Prototype/UtilitySounds]] '''utility-sounds'''
* [[Prototype/UtilitySprites]] '''utility-sprites'''
* [[Prototype/VirtualSignal]] '''virtual-signal'''
*/

View file

@ -6,16 +6,11 @@ import kotlinx.serialization.Serializable
@Serializable @Serializable
@SerialName("kafkatorio.resource.MinedProduct") @SerialName("kafkatorio.resource.MinedProduct")
data class MinedProduct( sealed interface MinedProduct {
/** `item` or `fluid`. */
val type: Type,
/** Prototype name of the result. */ val resultProtoId: PrototypeId
@SerialName("name") //Amount of the item or fluid to give. If not specified, amount_min, amount_max and probability must all be specified.
val resultPrototype: PrototypeName, val amount: Double?
//Amount of the item or fluid to give. If not specified, amount_min, amount_max and probability must all be specified.
val amount: Double?,
//Minimal amount of the item or fluid to give. Has no effect when amount is specified. //Minimal amount of the item or fluid to give. Has no effect when amount is specified.
//amount_min : Uint or double?, //amount_min : Uint or double?,
@ -26,17 +21,24 @@ data class MinedProduct(
//A value in range [0, 1]. Item or fluid is only given with this probability; otherwise no product is produced. //A value in range [0, 1]. Item or fluid is only given with this probability; otherwise no product is produced.
//probability : Double?, //probability : Double?,
//How much of this product is a catalyst. //How much of this product is a catalyst.
//catalyst_amount : Uint or double?, //catalyst_amount : Uint or double?,
) {
@Serializable @Serializable
@SerialName("kafkatorio.resource.MinedProductType") @SerialName("kafkatorio.resource.MinedProduct.MinedProductFluid")
enum class Type { data class Fluid(
@SerialName("item") override val amount: Double? = null,
ITEM, override val resultProtoId: PrototypeId,
@SerialName("fluid") ) : MinedProduct
FLUID,
}
@Serializable
@SerialName("kafkatorio.resource.MinedProduct.MinedProductItem")
data class Item(
override val amount: Double? = null,
override val resultProtoId: PrototypeId,
) : MinedProduct
} }

View file

@ -4,12 +4,13 @@ import dev.adamko.kafkatorio.schema.common.Colour
import dev.adamko.kafkatorio.schema.common.EntityIdentifiers import dev.adamko.kafkatorio.schema.common.EntityIdentifiers
import dev.adamko.kafkatorio.schema.common.EntityIdentifiersData import dev.adamko.kafkatorio.schema.common.EntityIdentifiersData
import dev.adamko.kafkatorio.schema.common.EventName import dev.adamko.kafkatorio.schema.common.EventName
import dev.adamko.kafkatorio.schema.common.FactorioEntityData
import dev.adamko.kafkatorio.schema.common.ForceIndex import dev.adamko.kafkatorio.schema.common.ForceIndex
import dev.adamko.kafkatorio.schema.common.MapChunkPosition import dev.adamko.kafkatorio.schema.common.MapChunkPosition
import dev.adamko.kafkatorio.schema.common.MapEntityPosition import dev.adamko.kafkatorio.schema.common.MapEntityPosition
import dev.adamko.kafkatorio.schema.common.MapTileDictionary import dev.adamko.kafkatorio.schema.common.MapTileDictionary
import dev.adamko.kafkatorio.schema.common.PlayerIndex import dev.adamko.kafkatorio.schema.common.PlayerIndex
import dev.adamko.kafkatorio.schema.common.PrototypeName import dev.adamko.kafkatorio.schema.common.PrototypeId
import dev.adamko.kafkatorio.schema.common.SurfaceIndex import dev.adamko.kafkatorio.schema.common.SurfaceIndex
import dev.adamko.kafkatorio.schema.common.Tick import dev.adamko.kafkatorio.schema.common.Tick
import dev.adamko.kafkatorio.schema.common.UnitNumber import dev.adamko.kafkatorio.schema.common.UnitNumber
@ -23,6 +24,8 @@ import kotlinx.serialization.Serializable
sealed class KafkatorioKeyedPacketData : KafkatorioPacketData() { sealed class KafkatorioKeyedPacketData : KafkatorioPacketData() {
abstract val key: KafkatorioKeyedPacketKey abstract val key: KafkatorioKeyedPacketKey
/** A list of all events that have been aggregated into this packet. */ /** A list of all events that have been aggregated into this packet. */
// Maybe change to be Map<EventName, Tick>, where Tick is the most recent event?
// A complete event timeline isn't necessary. The most recent tick of an event is good enough, and requires less space.
abstract val events: Map<EventName, List<Tick>>? abstract val events: Map<EventName, List<Tick>>?
} }
@ -40,8 +43,7 @@ sealed class KafkatorioKeyedPacketKey
data class EntityUpdateKey( data class EntityUpdateKey(
/** While normally optional, here a [unitNumber] is required for caching */ /** While normally optional, here a [unitNumber] is required for caching */
override val unitNumber: UnitNumber, override val unitNumber: UnitNumber,
override val name: String, override val protoId: PrototypeId,
override val protoType: String,
) : EntityIdentifiers, KafkatorioKeyedPacketKey() ) : EntityIdentifiers, KafkatorioKeyedPacketKey()
@ -60,7 +62,6 @@ data class EntityUpdate(
val lastUser: UInt? = null, val lastUser: UInt? = null,
val localisedDescription: String? = null, val localisedDescription: String? = null,
val localisedName: String? = null, val localisedName: String? = null,
val prototype: PrototypeName? = null,
) : KafkatorioKeyedPacketData() ) : KafkatorioKeyedPacketData()
@ -68,17 +69,18 @@ data class EntityUpdate(
@Serializable @Serializable
@SerialName("kafkatorio.packet.keyed.MapChunkUpdateKey") @SerialName("kafkatorio.packet.keyed.MapChunkTileUpdateKey")
data class MapChunkUpdateKey( data class MapChunkTileUpdateKey(
// val index: PlayerIndex, // maybe add player/robot key, to allow metrics like 'player x mined y tiles'
val chunkPosition: MapChunkPosition, val chunkPosition: MapChunkPosition,
val surfaceIndex: SurfaceIndex, val surfaceIndex: SurfaceIndex,
) : KafkatorioKeyedPacketKey() ) : KafkatorioKeyedPacketKey()
@Serializable @Serializable
@SerialName("kafkatorio.packet.keyed.MapChunkUpdate") @SerialName("kafkatorio.packet.keyed.MapChunkTileUpdate")
data class MapChunkUpdate( data class MapChunkTileUpdate(
override val key: MapChunkUpdateKey, override val key: MapChunkTileUpdateKey,
override val events: Map<EventName, List<Tick>>? = null, override val events: Map<EventName, List<Tick>>? = null,
@ -93,6 +95,7 @@ data class MapChunkUpdate(
/* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
@Serializable @Serializable
@SerialName("kafkatorio.packet.keyed.PlayerUpdateKey") @SerialName("kafkatorio.packet.keyed.PlayerUpdateKey")
data class PlayerUpdateKey( data class PlayerUpdateKey(
@ -134,4 +137,32 @@ data class PlayerUpdate(
) : KafkatorioKeyedPacketData() ) : KafkatorioKeyedPacketData()
/* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
@Serializable
@SerialName("kafkatorio.packet.keyed.MapChunkEntityUpdateKey")
data class MapChunkEntityUpdateKey(
val protoId: PrototypeId,
val surfaceIndex: SurfaceIndex,
val chunkPosition: MapChunkPosition,
) : KafkatorioKeyedPacketKey()
/**
* @property[distinctEntities] Distinct entities. The key is arbitrary and is only used
* for de-duplicating updates. It should only contain data that can be obtained from
* [the value][FactorioEntityData].
*/
@Serializable
@SerialName("kafkatorio.packet.keyed.MapChunkEntityUpdate")
data class MapChunkEntityUpdate(
override val key: MapChunkEntityUpdateKey,
override val events: Map<EventName, List<Tick>>? = null,
val distinctEntities: Map<String, FactorioEntityData>? = null,
) : KafkatorioKeyedPacketData()
/* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

View file

@ -4,12 +4,12 @@ import dev.adamko.kafkatorio.library.jsonMapperKafkatorio
import dev.adamko.kafkatorio.schema.common.EventName import dev.adamko.kafkatorio.schema.common.EventName
import dev.adamko.kafkatorio.schema.common.MapChunkPosition import dev.adamko.kafkatorio.schema.common.MapChunkPosition
import dev.adamko.kafkatorio.schema.common.MapTileDictionary import dev.adamko.kafkatorio.schema.common.MapTileDictionary
import dev.adamko.kafkatorio.schema.common.PrototypeName import dev.adamko.kafkatorio.schema.common.PrototypeId
import dev.adamko.kafkatorio.schema.common.SurfaceIndex import dev.adamko.kafkatorio.schema.common.SurfaceIndex
import dev.adamko.kafkatorio.schema.common.tick import dev.adamko.kafkatorio.schema.common.tick
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket
import dev.adamko.kafkatorio.schema.packets.MapChunkUpdate import dev.adamko.kafkatorio.schema.packets.MapChunkTileUpdate
import dev.adamko.kafkatorio.schema.packets.MapChunkUpdateKey import dev.adamko.kafkatorio.schema.packets.MapChunkTileUpdateKey
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
@ -59,8 +59,8 @@ class MapChunkUpdateTest : FunSpec({
val expected = KafkatorioPacket( val expected = KafkatorioPacket(
tick = 36u.tick, tick = 36u.tick,
modVersion = "0.4.0", modVersion = "0.4.0",
data = MapChunkUpdate( data = MapChunkTileUpdate(
key = MapChunkUpdateKey( key = MapChunkTileUpdateKey(
MapChunkPosition(-6, -3), MapChunkPosition(-6, -3),
SurfaceIndex(1u), SurfaceIndex(1u),
), ),
@ -78,9 +78,9 @@ class MapChunkUpdateTest : FunSpec({
), ),
), ),
protos = mapOf( protos = mapOf(
PrototypeName("water") to MapTileDictionary.PrototypeKey(1), PrototypeId("tile", "water") to MapTileDictionary.PrototypeKey(1),
PrototypeName("grass-4") to MapTileDictionary.PrototypeKey(2), PrototypeId("tile", "grass-4") to MapTileDictionary.PrototypeKey(2),
PrototypeName("grass-3") to MapTileDictionary.PrototypeKey(32), PrototypeId("tile", "grass-3") to MapTileDictionary.PrototypeKey(32),
) )
) )
) )

View file

@ -3,7 +3,7 @@ package dev.adamko.kafkatorio.events.schema
import dev.adamko.kafkatorio.library.jsonMapperKafkatorio import dev.adamko.kafkatorio.library.jsonMapperKafkatorio
import dev.adamko.kafkatorio.schema.common.Colour import dev.adamko.kafkatorio.schema.common.Colour
import dev.adamko.kafkatorio.schema.common.FactorioPrototype import dev.adamko.kafkatorio.schema.common.FactorioPrototype
import dev.adamko.kafkatorio.schema.common.PrototypeName import dev.adamko.kafkatorio.schema.common.PrototypeId
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket
import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate
import io.kotest.core.spec.style.BehaviorSpec import io.kotest.core.spec.style.BehaviorSpec
@ -12,6 +12,7 @@ import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf import io.kotest.matchers.types.shouldBeInstanceOf
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
class PrototypesTest : BehaviorSpec({ class PrototypesTest : BehaviorSpec({
Given("Prototypes Json") { Given("Prototypes Json") {
// language=JSON // language=JSON
@ -669,7 +670,7 @@ class PrototypesTest : BehaviorSpec({
.prototypes .prototypes
.forOne { .forOne {
it.shouldBeInstanceOf<FactorioPrototype.MapTile>() it.shouldBeInstanceOf<FactorioPrototype.MapTile>()
it.name shouldBe PrototypeName("tutorial-grid") it.protoId shouldBe PrototypeId.MapTile("tutorial-grid")
it.order shouldBe "z[other]-c[tutorial]-a[tutorial-grid]" it.order shouldBe "z[other]-c[tutorial]-a[tutorial-grid]"
it.layer shouldBe 55u it.layer shouldBe 55u
it.collisionMasks shouldBe listOf("ground-tile") it.collisionMasks shouldBe listOf("ground-tile")

View file

@ -7,6 +7,7 @@ import dev.adamko.kafkatorio.schema.common.EventName
import dev.adamko.kafkatorio.schema.common.ForceIndex import dev.adamko.kafkatorio.schema.common.ForceIndex
import dev.adamko.kafkatorio.schema.common.MapEntityPosition import dev.adamko.kafkatorio.schema.common.MapEntityPosition
import dev.adamko.kafkatorio.schema.common.PlayerIndex import dev.adamko.kafkatorio.schema.common.PlayerIndex
import dev.adamko.kafkatorio.schema.common.PrototypeId
import dev.adamko.kafkatorio.schema.common.SurfaceIndex import dev.adamko.kafkatorio.schema.common.SurfaceIndex
import dev.adamko.kafkatorio.schema.common.Tick import dev.adamko.kafkatorio.schema.common.Tick
import dev.adamko.kafkatorio.schema.common.UnitNumber import dev.adamko.kafkatorio.schema.common.UnitNumber
@ -190,8 +191,7 @@ class UpdatePacketsTest : FunSpec({
colour = null, colour = null,
diedCause = EntityIdentifiersData( diedCause = EntityIdentifiersData(
unitNumber = UnitNumber(66u), unitNumber = UnitNumber(66u),
name = "small-biter", protoId = PrototypeId("unit/small-biter"),
protoType = "unit",
), ),
disconnectReason = null, disconnectReason = null,
events = mapOf( events = mapOf(

View file

@ -20,22 +20,22 @@ class MapTileDictionaryTest : FunSpec({
"44" to mapOf("1" to MapTileDictionary.PrototypeKey(44)), "44" to mapOf("1" to MapTileDictionary.PrototypeKey(44)),
), ),
protos = mapOf( protos = mapOf(
PrototypeName("water") to MapTileDictionary.PrototypeKey(1), PrototypeId.MapTile("water") to MapTileDictionary.PrototypeKey(1),
PrototypeName("grass-4") to MapTileDictionary.PrototypeKey(2), PrototypeId.MapTile("grass-4") to MapTileDictionary.PrototypeKey(2),
PrototypeName("grass-3") to MapTileDictionary.PrototypeKey(32), PrototypeId.MapTile("grass-3") to MapTileDictionary.PrototypeKey(32),
PrototypeName("not-used") to MapTileDictionary.PrototypeKey(99), PrototypeId.MapTile("not-used") to MapTileDictionary.PrototypeKey(99),
) )
) )
test("toMapTileList") { test("toMapTileList") {
actual.toMapTileList() shouldContainAll listOf( actual.toMapTileList() shouldContainAll listOf(
MapTile(-192, -65, PrototypeName("grass-4")), MapTile(-192, -65, PrototypeId.MapTile("grass-4")),
MapTile(161, -96, PrototypeName("water")), MapTile(161, -96, PrototypeId.MapTile("water")),
MapTile(161, -95, PrototypeName("grass-4")), MapTile(161, -95, PrototypeId.MapTile("grass-4")),
MapTile(161, 94, PrototypeName("grass-4")), MapTile(161, 94, PrototypeId.MapTile("grass-4")),
MapTile(161, 93, PrototypeName("grass-3")), MapTile(161, 93, PrototypeId.MapTile("grass-3")),
) )
} }
} }

View file

@ -1,11 +1,16 @@
package dev.adamko.kafkatorio.events.schema package dev.adamko.kafkatorio.events.schema
import dev.adamko.kafkatorio.schema.common.PlayerIndex
import dev.adamko.kafkatorio.schema.common.SurfaceIndex
import dev.adamko.kafkatorio.schema.common.UnitNumber
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket
import dev.adamko.kxstsgen.KxsTsConfig import dev.adamko.kxstsgen.KxsTsConfig
import dev.adamko.kxstsgen.KxsTsConfig.TypeAliasTypingConfig.BrandTyping
import dev.adamko.kxstsgen.KxsTsGenerator import dev.adamko.kxstsgen.KxsTsGenerator
import dev.adamko.kxstsgen.core.TsDeclaration.TsTypeAlias import dev.adamko.kxstsgen.core.TsDeclaration.TsTypeAlias
import dev.adamko.kxstsgen.core.TsElementId import dev.adamko.kxstsgen.core.TsElementId
import dev.adamko.kxstsgen.core.TsLiteral import dev.adamko.kxstsgen.core.TsLiteral
import dev.adamko.kxstsgen.core.TsSourceCodeGenerator
import dev.adamko.kxstsgen.core.TsTypeRef import dev.adamko.kxstsgen.core.TsTypeRef
import kotlin.io.path.Path import kotlin.io.path.Path
import kotlin.io.path.createDirectories import kotlin.io.path.createDirectories
@ -13,14 +18,24 @@ import kotlinx.serialization.builtins.serializer
import org.intellij.lang.annotations.Language import org.intellij.lang.annotations.Language
@ExperimentalUnsignedTypes
fun main(args: Array<String>) { fun main(args: Array<String>) {
val config = KxsTsConfig( val config = KxsTsConfig(
// typeAliasTyping = BrandTyping typeAliasTyping = BrandTyping
) )
val gen2 = KxsTsGenerator(config) val gen2 = KxsTsGenerator(
config = config,
sourceCodeGenerator = MySourceCodeGenerator(config),
)
// gen2.serializerDescriptorOverrides += mapOf(
////@formatter:off
// SurfaceIndex.serializer() to emptySet(),
// PlayerIndex.serializer() to emptySet(),
// UnitNumber.serializer() to emptySet(),
////@formatter:on
// )
gen2.descriptorOverrides += mapOf( gen2.descriptorOverrides += mapOf(
//@formatter:off //@formatter:off
@ -32,6 +47,10 @@ fun main(args: Array<String>) {
UByte .serializer().descriptor to TsTypeAlias(TsElementId("kotlin.UByte" ), TsTypeRef.Literal(TsLiteral.Custom("uint8" ), false)), UByte .serializer().descriptor to TsTypeAlias(TsElementId("kotlin.UByte" ), TsTypeRef.Literal(TsLiteral.Custom("uint8" ), false)),
UShort.serializer().descriptor to TsTypeAlias(TsElementId("kotlin.UShort"), TsTypeRef.Literal(TsLiteral.Custom("uint16"), false)), UShort.serializer().descriptor to TsTypeAlias(TsElementId("kotlin.UShort"), TsTypeRef.Literal(TsLiteral.Custom("uint16"), false)),
ULong .serializer().descriptor to TsTypeAlias(TsElementId("kotlin.ULong" ), TsTypeRef.Literal(TsLiteral.Custom("uint64"), false)), ULong .serializer().descriptor to TsTypeAlias(TsElementId("kotlin.ULong" ), TsTypeRef.Literal(TsLiteral.Custom("uint64"), false)),
PlayerIndex.serializer().descriptor to TsTypeAlias(TsElementId("PlayerIndex" ), TsTypeRef.Literal(TsLiteral.Custom("PlayerIndex"), false)),
SurfaceIndex.serializer().descriptor to TsTypeAlias(TsElementId("SurfaceIndex" ), TsTypeRef.Literal(TsLiteral.Custom("SurfaceIndex"), false)),
UnitNumber.serializer().descriptor to TsTypeAlias(TsElementId("UnitNumber" ), TsTypeRef.Literal(TsLiteral.Custom("UnitNumber"), false)),
//@formatter:on //@formatter:on
) )
@ -60,3 +79,26 @@ val kt2tsHeader = """
|// Generated by kxs-ts-gen - do not edit this file manually |// Generated by kxs-ts-gen - do not edit this file manually
| |
""".trimMargin() """.trimMargin()
class MySourceCodeGenerator(
config: KxsTsConfig,
) : TsSourceCodeGenerator.Default(config) {
override fun generateTypeAlias(element: TsTypeAlias): String {
return if (element.id.name in listOf("PlayerIndex", "SurfaceIndex", "UnitNumber")) {
""
} else if (
(element.typeRef as? TsTypeRef.Literal)?.element is TsLiteral.Custom
|| element.id.name == "Tick"
) {
val aliasedRef = generateTypeReference(element.typeRef)
"""
|export type ${element.id.name} = ${aliasedRef};
""".trimMargin()
} else {
super.generateTypeAlias(element)
}
}
}

View file

@ -101,7 +101,7 @@ val installEventsTsSchema by tasks.registering(Sync::class) {
} }
) { ) {
// drop the first directory inside the zip // drop the first directory inside the zip
eachFile { relativePath = dropDirectory() } // eachFile { relativePath = dropDirectory() }
includeEmptyDirs = false includeEmptyDirs = false
} }
into(outputDir) into(outputDir)

View file

@ -75,9 +75,9 @@
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="
}, },
"typed-factorio": { "typed-factorio": {
"version": "1.3.0", "version": "1.3.2",
"resolved": "https://registry.npmjs.org/typed-factorio/-/typed-factorio-1.3.0.tgz", "resolved": "https://registry.npmjs.org/typed-factorio/-/typed-factorio-1.3.2.tgz",
"integrity": "sha512-qBHKjE+m9Im7vDhsGvl0uwaSFzJ5asqyfw414gF0owZwmSax2CIjdLx367qUgdD4flsB0n9HecBaZ0Yzt9zMPQ==" "integrity": "sha512-sAVIDvSSBPWL7trI94SPd2Suq9dLjXmXL1WFKJIYJpFQocNwJUb0ydGRBsvJjZhVAyEZYJC0lHlDWH47RWP/tw=="
}, },
"typescript": { "typescript": {
"version": "4.7.4", "version": "4.7.4",

View file

@ -9,15 +9,19 @@
"engines": { "engines": {
"node": "~14.19.1" "node": "~14.19.1"
}, },
"devDependencies": {}, "devDependencies": {
},
"dependencies": { "dependencies": {
"lua-types": "^2.11.0", "lua-types": "^2.11.0",
"typescript-to-lua": "1.6.1", "typescript-to-lua": "1.6.1",
"typed-factorio": "1.3.0", "typed-factorio": "1.3.2",
"typescript": "4.7.4" "typescript": "4.7.4"
}, },
"license": "UNLICENSED", "license": "UNLICENSED",
"peerDependencies": {}, "peerDependencies": {
"optionalDependencies": {}, },
"bundledDependencies": [] "optionalDependencies": {
},
"bundledDependencies": [
]
} }

View file

@ -3,7 +3,7 @@ local ____global_2Dinit = require("main.global-init")
local initGlobal = ____global_2Dinit.initGlobal local initGlobal = ____global_2Dinit.initGlobal
local ____prototypeUpdates = require("main.events.prototypeUpdates") local ____prototypeUpdates = require("main.events.prototypeUpdates")
local emitPrototypes = ____prototypeUpdates.emitPrototypes local emitPrototypes = ____prototypeUpdates.emitPrototypes
require("main.events.registerHandlers") require("main.events.registerEventListeners")
require("main.events.mapChunkUpdates") require("main.events.mapChunkUpdates")
require("main.events.playerUpdates") require("main.events.playerUpdates")
require("main.events.entityUpdates") require("main.events.entityUpdates")

View file

@ -9,7 +9,8 @@ do
KafkatorioPacketData.Type.PrototypesUpdate = "kafkatorio.packet.instant.PrototypesUpdate" KafkatorioPacketData.Type.PrototypesUpdate = "kafkatorio.packet.instant.PrototypesUpdate"
KafkatorioPacketData.Type.SurfaceUpdate = "kafkatorio.packet.instant.SurfaceUpdate" KafkatorioPacketData.Type.SurfaceUpdate = "kafkatorio.packet.instant.SurfaceUpdate"
KafkatorioPacketData.Type.EntityUpdate = "kafkatorio.packet.keyed.EntityUpdate" KafkatorioPacketData.Type.EntityUpdate = "kafkatorio.packet.keyed.EntityUpdate"
KafkatorioPacketData.Type.MapChunkUpdate = "kafkatorio.packet.keyed.MapChunkUpdate" KafkatorioPacketData.Type.MapChunkEntityUpdate = "kafkatorio.packet.keyed.MapChunkEntityUpdate"
KafkatorioPacketData.Type.MapChunkTileUpdate = "kafkatorio.packet.keyed.MapChunkTileUpdate"
KafkatorioPacketData.Type.PlayerUpdate = "kafkatorio.packet.keyed.PlayerUpdate" KafkatorioPacketData.Type.PlayerUpdate = "kafkatorio.packet.keyed.PlayerUpdate"
KafkatorioPacketData.Type.Error = "kafkatorio.packet.KafkatorioPacketData.Error" KafkatorioPacketData.Type.Error = "kafkatorio.packet.KafkatorioPacketData.Error"
end end
@ -20,7 +21,62 @@ do
FactorioPrototype.Type.Entity = "kafkatorio.prototype.Entity" FactorioPrototype.Type.Entity = "kafkatorio.prototype.Entity"
FactorioPrototype.Type.MapTile = "kafkatorio.prototype.MapTile" FactorioPrototype.Type.MapTile = "kafkatorio.prototype.MapTile"
end end
____exports.MinedProductType = MinedProductType or ({}) ____exports.FactorioEntityData = {}
____exports.MinedProductType.item = "item" local FactorioEntityData = ____exports.FactorioEntityData
____exports.MinedProductType.fluid = "fluid" do
FactorioEntityData.Type = Type or ({})
FactorioEntityData.Type.Resource = "kafkatorio.entity.FactorioEntityData.Resource"
FactorioEntityData.Type.Standard = "kafkatorio.entity.FactorioEntityData.Standard"
end
____exports.EntityStatus = EntityStatus or ({})
____exports.EntityStatus.CANT_DIVIDE_SEGMENTS = "CANT_DIVIDE_SEGMENTS"
____exports.EntityStatus.CHARGING = "CHARGING"
____exports.EntityStatus.CLOSED_BY_CIRCUIT_NETWORK = "CLOSED_BY_CIRCUIT_NETWORK"
____exports.EntityStatus.DISABLED = "DISABLED"
____exports.EntityStatus.DISABLED_BY_CONTROL_BEHAVIOR = "DISABLED_BY_CONTROL_BEHAVIOR"
____exports.EntityStatus.DISABLED_BY_SCRIPT = "DISABLED_BY_SCRIPT"
____exports.EntityStatus.DISCHARGING = "DISCHARGING"
____exports.EntityStatus.FLUID_INGREDIENT_SHORTAGE = "FLUID_INGREDIENT_SHORTAGE"
____exports.EntityStatus.FULLY_CHARGED = "FULLY_CHARGED"
____exports.EntityStatus.FULL_OUTPUT = "FULL_OUTPUT"
____exports.EntityStatus.ITEM_INGREDIENT_SHORTAGE = "ITEM_INGREDIENT_SHORTAGE"
____exports.EntityStatus.LAUNCHING_ROCKET = "LAUNCHING_ROCKET"
____exports.EntityStatus.LOW_INPUT_FLUID = "LOW_INPUT_FLUID"
____exports.EntityStatus.LOW_POWER = "LOW_POWER"
____exports.EntityStatus.LOW_TEMPERATURE = "LOW_TEMPERATURE"
____exports.EntityStatus.MARKED_FOR_DECONSTRUCTION = "MARKED_FOR_DECONSTRUCTION"
____exports.EntityStatus.MISSING_REQUIRED_FLUID = "MISSING_REQUIRED_FLUID"
____exports.EntityStatus.MISSING_SCIENCE_PACKS = "MISSING_SCIENCE_PACKS"
____exports.EntityStatus.NETWORKS_CONNECTED = "NETWORKS_CONNECTED"
____exports.EntityStatus.NETWORKS_DISCONNECTED = "NETWORKS_DISCONNECTED"
____exports.EntityStatus.NORMAL = "NORMAL"
____exports.EntityStatus.NOT_CONNECTED_TO_RAIL = "NOT_CONNECTED_TO_RAIL"
____exports.EntityStatus.NOT_PLUGGED_IN_ELECTRIC_NETWORK = "NOT_PLUGGED_IN_ELECTRIC_NETWORK"
____exports.EntityStatus.NO_AMMO = "NO_AMMO"
____exports.EntityStatus.NO_FUEL = "NO_FUEL"
____exports.EntityStatus.NO_INGREDIENTS = "NO_INGREDIENTS"
____exports.EntityStatus.NO_INPUT_FLUID = "NO_INPUT_FLUID"
____exports.EntityStatus.NO_MINABLE_RESOURCES = "NO_MINABLE_RESOURCES"
____exports.EntityStatus.NO_MODULES_TO_TRANSMIT = "NO_MODULES_TO_TRANSMIT"
____exports.EntityStatus.NO_POWER = "NO_POWER"
____exports.EntityStatus.NO_RECIPE = "NO_RECIPE"
____exports.EntityStatus.NO_RESEARCH_IN_PROGRESS = "NO_RESEARCH_IN_PROGRESS"
____exports.EntityStatus.OPENED_BY_CIRCUIT_NETWORK = "OPENED_BY_CIRCUIT_NETWORK"
____exports.EntityStatus.OUT_OF_LOGISTIC_NETWORK = "OUT_OF_LOGISTIC_NETWORK"
____exports.EntityStatus.PREPARING_ROCKET_FOR_LAUNCH = "PREPARING_ROCKET_FOR_LAUNCH"
____exports.EntityStatus.RECHARGING_AFTER_POWER_OUTAGE = "RECHARGING_AFTER_POWER_OUTAGE"
____exports.EntityStatus.TURNED_OFF_DURING_DAYTIME = "TURNED_OFF_DURING_DAYTIME"
____exports.EntityStatus.WAITING_FOR_SOURCE_ITEMS = "WAITING_FOR_SOURCE_ITEMS"
____exports.EntityStatus.WAITING_FOR_SPACE_IN_DESTINATION = "WAITING_FOR_SPACE_IN_DESTINATION"
____exports.EntityStatus.WAITING_FOR_TARGET_TO_BE_BUILT = "WAITING_FOR_TARGET_TO_BE_BUILT"
____exports.EntityStatus.WAITING_FOR_TRAIN = "WAITING_FOR_TRAIN"
____exports.EntityStatus.WAITING_TO_LAUNCH_ROCKET = "WAITING_TO_LAUNCH_ROCKET"
____exports.EntityStatus.WORKING = "WORKING"
____exports.MinedProduct = {}
local MinedProduct = ____exports.MinedProduct
do
MinedProduct.Type = Type or ({})
MinedProduct.Type.MinedProductFluid = "kafkatorio.resource.MinedProduct.MinedProductFluid"
MinedProduct.Type.MinedProductItem = "kafkatorio.resource.MinedProduct.MinedProductItem"
end
return ____exports return ____exports

View file

@ -1,7 +1,22 @@
local ____exports = {} local ____exports = {}
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local EntityStatus = ____kafkatorio_2Dschema.EntityStatus
local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData
____exports.Converters = {} ____exports.Converters = {}
local Converters = ____exports.Converters local Converters = ____exports.Converters
do do
local convertEntityStatus, EntityStatusRecord
function convertEntityStatus(status)
if status == nil then
return nil
else
return EntityStatusRecord[status]
end
end
function Converters.prototypeId(____type, name)
return (____type .. "/") .. name
end
local floor = math.floor
local mapEventIdToName = {} local mapEventIdToName = {}
for eventName, eventId in pairs(defines.events) do for eventName, eventId in pairs(defines.events) do
mapEventIdToName[eventId] = eventName mapEventIdToName[eventId] = eventName
@ -36,5 +51,86 @@ do
end end
return masks return masks
end end
function Converters.convertResourceEntity(entity)
if entity.type ~= "resource" then
return nil
else
return {
type = FactorioEntityData.Type.Resource,
protoId = Converters.prototypeId(entity.type, entity.name),
status = convertEntityStatus(entity.status),
amount = entity.amount,
initialAmount = entity.initial_amount,
position = Converters.convertMapTablePosition(entity.position)
}
end
end
function Converters.prototypeIdEntity(entity)
return Converters.prototypeId(entity.type, entity.name)
end
function Converters.tilePositionToChunkPosition(mapPosition)
return {
floor(mapPosition.x / 32),
floor(mapPosition.y)
}
end
function Converters.mapPositionToChunkPosition(mapPosition)
return {
floor(mapPosition.x / 32),
floor(mapPosition.y)
}
end
function Converters.entityStatus(status)
if status == nil then
return nil
else
return EntityStatusRecord[status]
end
end
EntityStatusRecord = {
[defines.entity_status.cant_divide_segments] = EntityStatus.CANT_DIVIDE_SEGMENTS,
[defines.entity_status.charging] = EntityStatus.CHARGING,
[defines.entity_status.closed_by_circuit_network] = EntityStatus.CLOSED_BY_CIRCUIT_NETWORK,
[defines.entity_status.disabled] = EntityStatus.DISABLED,
[defines.entity_status.disabled_by_control_behavior] = EntityStatus.DISABLED_BY_CONTROL_BEHAVIOR,
[defines.entity_status.disabled_by_script] = EntityStatus.DISABLED_BY_SCRIPT,
[defines.entity_status.discharging] = EntityStatus.DISCHARGING,
[defines.entity_status.fluid_ingredient_shortage] = EntityStatus.FLUID_INGREDIENT_SHORTAGE,
[defines.entity_status.fully_charged] = EntityStatus.FULLY_CHARGED,
[defines.entity_status.full_output] = EntityStatus.FULL_OUTPUT,
[defines.entity_status.item_ingredient_shortage] = EntityStatus.ITEM_INGREDIENT_SHORTAGE,
[defines.entity_status.launching_rocket] = EntityStatus.LAUNCHING_ROCKET,
[defines.entity_status.low_input_fluid] = EntityStatus.LOW_INPUT_FLUID,
[defines.entity_status.low_power] = EntityStatus.LOW_POWER,
[defines.entity_status.low_temperature] = EntityStatus.LOW_TEMPERATURE,
[defines.entity_status.marked_for_deconstruction] = EntityStatus.MARKED_FOR_DECONSTRUCTION,
[defines.entity_status.missing_required_fluid] = EntityStatus.MISSING_REQUIRED_FLUID,
[defines.entity_status.missing_science_packs] = EntityStatus.MISSING_SCIENCE_PACKS,
[defines.entity_status.networks_connected] = EntityStatus.NETWORKS_CONNECTED,
[defines.entity_status.networks_disconnected] = EntityStatus.NETWORKS_DISCONNECTED,
[defines.entity_status.normal] = EntityStatus.NORMAL,
[defines.entity_status.not_connected_to_rail] = EntityStatus.NOT_CONNECTED_TO_RAIL,
[defines.entity_status.not_plugged_in_electric_network] = EntityStatus.NOT_PLUGGED_IN_ELECTRIC_NETWORK,
[defines.entity_status.no_ammo] = EntityStatus.NO_AMMO,
[defines.entity_status.no_fuel] = EntityStatus.NO_FUEL,
[defines.entity_status.no_ingredients] = EntityStatus.NO_INGREDIENTS,
[defines.entity_status.no_input_fluid] = EntityStatus.NO_INPUT_FLUID,
[defines.entity_status.no_minable_resources] = EntityStatus.NO_MINABLE_RESOURCES,
[defines.entity_status.no_modules_to_transmit] = EntityStatus.NO_MODULES_TO_TRANSMIT,
[defines.entity_status.no_power] = EntityStatus.NO_POWER,
[defines.entity_status.no_recipe] = EntityStatus.NO_RECIPE,
[defines.entity_status.no_research_in_progress] = EntityStatus.NO_RESEARCH_IN_PROGRESS,
[defines.entity_status.opened_by_circuit_network] = EntityStatus.OPENED_BY_CIRCUIT_NETWORK,
[defines.entity_status.out_of_logistic_network] = EntityStatus.OUT_OF_LOGISTIC_NETWORK,
[defines.entity_status.preparing_rocket_for_launch] = EntityStatus.PREPARING_ROCKET_FOR_LAUNCH,
[defines.entity_status.recharging_after_power_outage] = EntityStatus.RECHARGING_AFTER_POWER_OUTAGE,
[defines.entity_status.turned_off_during_daytime] = EntityStatus.TURNED_OFF_DURING_DAYTIME,
[defines.entity_status.waiting_for_source_items] = EntityStatus.WAITING_FOR_SOURCE_ITEMS,
[defines.entity_status.waiting_for_space_in_destination] = EntityStatus.WAITING_FOR_SPACE_IN_DESTINATION,
[defines.entity_status.waiting_for_target_to_be_built] = EntityStatus.WAITING_FOR_TARGET_TO_BE_BUILT,
[defines.entity_status.waiting_for_train] = EntityStatus.WAITING_FOR_TRAIN,
[defines.entity_status.waiting_to_launch_rocket] = EntityStatus.WAITING_TO_LAUNCH_ROCKET,
[defines.entity_status.working] = EntityStatus.WORKING
}
end end
return ____exports return ____exports

View file

@ -1,105 +1,203 @@
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local __TS__New = ____lualib.__TS__New
local ____exports = {} local ____exports = {}
local handleBuiltEntityEvent, handleMinedEntityEvent
local ____converters = require("main.events.converters") local ____converters = require("main.events.converters")
local Converters = ____converters.Converters local Converters = ____converters.Converters
local ____EventDataCache = require("main.cache.EventDataCache") local ____EventDataCache = require("main.cache.EventDataCache")
local EventDataCache = ____EventDataCache.default local EventDataCache = ____EventDataCache.default
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
function handleBuiltEntityEvent(event) ____exports.EntityUpdatesHandler = __TS__Class()
local eventName = Converters.eventNameString(event.name) local EntityUpdatesHandler = ____exports.EntityUpdatesHandler
if event.created_entity.unit_number == nil then EntityUpdatesHandler.name = "EntityUpdatesHandler"
function EntityUpdatesHandler.prototype.____constructor(self)
end
function EntityUpdatesHandler.prototype.handleMinedTileEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return return
end end
local key = {name = event.created_entity.name, protoType = event.created_entity.prototype.name, unitNumber = event.created_entity.unit_number} local tilesByChunk = {}
EventDataCache:debounce( for ____, tile in ipairs(event.tiles) do
key, local chunkPosition = Converters.tilePositionToChunkPosition(tile.position)
KafkatorioPacketData.Type.EntityUpdate, tilesByChunk[chunkPosition] = tile
end
for chunkPos, tiles in pairs(tilesByChunk) do
local entities = {}
for tile in pairs(tiles) do
local resources = ____exports.EntityUpdatesHandler:getTileResourceEntities(surface, chunkPos)
for ____, resource in ipairs(resources) do
entities[#entities + 1] = resource
end
end
____exports.EntityUpdatesHandler:throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick,
event.surface_index,
{chunkPos[1], chunkPos[2]},
entities
)
end
end
function EntityUpdatesHandler.prototype.handleMinedEntityEvent(self, event)
____exports.EntityUpdatesHandler:throttleEntityUpdate(event, event.entity)
end
function EntityUpdatesHandler.prototype.handleBuiltEntityEvent(self, event)
____exports.EntityUpdatesHandler:throttleEntityUpdate(event, event.created_entity)
end
function EntityUpdatesHandler.prototype.handleChunkGeneratedEvent(self, event)
local entities = ____exports.EntityUpdatesHandler:getAreaResourceEntities(event.surface, event.area)
____exports.EntityUpdatesHandler:throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick,
event.surface.index,
{event.position.x, event.position.y},
entities
)
end
function EntityUpdatesHandler.throttleEntityUpdate(self, event, entity)
if entity.unit_number == nil then
return
end
local eventName = Converters.eventNameString(event.name)
local entityUpdateKey = {
protoId = Converters.prototypeIdEntity(entity),
surfaceIndex = entity.surface.index,
chunkPosition = Converters.mapPositionToChunkPosition(entity.position)
}
local ____FactorioEntityData_Type_Standard_2 = FactorioEntityData.Type.Standard
local ____Converters_prototypeIdEntity_result_3 = Converters.prototypeIdEntity(entity)
local ____entity_graphics_variation_4 = entity.graphics_variation
local ____entity_health_5 = entity.health
local ____entity_active_6 = entity.active
local ____entity_rotatable_7 = entity.rotatable
local ____entity_last_user_index_0 = entity.last_user
if ____entity_last_user_index_0 ~= nil then
____entity_last_user_index_0 = ____entity_last_user_index_0.index
end
local entityUpdate = {
type = ____FactorioEntityData_Type_Standard_2,
protoId = ____Converters_prototypeIdEntity_result_3,
graphicsVariation = ____entity_graphics_variation_4,
health = ____entity_health_5,
isActive = ____entity_active_6,
isRotatable = ____entity_rotatable_7,
lastUser = ____entity_last_user_index_0,
localisedDescription = nil,
localisedName = nil,
position = {entity.position.x, entity.position.y},
status = Converters.entityStatus(entity.status)
}
local entityKey = tostring(entity.unit_number)
EventDataCache:throttle(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
function(data) function(data)
if data.events == nil then if data.events == nil then
data.events = {} data.events = {}
end end
local ____data_events_0, ____eventName_1 = data.events, eventName local ____data_events_8, ____eventName_9 = data.events, eventName
if ____data_events_0[____eventName_1] == nil then if ____data_events_8[____eventName_9] == nil then
____data_events_0[____eventName_1] = {} ____data_events_8[____eventName_9] = {}
end end
local ____data_events_eventName_2 = data.events[eventName] local ____data_events_eventName_10 = data.events[eventName]
____data_events_eventName_2[#____data_events_eventName_2 + 1] = event.tick ____data_events_eventName_10[#____data_events_eventName_10 + 1] = event.tick
data.chunkPosition = Converters.convertMapTablePosition(event.created_entity.position) if data.distinctEntities == nil then
data.graphicsVariation = event.created_entity.graphics_variation data.distinctEntities = {}
data.health = event.created_entity.health
data.isActive = event.created_entity.active
data.isRotatable = event.created_entity.rotatable
local ____data_5 = data
local ____event_created_entity_last_user_index_3 = event.created_entity.last_user
if ____event_created_entity_last_user_index_3 ~= nil then
____event_created_entity_last_user_index_3 = ____event_created_entity_last_user_index_3.index
end end
____data_5.lastUser = ____event_created_entity_last_user_index_3 data.distinctEntities[entityKey] = entityUpdate
data.prototype = event.created_entity.prototype.name
end end
) )
end end
function handleMinedEntityEvent(event) function EntityUpdatesHandler.throttleResourceEntitiesUpdate(self, eventName, eventTick, surfaceIndex, chunkPosition, entities)
local eventName = Converters.eventNameString(event.name) local entitiesByProtoId = {}
if event.entity.unit_number == nil then for ____, entity in ipairs(entities) do
return local ____entitiesByProtoId_11, ____entity_protoId_12 = entitiesByProtoId, entity.protoId
if ____entitiesByProtoId_11[____entity_protoId_12] == nil then
____entitiesByProtoId_11[____entity_protoId_12] = {}
end
local ____entitiesByProtoId_entity_protoId_13 = entitiesByProtoId[entity.protoId]
____entitiesByProtoId_entity_protoId_13[#____entitiesByProtoId_entity_protoId_13 + 1] = entity
end end
local key = {name = event.entity.name, protoType = event.entity.prototype.name, unitNumber = event.entity.unit_number} for protoId, resourceEntities in pairs(entitiesByProtoId) do
EventDataCache:debounce( local entityUpdateKey = {protoId = protoId, surfaceIndex = surfaceIndex, chunkPosition = {chunkPosition[1], chunkPosition[2]}}
key, EventDataCache:throttle(
KafkatorioPacketData.Type.EntityUpdate, entityUpdateKey,
function(data) KafkatorioPacketData.Type.MapChunkEntityUpdate,
if data.events == nil then function(data)
data.events = {} if data.events == nil then
data.events = {}
end
local ____data_events_14, ____eventName_15 = data.events, eventName
if ____data_events_14[____eventName_15] == nil then
____data_events_14[____eventName_15] = {}
end
local ____data_events_eventName_16 = data.events[eventName]
____data_events_eventName_16[#____data_events_eventName_16 + 1] = eventTick
for ____, entity in ipairs(resourceEntities) do
local x, y = table.unpack(entity.position)
local entityKey = (tostring(x) .. ",") .. tostring(y)
if data.distinctEntities == nil then
data.distinctEntities = {}
end
data.distinctEntities[entityKey] = entity
end
end end
local ____data_events_6, ____eventName_7 = data.events, eventName )
if ____data_events_6[____eventName_7] == nil then end
____data_events_6[____eventName_7] = {}
end
local ____data_events_eventName_8 = data.events[eventName]
____data_events_eventName_8[#____data_events_eventName_8 + 1] = event.tick
data.chunkPosition = Converters.convertMapTablePosition(event.entity.position)
data.graphicsVariation = event.entity.graphics_variation
data.health = event.entity.health
data.isActive = event.entity.active
data.isRotatable = event.entity.rotatable
local ____data_11 = data
local ____event_entity_last_user_index_9 = event.entity.last_user
if ____event_entity_last_user_index_9 ~= nil then
____event_entity_last_user_index_9 = ____event_entity_last_user_index_9.index
end
____data_11.lastUser = ____event_entity_last_user_index_9
data.prototype = event.entity.prototype.name
end
)
end end
function EntityUpdatesHandler.getTileResourceEntities(self, surface, mapPosition)
local rawEntities = surface.find_entities_filtered({position = mapPosition, collision_mask = "resource-layer"})
local resources = {}
for ____, rawEntity in ipairs(rawEntities) do
local entity = Converters.convertResourceEntity(rawEntity)
if entity ~= nil then
resources[#resources + 1] = entity
end
end
return resources
end
function EntityUpdatesHandler.getAreaResourceEntities(self, surface, area)
local rawEntities = surface.find_entities_filtered({area = area, collision_mask = "resource-layer"})
local resources = {}
for ____, rawEntity in ipairs(rawEntities) do
local entity = Converters.convertResourceEntity(rawEntity)
if entity ~= nil then
resources[#resources + 1] = entity
end
end
return resources
end
local EntityUpdates = __TS__New(____exports.EntityUpdatesHandler)
____exports.default = EntityUpdates
script.on_event( script.on_event(
defines.events.on_built_entity, defines.events.on_built_entity,
function(e) function(e)
log("on_built_entity " .. tostring(e.tick)) log("on_built_entity " .. tostring(e.tick))
handleBuiltEntityEvent(e) EntityUpdates:handleBuiltEntityEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.on_robot_built_entity, defines.events.on_robot_built_entity,
function(e) function(e)
log("on_robot_built_entity " .. tostring(e.tick)) log("on_robot_built_entity " .. tostring(e.tick))
handleBuiltEntityEvent(e) EntityUpdates:handleBuiltEntityEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.on_player_mined_entity, defines.events.on_player_mined_entity,
function(e) function(e)
log("on_player_mined_entity " .. tostring(e.tick)) log("on_player_mined_entity " .. tostring(e.tick))
handleMinedEntityEvent(e) EntityUpdates:handleMinedEntityEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.on_robot_mined_entity, defines.events.on_robot_mined_entity,
function(e) function(e)
log("on_robot_mined_entity " .. tostring(e.tick)) log("on_robot_mined_entity " .. tostring(e.tick))
handleMinedEntityEvent(e) EntityUpdates:handleMinedEntityEvent(e)
end end
) )
return ____exports return ____exports

View file

@ -1,9 +1,9 @@
local ____lualib = require("lualib_bundle") local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local Map = ____lualib.Map local Map = ____lualib.Map
local __TS__Iterator = ____lualib.__TS__Iterator local __TS__Iterator = ____lualib.__TS__Iterator
local __TS__New = ____lualib.__TS__New local __TS__New = ____lualib.__TS__New
local ____exports = {} local ____exports = {}
local mapTilesUpdateDebounce, getTiles, getSurface, groupTiles, handleBuiltTileEvent, handleMinedTileEvent, Type
local ____eventTypeCheck = require("main.events.eventTypeCheck") local ____eventTypeCheck = require("main.events.eventTypeCheck")
local isEventType = ____eventTypeCheck.isEventType local isEventType = ____eventTypeCheck.isEventType
local ____converters = require("main.events.converters") local ____converters = require("main.events.converters")
@ -12,65 +12,16 @@ local ____EventDataCache = require("main.cache.EventDataCache")
local EventUpdatesManager = ____EventDataCache.default local EventUpdatesManager = ____EventDataCache.default
local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema")
local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData
function mapTilesUpdateDebounce(surface, chunkPosition, tiles, event, updater, expirationDurationTicks) local ____entityUpdates = require("main.events.entityUpdates")
if surface == nil then local EntityUpdates = ____entityUpdates.default
return local Type = KafkatorioPacketData.Type
end local MapChunkUpdateHandler = __TS__Class()
local eventName = Converters.eventNameString(event.name) MapChunkUpdateHandler.name = "MapChunkUpdateHandler"
local key = {surfaceIndex = surface.index, chunkPosition = chunkPosition} function MapChunkUpdateHandler.prototype.____constructor(self)
EventUpdatesManager:debounce(
key,
Type.MapChunkUpdate,
function(data)
if data.tileDictionary == nil then
data.tileDictionary = {tilesXY = {}, protos = {}}
end
local protosCount = table_size(data.tileDictionary.protos)
for ____, tile in ipairs(tiles) do
local ____data_tileDictionary_protos_1, ____tile_name_2 = data.tileDictionary.protos, tile.name
if ____data_tileDictionary_protos_1[____tile_name_2] == nil then
local ____protosCount_0 = protosCount
protosCount = ____protosCount_0 + 1
____data_tileDictionary_protos_1[____tile_name_2] = ____protosCount_0
end
local protoKey = data.tileDictionary.protos[tile.name]
local xString = tostring(tile.position.x)
local yString = tostring(tile.position.y)
local ____data_tileDictionary_tilesXY_3, ____xString_4 = data.tileDictionary.tilesXY, xString
if ____data_tileDictionary_tilesXY_3[____xString_4] == nil then
____data_tileDictionary_tilesXY_3[____xString_4] = {}
end
data.tileDictionary.tilesXY[xString][yString] = protoKey
end
if data.events == nil then
data.events = {}
end
local ____data_events_5, ____eventName_6 = data.events, eventName
if ____data_events_5[____eventName_6] == nil then
____data_events_5[____eventName_6] = {}
end
local ____data_events_eventName_7 = data.events[eventName]
____data_events_eventName_7[#____data_events_eventName_7 + 1] = event.tick
if updater ~= nil then
updater(data)
end
end,
expirationDurationTicks
)
end end
function getTiles(surface, area) function MapChunkUpdateHandler.prototype.handleChunkGeneratedEvent(self, event, expirationDurationTicks)
local ____surface_find_tiles_filtered_result_8 = surface local tiles = event.surface.find_tiles_filtered({area = event.area})
if ____surface_find_tiles_filtered_result_8 ~= nil then MapChunkUpdateHandler:mapTilesUpdateDebounce(
____surface_find_tiles_filtered_result_8 = ____surface_find_tiles_filtered_result_8.find_tiles_filtered({area = area})
end
return ____surface_find_tiles_filtered_result_8 or ({})
end
function getSurface(surfaceIndex)
return game.surfaces[surfaceIndex]
end
function ____exports.handleChunkGeneratedEvent(event, expirationDurationTicks)
local tiles = getTiles(event.surface, event.area)
mapTilesUpdateDebounce(
event.surface, event.surface,
Converters.convertMapTablePosition(event.position), Converters.convertMapTablePosition(event.position),
tiles, tiles,
@ -79,38 +30,19 @@ function ____exports.handleChunkGeneratedEvent(event, expirationDurationTicks)
expirationDurationTicks expirationDurationTicks
) )
end end
function groupTiles(tiles) function MapChunkUpdateHandler.prototype.handleBuiltTileEvent(self, event)
local mapChunkPositionToTiles = __TS__New(Map) local surface = game.get_surface(event.surface_index)
for ____, tile in ipairs(tiles) do
local chunkPosition = {
math.floor(tile.position.x / 32),
math.floor(tile.position.y / 32)
}
if not mapChunkPositionToTiles:has(chunkPosition) then
mapChunkPositionToTiles:set(chunkPosition, {})
end
local ____mapChunkPositionToTiles_get_result_push_result_10 = mapChunkPositionToTiles:get(chunkPosition)
if ____mapChunkPositionToTiles_get_result_push_result_10 ~= nil then
local ____temp_11 = mapChunkPositionToTiles:get(chunkPosition)
____temp_11[#____temp_11 + 1] = tile
____mapChunkPositionToTiles_get_result_push_result_10 = nil
end
end
return mapChunkPositionToTiles
end
function handleBuiltTileEvent(event)
local surface = getSurface(event.surface_index)
if surface == nil then if surface == nil then
local eventName = Converters.eventNameString(event.name) local eventName = Converters.eventNameString(event.name)
log("[handleBuiltTileEvent] undefined surface " .. eventName) log("[handleBuiltTileEvent] undefined surface " .. eventName)
return return
end end
local tiles = Converters.convertPlacedTiles(event.tile, event.tiles) local tiles = Converters.convertPlacedTiles(event.tile, event.tiles)
local groupedTiles = groupTiles(tiles) local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1] local chunkPos = ____value[1]
local tiles = ____value[2] local tiles = ____value[2]
mapTilesUpdateDebounce( MapChunkUpdateHandler:mapTilesUpdateDebounce(
surface, surface,
chunkPos, chunkPos,
tiles, tiles,
@ -121,12 +53,15 @@ function handleBuiltTileEvent(event)
return return
end end
if isEventType(event, defines.events.on_robot_built_tile) then if isEventType(event, defines.events.on_robot_built_tile) then
local ____data_15 = data local ____data_2 = data
local ____event_robot_unit_number_13 = event.robot local ____event_robot_unit_number_0 = event.robot
if ____event_robot_unit_number_13 ~= nil then if ____event_robot_unit_number_0 ~= nil then
____event_robot_unit_number_13 = ____event_robot_unit_number_13.unit_number ____event_robot_unit_number_0 = ____event_robot_unit_number_0.unit_number
end end
____data_15.robot = {unitNumber = ____event_robot_unit_number_13 or nil, name = event.robot.name, protoType = event.robot.type} ____data_2.robot = {
unitNumber = ____event_robot_unit_number_0 or nil,
protoId = Converters.prototypeId(event.robot.type, event.robot.name)
}
return return
end end
local exhaustiveCheck = event local exhaustiveCheck = event
@ -134,19 +69,19 @@ function handleBuiltTileEvent(event)
) )
end end
end end
function handleMinedTileEvent(event) function MapChunkUpdateHandler.prototype.handleMinedTileEvent(self, event)
local surface = getSurface(event.surface_index) local surface = game.get_surface(event.surface_index)
if surface == nil then if surface == nil then
local eventName = Converters.eventNameString(event.name) local eventName = Converters.eventNameString(event.name)
log("[handleMinedTileEvent] undefined surface " .. eventName) log("[handleMinedTileEvent] undefined surface " .. eventName)
return return
end end
local tiles = Converters.convertRemovedTiles(surface, event.tiles) local tiles = Converters.convertRemovedTiles(surface, event.tiles)
local groupedTiles = groupTiles(tiles) local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1] local chunkPos = ____value[1]
local tiles = ____value[2] local tiles = ____value[2]
mapTilesUpdateDebounce( MapChunkUpdateHandler:mapTilesUpdateDebounce(
surface, surface,
chunkPos, chunkPos,
tiles, tiles,
@ -157,12 +92,15 @@ function handleMinedTileEvent(event)
return return
end end
if isEventType(event, defines.events.on_robot_mined_tile) then if isEventType(event, defines.events.on_robot_mined_tile) then
local ____data_18 = data local ____data_5 = data
local ____event_robot_unit_number_16 = event.robot local ____event_robot_unit_number_3 = event.robot
if ____event_robot_unit_number_16 ~= nil then if ____event_robot_unit_number_3 ~= nil then
____event_robot_unit_number_16 = ____event_robot_unit_number_16.unit_number ____event_robot_unit_number_3 = ____event_robot_unit_number_3.unit_number
end end
____data_18.robot = {unitNumber = ____event_robot_unit_number_16 or nil, name = event.robot.name, protoType = event.robot.type} ____data_5.robot = {
unitNumber = ____event_robot_unit_number_3 or nil,
protoId = Converters.prototypeId(event.robot.type, event.robot.name)
}
return return
end end
local exhaustiveCheck = event local exhaustiveCheck = event
@ -170,78 +108,155 @@ function handleMinedTileEvent(event)
) )
end end
end end
Type = KafkatorioPacketData.Type function MapChunkUpdateHandler.prototype.handleScriptSetTilesEvent(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
local groupedTiles = MapChunkUpdateHandler:groupTiles(event.tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
MapChunkUpdateHandler:mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
end
end
function MapChunkUpdateHandler.prototype.handlePreChunkDeleted(self, event)
local surface = game.get_surface(event.surface_index)
if surface == nil then
return
end
for ____, position in ipairs(event.positions) do
local key = {surfaceIndex = surface.index, chunkPosition = {position.x, position.y}}
EventUpdatesManager:debounce(
key,
Type.MapChunkTileUpdate,
function(data)
data.isDeleted = true
return true
end,
0
)
end
end
function MapChunkUpdateHandler.mapTilesUpdateDebounce(self, surface, chunkPosition, tiles, event, updater, expirationDurationTicks)
if surface == nil then
return
end
local eventName = Converters.eventNameString(event.name)
local key = {surfaceIndex = surface.index, chunkPosition = chunkPosition}
EventUpdatesManager:debounce(
key,
Type.MapChunkTileUpdate,
function(data)
if data.tileDictionary == nil then
data.tileDictionary = {tilesXY = {}, protos = {}}
end
local protosCount = table_size(data.tileDictionary.protos)
for ____, tile in ipairs(tiles) do
local protoId = Converters.prototypeId("tile", tile.name)
if data.tileDictionary.protos[protoId] == nil then
end
local ____data_tileDictionary_protos_7, ____protoId_8 = data.tileDictionary.protos, protoId
if ____data_tileDictionary_protos_7[____protoId_8] == nil then
local ____protosCount_6 = protosCount
protosCount = ____protosCount_6 + 1
____data_tileDictionary_protos_7[____protoId_8] = ____protosCount_6
end
local protoKey = data.tileDictionary.protos[protoId]
local xString = tostring(tile.position.x)
local yString = tostring(tile.position.y)
local ____data_tileDictionary_tilesXY_9, ____xString_10 = data.tileDictionary.tilesXY, xString
if ____data_tileDictionary_tilesXY_9[____xString_10] == nil then
____data_tileDictionary_tilesXY_9[____xString_10] = {}
end
data.tileDictionary.tilesXY[xString][yString] = protoKey
end
if data.events == nil then
data.events = {}
end
local ____data_events_11, ____eventName_12 = data.events, eventName
if ____data_events_11[____eventName_12] == nil then
____data_events_11[____eventName_12] = {}
end
local ____data_events_eventName_13 = data.events[eventName]
____data_events_eventName_13[#____data_events_eventName_13 + 1] = event.tick
if updater ~= nil then
updater(data)
end
end,
expirationDurationTicks
)
end
function MapChunkUpdateHandler.groupTiles(self, tiles)
local mapChunkPositionToTiles = __TS__New(Map)
for ____, tile in ipairs(tiles) do
local chunkPosition = {
math.floor(tile.position.x / 32),
math.floor(tile.position.y / 32)
}
if not mapChunkPositionToTiles:has(chunkPosition) then
mapChunkPositionToTiles:set(chunkPosition, {})
end
local ____mapChunkPositionToTiles_get_result_push_result_14 = mapChunkPositionToTiles:get(chunkPosition)
if ____mapChunkPositionToTiles_get_result_push_result_14 ~= nil then
local ____temp_15 = mapChunkPositionToTiles:get(chunkPosition)
____temp_15[#____temp_15 + 1] = tile
____mapChunkPositionToTiles_get_result_push_result_14 = nil
end
end
return mapChunkPositionToTiles
end
local MapChunkUpdate = __TS__New(MapChunkUpdateHandler)
____exports.default = MapChunkUpdate
script.on_event( script.on_event(
defines.events.on_chunk_generated, defines.events.on_chunk_generated,
function(e) function(e)
log("on_chunk_generated " .. tostring(e.tick)) log("on_chunk_generated " .. tostring(e.tick))
____exports.handleChunkGeneratedEvent(e) MapChunkUpdate:handleChunkGeneratedEvent(e)
EntityUpdates:handleChunkGeneratedEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.script_raised_set_tiles, defines.events.script_raised_set_tiles,
function(event) function(event)
log("script_raised_set_tiles " .. tostring(event.tick)) log("script_raised_set_tiles " .. tostring(event.tick))
local surface = getSurface(event.surface_index) MapChunkUpdate:handleScriptSetTilesEvent(event)
if surface == nil then
return
end
local groupedTiles = groupTiles(event.tiles)
for ____, ____value in __TS__Iterator(groupedTiles) do
local chunkPos = ____value[1]
local tiles = ____value[2]
mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
end
end end
) )
script.on_event( script.on_event(
defines.events.on_player_built_tile, defines.events.on_player_built_tile,
function(e) function(e)
log("on_player_built_tile " .. tostring(e.tick)) log("on_player_built_tile " .. tostring(e.tick))
handleBuiltTileEvent(e) MapChunkUpdate:handleBuiltTileEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.on_robot_built_tile, defines.events.on_robot_built_tile,
function(e) function(e)
log("on_robot_built_tile " .. tostring(e.tick)) log("on_robot_built_tile " .. tostring(e.tick))
handleBuiltTileEvent(e) MapChunkUpdate:handleBuiltTileEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.on_player_mined_tile, defines.events.on_player_mined_tile,
function(e) function(e)
log("on_player_mined_tile " .. tostring(e.tick)) log("on_player_mined_tile " .. tostring(e.tick))
handleMinedTileEvent(e) MapChunkUpdate:handleMinedTileEvent(e)
EntityUpdates:handleMinedTileEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.on_robot_mined_tile, defines.events.on_robot_mined_tile,
function(e) function(e)
log("on_robot_mined_tile " .. tostring(e.tick)) log("on_robot_mined_tile " .. tostring(e.tick))
handleMinedTileEvent(e) MapChunkUpdate:handleMinedTileEvent(e)
end end
) )
script.on_event( script.on_event(
defines.events.on_pre_chunk_deleted, defines.events.on_pre_chunk_deleted,
function(e) function(e)
log("on_pre_chunk_deleted " .. tostring(e.tick)) log("on_pre_chunk_deleted " .. tostring(e.tick))
local surface = getSurface(e.surface_index) MapChunkUpdate:handlePreChunkDeleted(e)
if surface == nil then
return
end
for ____, position in ipairs(e.positions) do
local key = {surfaceIndex = surface.index, chunkPosition = {position.x, position.y}}
EventUpdatesManager:debounce(
key,
Type.MapChunkUpdate,
function(data)
data.isDeleted = true
return true
end,
0
)
end
end end
) )
return ____exports return ____exports

View file

@ -115,7 +115,10 @@ script.on_event(
data.ticksToRespawn = player.ticks_to_respawn or nil data.ticksToRespawn = player.ticks_to_respawn or nil
playerOnlineInfo(player, data) playerOnlineInfo(player, data)
if e.cause ~= nil then if e.cause ~= nil then
data.diedCause = {unitNumber = e.cause.unit_number or nil, name = e.cause.name, protoType = e.cause.type} data.diedCause = {
unitNumber = e.cause.unit_number or nil,
protoId = Converters.prototypeId(e.cause.type, e.cause.name)
}
end end
end end
) )

View file

@ -22,7 +22,7 @@ function getMapTilePrototypes()
for ____, tile in pairs(game.tile_prototypes) do for ____, tile in pairs(game.tile_prototypes) do
tiles[#tiles + 1] = { tiles[#tiles + 1] = {
type = FactorioPrototype.Type.MapTile, type = FactorioPrototype.Type.MapTile,
name = tile.name, protoId = Converters.prototypeId("tile", tile.name),
order = tile.order, order = tile.order,
layer = tile.layer, layer = tile.layer,
collisionMasks = Converters.convertCollisionMaskToNames(tile.collision_mask), collisionMasks = Converters.convertCollisionMaskToNames(tile.collision_mask),

View file

@ -5,12 +5,12 @@ local ____eventTypeCheck = require("main.events.eventTypeCheck")
local isEventType = ____eventTypeCheck.isEventType local isEventType = ____eventTypeCheck.isEventType
local ____converters = require("main.events.converters") local ____converters = require("main.events.converters")
local Converters = ____converters.Converters local Converters = ____converters.Converters
local ____mapChunkUpdates = require("main.events.mapChunkUpdates")
local handleChunkGeneratedEvent = ____mapChunkUpdates.handleChunkGeneratedEvent
local ____surfaceUpdates = require("main.events.surfaceUpdates") local ____surfaceUpdates = require("main.events.surfaceUpdates")
local handleSurfaceUpdate = ____surfaceUpdates.handleSurfaceUpdate local handleSurfaceUpdate = ____surfaceUpdates.handleSurfaceUpdate
local ____EventDataCache = require("main.cache.EventDataCache") local ____EventDataCache = require("main.cache.EventDataCache")
local EventCacheService = ____EventDataCache.default local EventCacheService = ____EventDataCache.default
local ____mapChunkUpdates = require("main.events.mapChunkUpdates")
local MapChunkUpdate = ____mapChunkUpdates.default
script.on_event( script.on_event(
defines.events.on_tick, defines.events.on_tick,
function(event) function(event)
@ -38,7 +38,7 @@ script.on_event(
if isEventType(event, defines.events.on_chunk_generated) then if isEventType(event, defines.events.on_chunk_generated) then
local eName = Converters.eventNameString(event.name) local eName = Converters.eventNameString(event.name)
log((((("[on_tick:" .. tostring(event.tick)) .. "] dequed event ") .. eName) .. ", delay ") .. tostring(i)) log((((("[on_tick:" .. tostring(event.tick)) .. "] dequed event ") .. eName) .. ", delay ") .. tostring(i))
handleChunkGeneratedEvent(event, i) MapChunkUpdate:handleChunkGeneratedEvent(event, i)
i = i + 1 i = i + 1
end end
end end

View file

@ -34,7 +34,7 @@ end
function KafkatorioSettingsConfig.cacheDurationSettingName(self, ____type) function KafkatorioSettingsConfig.cacheDurationSettingName(self, ____type)
return "kafkatorio:cache-expiration-seconds_" .. __TS__StringReplaceAll(____type, ".", "-") return "kafkatorio:cache-expiration-seconds_" .. __TS__StringReplaceAll(____type, ".", "-")
end end
KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds = {["kafkatorio.packet.keyed.PlayerUpdate"] = 0.5, ["kafkatorio.packet.keyed.MapChunkUpdate"] = 30, ["kafkatorio.packet.keyed.EntityUpdate"] = 5} KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds = {["kafkatorio.packet.keyed.PlayerUpdate"] = 0.5, ["kafkatorio.packet.keyed.MapChunkTileUpdate"] = 30, ["kafkatorio.packet.keyed.MapChunkEntityUpdate"] = 30, ["kafkatorio.packet.keyed.EntityUpdate"] = 5}
local KafkatorioSettings = __TS__New(____exports.KafkatorioSettingsConfig) local KafkatorioSettings = __TS__New(____exports.KafkatorioSettingsConfig)
____exports.default = KafkatorioSettings ____exports.default = KafkatorioSettings
return ____exports return ____exports

View file

@ -1,14 +1,16 @@
[mod-setting-name] [mod-setting-name]
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-PlayerUpdate=Player update rate (seconds) kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-PlayerUpdate=Player update rate (seconds)
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkUpdate=Map update rate (seconds) kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkTileUpdate=Map tile update rate (seconds)
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkEntityUpdate=Entity update rate (seconds)
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-EntityUpdate=Entity update rate (seconds) kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-EntityUpdate=Entity update rate (seconds)
[mod-setting-description] [mod-setting-description]
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-PlayerUpdate=How frequently Player updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (0.25 seconds) is probably fine! kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-PlayerUpdate=How frequently Player updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (0.25 seconds) is probably fine!
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkUpdate=How frequently Map updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (30 seconds) is probably fine! kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkTileUpdate=How frequently Map updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (30 seconds) is probably fine!
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-MapChunkEntityUpdate=How frequently entity updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (30 seconds) is probably fine!
kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-EntityUpdate=How frequently Entity updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (5 seconds) is probably fine! kafkatorio:cache-expiration-seconds_kafkatorio-packet-keyed-EntityUpdate=How frequently Entity updates are sent to the Kafkatorio server, in seconds. Lower means updates are sent more frequently, which may cause network congestion or reduce performance. The default (5 seconds) is probably fine!

View file

@ -1,7 +1,7 @@
import {initGlobal} from "./main/global-init"; import {initGlobal} from "./main/global-init";
import {emitPrototypes} from "./main/events/prototypeUpdates"; import {emitPrototypes} from "./main/events/prototypeUpdates";
require("./main/events/registerHandlers") require("./main/events/registerEventListeners")
require("./main/events/mapChunkUpdates") require("./main/events/mapChunkUpdates")
require("./main/events/playerUpdates") require("./main/events/playerUpdates")
require("./main/events/entityUpdates") require("./main/events/entityUpdates")

View file

@ -14,7 +14,8 @@ export type KafkatorioPacketData =
| KafkatorioPacketData.ConsoleCommandUpdate | KafkatorioPacketData.ConsoleCommandUpdate
| KafkatorioPacketData.EntityUpdate | KafkatorioPacketData.EntityUpdate
| KafkatorioPacketData.Error | KafkatorioPacketData.Error
| KafkatorioPacketData.MapChunkUpdate | KafkatorioPacketData.MapChunkEntityUpdate
| KafkatorioPacketData.MapChunkTileUpdate
| KafkatorioPacketData.PlayerUpdate | KafkatorioPacketData.PlayerUpdate
| KafkatorioPacketData.PrototypesUpdate | KafkatorioPacketData.PrototypesUpdate
| KafkatorioPacketData.SurfaceUpdate; | KafkatorioPacketData.SurfaceUpdate;
@ -27,7 +28,8 @@ export namespace KafkatorioPacketData {
PrototypesUpdate = "kafkatorio.packet.instant.PrototypesUpdate", PrototypesUpdate = "kafkatorio.packet.instant.PrototypesUpdate",
SurfaceUpdate = "kafkatorio.packet.instant.SurfaceUpdate", SurfaceUpdate = "kafkatorio.packet.instant.SurfaceUpdate",
EntityUpdate = "kafkatorio.packet.keyed.EntityUpdate", EntityUpdate = "kafkatorio.packet.keyed.EntityUpdate",
MapChunkUpdate = "kafkatorio.packet.keyed.MapChunkUpdate", MapChunkEntityUpdate = "kafkatorio.packet.keyed.MapChunkEntityUpdate",
MapChunkTileUpdate = "kafkatorio.packet.keyed.MapChunkTileUpdate",
PlayerUpdate = "kafkatorio.packet.keyed.PlayerUpdate", PlayerUpdate = "kafkatorio.packet.keyed.PlayerUpdate",
Error = "kafkatorio.packet.KafkatorioPacketData.Error", Error = "kafkatorio.packet.KafkatorioPacketData.Error",
} }
@ -77,12 +79,18 @@ export namespace KafkatorioPacketData {
lastUser?: UInt | null; lastUser?: UInt | null;
localisedDescription?: string | null; localisedDescription?: string | null;
localisedName?: string | null; localisedName?: string | null;
prototype?: PrototypeName | null;
} }
export interface MapChunkUpdate { export interface MapChunkEntityUpdate {
type: KafkatorioPacketData.Type.MapChunkUpdate; type: KafkatorioPacketData.Type.MapChunkEntityUpdate;
key: MapChunkUpdateKey; key: MapChunkEntityUpdateKey;
events?: { [key: EventName]: Tick[] } | null;
distinctEntities?: { [key: string]: FactorioEntityData } | null;
}
export interface MapChunkTileUpdate {
type: KafkatorioPacketData.Type.MapChunkTileUpdate;
key: MapChunkTileUpdateKey;
events?: { [key: EventName]: Tick[] } | null; events?: { [key: EventName]: Tick[] } | null;
player?: PlayerIndex | null; player?: PlayerIndex | null;
robot?: EntityIdentifiersData | null; robot?: EntityIdentifiersData | null;
@ -132,16 +140,11 @@ export interface ConfigurationUpdateGameData {
newVersion?: string | null; newVersion?: string | null;
} }
export type PlayerIndex = UInt;
export type SurfaceIndex = UInt;
export type Double = double; export type Double = double;
export interface EntityUpdateKey { export interface EntityUpdateKey {
unitNumber: UnitNumber; unitNumber: UnitNumber;
name: string; protoId: PrototypeId;
protoType: string;
} }
export type MapEntityPosition = [ export type MapEntityPosition = [
@ -153,32 +156,33 @@ export type UByte = uint8;
export type Float = float; export type Float = float;
export type PrototypeName = string; export interface MapChunkEntityUpdateKey {
protoId: PrototypeId;
surfaceIndex: SurfaceIndex;
chunkPosition: MapChunkPosition;
}
export interface MapChunkUpdateKey { export interface MapChunkTileUpdateKey {
chunkPosition: MapChunkPosition; chunkPosition: MapChunkPosition;
surfaceIndex: SurfaceIndex; surfaceIndex: SurfaceIndex;
} }
export interface EntityIdentifiersData { export interface EntityIdentifiersData {
unitNumber?: UnitNumber | null; unitNumber?: UnitNumber | null;
name: string; protoId: PrototypeId;
protoType: string;
} }
export type ForceIndex = UInt; export type ForceIndex = UInt & { __ForceIndex__: void };
export interface MapTileDictionary { export interface MapTileDictionary {
tilesXY: { [key: string]: { [key: string]: PrototypeKey } }; tilesXY: { [key: string]: { [key: string]: PrototypeKey } };
protos: { [key: PrototypeName]: PrototypeKey }; protos: { [key: PrototypeId]: PrototypeKey };
} }
export interface PlayerUpdateKey { export interface PlayerUpdateKey {
index: PlayerIndex; index: PlayerIndex;
} }
export type UnitNumber = UInt;
export type Colour = [ export type Colour = [
red: Float, red: Float,
green: Float, green: Float,
@ -206,7 +210,7 @@ export namespace FactorioPrototype {
export interface Entity { export interface Entity {
type: FactorioPrototype.Type.Entity; type: FactorioPrototype.Type.Entity;
name: PrototypeName; protoId: PrototypeId;
mapColour: Colour; mapColour: Colour;
protoType: string; protoType: string;
objectName: string; objectName: string;
@ -220,7 +224,7 @@ export namespace FactorioPrototype {
export interface MapTile { export interface MapTile {
type: FactorioPrototype.Type.MapTile; type: FactorioPrototype.Type.MapTile;
name: PrototypeName; protoId: PrototypeId;
mapColour: Colour; mapColour: Colour;
layer: UInt; layer: UInt;
collisionMasks: List; collisionMasks: List;
@ -229,7 +233,9 @@ export namespace FactorioPrototype {
} }
} }
export type EventName = string; export type PrototypeId = string & { __PrototypeId__: void };
export type EventName = string & { __EventName__: void };
export type Byte = int8; export type Byte = int8;
@ -238,22 +244,114 @@ export type MapChunkPosition = [
y: Int, y: Int,
]; ];
export type FactorioEntityData =
| FactorioEntityData.Resource
| FactorioEntityData.Standard;
export namespace FactorioEntityData {
export enum Type {
Resource = "kafkatorio.entity.FactorioEntityData.Resource",
Standard = "kafkatorio.entity.FactorioEntityData.Standard",
}
export interface Resource {
type: FactorioEntityData.Type.Resource;
protoId: PrototypeId;
status?: EntityStatus | null;
position: MapEntityPosition;
amount: UInt;
initialAmount?: UInt | null;
}
export interface Standard {
type: FactorioEntityData.Type.Standard;
protoId: PrototypeId;
status?: EntityStatus | null;
position: MapEntityPosition;
graphicsVariation?: UByte | null;
health?: Float | null;
isActive?: boolean | null;
isRotatable?: boolean | null;
lastUser?: UInt | null;
localisedDescription?: string | null;
localisedName?: string | null;
}
}
export interface MiningProperties { export interface MiningProperties {
canBeMined: boolean; canBeMined: boolean;
products: MinedProduct[] | null; products: MinedProduct[] | null;
} }
export type List = any; export type List = any & { __List__: void };
export type PrototypeKey = Int; export enum EntityStatus {
CANT_DIVIDE_SEGMENTS = "CANT_DIVIDE_SEGMENTS",
export interface MinedProduct { CHARGING = "CHARGING",
type: MinedProductType; CLOSED_BY_CIRCUIT_NETWORK = "CLOSED_BY_CIRCUIT_NETWORK",
name: PrototypeName; DISABLED = "DISABLED",
amount: Double | null; DISABLED_BY_CONTROL_BEHAVIOR = "DISABLED_BY_CONTROL_BEHAVIOR",
DISABLED_BY_SCRIPT = "DISABLED_BY_SCRIPT",
DISCHARGING = "DISCHARGING",
FLUID_INGREDIENT_SHORTAGE = "FLUID_INGREDIENT_SHORTAGE",
FULLY_CHARGED = "FULLY_CHARGED",
FULL_OUTPUT = "FULL_OUTPUT",
ITEM_INGREDIENT_SHORTAGE = "ITEM_INGREDIENT_SHORTAGE",
LAUNCHING_ROCKET = "LAUNCHING_ROCKET",
LOW_INPUT_FLUID = "LOW_INPUT_FLUID",
LOW_POWER = "LOW_POWER",
LOW_TEMPERATURE = "LOW_TEMPERATURE",
MARKED_FOR_DECONSTRUCTION = "MARKED_FOR_DECONSTRUCTION",
MISSING_REQUIRED_FLUID = "MISSING_REQUIRED_FLUID",
MISSING_SCIENCE_PACKS = "MISSING_SCIENCE_PACKS",
NETWORKS_CONNECTED = "NETWORKS_CONNECTED",
NETWORKS_DISCONNECTED = "NETWORKS_DISCONNECTED",
NORMAL = "NORMAL",
NOT_CONNECTED_TO_RAIL = "NOT_CONNECTED_TO_RAIL",
NOT_PLUGGED_IN_ELECTRIC_NETWORK = "NOT_PLUGGED_IN_ELECTRIC_NETWORK",
NO_AMMO = "NO_AMMO",
NO_FUEL = "NO_FUEL",
NO_INGREDIENTS = "NO_INGREDIENTS",
NO_INPUT_FLUID = "NO_INPUT_FLUID",
NO_MINABLE_RESOURCES = "NO_MINABLE_RESOURCES",
NO_MODULES_TO_TRANSMIT = "NO_MODULES_TO_TRANSMIT",
NO_POWER = "NO_POWER",
NO_RECIPE = "NO_RECIPE",
NO_RESEARCH_IN_PROGRESS = "NO_RESEARCH_IN_PROGRESS",
OPENED_BY_CIRCUIT_NETWORK = "OPENED_BY_CIRCUIT_NETWORK",
OUT_OF_LOGISTIC_NETWORK = "OUT_OF_LOGISTIC_NETWORK",
PREPARING_ROCKET_FOR_LAUNCH = "PREPARING_ROCKET_FOR_LAUNCH",
RECHARGING_AFTER_POWER_OUTAGE = "RECHARGING_AFTER_POWER_OUTAGE",
TURNED_OFF_DURING_DAYTIME = "TURNED_OFF_DURING_DAYTIME",
WAITING_FOR_SOURCE_ITEMS = "WAITING_FOR_SOURCE_ITEMS",
WAITING_FOR_SPACE_IN_DESTINATION = "WAITING_FOR_SPACE_IN_DESTINATION",
WAITING_FOR_TARGET_TO_BE_BUILT = "WAITING_FOR_TARGET_TO_BE_BUILT",
WAITING_FOR_TRAIN = "WAITING_FOR_TRAIN",
WAITING_TO_LAUNCH_ROCKET = "WAITING_TO_LAUNCH_ROCKET",
WORKING = "WORKING",
} }
export enum MinedProductType { export type PrototypeKey = Int & { __PrototypeKey__: void };
item = "item",
fluid = "fluid", export type MinedProduct =
| MinedProduct.MinedProductFluid
| MinedProduct.MinedProductItem;
export namespace MinedProduct {
export enum Type {
MinedProductFluid = "kafkatorio.resource.MinedProduct.MinedProductFluid",
MinedProductItem = "kafkatorio.resource.MinedProduct.MinedProductItem",
}
export interface MinedProductFluid {
type: MinedProduct.Type.MinedProductFluid;
amount?: Double | null;
resultProtoId: PrototypeId;
}
export interface MinedProductItem {
type: MinedProduct.Type.MinedProductItem;
amount?: Double | null;
resultProtoId: PrototypeId;
}
} }

View file

@ -101,7 +101,7 @@ export namespace EventUpdates {
let countExpired = 0 let countExpired = 0
let countTotal = 0 let countTotal = 0
const expiredData: Array<KafkatorioKeyedPacketData> = [] const expiredData: Array<KafkatorioKeyedPacketData> = []
for (let [key, entry] of global.cache) { for (const [key, entry] of global.cache) {
countTotal++ countTotal++
if (this.isExpired(entry)) { if (this.isExpired(entry)) {
countExpired++ countExpired++

View file

@ -23,7 +23,7 @@ script.on_event(
const update: KafkatorioPacketData.ConsoleCommandUpdate = { const update: KafkatorioPacketData.ConsoleCommandUpdate = {
type: Type.ConsoleCommandUpdate, type: Type.ConsoleCommandUpdate,
authorPlayerIndex: event.player_index ?? null, authorPlayerIndex: event.player_index ?? null,
command: event.command, command: event.command,
parameters: event.parameters, parameters: event.parameters,
} }

View file

@ -1,16 +1,25 @@
import {EventName} from "../types"; import {DefinedEventName} from "../types";
import {Colour, MapChunkPosition} from "../../generated/kafkatorio-schema"; import {
Colour,
EntityStatus,
EventName,
FactorioEntityData,
MapChunkPosition,
PrototypeId,
} from "../../generated/kafkatorio-schema";
export namespace Converters { export namespace Converters {
const mapEventIdToName = new LuaTable<defines.Events, EventName>()
import floor = math.floor;
const mapEventIdToName = new LuaTable<defines.Events, DefinedEventName>()
for (const [eventName, eventId] of pairs(defines.events)) { for (const [eventName, eventId] of pairs(defines.events)) {
mapEventIdToName.set(eventId, eventName) mapEventIdToName.set(eventId, eventName)
} }
export function eventNameString(event: defines.Events): EventName { export function eventNameString(event: defines.Events): EventName {
return mapEventIdToName.get(event) return mapEventIdToName.get(event) as EventName
} }
@ -60,10 +69,115 @@ export namespace Converters {
export function convertCollisionMaskToNames(cm: CollisionMask): string[] { export function convertCollisionMaskToNames(cm: CollisionMask): string[] {
let masks: string[] = [] let masks: string[] = []
for (let [name] of pairs(cm)) { for (const [name] of pairs(cm)) {
masks.push(name) masks.push(name)
} }
return masks return masks
} }
export function convertResourceEntity(
entity: LuaEntity
): FactorioEntityData.Resource | null {
if (entity.type != "resource") {
return null
} else {
return {
type: FactorioEntityData.Type.Resource,
protoId: prototypeId(entity.type, entity.name),
status: convertEntityStatus(entity.status),
amount: entity.amount,
initialAmount: entity.initial_amount,
position: convertMapTablePosition(entity.position),
}
}
}
function convertEntityStatus(
status: defines.entity_status | undefined
): EntityStatus | null {
if (status == undefined) {
return null
} else {
return EntityStatusRecord[status]
}
}
export function prototypeIdEntity(entity: LuaEntity): PrototypeId {
return prototypeId(entity.type, entity.name)
}
export function prototypeId(type: string, name: string): PrototypeId {
return `${type}/${name}` as PrototypeId
}
export function tilePositionToChunkPosition(mapPosition: TilePositionTable): MapChunkPosition {
return [floor(mapPosition.x / 32), floor(mapPosition.y)]
}
export function mapPositionToChunkPosition(mapPosition: MapPositionTable): MapChunkPosition {
return [floor(mapPosition.x / 32), floor(mapPosition.y)]
}
export function entityStatus(status: defines.entity_status | undefined): EntityStatus | undefined {
if (status == undefined) {
return undefined
} else {
return EntityStatusRecord[status]
}
}
const EntityStatusRecord: Record<defines.entity_status, EntityStatus> = {
//@formatter:off
[ defines.entity_status.cant_divide_segments ]: EntityStatus.CANT_DIVIDE_SEGMENTS,
[ defines.entity_status.charging ]: EntityStatus.CHARGING,
[ defines.entity_status.closed_by_circuit_network ]: EntityStatus.CLOSED_BY_CIRCUIT_NETWORK,
[ defines.entity_status.disabled ]: EntityStatus.DISABLED,
[ defines.entity_status.disabled_by_control_behavior ]: EntityStatus.DISABLED_BY_CONTROL_BEHAVIOR,
[ defines.entity_status.disabled_by_script ]: EntityStatus.DISABLED_BY_SCRIPT,
[ defines.entity_status.discharging ]: EntityStatus.DISCHARGING,
[ defines.entity_status.fluid_ingredient_shortage ]: EntityStatus.FLUID_INGREDIENT_SHORTAGE,
[ defines.entity_status.fully_charged ]: EntityStatus.FULLY_CHARGED,
[ defines.entity_status.full_output ]: EntityStatus.FULL_OUTPUT,
[ defines.entity_status.item_ingredient_shortage ]: EntityStatus.ITEM_INGREDIENT_SHORTAGE,
[ defines.entity_status.launching_rocket ]: EntityStatus.LAUNCHING_ROCKET,
[ defines.entity_status.low_input_fluid ]: EntityStatus.LOW_INPUT_FLUID,
[ defines.entity_status.low_power ]: EntityStatus.LOW_POWER,
[ defines.entity_status.low_temperature ]: EntityStatus.LOW_TEMPERATURE,
[ defines.entity_status.marked_for_deconstruction ]: EntityStatus.MARKED_FOR_DECONSTRUCTION,
[ defines.entity_status.missing_required_fluid ]: EntityStatus.MISSING_REQUIRED_FLUID,
[ defines.entity_status.missing_science_packs ]: EntityStatus.MISSING_SCIENCE_PACKS,
[ defines.entity_status.networks_connected ]: EntityStatus.NETWORKS_CONNECTED,
[ defines.entity_status.networks_disconnected ]: EntityStatus.NETWORKS_DISCONNECTED,
[ defines.entity_status.normal ]: EntityStatus.NORMAL,
[ defines.entity_status.not_connected_to_rail ]: EntityStatus.NOT_CONNECTED_TO_RAIL,
[ defines.entity_status.not_plugged_in_electric_network ]: EntityStatus.NOT_PLUGGED_IN_ELECTRIC_NETWORK,
[ defines.entity_status.no_ammo ]: EntityStatus.NO_AMMO,
[ defines.entity_status.no_fuel ]: EntityStatus.NO_FUEL,
[ defines.entity_status.no_ingredients ]: EntityStatus.NO_INGREDIENTS,
[ defines.entity_status.no_input_fluid ]: EntityStatus.NO_INPUT_FLUID,
[ defines.entity_status.no_minable_resources ]: EntityStatus.NO_MINABLE_RESOURCES,
[ defines.entity_status.no_modules_to_transmit ]: EntityStatus.NO_MODULES_TO_TRANSMIT,
[ defines.entity_status.no_power ]: EntityStatus.NO_POWER,
[ defines.entity_status.no_recipe ]: EntityStatus.NO_RECIPE,
[ defines.entity_status.no_research_in_progress ]: EntityStatus.NO_RESEARCH_IN_PROGRESS,
[ defines.entity_status.opened_by_circuit_network ]: EntityStatus.OPENED_BY_CIRCUIT_NETWORK,
[ defines.entity_status.out_of_logistic_network ]: EntityStatus.OUT_OF_LOGISTIC_NETWORK,
[ defines.entity_status.preparing_rocket_for_launch ]: EntityStatus.PREPARING_ROCKET_FOR_LAUNCH,
[ defines.entity_status.recharging_after_power_outage ]: EntityStatus.RECHARGING_AFTER_POWER_OUTAGE,
[ defines.entity_status.turned_off_during_daytime ]: EntityStatus.TURNED_OFF_DURING_DAYTIME,
[ defines.entity_status.waiting_for_source_items ]: EntityStatus.WAITING_FOR_SOURCE_ITEMS,
[ defines.entity_status.waiting_for_space_in_destination ]: EntityStatus.WAITING_FOR_SPACE_IN_DESTINATION,
[ defines.entity_status.waiting_for_target_to_be_built ]: EntityStatus.WAITING_FOR_TARGET_TO_BE_BUILT,
[ defines.entity_status.waiting_for_train ]: EntityStatus.WAITING_FOR_TRAIN,
[ defines.entity_status.waiting_to_launch_rocket ]: EntityStatus.WAITING_TO_LAUNCH_ROCKET,
[ defines.entity_status.working ]: EntityStatus.WORKING,
//@formatter:on
}
} }

View file

@ -1,97 +1,276 @@
import {Converters} from "./converters"; import {Converters} from "./converters";
import EventDataCache from "../cache/EventDataCache"; import EventDataCache from "../cache/EventDataCache";
import { import {
EntityUpdateKey, EventName,
KafkatorioPacketData FactorioEntityData,
KafkatorioPacketData,
MapChunkPosition,
PrototypeId,
Tick,
} from "../../generated/kafkatorio-schema"; } from "../../generated/kafkatorio-schema";
export class EntityUpdatesHandler {
handleMinedTileEvent(event: OnPlayerMinedTileEvent | OnRobotMinedTileEvent) {
const surface = game.get_surface(event.surface_index)
if (surface == null) {
return
}
const tilesByChunk: LuaTable<MapChunkPosition, OldTileAndPosition> = new LuaTable<MapChunkPosition, OldTileAndPosition>()
for (const tile of event.tiles) {
const chunkPosition = Converters.tilePositionToChunkPosition(tile.position)
tilesByChunk.set(chunkPosition, tile)
}
for (const [chunkPos, tiles] of pairs(tilesByChunk)) {
const entities: FactorioEntityData.Resource[] = []
for (const tile in tiles) {
const resources: FactorioEntityData.Resource[] = EntityUpdatesHandler.getTileResourceEntities(surface, chunkPos)
for (const resource of resources) {
entities[entities.length] = resource
}
}
EntityUpdatesHandler.throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick as Tick,
event.surface_index,
[chunkPos[0], chunkPos[1]],
entities,
)
}
}
handleMinedEntityEvent(
event: OnPlayerMinedEntityEvent | OnRobotMinedEntityEvent,
) {
EntityUpdatesHandler.throttleEntityUpdate(event, event.entity)
}
handleBuiltEntityEvent(
event: OnBuiltEntityEvent | OnRobotBuiltEntityEvent,
) {
EntityUpdatesHandler.throttleEntityUpdate(event, event.created_entity)
}
handleChunkGeneratedEvent(event: OnChunkGeneratedEvent) {
const entities = EntityUpdatesHandler.getAreaResourceEntities(event.surface, event.area)
EntityUpdatesHandler.throttleResourceEntitiesUpdate(
Converters.eventNameString(event.name),
event.tick as Tick,
event.surface.index,
[event.position.x, event.position.y],
entities,
)
}
private static throttleEntityUpdate(event: EntityUpdateEvent, entity: LuaEntity) {
if (entity.unit_number == undefined) {
// ignore for now - I'm not sure how to track entities without a unit_number
return
}
const eventName = Converters.eventNameString(event.name)
const entityUpdateKey: KafkatorioPacketData.MapChunkEntityUpdate["key"] = {
protoId: Converters.prototypeIdEntity(entity),
surfaceIndex: entity.surface.index,
chunkPosition: Converters.mapPositionToChunkPosition(entity.position)
}
const entityUpdate: FactorioEntityData.Standard = {
type: FactorioEntityData.Type.Standard,
protoId: Converters.prototypeIdEntity(entity),
graphicsVariation: entity.graphics_variation,
health: entity.health,
isActive: entity.active,
isRotatable: entity.rotatable,
lastUser: entity.last_user?.index,
localisedDescription: null,
localisedName: null,
position: [entity.position.x, entity.position.y],
status: Converters.entityStatus(entity.status),
}
const entityKey: string = `${entity.unit_number}`
EventDataCache.throttle<KafkatorioPacketData.MapChunkEntityUpdate>(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
data => {
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
data.distinctEntities ??= {}
data.distinctEntities[entityKey] = entityUpdate
}
)
}
private static throttleResourceEntitiesUpdate(
eventName: EventName,
eventTick: Tick,
surfaceIndex: SurfaceIndex,
chunkPosition: MapChunkPosition,
entities: FactorioEntityData.Resource[],
) {
// first group by prototype ID
const entitiesByProtoId: { [protoId: PrototypeId]: FactorioEntityData.Resource[] } = {}
for (const entity of entities) {
entitiesByProtoId[entity.protoId] ??= []
entitiesByProtoId[entity.protoId].push(entity)
}
for (const [protoId, resourceEntities] of pairs(entitiesByProtoId)) {
// create an update for each prototype
const entityUpdateKey: KafkatorioPacketData.MapChunkEntityUpdate["key"] = {
protoId: protoId,
surfaceIndex: surfaceIndex,
chunkPosition: [chunkPosition[0], chunkPosition[1]],
}
EventDataCache.throttle<KafkatorioPacketData.MapChunkEntityUpdate>(
entityUpdateKey,
KafkatorioPacketData.Type.MapChunkEntityUpdate,
data => {
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(eventTick)
for (const entity of resourceEntities) {
const [x, y] = entity.position
const entityKey: string = `${x},${y}`
data.distinctEntities ??= {}
data.distinctEntities[entityKey] = entity
}
}
)
}
}
/** Get all resources on a tile-position */
private static getTileResourceEntities(
surface: LuaSurface,
mapPosition: MapPosition,
): FactorioEntityData.Resource[] {
const rawEntities = surface.find_entities_filtered({
position: mapPosition,
collision_mask: "resource-layer",
}
)
const resources: FactorioEntityData.Resource[] = []
for (const rawEntity of rawEntities) {
const entity = Converters.convertResourceEntity(rawEntity)
if (entity != null) {
resources[resources.length] = entity
}
}
return resources
}
/** Get all resources within a map-area */
private static getAreaResourceEntities(
surface: LuaSurface,
area: BoundingBoxTable,
): FactorioEntityData.Resource[] {
const rawEntities = surface.find_entities_filtered({
area: area,
collision_mask: "resource-layer",
}
)
const resources: FactorioEntityData.Resource[] = []
for (const rawEntity of rawEntities) {
const entity = Converters.convertResourceEntity(rawEntity)
if (entity != null) {
resources[resources.length] = entity
}
}
return resources
}
}
const EntityUpdates = new EntityUpdatesHandler()
export default EntityUpdates
script.on_event(defines.events.on_built_entity, (e: OnBuiltEntityEvent) => { script.on_event(defines.events.on_built_entity, (e: OnBuiltEntityEvent) => {
log(`on_built_entity ${e.tick}`) log(`on_built_entity ${e.tick}`)
handleBuiltEntityEvent(e) EntityUpdates.handleBuiltEntityEvent(e)
}) })
script.on_event(defines.events.on_robot_built_entity, (e: OnRobotBuiltEntityEvent) => { script.on_event(defines.events.on_robot_built_entity, (e: OnRobotBuiltEntityEvent) => {
log(`on_robot_built_entity ${e.tick}`) log(`on_robot_built_entity ${e.tick}`)
handleBuiltEntityEvent(e) EntityUpdates.handleBuiltEntityEvent(e)
}) })
function handleBuiltEntityEvent(event: OnBuiltEntityEvent | OnRobotBuiltEntityEvent) {
const eventName = Converters.eventNameString(event.name)
if (event.created_entity.unit_number == undefined) {
return
}
const key: EntityUpdateKey = {
name: event.created_entity.name,
protoType: event.created_entity.prototype.name,
unitNumber: event.created_entity.unit_number
}
EventDataCache.debounce<KafkatorioPacketData.EntityUpdate>(
key,
KafkatorioPacketData.Type.EntityUpdate,
data => {
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
data.chunkPosition = Converters.convertMapTablePosition(event.created_entity.position)
data.graphicsVariation = event.created_entity.graphics_variation
data.health = event.created_entity.health
data.isActive = event.created_entity.active
data.isRotatable = event.created_entity.rotatable
data.lastUser = event.created_entity.last_user?.index
data.prototype = event.created_entity.prototype.name
}
)
}
script.on_event(defines.events.on_player_mined_entity, (e: OnPlayerMinedEntityEvent) => { script.on_event(defines.events.on_player_mined_entity, (e: OnPlayerMinedEntityEvent) => {
log(`on_player_mined_entity ${e.tick}`) log(`on_player_mined_entity ${e.tick}`)
handleMinedEntityEvent(e) EntityUpdates.handleMinedEntityEvent(e)
}) })
script.on_event(defines.events.on_robot_mined_entity, (e: OnRobotMinedEntityEvent) => { script.on_event(defines.events.on_robot_mined_entity, (e: OnRobotMinedEntityEvent) => {
log(`on_robot_mined_entity ${e.tick}`) log(`on_robot_mined_entity ${e.tick}`)
handleMinedEntityEvent(e) EntityUpdates.handleMinedEntityEvent(e)
}) })
function handleMinedEntityEvent(event: OnPlayerMinedEntityEvent | OnRobotMinedEntityEvent) { type EntityUpdateEvent =
const eventName = Converters.eventNameString(event.name) | OnBuiltEntityEvent
if (event.entity.unit_number == undefined) { | OnEntityClonedEvent
return | OnEntityDamagedEvent
} | OnEntityDestroyedEvent
| OnEntityDiedEvent
| OnEntityLogisticSlotChangedEvent
| OnEntityRenamedEvent
| OnEntitySettingsPastedEvent
| OnEntitySpawnedEvent
const key: EntityUpdateKey = { | OnPlayerMinedEntityEvent
name: event.entity.name, | OnPlayerRepairedEntityEvent
protoType: event.entity.prototype.name, | OnPlayerRotatedEntityEvent
unitNumber: event.entity.unit_number
}
EventDataCache.debounce<KafkatorioPacketData.EntityUpdate>( | OnRobotMinedEntityEvent
key, | OnRobotBuiltEntityEvent
KafkatorioPacketData.Type.EntityUpdate,
data => {
data.events ??= {} | OnPostEntityDiedEvent
data.events[eventName] ??= [] | OnPreEntitySettingsPastedEvent
data.events[eventName].push(event.tick)
data.chunkPosition = Converters.convertMapTablePosition(event.entity.position) | OnSelectedEntityChangedEvent
data.graphicsVariation = event.entity.graphics_variation | OnTriggerCreatedEntityEvent
data.health = event.entity.health
data.isActive = event.entity.active
data.isRotatable = event.entity.rotatable
data.lastUser = event.entity.last_user?.index
data.prototype = event.entity.prototype.name
}
)
}

View file

@ -3,129 +3,270 @@ import {Converters} from "./converters";
import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache"; import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache";
import { import {
KafkatorioPacketData, KafkatorioPacketData,
MapChunkPosition MapChunkPosition, PrototypeId,
PrototypeKey,
} from "../../generated/kafkatorio-schema"; } from "../../generated/kafkatorio-schema";
import EntityUpdates from "./entityUpdates";
import CacheKey = EventUpdates.PacketKey; import CacheKey = EventUpdates.PacketKey;
import Type = KafkatorioPacketData.Type; import Type = KafkatorioPacketData.Type;
type MapChunkUpdater = (data: KafkatorioPacketData.MapChunkUpdate) => void type MapChunkTileUpdater = (data: KafkatorioPacketData.MapChunkTileUpdate) => void
type MapTileUpdateEvent = export type MapTileChangeEvent =
| OnChunkGeneratedEvent
| OnPlayerBuiltTileEvent | OnPlayerBuiltTileEvent
| OnPlayerMinedEntityEvent
| OnPlayerMinedTileEvent | OnPlayerMinedTileEvent
| OnRobotBuiltTileEvent | OnRobotBuiltTileEvent
| OnRobotMinedEntityEvent
| OnRobotMinedTileEvent | OnRobotMinedTileEvent
| ScriptRaisedSetTilesEvent | ScriptRaisedSetTilesEvent
function mapTilesUpdateDebounce( export type MapChunkUpdateEvent =
surface: LuaSurface | undefined, | OnChunkChartedEvent
chunkPosition: MapChunkPosition, | OnChunkDeletedEvent
tiles: TileRead[], | OnChunkGeneratedEvent
event: MapTileUpdateEvent, | OnPreChunkDeletedEvent
updater?: MapChunkUpdater,
expirationDurationTicks?: uint,
) {
if (surface == undefined) {
return class MapChunkUpdateHandler {
handleChunkGeneratedEvent(
event: OnChunkGeneratedEvent,
expirationDurationTicks?: uint,
) {
const tiles = event.surface.find_tiles_filtered({area: event.area})
MapChunkUpdateHandler.mapTilesUpdateDebounce(
event.surface,
Converters.convertMapTablePosition(event.position),
tiles,
event,
undefined,
expirationDurationTicks,
)
} }
const eventName = Converters.eventNameString(event.name)
const key: KafkatorioPacketData.MapChunkUpdate["key"] = { handleBuiltTileEvent(event: OnPlayerBuiltTileEvent | OnRobotBuiltTileEvent) {
surfaceIndex: surface.index,
chunkPosition: chunkPosition, const surface = game.get_surface(event.surface_index)
if (surface == undefined) {
const eventName = Converters.eventNameString(event.name)
log(`[handleBuiltTileEvent] undefined surface ${eventName}`)
return
}
const tiles: TileRead[] = Converters.convertPlacedTiles(event.tile, event.tiles)
const groupedTiles = MapChunkUpdateHandler.groupTiles(tiles)
for (const [chunkPos, tiles] of groupedTiles) {
MapChunkUpdateHandler.mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
(data => {
if (isEventType(event, defines.events.on_player_built_tile)) {
data.player = event.player_index
return
}
if (isEventType(event, defines.events.on_robot_built_tile)) {
data.robot = {
unitNumber: event.robot?.unit_number ?? null,
protoId: Converters.prototypeId(event.robot.type, event.robot.name),
}
return
}
// this line will not compile if the previous 'if' statements are not exhaustive
// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
const exhaustiveCheck: never = event
}
)
)
}
} }
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkUpdate>(
key,
Type.MapChunkUpdate,
data => {
// tile dictionary update handleMinedTileEvent(event: OnPlayerMinedTileEvent | OnRobotMinedTileEvent) {
if (data.tileDictionary == undefined) { const surface = game.get_surface(event.surface_index)
data.tileDictionary = { if (surface == undefined) {
tilesXY: {}, const eventName = Converters.eventNameString(event.name)
protos: {}, log(`[handleMinedTileEvent] undefined surface ${eventName}`)
} return
} }
let protosCount: uint = table_size(data.tileDictionary.protos) const tiles: TileRead[] = Converters.convertRemovedTiles(surface, event.tiles)
for (const tile of tiles) { const groupedTiles = MapChunkUpdateHandler.groupTiles(tiles)
data.tileDictionary.protos[tile.name] ??= protosCount++
const protoKey = data.tileDictionary.protos[tile.name] for (const [chunkPos, tiles] of groupedTiles) {
const xString = `${tile.position.x}` MapChunkUpdateHandler.mapTilesUpdateDebounce(
const yString = `${tile.position.y}` surface,
chunkPos,
data.tileDictionary.tilesXY[xString] ??= {} tiles,
data.tileDictionary.tilesXY[xString][yString] = protoKey event,
} (data => {
if (isEventType(event, defines.events.on_player_mined_tile)) {
// events count update data.player = event.player_index
data.events ??= {} return
data.events[eventName] ??= [] }
data.events[eventName].push(event.tick) if (isEventType(event, defines.events.on_robot_mined_tile)) {
data.robot = {
// apply mutator unitNumber: event.robot?.unit_number ?? null,
if (updater != undefined) { protoId: Converters.prototypeId(event.robot.type, event.robot.name),
updater(data) }
} return
}, }
expirationDurationTicks, // this line will not compile if the previous 'if' statements are not exhaustive
) // noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
} const exhaustiveCheck: never = event
}
)
)
}
}
function getTiles( handleScriptSetTilesEvent(event: ScriptRaisedSetTilesEvent) {
surface: LuaSurface | undefined,
area: BoundingBoxTable const surface = game.get_surface(event.surface_index)
): LuaTile[] { if (surface == undefined) {
return surface?.find_tiles_filtered({ return
area: area, }
// collision_mask: ["ground-tile", "water-tile"]
const groupedTiles = MapChunkUpdateHandler.groupTiles(event.tiles)
for (const [chunkPos, tiles] of groupedTiles) {
MapChunkUpdateHandler.mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
}
}
handlePreChunkDeleted(event: OnPreChunkDeletedEvent) {
const surface = game.get_surface(event.surface_index)
if (surface == undefined) {
return
}
for (const position of event.positions) {
const key: CacheKey<KafkatorioPacketData.MapChunkTileUpdate> = {
surfaceIndex: surface.index,
chunkPosition: [position.x, position.y],
} }
) ?? []
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkTileUpdate>(
key,
Type.MapChunkTileUpdate,
data => data.isDeleted = true,
0, // deletion is important - emit ASAP
)
}
}
private static mapTilesUpdateDebounce(
surface: LuaSurface | undefined,
chunkPosition: MapChunkPosition,
tiles: TileRead[],
event: MapChunkUpdateEvent | MapTileChangeEvent,
updater?: MapChunkTileUpdater,
expirationDurationTicks?: uint,
) {
if (surface == undefined) {
return
}
const eventName = Converters.eventNameString(event.name)
const key: KafkatorioPacketData.MapChunkTileUpdate["key"] = {
surfaceIndex: surface.index,
chunkPosition: chunkPosition,
}
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkTileUpdate>(
key,
Type.MapChunkTileUpdate,
data => {
// tile dictionary update
if (data.tileDictionary == undefined) {
data.tileDictionary = {
tilesXY: {},
protos: {},
}
}
let protosCount: uint = table_size(data.tileDictionary.protos)
for (const tile of tiles) {
const protoId = Converters.prototypeId("tile", tile.name)
if (data.tileDictionary.protos[protoId] == null) {
}
data.tileDictionary.protos[protoId] ??= protosCount++ as PrototypeKey
const protoKey = data.tileDictionary.protos[protoId]
const xString = `${tile.position.x}`
const yString = `${tile.position.y}`
data.tileDictionary.tilesXY[xString] ??= {}
data.tileDictionary.tilesXY[xString][yString] = protoKey
}
// events count update
data.events ??= {}
data.events[eventName] ??= []
data.events[eventName].push(event.tick)
// apply mutator
if (updater != undefined) {
updater(data)
}
},
expirationDurationTicks,
)
}
private static groupTiles(tiles: TileRead[]): Map<MapChunkPosition, TileRead[]> {
const mapChunkPositionToTiles = new Map<MapChunkPosition, TileRead[]>()
for (const tile of tiles) {
const chunkPosition: MapChunkPosition = [
math.floor((tile.position.x / 32)),
math.floor((tile.position.y / 32)),
]
if (!mapChunkPositionToTiles.has(chunkPosition)) {
mapChunkPositionToTiles.set(chunkPosition, [])
}
mapChunkPositionToTiles.get(chunkPosition)?.push(tile)
}
return mapChunkPositionToTiles
}
} }
function getSurface(surfaceIndex: uint): LuaSurface | undefined { const MapChunkUpdate = new MapChunkUpdateHandler()
return game.surfaces[surfaceIndex]
} export default MapChunkUpdate
script.on_event( script.on_event(
defines.events.on_chunk_generated, defines.events.on_chunk_generated,
(e: OnChunkGeneratedEvent) => { (e: OnChunkGeneratedEvent) => {
log(`on_chunk_generated ${e.tick}`) log(`on_chunk_generated ${e.tick}`)
handleChunkGeneratedEvent(e) MapChunkUpdate.handleChunkGeneratedEvent(e)
EntityUpdates.handleChunkGeneratedEvent(e)
} }
) )
export function handleChunkGeneratedEvent(
event: OnChunkGeneratedEvent,
expirationDurationTicks?: uint,
) {
let tiles = getTiles(event.surface, event.area)
mapTilesUpdateDebounce(
event.surface,
Converters.convertMapTablePosition(event.position),
tiles,
event,
undefined,
expirationDurationTicks,
)
}
// script.on_event( // script.on_event(
// defines.events.on_chunk_charted, // defines.events.on_chunk_charted,
// (e: OnChunkChartedEvent) => { // (e: OnChunkChartedEvent) => {
@ -144,169 +285,38 @@ export function handleChunkGeneratedEvent(
// ) // )
script.on_event( script.on_event(defines.events.script_raised_set_tiles, (event: ScriptRaisedSetTilesEvent) => {
defines.events.script_raised_set_tiles, log(`script_raised_set_tiles ${event.tick}`)
(event: ScriptRaisedSetTilesEvent) => { MapChunkUpdate.handleScriptSetTilesEvent(event)
log(`script_raised_set_tiles ${event.tick}`) })
const surface = getSurface(event.surface_index)
if (surface == undefined) {
return
}
const groupedTiles = groupTiles(event.tiles)
for (const [chunkPos, tiles] of groupedTiles) {
mapTilesUpdateDebounce(surface, chunkPos, tiles, event)
}
}
)
function groupTiles(tiles: TileRead[]): Map<MapChunkPosition, TileRead[]> {
const mapChunkPositionToTiles = new Map<MapChunkPosition, TileRead[]>()
for (const tile of tiles) {
const chunkPosition: MapChunkPosition = [
math.floor((tile.position.x / 32)),
math.floor((tile.position.y / 32)),
]
if (!mapChunkPositionToTiles.has(chunkPosition)) {
mapChunkPositionToTiles.set(chunkPosition, [])
}
// https://github.com/TypeScriptToLua/TypeScriptToLua/issues/1256
mapChunkPositionToTiles.get(chunkPosition)?.push(tile)
// const tiles = mapChunkPositionToTiles.get(chunkPosition)
// if (tiles != null) {
// tiles.push(tile)
// }
}
return mapChunkPositionToTiles
}
script.on_event(defines.events.on_player_built_tile, (e: OnPlayerBuiltTileEvent) => { script.on_event(defines.events.on_player_built_tile, (e: OnPlayerBuiltTileEvent) => {
log(`on_player_built_tile ${e.tick}`) log(`on_player_built_tile ${e.tick}`)
handleBuiltTileEvent(e) MapChunkUpdate.handleBuiltTileEvent(e)
}) })
script.on_event(defines.events.on_robot_built_tile, (e: OnRobotBuiltTileEvent) => { script.on_event(defines.events.on_robot_built_tile, (e: OnRobotBuiltTileEvent) => {
log(`on_robot_built_tile ${e.tick}`) log(`on_robot_built_tile ${e.tick}`)
handleBuiltTileEvent(e) MapChunkUpdate.handleBuiltTileEvent(e)
}) })
function handleBuiltTileEvent(event: OnPlayerBuiltTileEvent | OnRobotBuiltTileEvent) {
const surface = getSurface(event.surface_index)
if (surface == undefined) {
const eventName = Converters.eventNameString(event.name)
log(`[handleBuiltTileEvent] undefined surface ${eventName}`)
return
}
const tiles: TileRead[] = Converters.convertPlacedTiles(event.tile, event.tiles)
const groupedTiles = groupTiles(tiles)
for (const [chunkPos, tiles] of groupedTiles) {
mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
(data => {
if (isEventType(event, defines.events.on_player_built_tile)) {
data.player = event.player_index
return
}
if (isEventType(event, defines.events.on_robot_built_tile)) {
data.robot = {
unitNumber: event.robot?.unit_number ?? null,
name: event.robot.name,
protoType: event.robot.type,
}
return
}
// this line will not compile if the previous 'if' statements are not exhaustive
// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
const exhaustiveCheck: never = event
}
)
)
}
}
script.on_event(defines.events.on_player_mined_tile, (e: OnPlayerMinedTileEvent) => { script.on_event(defines.events.on_player_mined_tile, (e: OnPlayerMinedTileEvent) => {
log(`on_player_mined_tile ${e.tick}`) log(`on_player_mined_tile ${e.tick}`)
handleMinedTileEvent(e) MapChunkUpdate.handleMinedTileEvent(e)
EntityUpdates.handleMinedTileEvent(e)
}) })
script.on_event(defines.events.on_robot_mined_tile, (e: OnRobotMinedTileEvent) => { script.on_event(defines.events.on_robot_mined_tile, (e: OnRobotMinedTileEvent) => {
log(`on_robot_mined_tile ${e.tick}`) log(`on_robot_mined_tile ${e.tick}`)
handleMinedTileEvent(e) MapChunkUpdate.handleMinedTileEvent(e)
}) })
function handleMinedTileEvent(event: OnPlayerMinedTileEvent | OnRobotMinedTileEvent) {
const surface = getSurface(event.surface_index)
if (surface == undefined) {
const eventName = Converters.eventNameString(event.name)
log(`[handleMinedTileEvent] undefined surface ${eventName}`)
return
}
const tiles: TileRead[] = Converters.convertRemovedTiles(surface, event.tiles) script.on_event(defines.events.on_pre_chunk_deleted, (e: OnPreChunkDeletedEvent) => {
const groupedTiles = groupTiles(tiles) log(`on_pre_chunk_deleted ${e.tick}`)
MapChunkUpdate.handlePreChunkDeleted(e)
for (const [chunkPos, tiles] of groupedTiles) { })
mapTilesUpdateDebounce(
surface,
chunkPos,
tiles,
event,
(data => {
if (isEventType(event, defines.events.on_player_mined_tile)) {
data.player = event.player_index
return
}
if (isEventType(event, defines.events.on_robot_mined_tile)) {
data.robot = {
unitNumber: event.robot?.unit_number ?? null,
name: event.robot.name,
protoType: event.robot.type,
}
return
}
// this line will not compile if the previous 'if' statements are not exhaustive
// noinspection UnnecessaryLocalVariableJS,JSUnusedLocalSymbols
const exhaustiveCheck: never = event
}
)
)
}
}
script.on_event(
defines.events.on_pre_chunk_deleted,
(e: OnPreChunkDeletedEvent) => {
log(`on_pre_chunk_deleted ${e.tick}`)
const surface = getSurface(e.surface_index)
if (surface == undefined) {
return
}
for (const position of e.positions) {
const key: CacheKey<KafkatorioPacketData.MapChunkUpdate> = {
surfaceIndex: surface.index,
chunkPosition: [position.x, position.y],
}
EventUpdatesManager.debounce<KafkatorioPacketData.MapChunkUpdate>(
key,
Type.MapChunkUpdate,
data => data.isDeleted = true,
0, // deletion is important - emit ASAP
)
}
}
)

View file

@ -1,11 +1,8 @@
import {Converters} from "./converters"; import {Converters} from "./converters";
import EventUpdatesManager from "../cache/EventDataCache"; import EventUpdatesManager from "../cache/EventDataCache";
import { import {ForceIndex, KafkatorioPacketData, PlayerUpdateKey} from "../../generated/kafkatorio-schema";
KafkatorioPacketData,
PlayerUpdateKey
} from "../../generated/kafkatorio-schema";
import Type = KafkatorioPacketData.Type;
import packetEmitter from "../PacketEmitter"; import packetEmitter from "../PacketEmitter";
import Type = KafkatorioPacketData.Type;
type PlayerUpdater = (player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) => void type PlayerUpdater = (player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) => void
@ -36,7 +33,7 @@ function playerUpdateThrottle(
const eventName = Converters.eventNameString(event.name) const eventName = Converters.eventNameString(event.name)
EventUpdatesManager.throttle<KafkatorioPacketData.PlayerUpdate>( EventUpdatesManager.throttle<KafkatorioPacketData.PlayerUpdate>(
{index: playerIndex}, {index: playerIndex },
Type.PlayerUpdate, Type.PlayerUpdate,
data => { data => {
const player = game.players[playerIndex] const player = game.players[playerIndex]
@ -88,7 +85,7 @@ script.on_event(
data.characterUnitNumber = player.character?.unit_number ?? null data.characterUnitNumber = player.character?.unit_number ?? null
data.chatColour = Converters.mapColour(player.chat_color) data.chatColour = Converters.mapColour(player.chat_color)
data.colour = Converters.mapColour(player.color) data.colour = Converters.mapColour(player.color)
data.forceIndex = player.force.index data.forceIndex = player.force.index as ForceIndex
data.name = player.name data.name = player.name
data.isShowOnMap = player.show_on_map data.isShowOnMap = player.show_on_map
data.isSpectator = player.spectator data.isSpectator = player.spectator
@ -139,8 +136,7 @@ script.on_event(
if (e.cause != undefined) { if (e.cause != undefined) {
data.diedCause = { data.diedCause = {
unitNumber: e.cause.unit_number ?? null, unitNumber: e.cause.unit_number ?? null,
name: e.cause.name, protoId: Converters.prototypeId(e.cause.type, e.cause.name),
protoType: e.cause.type
} }
} }
} }
@ -189,7 +185,7 @@ script.on_event(
log(`on_pre_player_left_game ${event.tick} ${event.name}`) log(`on_pre_player_left_game ${event.tick} ${event.name}`)
const playerUpdateKey: PlayerUpdateKey = { const playerUpdateKey: PlayerUpdateKey = {
index: event.player_index index: event.player_index ,
} }
const playerUpdate: KafkatorioPacketData.PlayerUpdate = { const playerUpdate: KafkatorioPacketData.PlayerUpdate = {

View file

@ -26,11 +26,11 @@ function prototypeUpdates(): FactorioPrototype[] {
function getMapTilePrototypes(): FactorioPrototype.MapTile[] { function getMapTilePrototypes(): FactorioPrototype.MapTile[] {
let tiles: FactorioPrototype.MapTile[] = [] let tiles: FactorioPrototype.MapTile[] = []
for (let [, tile] of game.tile_prototypes) { for (const [, tile] of game.tile_prototypes) {
tiles.push({ tiles.push({
type: FactorioPrototype.Type.MapTile, type: FactorioPrototype.Type.MapTile,
name: tile.name, protoId: Converters.prototypeId("tile", tile.name),
order: tile.order, order: tile.order,
layer: tile.layer, layer: tile.layer,
collisionMasks: Converters.convertCollisionMaskToNames(tile.collision_mask), collisionMasks: Converters.convertCollisionMaskToNames(tile.collision_mask),
@ -44,7 +44,7 @@ function getMapTilePrototypes(): FactorioPrototype.MapTile[] {
// function getEntityPrototypes(): FactorioPrototype.MapTile[] { // function getEntityPrototypes(): FactorioPrototype.MapTile[] {
// let tiles: FactorioPrototype.MapTile[] = [] // let tiles: FactorioPrototype.MapTile[] = []
// for (let [, tile] of game.tile_prototypes) { // for (const [, tile] of game.tile_prototypes) {
// tiles.push({ // tiles.push({
// type: FactorioPrototype.Type.MapTile, // type: FactorioPrototype.Type.MapTile,
// //

View file

@ -1,9 +1,9 @@
import {Queue} from "../queue/queue"; import {Queue} from "../queue/queue";
import {isEventType} from "./eventTypeCheck"; import {isEventType} from "./eventTypeCheck";
import {Converters} from "./converters"; import {Converters} from "./converters";
import {handleChunkGeneratedEvent} from "./mapChunkUpdates";
import {handleSurfaceUpdate} from "./surfaceUpdates"; import {handleSurfaceUpdate} from "./surfaceUpdates";
import EventCacheService from "../cache/EventDataCache"; import EventCacheService from "../cache/EventDataCache";
import MapChunkUpdate from "./mapChunkUpdates";
script.on_event( script.on_event(
@ -35,7 +35,7 @@ script.on_event(
let eName = Converters.eventNameString(event.name) let eName = Converters.eventNameString(event.name)
log(`[on_tick:${event.tick}] dequed event ${eName}, delay ${i}`) log(`[on_tick:${event.tick}] dequed event ${eName}, delay ${i}`)
handleChunkGeneratedEvent(event, i) MapChunkUpdate.handleChunkGeneratedEvent(event, i)
i += 1 i += 1
} }
} }

View file

@ -0,0 +1,99 @@
// import {isEventType} from "./eventTypeCheck";
// import {Converters} from "./converters";
// import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache";
// import {
// KafkatorioPacketData,
// MapChunkPosition,
// PrototypeKey,
// } from "../../generated/kafkatorio-schema";
// import CacheKey = EventUpdates.PacketKey;
// import Type = KafkatorioPacketData.Type;
//
//
// export class ResourceEntityUpdatesHandler {
//
//
// handleChunkGeneratedEvent(
// event: OnChunkGeneratedEvent,
// expirationDurationTicks?: uint,
// ) {
// const resourceEntities = this.getAreaResourceEntities(event.surface, event.area)
//
// mapTilesUpdateDebounce(
// event.surface,
// Converters.convertMapTablePosition(event.position),
// tiles,
// event,
// undefined,
// expirationDurationTicks,
// )
// }
//
//
// private resourceEntityUpdatesThrottle(
// surface: LuaSurface | undefined,
// chunkPosition: MapChunkPosition,
// tiles: TileRead[],
// event: MapTileUpdateEvent,
// updater?: MapChunkUpdater,
// expirationDurationTicks?: uint,
// ) {
//
// if (surface == undefined) {
// return
// }
//
// const eventName = Converters.eventNameString(event.name)
//
// const key: KafkatorioPacketData.ResourceEntitiesUpdate["key"] = {
// surfaceIndex: surface.index as SurfaceIndex,
// chunkPosition: chunkPosition,
// }
//
// EventUpdatesManager.throttle<KafkatorioPacketData.ResourceEntitiesUpdate>(
// key,
// Type.MapChunkUpdate,
// data => {
//
// // tile dictionary update
// if (data.tileDictionary == undefined) {
// data.tileDictionary = {
// tilesXY: {},
// protos: {},
// }
// }
//
// let protosCount: uint = table_size(data.tileDictionary.protos)
// for (const tile of tiles) {
// const tileName = tile.name as PrototypeIdMapTile
// const protoKey = protosCount++ as PrototypeKey
// data.tileDictionary.protos[tileName] ??= protoKey
//
// const xString = `${tile.position.x}`
// const yString = `${tile.position.y}`
//
// data.tileDictionary.tilesXY[xString] ??= {}
// data.tileDictionary.tilesXY[xString][yString] = protoKey
// }
//
// // events count update
// data.events ??= {}
// data.events[eventName] ??= []
// data.events[eventName].push(event.tick)
//
// // apply mutator
// if (updater != undefined) {
// updater(data)
// }
// },
// expirationDurationTicks,
// )
// }
//
// }
//
//
//
// const ResourceEntityUpdates = new ResourceEntityUpdatesHandler()
//
// export default ResourceEntityUpdates

View file

@ -13,7 +13,7 @@ export function handleSurfaceUpdate(
name: surface.name, name: surface.name,
index: surface.index, index: surface.index,
daytime: surface.daytime daytime: surface.daytime,
} }
PacketEmitter.emitInstantPacket(update) PacketEmitter.emitInstantPacket(update)

View file

@ -6,7 +6,8 @@ export class KafkatorioSettingsConfig {
private static eventCacheExpirationDefaultSeconds: Record<KafkatorioKeyedPacketTypes, double> = { private static eventCacheExpirationDefaultSeconds: Record<KafkatorioKeyedPacketTypes, double> = {
"kafkatorio.packet.keyed.PlayerUpdate": 0.5, "kafkatorio.packet.keyed.PlayerUpdate": 0.5,
"kafkatorio.packet.keyed.MapChunkUpdate": 30, "kafkatorio.packet.keyed.MapChunkTileUpdate": 30,
"kafkatorio.packet.keyed.MapChunkEntityUpdate": 30,
"kafkatorio.packet.keyed.EntityUpdate": 5, "kafkatorio.packet.keyed.EntityUpdate": 5,
} }
@ -21,7 +22,7 @@ export class KafkatorioSettingsConfig {
public initialiseSettings(data: Data): void { public initialiseSettings(data: Data): void {
for (const [type,] of pairs(KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds)) { for (const [type,] of pairs(KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds)) {
data.extend( data.extend(
[ KafkatorioSettingsConfig.createDefaultCacheDuration(type)] [KafkatorioSettingsConfig.createDefaultCacheDuration(type)]
) )
} }
} }

View file

@ -1,6 +1,6 @@
import {KafkatorioPacketData} from "../generated/kafkatorio-schema"; import {KafkatorioPacketData} from "../generated/kafkatorio-schema";
export type EventName = keyof typeof defines.events export type DefinedEventName = keyof typeof defines.events
/** Get all keys of `TYPE` that are not nullable. */ /** Get all keys of `TYPE` that are not nullable. */

View file

@ -10,7 +10,8 @@
"types": [ "types": [
"typescript-to-lua/language-extensions", "typescript-to-lua/language-extensions",
"lua-types/5.2", "lua-types/5.2",
"typed-factorio/runtime" "typed-factorio/runtime",
"typed-factorio/strict-index-types"
], ],
"plugins": [ "plugins": [
{ {
@ -32,8 +33,7 @@
"traceResolution": true, "traceResolution": true,
"noImplicitReturns": true, "noImplicitReturns": true,
"noImplicitOverride": true, "noImplicitOverride": true,
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true
"skipLibCheck": true
}, },
"tstl": { "tstl": {
"luaTarget": "5.2", "luaTarget": "5.2",

View file

@ -2,11 +2,13 @@ package dev.adamko.kafkatorio.server.processor
import com.github.palindromicity.syslog.dsl.SyslogFieldKeys import com.github.palindromicity.syslog.dsl.SyslogFieldKeys
import dev.adamko.kafkatorio.server.config.ApplicationProperties import dev.adamko.kafkatorio.server.config.ApplicationProperties
import dev.adamko.kafkatorio.server.processor.topology.broadcastToWebsocket
import dev.adamko.kafkatorio.server.processor.topology.colourMapChunks import dev.adamko.kafkatorio.server.processor.topology.colourMapChunks
import dev.adamko.kafkatorio.server.processor.topology.* import dev.adamko.kafkatorio.server.processor.topology.factorioServerPacketStream
import dev.adamko.kafkatorio.server.processor.topology.saveMapTiles
import dev.adamko.kafkatorio.server.processor.topology.splitFactorioServerPacketStream
import dev.adamko.kafkatorio.server.socket.SyslogSocketServer import dev.adamko.kafkatorio.server.socket.SyslogSocketServer
import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer
import dev.adamko.kafkatorio.server.web.websocket.broadcastToWebsocket
import java.util.Properties import java.util.Properties
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException import kotlin.coroutines.resumeWithException

View file

@ -1,7 +1,7 @@
package dev.adamko.kafkatorio.server.processor.admin package dev.adamko.kafkatorio.server.processor.admin
import dev.adamko.kafkatorio.server.processor.allTopics
import dev.adamko.kafkatorio.server.config.ApplicationProperties import dev.adamko.kafkatorio.server.config.ApplicationProperties
import dev.adamko.kafkatorio.server.processor.allTopics
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import mu.KotlinLogging import mu.KotlinLogging
import org.apache.kafka.clients.admin.Admin import org.apache.kafka.clients.admin.Admin

View file

@ -1,9 +1,9 @@
package dev.adamko.kafkatorio.server.processor package dev.adamko.kafkatorio.server.processor
import dev.adamko.kafkatorio.server.socket.SyslogSocketServer
import dev.adamko.kafkatorio.server.processor.admin.KafkatorioKafkaAdmin
import dev.adamko.kafkatorio.server.config.ApplicationProperties import dev.adamko.kafkatorio.server.config.ApplicationProperties
import dev.adamko.kafkatorio.server.processor.admin.KafkatorioKafkaAdmin
import dev.adamko.kafkatorio.server.socket.SyslogSocketServer
import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer
import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
@ -27,11 +27,11 @@ suspend fun eventsProcessor(
val topology = KafkatorioTopology(appProps, wsServer, syslogServer) val topology = KafkatorioTopology(appProps, wsServer, syslogServer)
launch { launch {
topology.start() topology.start()
println("launched KafkatorioTopology") println("launched KafkatorioTopology")
awaitCancellation() awaitCancellation()
} }
} }

View file

@ -5,7 +5,8 @@ import dev.adamko.kafkatorio.schema.packets.ConsoleChatUpdate
import dev.adamko.kafkatorio.schema.packets.ConsoleCommandUpdate import dev.adamko.kafkatorio.schema.packets.ConsoleCommandUpdate
import dev.adamko.kafkatorio.schema.packets.EntityUpdate import dev.adamko.kafkatorio.schema.packets.EntityUpdate
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData
import dev.adamko.kafkatorio.schema.packets.MapChunkUpdate import dev.adamko.kafkatorio.schema.packets.MapChunkEntityUpdate
import dev.adamko.kafkatorio.schema.packets.MapChunkTileUpdate
import dev.adamko.kafkatorio.schema.packets.PlayerUpdate import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate
import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate
@ -54,9 +55,10 @@ val KafkatorioPacketData.topicName: String
is PrototypesUpdate -> packetTopicNames.getValue(PrototypesUpdate::class) is PrototypesUpdate -> packetTopicNames.getValue(PrototypesUpdate::class)
is SurfaceUpdate -> packetTopicNames.getValue(SurfaceUpdate::class) is SurfaceUpdate -> packetTopicNames.getValue(SurfaceUpdate::class)
is EntityUpdate -> packetTopicNames.getValue(EntityUpdate::class) is EntityUpdate -> packetTopicNames.getValue(EntityUpdate::class)
is MapChunkUpdate -> packetTopicNames.getValue(MapChunkUpdate::class) is MapChunkTileUpdate -> packetTopicNames.getValue(MapChunkTileUpdate::class)
is PlayerUpdate -> packetTopicNames.getValue(PlayerUpdate::class) is PlayerUpdate -> packetTopicNames.getValue(PlayerUpdate::class)
is KafkatorioPacketData.Error -> packetTopicNames.getValue(KafkatorioPacketData.Error::class) is KafkatorioPacketData.Error -> packetTopicNames.getValue(KafkatorioPacketData.Error::class)
is MapChunkEntityUpdate -> packetTopicNames.getValue(MapChunkEntityUpdate::class)
} }
@ -67,12 +69,14 @@ private val packetTopicNames: Map<KClass<out KafkatorioPacketData>, String> = ma
PrototypesUpdate::class to "prototypes", PrototypesUpdate::class to "prototypes",
SurfaceUpdate::class to "surface", SurfaceUpdate::class to "surface",
EntityUpdate::class to "entity", EntityUpdate::class to "entity",
MapChunkUpdate::class to "map-chunk", MapChunkTileUpdate::class to "map-chunk-tile",
PlayerUpdate::class to "player", PlayerUpdate::class to "player",
MapChunkEntityUpdate::class to "map-chunk-entity",
KafkatorioPacketData.Error::class to "error", KafkatorioPacketData.Error::class to "error",
).mapValues { (_, v) -> ).mapValues { (_, v) ->
"$DOMAIN.packet.$v" "$DOMAIN.packet.$v"
} }
val KClass<out KafkatorioPacketData>.topicName: String val KClass<out KafkatorioPacketData>.topicName: String
get() = packetTopicNames.getValue(this) get() = packetTopicNames.getValue(this)

View file

@ -1,8 +1,5 @@
package dev.adamko.kafkatorio.server.processor.topology package dev.adamko.kafkatorio.server.processor.topology
import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_032_STATE
import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_STATE
import dev.adamko.kafkatorio.server.processor.DebounceProcessor.Companion.addDebounceProcessor
import dev.adamko.kafkatorio.library.kxsBinary import dev.adamko.kafkatorio.library.kxsBinary
import dev.adamko.kafkatorio.schema.common.ChunkSize import dev.adamko.kafkatorio.schema.common.ChunkSize
import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.ColourHex
@ -10,8 +7,11 @@ import dev.adamko.kafkatorio.schema.common.FactorioServerId
import dev.adamko.kafkatorio.schema.common.ServerMapChunkId import dev.adamko.kafkatorio.schema.common.ServerMapChunkId
import dev.adamko.kafkatorio.schema.common.leftTopTile import dev.adamko.kafkatorio.schema.common.leftTopTile
import dev.adamko.kafkatorio.schema.common.toMapChunkPosition import dev.adamko.kafkatorio.schema.common.toMapChunkPosition
import dev.adamko.kafkatorio.schema.packets.MapChunkUpdate import dev.adamko.kafkatorio.schema.packets.MapChunkTileUpdate
import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate
import dev.adamko.kafkatorio.server.processor.DebounceProcessor.Companion.addDebounceProcessor
import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_032_STATE
import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_STATE
import dev.adamko.kotka.extensions.consumedAs import dev.adamko.kotka.extensions.consumedAs
import dev.adamko.kotka.extensions.groupedAs import dev.adamko.kotka.extensions.groupedAs
import dev.adamko.kotka.extensions.materializedAs import dev.adamko.kotka.extensions.materializedAs
@ -39,10 +39,10 @@ import org.apache.kafka.streams.kstream.KTable
private const val pid: String = "colourMapChunks" private const val pid: String = "colourMapChunks"
/** Add colour to each [MapChunkUpdate] */ /** Add colour to each [MapChunkTileUpdate] */
fun colourMapChunks(builder: StreamsBuilder): Topology { fun colourMapChunks(builder: StreamsBuilder): Topology {
val mapChunksStream: KStream<FactorioServerId, MapChunkUpdate> = builder.streamPacketData() val mapChunksStream: KStream<FactorioServerId, MapChunkTileUpdate> = builder.streamPacketData()
val protosStream: KStream<FactorioServerId, PrototypesUpdate> = builder.streamPacketData() val protosStream: KStream<FactorioServerId, PrototypesUpdate> = builder.streamPacketData()
val protosTable: KTable<FactorioServerId, TileColourDict> = val protosTable: KTable<FactorioServerId, TileColourDict> =
@ -78,7 +78,7 @@ fun colourMapChunks(builder: StreamsBuilder): Topology {
ChunkSize.CHUNK_032 to ChunkSize.CHUNK_256, ChunkSize.CHUNK_032 to ChunkSize.CHUNK_256,
ChunkSize.CHUNK_256 to ChunkSize.CHUNK_512, ChunkSize.CHUNK_256 to ChunkSize.CHUNK_512,
).forEach { (from, to) -> ).forEach { (from, to) ->
chunkTilesColoured chunkTilesColoured
.filter("$pid.combine-chunks.filter-$from-to-$to") { key, _ -> .filter("$pid.combine-chunks.filter-$from-to-$to") { key, _ ->
key.chunkSize == from key.chunkSize == from
@ -98,12 +98,12 @@ fun colourMapChunks(builder: StreamsBuilder): Topology {
} }
private fun KStream<FactorioServerId, MapChunkUpdate>.convertToServerMapChunkTiles() private fun KStream<FactorioServerId, MapChunkTileUpdate>.convertToServerMapChunkTiles()
: KStream<ServerMapChunkId, ServerMapChunkTiles<TileProtoHashCode>> { : KStream<ServerMapChunkId, ServerMapChunkTiles<TileProtoHashCode>> {
val pid = "$pid.convertToMapTiles" val pid = "$pid.convertToMapTiles"
return map("$pid.map") { serverId: FactorioServerId, update: MapChunkUpdate -> return map("$pid.map") { serverId: FactorioServerId, update: MapChunkTileUpdate ->
val mapTileList = update.tileDictionary?.toMapTileList() ?: emptyList() val mapTileList = update.tileDictionary?.toMapTileList() ?: emptyList()
@ -112,7 +112,7 @@ private fun KStream<FactorioServerId, MapChunkUpdate>.convertToServerMapChunkTil
} }
if (invalidMapTilesList.isNotEmpty()) { if (invalidMapTilesList.isNotEmpty()) {
println("WARNING [reduceMapTilesToTable] MapChunkUpdate contained out-of-bounds tiles $invalidMapTilesList") println("WARNING [reduceMapTilesToTable] MapChunkTileUpdate contained out-of-bounds tiles $invalidMapTilesList")
} }
val validMapTilesToProtoHashCode = val validMapTilesToProtoHashCode =
@ -232,7 +232,7 @@ fun KTable<ServerMapChunkId, ServerMapChunkTiles<ColourHex>>.streamMapChunkColou
/** /**
* Group [MapChunkUpdate]s by the Chunk position. * Group [MapChunkTileUpdate]s by the Chunk position.
* *
* They should already be grouped, but do it again to make sure, and to filter out empty updates. * They should already be grouped, but do it again to make sure, and to filter out empty updates.
*/ */

View file

@ -1,12 +1,12 @@
package dev.adamko.kafkatorio.server.processor.topology package dev.adamko.kafkatorio.server.processor.topology
import dev.adamko.kafkatorio.server.processor.TOPIC_SRC_SERVER_LOG
import dev.adamko.kafkatorio.server.processor.topicName
import dev.adamko.kafkatorio.server.config.jsonMapper
import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.FactorioServerId
import dev.adamko.kafkatorio.schema.common.Tick import dev.adamko.kafkatorio.schema.common.Tick
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData
import dev.adamko.kafkatorio.server.config.jsonMapper
import dev.adamko.kafkatorio.server.processor.TOPIC_SRC_SERVER_LOG
import dev.adamko.kafkatorio.server.processor.topicName
import dev.adamko.kotka.extensions.component1 import dev.adamko.kotka.extensions.component1
import dev.adamko.kotka.extensions.component2 import dev.adamko.kotka.extensions.component2
import dev.adamko.kotka.extensions.consumedAs import dev.adamko.kotka.extensions.consumedAs
@ -35,7 +35,7 @@ fun factorioServerPacketStream(
val packet = runCatching { val packet = runCatching {
jsonMapper.decodeFromString<KafkatorioPacket>(value) jsonMapper.decodeFromString<KafkatorioPacket>(value)
}.getOrElse { e -> }.getOrElse { e ->
KafkatorioPacket( KafkatorioPacket(
modVersion = "unknown", modVersion = "unknown",
tick = Tick(0u), tick = Tick(0u),
data = KafkatorioPacketData.Error( data = KafkatorioPacketData.Error(

View file

@ -1,10 +1,10 @@
package dev.adamko.kafkatorio.server.processor.topology package dev.adamko.kafkatorio.server.processor.topology
import dev.adamko.kafkatorio.server.processor.topicName
import dev.adamko.kafkatorio.server.config.jsonMapper
import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.FactorioServerId
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData
import dev.adamko.kafkatorio.server.config.jsonMapper
import dev.adamko.kafkatorio.server.processor.topicName
import dev.adamko.kotka.extensions.consumedAs import dev.adamko.kotka.extensions.consumedAs
import dev.adamko.kotka.extensions.streams.filter import dev.adamko.kotka.extensions.streams.filter
import dev.adamko.kotka.extensions.streams.mapValues import dev.adamko.kotka.extensions.streams.mapValues

View file

@ -22,8 +22,8 @@ import org.apache.kafka.streams.kstream.KTable
@JvmInline @JvmInline
@Serializable @Serializable
value class TileProtoHashCode private constructor(val code: Int) { value class TileProtoHashCode private constructor(val code: Int) {
constructor(tile: MapTile) : this(tile.proto.hashCode()) constructor(tile: MapTile) : this(tile.protoId.hashCode())
constructor(tile: FactorioPrototype.MapTile) : this(tile.name.hashCode()) constructor(tile: FactorioPrototype.MapTile) : this(tile.protoId.hashCode())
} }

View file

@ -3,15 +3,15 @@ package dev.adamko.kafkatorio.server.processor.topology
import com.sksamuel.scrimage.ImmutableImage import com.sksamuel.scrimage.ImmutableImage
import com.sksamuel.scrimage.ScaleMethod import com.sksamuel.scrimage.ScaleMethod
import com.sksamuel.scrimage.nio.PngWriter import com.sksamuel.scrimage.nio.PngWriter
import dev.adamko.kafkatorio.server.processor.TOPIC_BROADCAST_TO_WEBSOCKET
import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_STATE
import dev.adamko.kafkatorio.server.config.jsonMapper
import dev.adamko.kafkatorio.library.kxsBinary import dev.adamko.kafkatorio.library.kxsBinary
import dev.adamko.kafkatorio.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.ColourHex
import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.FactorioServerId
import dev.adamko.kafkatorio.schema.common.ServerMapChunkId import dev.adamko.kafkatorio.schema.common.ServerMapChunkId
import dev.adamko.kafkatorio.schema.common.TilePngFilename import dev.adamko.kafkatorio.schema.common.TilePngFilename
import dev.adamko.kafkatorio.schema.packets.EventServerPacket import dev.adamko.kafkatorio.schema.packets.EventServerPacket
import dev.adamko.kafkatorio.server.config.jsonMapper
import dev.adamko.kafkatorio.server.processor.TOPIC_BROADCAST_TO_WEBSOCKET
import dev.adamko.kafkatorio.server.processor.TOPIC_MAP_CHUNK_COLOURED_STATE
import dev.adamko.kotka.extensions.consumedAs import dev.adamko.kotka.extensions.consumedAs
import dev.adamko.kotka.extensions.producedAs import dev.adamko.kotka.extensions.producedAs
import dev.adamko.kotka.extensions.streams.map import dev.adamko.kotka.extensions.streams.map
@ -32,7 +32,7 @@ private const val WEB_MAP_TILE_SIZE_PX = 256
/** /**
* @param[serverDataDir] [dev.adamko.kafkatorio.processor.config.ApplicationProperties.serverDataDir] * @param[serverDataDir] [dev.adamko.kafkatorio.server.config.ApplicationProperties.serverDataDir]
*/ */
fun saveMapTiles( fun saveMapTiles(
builder: StreamsBuilder, builder: StreamsBuilder,

View file

@ -1,13 +1,14 @@
package dev.adamko.kafkatorio.server.web.websocket package dev.adamko.kafkatorio.server.processor.topology
import dev.adamko.kafkatorio.library.jsonMapperKafkatorio import dev.adamko.kafkatorio.library.jsonMapperKafkatorio
import dev.adamko.kafkatorio.server.processor.TOPIC_BROADCAST_TO_WEBSOCKET
import dev.adamko.kafkatorio.server.processor.topicName
import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.FactorioServerId
import dev.adamko.kafkatorio.schema.packets.EventServerPacket import dev.adamko.kafkatorio.schema.packets.EventServerPacket
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket
import dev.adamko.kafkatorio.schema.packets.PlayerUpdate import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate
import dev.adamko.kafkatorio.server.processor.TOPIC_BROADCAST_TO_WEBSOCKET
import dev.adamko.kafkatorio.server.processor.topicName
import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer
import dev.adamko.kotka.extensions.consumedAs import dev.adamko.kotka.extensions.consumedAs
import dev.adamko.kotka.extensions.producedAs import dev.adamko.kotka.extensions.producedAs
import dev.adamko.kotka.extensions.stream import dev.adamko.kotka.extensions.stream

View file

@ -59,12 +59,14 @@ class SyslogSocketServer(
launch { launch {
val channel = socket.openReadChannel() val channel = socket.openReadChannel()
try { try {
while (socket.socketContext.isActive) { while (socket.socketContext.isActive && !channel.isClosedForRead) {
val line = runCatching { val line = runCatching {
channel.readUTF8Line() channel.readUTF8Line()
}.fold( }.fold(
onSuccess = { line -> onSuccess = { line ->
log("received '$line' from $socket") if (line != null) {
log("received '$line' from ${socket.description()}")
}
line line
}, },
onFailure = { e -> onFailure = { e ->

View file

@ -10,9 +10,7 @@ import io.ktor.http.content.EntityTagVersion
import io.ktor.http.content.versions import io.ktor.http.content.versions
import io.ktor.resources.Resource import io.ktor.resources.Resource
import io.ktor.server.application.ApplicationCall import io.ktor.server.application.ApplicationCall
import io.ktor.server.application.application
import io.ktor.server.application.call import io.ktor.server.application.call
import io.ktor.server.application.log
import io.ktor.server.http.content.LastModifiedVersion import io.ktor.server.http.content.LastModifiedVersion
import io.ktor.server.resources.get import io.ktor.server.resources.get
import io.ktor.server.response.respond import io.ktor.server.response.respond

View file

@ -41,7 +41,9 @@ val deployModToLocalClient by tasks.registering(Copy::class) {
description = "Copy the mod to the Factorio client" description = "Copy the mod to the Factorio client"
group = FactorioMod.TASK_GROUP group = FactorioMod.TASK_GROUP
onlyIf { clientModsDirectory.orNull?.asFile?.exists() == true } val clientModsDirectory123 = clientModsDirectory
onlyIf { clientModsDirectory123.orNull?.asFile?.exists() == true }
from(factorioMod) from(factorioMod)
into(clientModsDirectory) into(clientModsDirectory)
@ -61,9 +63,12 @@ val clientLaunch by tasks.registering(Exec::class) {
description = "Run local Factorio Steam game client" description = "Run local Factorio Steam game client"
group = FactorioMod.TASK_GROUP group = FactorioMod.TASK_GROUP
val steamExe123 = steamExe
val clientModsDirectory444 = clientModsDirectory
onlyIf(!serviceOf<ExecOperations>().isFactorioRunning()) onlyIf(!serviceOf<ExecOperations>().isFactorioRunning())
onlyIf { steamExe.orNull?.asFile?.exists() == true } onlyIf { steamExe123.orNull?.asFile?.exists() == true }
onlyIf { clientModsDirectory.orNull?.asFile?.exists() == true } onlyIf { clientModsDirectory444.orNull?.asFile?.exists() == true }
dependsOn(deployModToLocalClient) dependsOn(deployModToLocalClient)
mustRunAfter(clientKill, ":modules:infra-factorio-server:processRun") mustRunAfter(clientKill, ":modules:infra-factorio-server:processRun")

View file

@ -1,4 +1,4 @@
# Do not edit manually. This file was created with task 'dockerEnv' # Do not edit manually. This file was created with task 'dockerEnv'
COMPOSE_PROJECT_NAME=kafkatorio COMPOSE_PROJECT_NAME=kafkatorio
FACTORIO_VERSION=1.1.59 FACTORIO_VERSION=1.1.61
KAFKATORIO_VERSION=0.6.1 KAFKATORIO_VERSION=0.6.1

View file

@ -19,7 +19,7 @@ services:
logging: logging:
driver: syslog driver: syslog
options: options:
syslog-address: "tcp://host.docker.internal:12092" syslog-address: "tcp://host.docker.internal:12034"
syslog-format: "rfc5424" syslog-format: "rfc5424"
# environment: # environment:

View file

@ -6,7 +6,7 @@ import dev.adamko.kafkatorio.schema.packets.ConsoleCommandUpdate
import dev.adamko.kafkatorio.schema.packets.EntityUpdate import dev.adamko.kafkatorio.schema.packets.EntityUpdate
import dev.adamko.kafkatorio.schema.packets.EventServerPacket import dev.adamko.kafkatorio.schema.packets.EventServerPacket
import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData import dev.adamko.kafkatorio.schema.packets.KafkatorioPacketData
import dev.adamko.kafkatorio.schema.packets.MapChunkUpdate import dev.adamko.kafkatorio.schema.packets.MapChunkTileUpdate
import dev.adamko.kafkatorio.schema.packets.PlayerUpdate import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate
import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate
@ -84,7 +84,7 @@ class WebsocketService(
is PrototypesUpdate, is PrototypesUpdate,
is SurfaceUpdate, is SurfaceUpdate,
is EntityUpdate, is EntityUpdate,
is MapChunkUpdate, is MapChunkTileUpdate,
is KafkatorioPacketData.Error -> { is KafkatorioPacketData.Error -> {
// to be continued... // to be continued...
} }