diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/gradle/artifactDistributions.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/gradle/artifactDistributions.kt index 02bf554..b2f9beb 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/gradle/artifactDistributions.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/gradle/artifactDistributions.kt @@ -18,12 +18,14 @@ fun Configuration.asProvider() { isCanBeConsumed = true } + fun Configuration.asConsumer() { isVisible = false isCanBeResolved = true isCanBeConsumed = false } + fun Configuration.factorioModAttributes(objects: ObjectFactory): Configuration = attributes { attribute(USAGE_ATTRIBUTE, objects.named("factorio")) @@ -32,6 +34,7 @@ fun Configuration.factorioModAttributes(objects: ObjectFactory): Configuration = attribute(BUNDLING_ATTRIBUTE, objects.named(Bundling.EMBEDDED)) } + fun Configuration.typescriptAttributes(objects: ObjectFactory): Configuration = attributes { attribute(USAGE_ATTRIBUTE, objects.named("typescript")) diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/GenerateTypeScriptTask.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/GenerateTypeScriptTask.kt index fab29ae..331275b 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/GenerateTypeScriptTask.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/GenerateTypeScriptTask.kt @@ -6,8 +6,10 @@ import org.gradle.api.file.FileSystemOperations import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction +import org.gradle.work.DisableCachingByDefault +@DisableCachingByDefault(because = "caching makes regenerating more difficult") abstract class GenerateTypeScriptTask @Inject constructor( private val fileOps: FileSystemOperations, ) : JavaExec() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 10449f7..a4a42ab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,20 +16,22 @@ kvision = "5.11.0" log4j2 = "2.17.2" qosLogback = "1.2.11" slf4j = "1.7.36" -okio = "3.1.0" +okio = "3.2.0" scrimage = "4.0.31" semver = "1.2.0" kotlinx-serialization = "1.3.3" kxs-charleskornKaml = "0.44.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-nodejs = "0.0.7" -kotlinx-coroutines = "1.6.1" -kotlinx-cli = "0.3.4" -kotlinx-datetime = "0.3.3" ktor = "2.0.3" @@ -39,20 +41,24 @@ simpleSyslogParser = "0.0.6" kotkaStreams = "dev-SNAPSHOT" + ## test ## junit = "5.8.2" kotest = "5.3.1" mockk = "1.12.4" + ## infra ## -factorio = "1.1.59" +factorio = "1.1.61" confluent-kafkaConnect = "7.0.1" grafana = "8.5.0" prometheus = "v2.34.0" + ## gradle plugins ## gradleNodePlugin = "3.3.0" # https://github.com/node-gradle/gradle-node-plugin/releases + ######### [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-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf" } -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-charleskornKaml = { group = "com.charleskorn.kaml", name = "kaml", version.ref = "kxs-charleskornKaml" } +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" } diff --git a/modules/events-library/build.gradle.kts b/modules/events-library/build.gradle.kts index 8a716fa..b99515a 100644 --- a/modules/events-library/build.gradle.kts +++ b/modules/events-library/build.gradle.kts @@ -1,6 +1,9 @@ import dev.adamko.kafkatorio.gradle.asProvider import dev.adamko.kafkatorio.gradle.typescriptAttributes 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 { @@ -36,6 +39,7 @@ kotlin { all { languageSettings.apply { optIn("kotlin.ExperimentalStdlibApi") + optIn("kotlin.ExperimentalUnsignedTypes") optIn("kotlin.RequiresOptIn") optIn("kotlin.js.ExperimentalJsExport") optIn("kotlin.time.ExperimentalTime") @@ -51,7 +55,7 @@ kotlin { implementation(project.dependencies.platform(libs.kotlinx.serialization.bom)) implementation(libs.kotlinx.serialization.core) 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(libs.okio.core) @@ -96,16 +100,34 @@ kotlin { } +val kotlinJvmMainCompilation: NamedDomainObjectProvider = + kotlin.jvm().compilations.named(KotlinCompilation.MAIN_COMPILATION_NAME) + + val jvmJar: TaskProvider = tasks.named(kotlin.jvm().artifactsTaskName) -val mainCompilation: Provider = - kotlin.jvm().compilations.named("main").map { it.runtimeDependencyFiles } + +val kotlinMainRuntimeDependencies: Provider = + kotlinJvmMainCompilation.map { it.runtimeDependencyFiles } + +val kotlinMainCompileDependencies: Provider = + kotlinJvmMainCompilation.map { it.compileDependencyFiles } + +val kotlinMainCompileTask: Provider = + kotlinJvmMainCompilation.map { it.compileKotlinTask } val generateTypeScript by tasks.registering(GenerateTypeScriptTask::class) { dependsOn(jvmJar) +// dependsOn(kotlinMainCompileTask) + +// inputs.files(jvmJar.map { it.outputs.files }) +// inputs.files(kotlinMainCompileTask.map { it.javaSources }) + classpath( jvmJar, - mainCompilation, + kotlinMainRuntimeDependencies, +// kotlinMainCompileTask.map { it.libraries } +// kotlinMainDependencies, ) output.set(layout.buildDirectory.dir("generated/typescript")) mainClass.set("dev.adamko.kafkatorio.events.schema.Kt2ts2Kt") @@ -122,16 +144,26 @@ val generateTypeScriptOutputFiles: Provider = generateTypeScript.map { it.outputs.files.asFileTree } -val schemaTs by distributions.registering { - distributionBaseName.set(schemaTsDistributionName) - contents { - from(generateTypeScriptOutputFiles) - } +//val schemaTs by distributions.registering { +// distributionBaseName.set(schemaTsDistributionName) +// contents { +// from(generateTypeScriptOutputFiles) +// } +//} + + +//val schemaTsZipTask: TaskProvider = tasks.named("${schemaTs.name}DistZip") +//val schemaTsZipTaskArchiveFile: Provider = 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 schemaTsZipTask: TaskProvider = tasks.named("${schemaTs.name}DistZip") -val schemaTsZipTaskArchiveFile: Provider = schemaTsZipTask.flatMap { it.archiveFile } +val schemaTsZipTaskArchiveFile: Provider = schemaTsZip.flatMap { it.archiveFile } val typeScriptModelGenerated: Configuration by configurations.creating { @@ -139,4 +171,5 @@ val typeScriptModelGenerated: Configuration by configurations.creating { typescriptAttributes(objects) outgoing.artifact(schemaTsZipTaskArchiveFile) +// outgoing.artifact(schemaTsZipTaskArchiveFile) } diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt index a7b6b54..6aa4cae 100644 --- a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/colours.kt @@ -5,6 +5,7 @@ import kotlin.math.roundToInt import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable + /** * Red, green, blue and alpha values, all in range `[0, 1]` or all in range `[0, 255]` if any * value is > 1. diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/entities.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/entities.kt new file mode 100644 index 0000000..2a101a2 --- /dev/null +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/entities.kt @@ -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 + */ diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt index 9384d90..d091e67 100644 --- a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioIds.kt @@ -1,10 +1,12 @@ package dev.adamko.kafkatorio.schema.common import kotlin.jvm.JvmInline +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable +@SerialName("kafkatorio.id.Tick") @JvmInline 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) */ @Serializable +@SerialName("kafkatorio.id.SurfaceIndex") @JvmInline value class SurfaceIndex(private val id: UInt) { override fun toString(): String = "$id" @@ -24,6 +27,7 @@ value class SurfaceIndex(private val id: UInt) { @Serializable +@SerialName("kafkatorio.id.ForceIndex") @JvmInline value class ForceIndex(private val id: UInt) { override fun toString(): String = "$id" @@ -32,6 +36,7 @@ value class ForceIndex(private val id: UInt) { /** The player's index in `LuaGameScript::players` */ @Serializable +@SerialName("kafkatorio.id.PlayerIndex") @JvmInline value class PlayerIndex(private val id: UInt) { 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. */ @Serializable +@SerialName("kafkatorio.id.UnitNumber") @JvmInline value class UnitNumber(private val id: UInt) { override fun toString(): String = "$id" @@ -47,13 +53,7 @@ value class UnitNumber(private val id: UInt) { @Serializable -@JvmInline -value class PrototypeName(private val id: String) { - override fun toString(): String = id -} - - -@Serializable +@SerialName("kafkatorio.id.EventName") @JvmInline value class EventName(private val name: String) { override fun toString(): String = name @@ -62,23 +62,23 @@ value class EventName(private val name: String) { interface EntityIdentifiers { val unitNumber: UnitNumber? - val name: String - /** The prototype-type of the entity. */ - val protoType: String + /** The 'prototype type' and 'prototype name' of the entity. */ + val protoId: PrototypeId } // instant of EntityIdentifiers, because kxs needs a concrete instance @Serializable +@SerialName("kafkatorio.id.EntityIdentifiersData") data class EntityIdentifiersData( override val unitNumber: UnitNumber? = null, - override val name: String, - override val protoType: String, + override val protoId: PrototypeId, ) : EntityIdentifiers -@JvmInline @Serializable +@SerialName("kafkatorio.id.FactorioServerId") +@JvmInline value class FactorioServerId(private val id: String) { override fun toString() = id } diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt index 5f08e0c..393ad8a 100644 --- a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/factorioPrototypes.kt @@ -8,13 +8,14 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("kafkatorio.prototype.FactorioPrototype") sealed interface FactorioPrototype { - val name: PrototypeName + val protoId: PrototypeId val mapColour: Colour + @SerialName("kafkatorio.prototype.MapTile") @Serializable data class MapTile( - override val name: PrototypeName, + override val protoId: PrototypeId, override val mapColour: Colour, val layer: UInt, @@ -29,7 +30,7 @@ sealed interface FactorioPrototype { @SerialName("kafkatorio.prototype.Entity") @Serializable data class Entity( - override val name: PrototypeName, + override val protoId: PrototypeId, override val mapColour: Colour, val protoType: String, diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt index 20f41af..c7b98b8 100644 --- a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/mapTile.kt @@ -12,16 +12,16 @@ const val MAP_CHUNK_SIZE = 32 data class MapTile( val x: Int, val y: Int, - val proto: PrototypeName, + val protoId: PrototypeId, ) /** * 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]. * * Each X/Y coordinate in [tilesXY] maps to a [PrototypeKey]. @@ -30,9 +30,10 @@ data class MapTile( data class MapTileDictionary( /** Map an X,Y coordinate a prototype name */ val tilesXY: Map>, - val protos: Map, + val protos: Map, ) { - private val protosIndexToName: Map by lazy { + + private val protosIndexToId: Map by lazy { protos.entries.associate { (name, key) -> key to name } } @@ -41,11 +42,11 @@ data class MapTileDictionary( row.forEach { (yString, protoIndex) -> val x = xString.toIntOrNull() val y = yString.toIntOrNull() - val protoName = protosIndexToName[protoIndex] + val protoName = protosIndexToId[protoIndex] if (x != null && y != null && protoName != null) { add(MapTile(x, y, protoName)) } else if (protoName == null) { - println("warning: no prototype name found for index:$protoIndex. $protosIndexToName") + println("warning: no prototype name found for index:$protoIndex. $protosIndexToId") } } } diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/prototypeIds.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/prototypeIds.kt new file mode 100644 index 0000000..9cc98ba --- /dev/null +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/prototypeIds.kt @@ -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(""), +// 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(""), +// EntityWithOwner(""), +// Accumulator("accumulator"), +// ArtilleryTurret("artillery-turret"), +// Beacon("beacon"), +// Boiler("boiler"), +// BurnerGenerator("burner-generator"), +// Character("character"), +// Combinator(""), +// ArithmeticCombinator("arithmetic-combinator"), +// DeciderCombinator("decider-combinator"), +// ConstantCombinator("constant-combinator"), +// Container("container"), +// LogisticContainer("logistic-container"), +// InfinityContainer("infinity-container"), +// CraftingMachine(""), +// AssemblingMachine("assembling-machine"), +// RocketSilo("rocket-silo"), +// Furnace("furnace"), +// ElectricEnergyInterface("electric-energy-interface"), +// ElectricPole("electric-pole"), +// EnemySpawner("unit-spawner"), +// FlyingRobot(""), +// CombatRobot("combat-robot"), +// RobotWithLogisticInterface(""), +// 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(""), +// CurvedRail("curved-rail"), +// StraightRail("straight-rail"), +// RailSignalBase(""), +// 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(""), +// 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(""), +// Car("car"), +// RollingStock(""), +// 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(""), +// /** for migration, cannot be used */ +// SimpleSmoke("smoke"), +// SmokeWithTrigger("smoke-with-trigger"), +// SpeechBubble("speech-bubble"), +// Sticker("sticker"), +// TileGhost("tile-ghost"), +// Equipment(""), +// 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 = 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]] +
+* [[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]] +** [[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]] +*** [[Prototype/EntityWithOwner]] +**** [[Prototype/Accumulator]] '''accumulator''' +**** [[Prototype/ArtilleryTurret]] '''artillery-turret''' +**** [[Prototype/Beacon]] '''beacon''' +**** [[Prototype/Boiler]] '''boiler''' +**** [[Prototype/BurnerGenerator]] '''burner-generator''' +**** [[Prototype/Character]] '''character''' +**** [[Prototype/Combinator]] +***** [[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]] +***** [[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]] +***** [[Prototype/CombatRobot]] '''combat-robot''' +***** [[Prototype/RobotWithLogisticInterface]] +****** [[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]] +***** [[Prototype/CurvedRail]] '''curved-rail''' +***** [[Prototype/StraightRail]] '''straight-rail''' +**** [[Prototype/RailSignalBase]] +***** [[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]] +***** [[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]] +***** [[Prototype/Car]] '''car''' +***** [[Prototype/RollingStock]] +****** [[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]] +*** [[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]] +** [[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''' + + */ diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt index d21a750..bec5bf3 100644 --- a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/common/resources.kt @@ -6,16 +6,11 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("kafkatorio.resource.MinedProduct") -data class MinedProduct( - /** `item` or `fluid`. */ - val type: Type, +sealed interface MinedProduct { - /** Prototype name of the result. */ - @SerialName("name") - val resultPrototype: PrototypeName, - -//Amount of the item or fluid to give. If not specified, amount_min, amount_max and probability must all be specified. - val amount: Double?, + val resultProtoId: PrototypeId + //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. //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. //probability : Double?, -//How much of this product is a catalyst. + //How much of this product is a catalyst. //catalyst_amount : Uint or double?, -) { + @Serializable - @SerialName("kafkatorio.resource.MinedProductType") - enum class Type { - @SerialName("item") - ITEM, - @SerialName("fluid") - FLUID, - } + @SerialName("kafkatorio.resource.MinedProduct.MinedProductFluid") + data class Fluid( + override val amount: Double? = null, + override val resultProtoId: PrototypeId, + ) : MinedProduct + + + @Serializable + @SerialName("kafkatorio.resource.MinedProduct.MinedProductItem") + data class Item( + override val amount: Double? = null, + override val resultProtoId: PrototypeId, + ) : MinedProduct + } diff --git a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt index 8d93b8a..748ac8b 100644 --- a/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt +++ b/modules/events-library/src/commonMain/kotlin/dev/adamko/kafkatorio/schema/packets/kafkatorioPacketKeyed.kt @@ -4,12 +4,13 @@ import dev.adamko.kafkatorio.schema.common.Colour import dev.adamko.kafkatorio.schema.common.EntityIdentifiers import dev.adamko.kafkatorio.schema.common.EntityIdentifiersData 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.MapChunkPosition import dev.adamko.kafkatorio.schema.common.MapEntityPosition import dev.adamko.kafkatorio.schema.common.MapTileDictionary 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.Tick import dev.adamko.kafkatorio.schema.common.UnitNumber @@ -23,6 +24,8 @@ import kotlinx.serialization.Serializable sealed class KafkatorioKeyedPacketData : KafkatorioPacketData() { abstract val key: KafkatorioKeyedPacketKey /** A list of all events that have been aggregated into this packet. */ + // Maybe change to be Map, 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>? } @@ -40,8 +43,7 @@ sealed class KafkatorioKeyedPacketKey data class EntityUpdateKey( /** While normally optional, here a [unitNumber] is required for caching */ override val unitNumber: UnitNumber, - override val name: String, - override val protoType: String, + override val protoId: PrototypeId, ) : EntityIdentifiers, KafkatorioKeyedPacketKey() @@ -60,7 +62,6 @@ data class EntityUpdate( val lastUser: UInt? = null, val localisedDescription: String? = null, val localisedName: String? = null, - val prototype: PrototypeName? = null, ) : KafkatorioKeyedPacketData() @@ -68,17 +69,18 @@ data class EntityUpdate( @Serializable -@SerialName("kafkatorio.packet.keyed.MapChunkUpdateKey") -data class MapChunkUpdateKey( +@SerialName("kafkatorio.packet.keyed.MapChunkTileUpdateKey") +data class MapChunkTileUpdateKey( +// val index: PlayerIndex, // maybe add player/robot key, to allow metrics like 'player x mined y tiles' val chunkPosition: MapChunkPosition, val surfaceIndex: SurfaceIndex, ) : KafkatorioKeyedPacketKey() @Serializable -@SerialName("kafkatorio.packet.keyed.MapChunkUpdate") -data class MapChunkUpdate( - override val key: MapChunkUpdateKey, +@SerialName("kafkatorio.packet.keyed.MapChunkTileUpdate") +data class MapChunkTileUpdate( + override val key: MapChunkTileUpdateKey, override val events: Map>? = null, @@ -93,6 +95,7 @@ data class MapChunkUpdate( /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ + @Serializable @SerialName("kafkatorio.packet.keyed.PlayerUpdateKey") data class PlayerUpdateKey( @@ -134,4 +137,32 @@ data class PlayerUpdate( ) : 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>? = null, + + val distinctEntities: Map? = null, +) : KafkatorioKeyedPacketData() + + /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ diff --git a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt index 9a3aaf9..53c2b62 100644 --- a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt +++ b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/MapChunkUpdateTest.kt @@ -4,12 +4,12 @@ import dev.adamko.kafkatorio.library.jsonMapperKafkatorio import dev.adamko.kafkatorio.schema.common.EventName import dev.adamko.kafkatorio.schema.common.MapChunkPosition 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.tick import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket -import dev.adamko.kafkatorio.schema.packets.MapChunkUpdate -import dev.adamko.kafkatorio.schema.packets.MapChunkUpdateKey +import dev.adamko.kafkatorio.schema.packets.MapChunkTileUpdate +import dev.adamko.kafkatorio.schema.packets.MapChunkTileUpdateKey import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import kotlinx.serialization.decodeFromString @@ -59,8 +59,8 @@ class MapChunkUpdateTest : FunSpec({ val expected = KafkatorioPacket( tick = 36u.tick, modVersion = "0.4.0", - data = MapChunkUpdate( - key = MapChunkUpdateKey( + data = MapChunkTileUpdate( + key = MapChunkTileUpdateKey( MapChunkPosition(-6, -3), SurfaceIndex(1u), ), @@ -78,9 +78,9 @@ class MapChunkUpdateTest : FunSpec({ ), ), protos = mapOf( - PrototypeName("water") to MapTileDictionary.PrototypeKey(1), - PrototypeName("grass-4") to MapTileDictionary.PrototypeKey(2), - PrototypeName("grass-3") to MapTileDictionary.PrototypeKey(32), + PrototypeId("tile", "water") to MapTileDictionary.PrototypeKey(1), + PrototypeId("tile", "grass-4") to MapTileDictionary.PrototypeKey(2), + PrototypeId("tile", "grass-3") to MapTileDictionary.PrototypeKey(32), ) ) ) diff --git a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt index 17387a2..022e939 100644 --- a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt +++ b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/PrototypesTest.kt @@ -3,7 +3,7 @@ package dev.adamko.kafkatorio.events.schema import dev.adamko.kafkatorio.library.jsonMapperKafkatorio import dev.adamko.kafkatorio.schema.common.Colour 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.PrototypesUpdate import io.kotest.core.spec.style.BehaviorSpec @@ -12,6 +12,7 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeInstanceOf import kotlinx.serialization.decodeFromString + class PrototypesTest : BehaviorSpec({ Given("Prototypes Json") { // language=JSON @@ -669,7 +670,7 @@ class PrototypesTest : BehaviorSpec({ .prototypes .forOne { it.shouldBeInstanceOf() - it.name shouldBe PrototypeName("tutorial-grid") + it.protoId shouldBe PrototypeId.MapTile("tutorial-grid") it.order shouldBe "z[other]-c[tutorial]-a[tutorial-grid]" it.layer shouldBe 55u it.collisionMasks shouldBe listOf("ground-tile") diff --git a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt index b6249c6..b1f2e17 100644 --- a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt +++ b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/events/schema/UpdatePacketsTest.kt @@ -7,6 +7,7 @@ import dev.adamko.kafkatorio.schema.common.EventName import dev.adamko.kafkatorio.schema.common.ForceIndex import dev.adamko.kafkatorio.schema.common.MapEntityPosition 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.Tick import dev.adamko.kafkatorio.schema.common.UnitNumber @@ -190,8 +191,7 @@ class UpdatePacketsTest : FunSpec({ colour = null, diedCause = EntityIdentifiersData( unitNumber = UnitNumber(66u), - name = "small-biter", - protoType = "unit", + protoId = PrototypeId("unit/small-biter"), ), disconnectReason = null, events = mapOf( diff --git a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt index 720c405..c611056 100644 --- a/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt +++ b/modules/events-library/src/commonTest/kotlin/dev/adamko/kafkatorio/schema/common/MapTileDictionaryTest.kt @@ -20,22 +20,22 @@ class MapTileDictionaryTest : FunSpec({ "44" to mapOf("1" to MapTileDictionary.PrototypeKey(44)), ), protos = mapOf( - PrototypeName("water") to MapTileDictionary.PrototypeKey(1), - PrototypeName("grass-4") to MapTileDictionary.PrototypeKey(2), - PrototypeName("grass-3") to MapTileDictionary.PrototypeKey(32), + PrototypeId.MapTile("water") to MapTileDictionary.PrototypeKey(1), + PrototypeId.MapTile("grass-4") to MapTileDictionary.PrototypeKey(2), + 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") { actual.toMapTileList() shouldContainAll listOf( - MapTile(-192, -65, PrototypeName("grass-4")), + MapTile(-192, -65, PrototypeId.MapTile("grass-4")), - MapTile(161, -96, PrototypeName("water")), - MapTile(161, -95, PrototypeName("grass-4")), - MapTile(161, 94, PrototypeName("grass-4")), - MapTile(161, 93, PrototypeName("grass-3")), + MapTile(161, -96, PrototypeId.MapTile("water")), + MapTile(161, -95, PrototypeId.MapTile("grass-4")), + MapTile(161, 94, PrototypeId.MapTile("grass-4")), + MapTile(161, 93, PrototypeId.MapTile("grass-3")), ) } } diff --git a/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt b/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt index 36b0972..69be148 100644 --- a/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt +++ b/modules/events-library/src/jvmMain/kotlin/dev/adamko/kafkatorio/events/schema/kt2ts2.kt @@ -1,11 +1,16 @@ 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.kxstsgen.KxsTsConfig +import dev.adamko.kxstsgen.KxsTsConfig.TypeAliasTypingConfig.BrandTyping import dev.adamko.kxstsgen.KxsTsGenerator import dev.adamko.kxstsgen.core.TsDeclaration.TsTypeAlias import dev.adamko.kxstsgen.core.TsElementId import dev.adamko.kxstsgen.core.TsLiteral +import dev.adamko.kxstsgen.core.TsSourceCodeGenerator import dev.adamko.kxstsgen.core.TsTypeRef import kotlin.io.path.Path import kotlin.io.path.createDirectories @@ -13,14 +18,24 @@ import kotlinx.serialization.builtins.serializer import org.intellij.lang.annotations.Language -@ExperimentalUnsignedTypes fun main(args: Array) { 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( //@formatter:off @@ -32,6 +47,10 @@ fun main(args: Array) { 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)), 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 ) @@ -60,3 +79,26 @@ val kt2tsHeader = """ |// Generated by kxs-ts-gen - do not edit this file manually | """.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) + } + } +} diff --git a/modules/events-mod/build.gradle.kts b/modules/events-mod/build.gradle.kts index 9380d84..e1d4cd7 100644 --- a/modules/events-mod/build.gradle.kts +++ b/modules/events-mod/build.gradle.kts @@ -101,7 +101,7 @@ val installEventsTsSchema by tasks.registering(Sync::class) { } ) { // drop the first directory inside the zip - eachFile { relativePath = dropDirectory() } +// eachFile { relativePath = dropDirectory() } includeEmptyDirs = false } into(outputDir) diff --git a/modules/events-mod/package-lock.json b/modules/events-mod/package-lock.json index d3a6fbd..c81337c 100644 --- a/modules/events-mod/package-lock.json +++ b/modules/events-mod/package-lock.json @@ -75,9 +75,9 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" }, "typed-factorio": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/typed-factorio/-/typed-factorio-1.3.0.tgz", - "integrity": "sha512-qBHKjE+m9Im7vDhsGvl0uwaSFzJ5asqyfw414gF0owZwmSax2CIjdLx367qUgdD4flsB0n9HecBaZ0Yzt9zMPQ==" + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/typed-factorio/-/typed-factorio-1.3.2.tgz", + "integrity": "sha512-sAVIDvSSBPWL7trI94SPd2Suq9dLjXmXL1WFKJIYJpFQocNwJUb0ydGRBsvJjZhVAyEZYJC0lHlDWH47RWP/tw==" }, "typescript": { "version": "4.7.4", diff --git a/modules/events-mod/package.json b/modules/events-mod/package.json index 41f214b..a0f189b 100644 --- a/modules/events-mod/package.json +++ b/modules/events-mod/package.json @@ -9,15 +9,19 @@ "engines": { "node": "~14.19.1" }, - "devDependencies": {}, + "devDependencies": { + }, "dependencies": { "lua-types": "^2.11.0", "typescript-to-lua": "1.6.1", - "typed-factorio": "1.3.0", + "typed-factorio": "1.3.2", "typescript": "4.7.4" }, "license": "UNLICENSED", - "peerDependencies": {}, - "optionalDependencies": {}, - "bundledDependencies": [] + "peerDependencies": { + }, + "optionalDependencies": { + }, + "bundledDependencies": [ + ] } diff --git a/modules/events-mod/src/generated/lua/control.lua b/modules/events-mod/src/generated/lua/control.lua index 0bd8e16..a2839ec 100644 --- a/modules/events-mod/src/generated/lua/control.lua +++ b/modules/events-mod/src/generated/lua/control.lua @@ -3,7 +3,7 @@ local ____global_2Dinit = require("main.global-init") local initGlobal = ____global_2Dinit.initGlobal local ____prototypeUpdates = require("main.events.prototypeUpdates") local emitPrototypes = ____prototypeUpdates.emitPrototypes -require("main.events.registerHandlers") +require("main.events.registerEventListeners") require("main.events.mapChunkUpdates") require("main.events.playerUpdates") require("main.events.entityUpdates") diff --git a/modules/events-mod/src/generated/lua/generated/kafkatorio-schema.lua b/modules/events-mod/src/generated/lua/generated/kafkatorio-schema.lua index 65df7de..46a4058 100644 --- a/modules/events-mod/src/generated/lua/generated/kafkatorio-schema.lua +++ b/modules/events-mod/src/generated/lua/generated/kafkatorio-schema.lua @@ -9,7 +9,8 @@ do KafkatorioPacketData.Type.PrototypesUpdate = "kafkatorio.packet.instant.PrototypesUpdate" KafkatorioPacketData.Type.SurfaceUpdate = "kafkatorio.packet.instant.SurfaceUpdate" 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.Error = "kafkatorio.packet.KafkatorioPacketData.Error" end @@ -20,7 +21,62 @@ do FactorioPrototype.Type.Entity = "kafkatorio.prototype.Entity" FactorioPrototype.Type.MapTile = "kafkatorio.prototype.MapTile" end -____exports.MinedProductType = MinedProductType or ({}) -____exports.MinedProductType.item = "item" -____exports.MinedProductType.fluid = "fluid" +____exports.FactorioEntityData = {} +local FactorioEntityData = ____exports.FactorioEntityData +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 diff --git a/modules/events-mod/src/generated/lua/main/events/converters.lua b/modules/events-mod/src/generated/lua/main/events/converters.lua index 4dcc755..2131d67 100644 --- a/modules/events-mod/src/generated/lua/main/events/converters.lua +++ b/modules/events-mod/src/generated/lua/main/events/converters.lua @@ -1,7 +1,22 @@ local ____exports = {} +local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") +local EntityStatus = ____kafkatorio_2Dschema.EntityStatus +local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData ____exports.Converters = {} local Converters = ____exports.Converters 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 = {} for eventName, eventId in pairs(defines.events) do mapEventIdToName[eventId] = eventName @@ -36,5 +51,86 @@ do end return masks 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 return ____exports diff --git a/modules/events-mod/src/generated/lua/main/events/entityUpdates.lua b/modules/events-mod/src/generated/lua/main/events/entityUpdates.lua index c5fd3ee..86eb956 100644 --- a/modules/events-mod/src/generated/lua/main/events/entityUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/entityUpdates.lua @@ -1,105 +1,203 @@ +local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class +local __TS__New = ____lualib.__TS__New local ____exports = {} -local handleBuiltEntityEvent, handleMinedEntityEvent local ____converters = require("main.events.converters") local Converters = ____converters.Converters local ____EventDataCache = require("main.cache.EventDataCache") local EventDataCache = ____EventDataCache.default local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") +local FactorioEntityData = ____kafkatorio_2Dschema.FactorioEntityData local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData -function handleBuiltEntityEvent(event) - local eventName = Converters.eventNameString(event.name) - if event.created_entity.unit_number == nil then +____exports.EntityUpdatesHandler = __TS__Class() +local EntityUpdatesHandler = ____exports.EntityUpdatesHandler +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 end - local key = {name = event.created_entity.name, protoType = event.created_entity.prototype.name, unitNumber = event.created_entity.unit_number} - EventDataCache:debounce( - key, - KafkatorioPacketData.Type.EntityUpdate, + local tilesByChunk = {} + for ____, tile in ipairs(event.tiles) do + local chunkPosition = Converters.tilePositionToChunkPosition(tile.position) + 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) if data.events == nil then data.events = {} end - local ____data_events_0, ____eventName_1 = data.events, eventName - if ____data_events_0[____eventName_1] == nil then - ____data_events_0[____eventName_1] = {} + local ____data_events_8, ____eventName_9 = data.events, eventName + if ____data_events_8[____eventName_9] == nil then + ____data_events_8[____eventName_9] = {} end - local ____data_events_eventName_2 = data.events[eventName] - ____data_events_eventName_2[#____data_events_eventName_2 + 1] = 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 - 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 + local ____data_events_eventName_10 = data.events[eventName] + ____data_events_eventName_10[#____data_events_eventName_10 + 1] = event.tick + if data.distinctEntities == nil then + data.distinctEntities = {} end - ____data_5.lastUser = ____event_created_entity_last_user_index_3 - data.prototype = event.created_entity.prototype.name + data.distinctEntities[entityKey] = entityUpdate end ) end -function handleMinedEntityEvent(event) - local eventName = Converters.eventNameString(event.name) - if event.entity.unit_number == nil then - return +function EntityUpdatesHandler.throttleResourceEntitiesUpdate(self, eventName, eventTick, surfaceIndex, chunkPosition, entities) + local entitiesByProtoId = {} + for ____, entity in ipairs(entities) do + 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 - local key = {name = event.entity.name, protoType = event.entity.prototype.name, unitNumber = event.entity.unit_number} - EventDataCache:debounce( - key, - KafkatorioPacketData.Type.EntityUpdate, - function(data) - if data.events == nil then - data.events = {} + for protoId, resourceEntities in pairs(entitiesByProtoId) do + local entityUpdateKey = {protoId = protoId, surfaceIndex = surfaceIndex, chunkPosition = {chunkPosition[1], chunkPosition[2]}} + EventDataCache:throttle( + entityUpdateKey, + KafkatorioPacketData.Type.MapChunkEntityUpdate, + function(data) + 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 - local ____data_events_6, ____eventName_7 = data.events, eventName - if ____data_events_6[____eventName_7] == nil then - ____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( defines.events.on_built_entity, function(e) log("on_built_entity " .. tostring(e.tick)) - handleBuiltEntityEvent(e) + EntityUpdates:handleBuiltEntityEvent(e) end ) script.on_event( defines.events.on_robot_built_entity, function(e) log("on_robot_built_entity " .. tostring(e.tick)) - handleBuiltEntityEvent(e) + EntityUpdates:handleBuiltEntityEvent(e) end ) script.on_event( defines.events.on_player_mined_entity, function(e) log("on_player_mined_entity " .. tostring(e.tick)) - handleMinedEntityEvent(e) + EntityUpdates:handleMinedEntityEvent(e) end ) script.on_event( defines.events.on_robot_mined_entity, function(e) log("on_robot_mined_entity " .. tostring(e.tick)) - handleMinedEntityEvent(e) + EntityUpdates:handleMinedEntityEvent(e) end ) return ____exports diff --git a/modules/events-mod/src/generated/lua/main/events/mapChunkUpdates.lua b/modules/events-mod/src/generated/lua/main/events/mapChunkUpdates.lua index 146ade2..a21a929 100644 --- a/modules/events-mod/src/generated/lua/main/events/mapChunkUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/mapChunkUpdates.lua @@ -1,9 +1,9 @@ local ____lualib = require("lualib_bundle") +local __TS__Class = ____lualib.__TS__Class local Map = ____lualib.Map local __TS__Iterator = ____lualib.__TS__Iterator local __TS__New = ____lualib.__TS__New local ____exports = {} -local mapTilesUpdateDebounce, getTiles, getSurface, groupTiles, handleBuiltTileEvent, handleMinedTileEvent, Type local ____eventTypeCheck = require("main.events.eventTypeCheck") local isEventType = ____eventTypeCheck.isEventType local ____converters = require("main.events.converters") @@ -12,65 +12,16 @@ local ____EventDataCache = require("main.cache.EventDataCache") local EventUpdatesManager = ____EventDataCache.default local ____kafkatorio_2Dschema = require("generated.kafkatorio-schema") local KafkatorioPacketData = ____kafkatorio_2Dschema.KafkatorioPacketData -function mapTilesUpdateDebounce(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.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 - ) +local ____entityUpdates = require("main.events.entityUpdates") +local EntityUpdates = ____entityUpdates.default +local Type = KafkatorioPacketData.Type +local MapChunkUpdateHandler = __TS__Class() +MapChunkUpdateHandler.name = "MapChunkUpdateHandler" +function MapChunkUpdateHandler.prototype.____constructor(self) end -function getTiles(surface, area) - local ____surface_find_tiles_filtered_result_8 = surface - if ____surface_find_tiles_filtered_result_8 ~= nil then - ____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( +function MapChunkUpdateHandler.prototype.handleChunkGeneratedEvent(self, event, expirationDurationTicks) + local tiles = event.surface.find_tiles_filtered({area = event.area}) + MapChunkUpdateHandler:mapTilesUpdateDebounce( event.surface, Converters.convertMapTablePosition(event.position), tiles, @@ -79,38 +30,19 @@ function ____exports.handleChunkGeneratedEvent(event, expirationDurationTicks) expirationDurationTicks ) end -function groupTiles(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_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) +function MapChunkUpdateHandler.prototype.handleBuiltTileEvent(self, event) + local surface = game.get_surface(event.surface_index) if surface == nil then local eventName = Converters.eventNameString(event.name) log("[handleBuiltTileEvent] undefined surface " .. eventName) return end local tiles = Converters.convertPlacedTiles(event.tile, event.tiles) - local groupedTiles = groupTiles(tiles) + local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles) for ____, ____value in __TS__Iterator(groupedTiles) do local chunkPos = ____value[1] local tiles = ____value[2] - mapTilesUpdateDebounce( + MapChunkUpdateHandler:mapTilesUpdateDebounce( surface, chunkPos, tiles, @@ -121,12 +53,15 @@ function handleBuiltTileEvent(event) return end if isEventType(event, defines.events.on_robot_built_tile) then - local ____data_15 = data - local ____event_robot_unit_number_13 = event.robot - if ____event_robot_unit_number_13 ~= nil then - ____event_robot_unit_number_13 = ____event_robot_unit_number_13.unit_number + local ____data_2 = data + local ____event_robot_unit_number_0 = event.robot + if ____event_robot_unit_number_0 ~= nil then + ____event_robot_unit_number_0 = ____event_robot_unit_number_0.unit_number 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 end local exhaustiveCheck = event @@ -134,19 +69,19 @@ function handleBuiltTileEvent(event) ) end end -function handleMinedTileEvent(event) - local surface = getSurface(event.surface_index) +function MapChunkUpdateHandler.prototype.handleMinedTileEvent(self, event) + local surface = game.get_surface(event.surface_index) if surface == nil then local eventName = Converters.eventNameString(event.name) log("[handleMinedTileEvent] undefined surface " .. eventName) return end local tiles = Converters.convertRemovedTiles(surface, event.tiles) - local groupedTiles = groupTiles(tiles) + local groupedTiles = MapChunkUpdateHandler:groupTiles(tiles) for ____, ____value in __TS__Iterator(groupedTiles) do local chunkPos = ____value[1] local tiles = ____value[2] - mapTilesUpdateDebounce( + MapChunkUpdateHandler:mapTilesUpdateDebounce( surface, chunkPos, tiles, @@ -157,12 +92,15 @@ function handleMinedTileEvent(event) return end if isEventType(event, defines.events.on_robot_mined_tile) then - local ____data_18 = data - local ____event_robot_unit_number_16 = event.robot - if ____event_robot_unit_number_16 ~= nil then - ____event_robot_unit_number_16 = ____event_robot_unit_number_16.unit_number + local ____data_5 = data + local ____event_robot_unit_number_3 = event.robot + if ____event_robot_unit_number_3 ~= nil then + ____event_robot_unit_number_3 = ____event_robot_unit_number_3.unit_number 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 end local exhaustiveCheck = event @@ -170,78 +108,155 @@ function handleMinedTileEvent(event) ) 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( defines.events.on_chunk_generated, function(e) log("on_chunk_generated " .. tostring(e.tick)) - ____exports.handleChunkGeneratedEvent(e) + MapChunkUpdate:handleChunkGeneratedEvent(e) + EntityUpdates:handleChunkGeneratedEvent(e) end ) script.on_event( defines.events.script_raised_set_tiles, function(event) log("script_raised_set_tiles " .. tostring(event.tick)) - local surface = getSurface(event.surface_index) - 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 + MapChunkUpdate:handleScriptSetTilesEvent(event) end ) script.on_event( defines.events.on_player_built_tile, function(e) log("on_player_built_tile " .. tostring(e.tick)) - handleBuiltTileEvent(e) + MapChunkUpdate:handleBuiltTileEvent(e) end ) script.on_event( defines.events.on_robot_built_tile, function(e) log("on_robot_built_tile " .. tostring(e.tick)) - handleBuiltTileEvent(e) + MapChunkUpdate:handleBuiltTileEvent(e) end ) script.on_event( defines.events.on_player_mined_tile, function(e) log("on_player_mined_tile " .. tostring(e.tick)) - handleMinedTileEvent(e) + MapChunkUpdate:handleMinedTileEvent(e) + EntityUpdates:handleMinedTileEvent(e) end ) script.on_event( defines.events.on_robot_mined_tile, function(e) log("on_robot_mined_tile " .. tostring(e.tick)) - handleMinedTileEvent(e) + MapChunkUpdate:handleMinedTileEvent(e) end ) script.on_event( defines.events.on_pre_chunk_deleted, function(e) log("on_pre_chunk_deleted " .. tostring(e.tick)) - local surface = getSurface(e.surface_index) - 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 + MapChunkUpdate:handlePreChunkDeleted(e) end ) return ____exports diff --git a/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua b/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua index 3cfa307..47840de 100644 --- a/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/playerUpdates.lua @@ -115,7 +115,10 @@ script.on_event( data.ticksToRespawn = player.ticks_to_respawn or nil playerOnlineInfo(player, data) 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 ) diff --git a/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua b/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua index 1daa787..a1d6f07 100644 --- a/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua +++ b/modules/events-mod/src/generated/lua/main/events/prototypeUpdates.lua @@ -22,7 +22,7 @@ function getMapTilePrototypes() for ____, tile in pairs(game.tile_prototypes) do tiles[#tiles + 1] = { type = FactorioPrototype.Type.MapTile, - name = tile.name, + protoId = Converters.prototypeId("tile", tile.name), order = tile.order, layer = tile.layer, collisionMasks = Converters.convertCollisionMaskToNames(tile.collision_mask), diff --git a/modules/events-mod/src/generated/lua/main/events/registerHandlers.lua b/modules/events-mod/src/generated/lua/main/events/registerEventListeners.lua similarity index 93% rename from modules/events-mod/src/generated/lua/main/events/registerHandlers.lua rename to modules/events-mod/src/generated/lua/main/events/registerEventListeners.lua index 65aacb2..757ef9a 100644 --- a/modules/events-mod/src/generated/lua/main/events/registerHandlers.lua +++ b/modules/events-mod/src/generated/lua/main/events/registerEventListeners.lua @@ -5,12 +5,12 @@ local ____eventTypeCheck = require("main.events.eventTypeCheck") local isEventType = ____eventTypeCheck.isEventType local ____converters = require("main.events.converters") local Converters = ____converters.Converters -local ____mapChunkUpdates = require("main.events.mapChunkUpdates") -local handleChunkGeneratedEvent = ____mapChunkUpdates.handleChunkGeneratedEvent local ____surfaceUpdates = require("main.events.surfaceUpdates") local handleSurfaceUpdate = ____surfaceUpdates.handleSurfaceUpdate local ____EventDataCache = require("main.cache.EventDataCache") local EventCacheService = ____EventDataCache.default +local ____mapChunkUpdates = require("main.events.mapChunkUpdates") +local MapChunkUpdate = ____mapChunkUpdates.default script.on_event( defines.events.on_tick, function(event) @@ -38,7 +38,7 @@ script.on_event( if isEventType(event, defines.events.on_chunk_generated) then local eName = Converters.eventNameString(event.name) log((((("[on_tick:" .. tostring(event.tick)) .. "] dequed event ") .. eName) .. ", delay ") .. tostring(i)) - handleChunkGeneratedEvent(event, i) + MapChunkUpdate:handleChunkGeneratedEvent(event, i) i = i + 1 end end diff --git a/modules/events-mod/src/generated/lua/main/events/resourceEntityUpdates.lua b/modules/events-mod/src/generated/lua/main/events/resourceEntityUpdates.lua new file mode 100644 index 0000000..e69de29 diff --git a/modules/events-mod/src/generated/lua/main/settings/KafkatorioSettings.lua b/modules/events-mod/src/generated/lua/main/settings/KafkatorioSettings.lua index aa8a574..28eac97 100644 --- a/modules/events-mod/src/generated/lua/main/settings/KafkatorioSettings.lua +++ b/modules/events-mod/src/generated/lua/main/settings/KafkatorioSettings.lua @@ -34,7 +34,7 @@ end function KafkatorioSettingsConfig.cacheDurationSettingName(self, ____type) return "kafkatorio:cache-expiration-seconds_" .. __TS__StringReplaceAll(____type, ".", "-") 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) ____exports.default = KafkatorioSettings return ____exports diff --git a/modules/events-mod/src/main/resources/mod-data/locale/en/locale.cfg b/modules/events-mod/src/main/resources/mod-data/locale/en/locale.cfg index 491d391..f3d4ab6 100644 --- a/modules/events-mod/src/main/resources/mod-data/locale/en/locale.cfg +++ b/modules/events-mod/src/main/resources/mod-data/locale/en/locale.cfg @@ -1,14 +1,16 @@ [mod-setting-name] 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) [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-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! diff --git a/modules/events-mod/src/main/typescript/control.ts b/modules/events-mod/src/main/typescript/control.ts index 3800be5..3cb0824 100644 --- a/modules/events-mod/src/main/typescript/control.ts +++ b/modules/events-mod/src/main/typescript/control.ts @@ -1,7 +1,7 @@ import {initGlobal} from "./main/global-init"; import {emitPrototypes} from "./main/events/prototypeUpdates"; -require("./main/events/registerHandlers") +require("./main/events/registerEventListeners") require("./main/events/mapChunkUpdates") require("./main/events/playerUpdates") require("./main/events/entityUpdates") diff --git a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema.ts b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema.ts index e01e826..0ff6cea 100644 --- a/modules/events-mod/src/main/typescript/generated/kafkatorio-schema.ts +++ b/modules/events-mod/src/main/typescript/generated/kafkatorio-schema.ts @@ -14,7 +14,8 @@ export type KafkatorioPacketData = | KafkatorioPacketData.ConsoleCommandUpdate | KafkatorioPacketData.EntityUpdate | KafkatorioPacketData.Error - | KafkatorioPacketData.MapChunkUpdate + | KafkatorioPacketData.MapChunkEntityUpdate + | KafkatorioPacketData.MapChunkTileUpdate | KafkatorioPacketData.PlayerUpdate | KafkatorioPacketData.PrototypesUpdate | KafkatorioPacketData.SurfaceUpdate; @@ -27,7 +28,8 @@ export namespace KafkatorioPacketData { PrototypesUpdate = "kafkatorio.packet.instant.PrototypesUpdate", SurfaceUpdate = "kafkatorio.packet.instant.SurfaceUpdate", 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", Error = "kafkatorio.packet.KafkatorioPacketData.Error", } @@ -77,12 +79,18 @@ export namespace KafkatorioPacketData { lastUser?: UInt | null; localisedDescription?: string | null; localisedName?: string | null; - prototype?: PrototypeName | null; } - export interface MapChunkUpdate { - type: KafkatorioPacketData.Type.MapChunkUpdate; - key: MapChunkUpdateKey; + export interface MapChunkEntityUpdate { + type: KafkatorioPacketData.Type.MapChunkEntityUpdate; + 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; player?: PlayerIndex | null; robot?: EntityIdentifiersData | null; @@ -132,16 +140,11 @@ export interface ConfigurationUpdateGameData { newVersion?: string | null; } -export type PlayerIndex = UInt; - -export type SurfaceIndex = UInt; - export type Double = double; export interface EntityUpdateKey { unitNumber: UnitNumber; - name: string; - protoType: string; + protoId: PrototypeId; } export type MapEntityPosition = [ @@ -153,32 +156,33 @@ export type UByte = uint8; 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; surfaceIndex: SurfaceIndex; } export interface EntityIdentifiersData { unitNumber?: UnitNumber | null; - name: string; - protoType: string; + protoId: PrototypeId; } -export type ForceIndex = UInt; +export type ForceIndex = UInt & { __ForceIndex__: void }; export interface MapTileDictionary { tilesXY: { [key: string]: { [key: string]: PrototypeKey } }; - protos: { [key: PrototypeName]: PrototypeKey }; + protos: { [key: PrototypeId]: PrototypeKey }; } export interface PlayerUpdateKey { index: PlayerIndex; } -export type UnitNumber = UInt; - export type Colour = [ red: Float, green: Float, @@ -206,7 +210,7 @@ export namespace FactorioPrototype { export interface Entity { type: FactorioPrototype.Type.Entity; - name: PrototypeName; + protoId: PrototypeId; mapColour: Colour; protoType: string; objectName: string; @@ -220,7 +224,7 @@ export namespace FactorioPrototype { export interface MapTile { type: FactorioPrototype.Type.MapTile; - name: PrototypeName; + protoId: PrototypeId; mapColour: Colour; layer: UInt; 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; @@ -238,22 +244,114 @@ export type MapChunkPosition = [ 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 { canBeMined: boolean; products: MinedProduct[] | null; } -export type List = any; +export type List = any & { __List__: void }; -export type PrototypeKey = Int; - -export interface MinedProduct { - type: MinedProductType; - name: PrototypeName; - amount: Double | null; +export enum EntityStatus { + CANT_DIVIDE_SEGMENTS = "CANT_DIVIDE_SEGMENTS", + CHARGING = "CHARGING", + CLOSED_BY_CIRCUIT_NETWORK = "CLOSED_BY_CIRCUIT_NETWORK", + DISABLED = "DISABLED", + 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 { - item = "item", - fluid = "fluid", +export type PrototypeKey = Int & { __PrototypeKey__: void }; + +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; + } } \ No newline at end of file diff --git a/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts b/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts index 17bcabb..4c9b572 100644 --- a/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts +++ b/modules/events-mod/src/main/typescript/main/cache/EventDataCache.ts @@ -101,7 +101,7 @@ export namespace EventUpdates { let countExpired = 0 let countTotal = 0 const expiredData: Array = [] - for (let [key, entry] of global.cache) { + for (const [key, entry] of global.cache) { countTotal++ if (this.isExpired(entry)) { countExpired++ diff --git a/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts b/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts index 08b2c48..2dcd812 100644 --- a/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/consoleUpdates.ts @@ -23,7 +23,7 @@ script.on_event( const update: KafkatorioPacketData.ConsoleCommandUpdate = { type: Type.ConsoleCommandUpdate, - authorPlayerIndex: event.player_index ?? null, + authorPlayerIndex: event.player_index ?? null, command: event.command, parameters: event.parameters, } diff --git a/modules/events-mod/src/main/typescript/main/events/converters.ts b/modules/events-mod/src/main/typescript/main/events/converters.ts index db6fe3e..220484e 100644 --- a/modules/events-mod/src/main/typescript/main/events/converters.ts +++ b/modules/events-mod/src/main/typescript/main/events/converters.ts @@ -1,16 +1,25 @@ -import {EventName} from "../types"; -import {Colour, MapChunkPosition} from "../../generated/kafkatorio-schema"; +import {DefinedEventName} from "../types"; +import { + Colour, + EntityStatus, + EventName, + FactorioEntityData, + MapChunkPosition, + PrototypeId, +} from "../../generated/kafkatorio-schema"; export namespace Converters { - const mapEventIdToName = new LuaTable() + + import floor = math.floor; + const mapEventIdToName = new LuaTable() for (const [eventName, eventId] of pairs(defines.events)) { mapEventIdToName.set(eventId, 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[] { let masks: string[] = [] - for (let [name] of pairs(cm)) { + for (const [name] of pairs(cm)) { masks.push(name) } 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 = { + //@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 + } } diff --git a/modules/events-mod/src/main/typescript/main/events/entityUpdates.ts b/modules/events-mod/src/main/typescript/main/events/entityUpdates.ts index 791f3e6..f262eb3 100644 --- a/modules/events-mod/src/main/typescript/main/events/entityUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/entityUpdates.ts @@ -1,97 +1,276 @@ import {Converters} from "./converters"; import EventDataCache from "../cache/EventDataCache"; import { - EntityUpdateKey, - KafkatorioPacketData + EventName, + FactorioEntityData, + KafkatorioPacketData, + MapChunkPosition, + PrototypeId, + Tick, } 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 = new LuaTable() + + 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( + 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( + 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) => { log(`on_built_entity ${e.tick}`) - handleBuiltEntityEvent(e) + EntityUpdates.handleBuiltEntityEvent(e) }) script.on_event(defines.events.on_robot_built_entity, (e: OnRobotBuiltEntityEvent) => { 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( - 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) => { log(`on_player_mined_entity ${e.tick}`) - handleMinedEntityEvent(e) + EntityUpdates.handleMinedEntityEvent(e) }) script.on_event(defines.events.on_robot_mined_entity, (e: OnRobotMinedEntityEvent) => { log(`on_robot_mined_entity ${e.tick}`) - handleMinedEntityEvent(e) + EntityUpdates.handleMinedEntityEvent(e) }) -function handleMinedEntityEvent(event: OnPlayerMinedEntityEvent | OnRobotMinedEntityEvent) { - const eventName = Converters.eventNameString(event.name) +type EntityUpdateEvent = + | OnBuiltEntityEvent - if (event.entity.unit_number == undefined) { - return - } + | OnEntityClonedEvent + | OnEntityDamagedEvent + | OnEntityDestroyedEvent + | OnEntityDiedEvent + | OnEntityLogisticSlotChangedEvent + | OnEntityRenamedEvent + | OnEntitySettingsPastedEvent + | OnEntitySpawnedEvent - const key: EntityUpdateKey = { - name: event.entity.name, - protoType: event.entity.prototype.name, - unitNumber: event.entity.unit_number - } + | OnPlayerMinedEntityEvent + | OnPlayerRepairedEntityEvent + | OnPlayerRotatedEntityEvent - EventDataCache.debounce( - key, - KafkatorioPacketData.Type.EntityUpdate, - data => { + | OnRobotMinedEntityEvent + | OnRobotBuiltEntityEvent - data.events ??= {} - data.events[eventName] ??= [] - data.events[eventName].push(event.tick) + | OnPostEntityDiedEvent + | OnPreEntitySettingsPastedEvent - 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 - data.lastUser = event.entity.last_user?.index - data.prototype = event.entity.prototype.name - } - ) -} + | OnSelectedEntityChangedEvent + | OnTriggerCreatedEntityEvent diff --git a/modules/events-mod/src/main/typescript/main/events/mapChunkUpdates.ts b/modules/events-mod/src/main/typescript/main/events/mapChunkUpdates.ts index 509afc5..e914a5e 100644 --- a/modules/events-mod/src/main/typescript/main/events/mapChunkUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/mapChunkUpdates.ts @@ -3,129 +3,270 @@ import {Converters} from "./converters"; import EventUpdatesManager, {EventUpdates} from "../cache/EventDataCache"; import { KafkatorioPacketData, - MapChunkPosition + MapChunkPosition, PrototypeId, + PrototypeKey, } from "../../generated/kafkatorio-schema"; +import EntityUpdates from "./entityUpdates"; import CacheKey = EventUpdates.PacketKey; import Type = KafkatorioPacketData.Type; -type MapChunkUpdater = (data: KafkatorioPacketData.MapChunkUpdate) => void +type MapChunkTileUpdater = (data: KafkatorioPacketData.MapChunkTileUpdate) => void -type MapTileUpdateEvent = - | OnChunkGeneratedEvent +export type MapTileChangeEvent = | OnPlayerBuiltTileEvent - | OnPlayerMinedEntityEvent | OnPlayerMinedTileEvent | OnRobotBuiltTileEvent - | OnRobotMinedEntityEvent | OnRobotMinedTileEvent | ScriptRaisedSetTilesEvent -function mapTilesUpdateDebounce( - surface: LuaSurface | undefined, - chunkPosition: MapChunkPosition, - tiles: TileRead[], - event: MapTileUpdateEvent, - updater?: MapChunkUpdater, - expirationDurationTicks?: uint, -) { +export type MapChunkUpdateEvent = + | OnChunkChartedEvent + | OnChunkDeletedEvent + | OnChunkGeneratedEvent + | OnPreChunkDeletedEvent - 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"] = { - surfaceIndex: surface.index, - chunkPosition: chunkPosition, + handleBuiltTileEvent(event: OnPlayerBuiltTileEvent | OnRobotBuiltTileEvent) { + + 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( - key, - Type.MapChunkUpdate, - data => { - // tile dictionary update - if (data.tileDictionary == undefined) { - data.tileDictionary = { - tilesXY: {}, - protos: {}, - } - } + handleMinedTileEvent(event: OnPlayerMinedTileEvent | OnRobotMinedTileEvent) { + const surface = game.get_surface(event.surface_index) + if (surface == undefined) { + const eventName = Converters.eventNameString(event.name) + log(`[handleMinedTileEvent] undefined surface ${eventName}`) + return + } - let protosCount: uint = table_size(data.tileDictionary.protos) - for (const tile of tiles) { - data.tileDictionary.protos[tile.name] ??= protosCount++ + const tiles: TileRead[] = Converters.convertRemovedTiles(surface, event.tiles) + const groupedTiles = MapChunkUpdateHandler.groupTiles(tiles) - const protoKey = data.tileDictionary.protos[tile.name] + for (const [chunkPos, tiles] of groupedTiles) { - 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, - ) -} + MapChunkUpdateHandler.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, + 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 + } + ) + ) + } + } -function getTiles( - surface: LuaSurface | undefined, - area: BoundingBoxTable -): LuaTile[] { - return surface?.find_tiles_filtered({ - area: area, - // collision_mask: ["ground-tile", "water-tile"] + handleScriptSetTilesEvent(event: ScriptRaisedSetTilesEvent) { + + const surface = game.get_surface(event.surface_index) + if (surface == undefined) { + return + } + + 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 = { + surfaceIndex: surface.index, + chunkPosition: [position.x, position.y], } - ) ?? [] + + EventUpdatesManager.debounce( + 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( + 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 { + + const mapChunkPositionToTiles = new Map() + 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 { - return game.surfaces[surfaceIndex] -} +const MapChunkUpdate = new MapChunkUpdateHandler() + +export default MapChunkUpdate script.on_event( defines.events.on_chunk_generated, (e: OnChunkGeneratedEvent) => { 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( // defines.events.on_chunk_charted, // (e: OnChunkChartedEvent) => { @@ -144,169 +285,38 @@ export function handleChunkGeneratedEvent( // ) -script.on_event( - defines.events.script_raised_set_tiles, - (event: ScriptRaisedSetTilesEvent) => { - 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 { - - const mapChunkPositionToTiles = new Map() - 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.script_raised_set_tiles, (event: ScriptRaisedSetTilesEvent) => { + log(`script_raised_set_tiles ${event.tick}`) + MapChunkUpdate.handleScriptSetTilesEvent(event) +}) script.on_event(defines.events.on_player_built_tile, (e: OnPlayerBuiltTileEvent) => { log(`on_player_built_tile ${e.tick}`) - handleBuiltTileEvent(e) + MapChunkUpdate.handleBuiltTileEvent(e) }) + + script.on_event(defines.events.on_robot_built_tile, (e: OnRobotBuiltTileEvent) => { 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) => { 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) => { 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) - const groupedTiles = groupTiles(tiles) - - 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 = { - surfaceIndex: surface.index, - chunkPosition: [position.x, position.y], - } - - EventUpdatesManager.debounce( - key, - Type.MapChunkUpdate, - data => data.isDeleted = true, - 0, // deletion is important - emit ASAP - ) - } - } -) +script.on_event(defines.events.on_pre_chunk_deleted, (e: OnPreChunkDeletedEvent) => { + log(`on_pre_chunk_deleted ${e.tick}`) + MapChunkUpdate.handlePreChunkDeleted(e) +}) diff --git a/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts b/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts index da55741..18b46f2 100644 --- a/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/playerUpdates.ts @@ -1,11 +1,8 @@ import {Converters} from "./converters"; import EventUpdatesManager from "../cache/EventDataCache"; -import { - KafkatorioPacketData, - PlayerUpdateKey -} from "../../generated/kafkatorio-schema"; -import Type = KafkatorioPacketData.Type; +import {ForceIndex, KafkatorioPacketData, PlayerUpdateKey} from "../../generated/kafkatorio-schema"; import packetEmitter from "../PacketEmitter"; +import Type = KafkatorioPacketData.Type; type PlayerUpdater = (player: LuaPlayer, data: KafkatorioPacketData.PlayerUpdate) => void @@ -36,7 +33,7 @@ function playerUpdateThrottle( const eventName = Converters.eventNameString(event.name) EventUpdatesManager.throttle( - {index: playerIndex}, + {index: playerIndex }, Type.PlayerUpdate, data => { const player = game.players[playerIndex] @@ -88,7 +85,7 @@ script.on_event( data.characterUnitNumber = player.character?.unit_number ?? null data.chatColour = Converters.mapColour(player.chat_color) data.colour = Converters.mapColour(player.color) - data.forceIndex = player.force.index + data.forceIndex = player.force.index as ForceIndex data.name = player.name data.isShowOnMap = player.show_on_map data.isSpectator = player.spectator @@ -139,8 +136,7 @@ script.on_event( if (e.cause != undefined) { data.diedCause = { unitNumber: e.cause.unit_number ?? null, - name: e.cause.name, - protoType: e.cause.type + protoId: Converters.prototypeId(e.cause.type, e.cause.name), } } } @@ -189,7 +185,7 @@ script.on_event( log(`on_pre_player_left_game ${event.tick} ${event.name}`) const playerUpdateKey: PlayerUpdateKey = { - index: event.player_index + index: event.player_index , } const playerUpdate: KafkatorioPacketData.PlayerUpdate = { diff --git a/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts b/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts index 8c71f9b..b424383 100644 --- a/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/prototypeUpdates.ts @@ -26,11 +26,11 @@ function prototypeUpdates(): FactorioPrototype[] { function getMapTilePrototypes(): FactorioPrototype.MapTile[] { let tiles: FactorioPrototype.MapTile[] = [] - for (let [, tile] of game.tile_prototypes) { + for (const [, tile] of game.tile_prototypes) { tiles.push({ type: FactorioPrototype.Type.MapTile, - name: tile.name, + protoId: Converters.prototypeId("tile", tile.name), order: tile.order, layer: tile.layer, collisionMasks: Converters.convertCollisionMaskToNames(tile.collision_mask), @@ -44,7 +44,7 @@ function getMapTilePrototypes(): FactorioPrototype.MapTile[] { // function getEntityPrototypes(): FactorioPrototype.MapTile[] { // let tiles: FactorioPrototype.MapTile[] = [] -// for (let [, tile] of game.tile_prototypes) { +// for (const [, tile] of game.tile_prototypes) { // tiles.push({ // type: FactorioPrototype.Type.MapTile, // diff --git a/modules/events-mod/src/main/typescript/main/events/registerHandlers.ts b/modules/events-mod/src/main/typescript/main/events/registerEventListeners.ts similarity index 92% rename from modules/events-mod/src/main/typescript/main/events/registerHandlers.ts rename to modules/events-mod/src/main/typescript/main/events/registerEventListeners.ts index d3758c7..095c3a2 100644 --- a/modules/events-mod/src/main/typescript/main/events/registerHandlers.ts +++ b/modules/events-mod/src/main/typescript/main/events/registerEventListeners.ts @@ -1,9 +1,9 @@ import {Queue} from "../queue/queue"; import {isEventType} from "./eventTypeCheck"; import {Converters} from "./converters"; -import {handleChunkGeneratedEvent} from "./mapChunkUpdates"; import {handleSurfaceUpdate} from "./surfaceUpdates"; import EventCacheService from "../cache/EventDataCache"; +import MapChunkUpdate from "./mapChunkUpdates"; script.on_event( @@ -35,7 +35,7 @@ script.on_event( let eName = Converters.eventNameString(event.name) log(`[on_tick:${event.tick}] dequed event ${eName}, delay ${i}`) - handleChunkGeneratedEvent(event, i) + MapChunkUpdate.handleChunkGeneratedEvent(event, i) i += 1 } } diff --git a/modules/events-mod/src/main/typescript/main/events/resourceEntityUpdates.ts b/modules/events-mod/src/main/typescript/main/events/resourceEntityUpdates.ts new file mode 100644 index 0000000..5955137 --- /dev/null +++ b/modules/events-mod/src/main/typescript/main/events/resourceEntityUpdates.ts @@ -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( +// 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 diff --git a/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts b/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts index 9c90da5..a2bde69 100644 --- a/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts +++ b/modules/events-mod/src/main/typescript/main/events/surfaceUpdates.ts @@ -13,7 +13,7 @@ export function handleSurfaceUpdate( name: surface.name, index: surface.index, - daytime: surface.daytime + daytime: surface.daytime, } PacketEmitter.emitInstantPacket(update) diff --git a/modules/events-mod/src/main/typescript/main/settings/KafkatorioSettings.ts b/modules/events-mod/src/main/typescript/main/settings/KafkatorioSettings.ts index 618554a..f5caa89 100644 --- a/modules/events-mod/src/main/typescript/main/settings/KafkatorioSettings.ts +++ b/modules/events-mod/src/main/typescript/main/settings/KafkatorioSettings.ts @@ -6,7 +6,8 @@ export class KafkatorioSettingsConfig { private static eventCacheExpirationDefaultSeconds: Record = { "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, } @@ -21,7 +22,7 @@ export class KafkatorioSettingsConfig { public initialiseSettings(data: Data): void { for (const [type,] of pairs(KafkatorioSettingsConfig.eventCacheExpirationDefaultSeconds)) { data.extend( - [ KafkatorioSettingsConfig.createDefaultCacheDuration(type)] + [KafkatorioSettingsConfig.createDefaultCacheDuration(type)] ) } } diff --git a/modules/events-mod/src/main/typescript/main/types.d.ts b/modules/events-mod/src/main/typescript/main/types.d.ts index fcdc914..10270f3 100644 --- a/modules/events-mod/src/main/typescript/main/types.d.ts +++ b/modules/events-mod/src/main/typescript/main/types.d.ts @@ -1,6 +1,6 @@ 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. */ diff --git a/modules/events-mod/tsconfig.json b/modules/events-mod/tsconfig.json index 7036839..eaf883f 100644 --- a/modules/events-mod/tsconfig.json +++ b/modules/events-mod/tsconfig.json @@ -10,7 +10,8 @@ "types": [ "typescript-to-lua/language-extensions", "lua-types/5.2", - "typed-factorio/runtime" + "typed-factorio/runtime", + "typed-factorio/strict-index-types" ], "plugins": [ { @@ -32,8 +33,7 @@ "traceResolution": true, "noImplicitReturns": true, "noImplicitOverride": true, - "noFallthroughCasesInSwitch": true, - "skipLibCheck": true + "noFallthroughCasesInSwitch": true }, "tstl": { "luaTarget": "5.2", diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/KafkatorioTopology.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/KafkatorioTopology.kt index facbf6d..f1c547d 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/KafkatorioTopology.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/KafkatorioTopology.kt @@ -2,11 +2,13 @@ package dev.adamko.kafkatorio.server.processor import com.github.palindromicity.syslog.dsl.SyslogFieldKeys 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.* +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.web.websocket.WebmapWebsocketServer -import dev.adamko.kafkatorio.server.web.websocket.broadcastToWebsocket import java.util.Properties import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/admin/KafkatorioKafkaAdmin.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/admin/KafkatorioKafkaAdmin.kt index 071a52f..a052945 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/admin/KafkatorioKafkaAdmin.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/admin/KafkatorioKafkaAdmin.kt @@ -1,7 +1,7 @@ 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.processor.allTopics import java.util.concurrent.TimeUnit import mu.KotlinLogging import org.apache.kafka.clients.admin.Admin diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt index 8dc6cf1..95b2be4 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/eventProcessor.kt @@ -1,9 +1,9 @@ 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.processor.admin.KafkatorioKafkaAdmin +import dev.adamko.kafkatorio.server.socket.SyslogSocketServer import dev.adamko.kafkatorio.server.web.websocket.WebmapWebsocketServer import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.coroutineScope @@ -27,11 +27,11 @@ suspend fun eventsProcessor( val topology = KafkatorioTopology(appProps, wsServer, syslogServer) - launch { - topology.start() + launch { + topology.start() - println("launched KafkatorioTopology") + println("launched KafkatorioTopology") - awaitCancellation() - } + awaitCancellation() + } } diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/kafkatorioTopics.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/kafkatorioTopics.kt index e25ee8f..8eb65a3 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/kafkatorioTopics.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/kafkatorioTopics.kt @@ -5,7 +5,8 @@ import dev.adamko.kafkatorio.schema.packets.ConsoleChatUpdate import dev.adamko.kafkatorio.schema.packets.ConsoleCommandUpdate import dev.adamko.kafkatorio.schema.packets.EntityUpdate 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.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate @@ -54,9 +55,10 @@ val KafkatorioPacketData.topicName: String is PrototypesUpdate -> packetTopicNames.getValue(PrototypesUpdate::class) is SurfaceUpdate -> packetTopicNames.getValue(SurfaceUpdate::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 KafkatorioPacketData.Error -> packetTopicNames.getValue(KafkatorioPacketData.Error::class) + is MapChunkEntityUpdate -> packetTopicNames.getValue(MapChunkEntityUpdate::class) } @@ -67,12 +69,14 @@ private val packetTopicNames: Map, String> = ma PrototypesUpdate::class to "prototypes", SurfaceUpdate::class to "surface", EntityUpdate::class to "entity", - MapChunkUpdate::class to "map-chunk", + MapChunkTileUpdate::class to "map-chunk-tile", PlayerUpdate::class to "player", + MapChunkEntityUpdate::class to "map-chunk-entity", KafkatorioPacketData.Error::class to "error", ).mapValues { (_, v) -> "$DOMAIN.packet.$v" } + val KClass.topicName: String get() = packetTopicNames.getValue(this) diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/colourMapChunks.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/colourMapChunks.kt index 5800e33..b4a7528 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/colourMapChunks.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/colourMapChunks.kt @@ -1,8 +1,5 @@ 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.schema.common.ChunkSize 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.leftTopTile 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.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.groupedAs import dev.adamko.kotka.extensions.materializedAs @@ -39,10 +39,10 @@ import org.apache.kafka.streams.kstream.KTable private const val pid: String = "colourMapChunks" -/** Add colour to each [MapChunkUpdate] */ +/** Add colour to each [MapChunkTileUpdate] */ fun colourMapChunks(builder: StreamsBuilder): Topology { - val mapChunksStream: KStream = builder.streamPacketData() + val mapChunksStream: KStream = builder.streamPacketData() val protosStream: KStream = builder.streamPacketData() val protosTable: KTable = @@ -78,7 +78,7 @@ fun colourMapChunks(builder: StreamsBuilder): Topology { ChunkSize.CHUNK_032 to ChunkSize.CHUNK_256, ChunkSize.CHUNK_256 to ChunkSize.CHUNK_512, - ).forEach { (from, to) -> + ).forEach { (from, to) -> chunkTilesColoured .filter("$pid.combine-chunks.filter-$from-to-$to") { key, _ -> key.chunkSize == from @@ -98,12 +98,12 @@ fun colourMapChunks(builder: StreamsBuilder): Topology { } -private fun KStream.convertToServerMapChunkTiles() +private fun KStream.convertToServerMapChunkTiles() : KStream> { 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() @@ -112,7 +112,7 @@ private fun KStream.convertToServerMapChunkTil } 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 = @@ -232,7 +232,7 @@ fun KTable>.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. */ diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/factorioServerPackets.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/factorioServerPackets.kt index 013f635..c7e4ae1 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/factorioServerPackets.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/factorioServerPackets.kt @@ -1,12 +1,12 @@ 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.Tick import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket 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.component2 import dev.adamko.kotka.extensions.consumedAs @@ -35,7 +35,7 @@ fun factorioServerPacketStream( val packet = runCatching { jsonMapper.decodeFromString(value) }.getOrElse { e -> - KafkatorioPacket( + KafkatorioPacket( modVersion = "unknown", tick = Tick(0u), data = KafkatorioPacketData.Error( diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/packetDataStreams.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/packetDataStreams.kt index 67a882a..f21625f 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/packetDataStreams.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/packetDataStreams.kt @@ -1,10 +1,10 @@ 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.packets.KafkatorioPacket 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.streams.filter import dev.adamko.kotka.extensions.streams.mapValues diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/prototypes.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/prototypes.kt index f74fab9..825f7b7 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/prototypes.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/prototypes.kt @@ -22,8 +22,8 @@ import org.apache.kafka.streams.kstream.KTable @JvmInline @Serializable value class TileProtoHashCode private constructor(val code: Int) { - constructor(tile: MapTile) : this(tile.proto.hashCode()) - constructor(tile: FactorioPrototype.MapTile) : this(tile.name.hashCode()) + constructor(tile: MapTile) : this(tile.protoId.hashCode()) + constructor(tile: FactorioPrototype.MapTile) : this(tile.protoId.hashCode()) } diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/saveMapTiles.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/saveMapTiles.kt index 3d986dc..3592c58 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/saveMapTiles.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/saveMapTiles.kt @@ -3,15 +3,15 @@ package dev.adamko.kafkatorio.server.processor.topology import com.sksamuel.scrimage.ImmutableImage import com.sksamuel.scrimage.ScaleMethod 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.schema.common.ColourHex import dev.adamko.kafkatorio.schema.common.FactorioServerId import dev.adamko.kafkatorio.schema.common.ServerMapChunkId import dev.adamko.kafkatorio.schema.common.TilePngFilename 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.producedAs 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( builder: StreamsBuilder, diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/websocketBroadcaster.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/websocketBroadcaster.kt index 6783dd1..a173a26 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/websocketBroadcaster.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/processor/topology/websocketBroadcaster.kt @@ -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.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.packets.EventServerPacket import dev.adamko.kafkatorio.schema.packets.KafkatorioPacket import dev.adamko.kafkatorio.schema.packets.PlayerUpdate 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.producedAs import dev.adamko.kotka.extensions.stream diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt index 7b518d5..86f3637 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/socket/SyslogSocketServer.kt @@ -59,12 +59,14 @@ class SyslogSocketServer( launch { val channel = socket.openReadChannel() try { - while (socket.socketContext.isActive) { + while (socket.socketContext.isActive && !channel.isClosedForRead) { val line = runCatching { channel.readUTF8Line() }.fold( onSuccess = { line -> - log("received '$line' from $socket") + if (line != null) { + log("received '$line' from ${socket.description()}") + } line }, onFailure = { e -> diff --git a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt index 01035d2..906c692 100644 --- a/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt +++ b/modules/events-server/src/main/kotlin/dev/adamko/kafkatorio/server/web/rest/factorioServersRoutes.kt @@ -10,9 +10,7 @@ import io.ktor.http.content.EntityTagVersion import io.ktor.http.content.versions import io.ktor.resources.Resource import io.ktor.server.application.ApplicationCall -import io.ktor.server.application.application import io.ktor.server.application.call -import io.ktor.server.application.log import io.ktor.server.http.content.LastModifiedVersion import io.ktor.server.resources.get import io.ktor.server.response.respond diff --git a/modules/infra-factorio-client/build.gradle.kts b/modules/infra-factorio-client/build.gradle.kts index 4c29a79..5ecf3ec 100644 --- a/modules/infra-factorio-client/build.gradle.kts +++ b/modules/infra-factorio-client/build.gradle.kts @@ -41,7 +41,9 @@ val deployModToLocalClient by tasks.registering(Copy::class) { description = "Copy the mod to the Factorio client" group = FactorioMod.TASK_GROUP - onlyIf { clientModsDirectory.orNull?.asFile?.exists() == true } + val clientModsDirectory123 = clientModsDirectory + + onlyIf { clientModsDirectory123.orNull?.asFile?.exists() == true } from(factorioMod) into(clientModsDirectory) @@ -61,9 +63,12 @@ val clientLaunch by tasks.registering(Exec::class) { description = "Run local Factorio Steam game client" group = FactorioMod.TASK_GROUP + val steamExe123 = steamExe + val clientModsDirectory444 = clientModsDirectory + onlyIf(!serviceOf().isFactorioRunning()) - onlyIf { steamExe.orNull?.asFile?.exists() == true } - onlyIf { clientModsDirectory.orNull?.asFile?.exists() == true } + onlyIf { steamExe123.orNull?.asFile?.exists() == true } + onlyIf { clientModsDirectory444.orNull?.asFile?.exists() == true } dependsOn(deployModToLocalClient) mustRunAfter(clientKill, ":modules:infra-factorio-server:processRun") diff --git a/modules/infra-factorio-server/src/.env b/modules/infra-factorio-server/src/.env index da16a1f..c6d1744 100644 --- a/modules/infra-factorio-server/src/.env +++ b/modules/infra-factorio-server/src/.env @@ -1,4 +1,4 @@ # Do not edit manually. This file was created with task 'dockerEnv' COMPOSE_PROJECT_NAME=kafkatorio -FACTORIO_VERSION=1.1.59 +FACTORIO_VERSION=1.1.61 KAFKATORIO_VERSION=0.6.1 diff --git a/modules/infra-factorio-server/src/docker-compose.yml b/modules/infra-factorio-server/src/docker-compose.yml index 34fd329..9e1e947 100644 --- a/modules/infra-factorio-server/src/docker-compose.yml +++ b/modules/infra-factorio-server/src/docker-compose.yml @@ -19,7 +19,7 @@ services: logging: driver: syslog options: - syslog-address: "tcp://host.docker.internal:12092" + syslog-address: "tcp://host.docker.internal:12034" syslog-format: "rfc5424" # environment: diff --git a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/websockets.kt b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/websockets.kt index 077472f..7c94823 100644 --- a/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/websockets.kt +++ b/modules/web-map/src/main/kotlin/dev/adamko/kafkatorio/webmap/websockets.kt @@ -6,7 +6,7 @@ import dev.adamko.kafkatorio.schema.packets.ConsoleCommandUpdate import dev.adamko.kafkatorio.schema.packets.EntityUpdate import dev.adamko.kafkatorio.schema.packets.EventServerPacket 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.PrototypesUpdate import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate @@ -84,7 +84,7 @@ class WebsocketService( is PrototypesUpdate, is SurfaceUpdate, is EntityUpdate, - is MapChunkUpdate, + is MapChunkTileUpdate, is KafkatorioPacketData.Error -> { // to be continued... }