tiles are visible! the tileserver works! they're the right way up! they have colours!

This commit is contained in:
Adam 2022-01-19 22:42:22 +01:00
parent 6fe3132f23
commit a557c437cc
4 changed files with 72 additions and 35 deletions

View file

@ -11,6 +11,11 @@
While this project is under development, [no license](https://choosealicense.com/no-permission/) While this project is under development, [no license](https://choosealicense.com/no-permission/)
is provided. is provided.
## cmds
`./bin/kafka-streams-application-reset.sh --application-id kafkatorio-events-processor --input-topics factorio-server-log`
## todo ## todo
* add settings * add settings

View file

@ -22,6 +22,7 @@ import dev.adamko.kafkatorio.events.schema.converters.toMapChunkPosition
import dev.adamko.kotka.extensions.consumedAs import dev.adamko.kotka.extensions.consumedAs
import dev.adamko.kotka.extensions.groupedAs import dev.adamko.kotka.extensions.groupedAs
import dev.adamko.kotka.extensions.materializedAs import dev.adamko.kotka.extensions.materializedAs
import dev.adamko.kotka.extensions.materializedWith
import dev.adamko.kotka.extensions.producedAs import dev.adamko.kotka.extensions.producedAs
import dev.adamko.kotka.extensions.streams.filter import dev.adamko.kotka.extensions.streams.filter
import dev.adamko.kotka.extensions.streams.flatMap import dev.adamko.kotka.extensions.streams.flatMap
@ -29,6 +30,8 @@ import dev.adamko.kotka.extensions.streams.map
import dev.adamko.kotka.extensions.streams.mapValues import dev.adamko.kotka.extensions.streams.mapValues
import dev.adamko.kotka.extensions.streams.merge import dev.adamko.kotka.extensions.streams.merge
import dev.adamko.kotka.extensions.streams.to import dev.adamko.kotka.extensions.streams.to
import dev.adamko.kotka.extensions.streams.toTable
import dev.adamko.kotka.extensions.tables.join
import dev.adamko.kotka.kxs.serde import dev.adamko.kotka.kxs.serde
import dev.adamko.kotka.topicdata.TopicRecord import dev.adamko.kotka.topicdata.TopicRecord
import dev.adamko.kotka.topicdata.flatMapTopicRecords import dev.adamko.kotka.topicdata.flatMapTopicRecords
@ -73,17 +76,17 @@ class KafkatorioTopology(
sendPlayerUpdatesToWebSocket() sendPlayerUpdatesToWebSocket()
// createMapTileImages() // createMapTileImages()
val tilePrototypesTable: KTable<String, MapTilePrototype> = tilePrototypesTable() val tilePrototypesTable: KTable<String, MapTilePrototype> = tilePrototypesTable()
mapChunksStream() mapChunksStream(tilePrototypesTable)
val topology = builder.build() val topology = builder.build()
val streams = KafkaStreams(topology, appProps.kafkaConfig) val streams = KafkaStreams(topology, appProps.kafkaConfig)
// streams.cleanUp()
streams.setUncaughtExceptionHandler(StreamsExceptionHandler()) streams.setUncaughtExceptionHandler(StreamsExceptionHandler())
Runtime.getRuntime().addShutdownHook(Thread { streams.close(Duration.ofSeconds(10)) }) Runtime.getRuntime().addShutdownHook(Thread { streams.close(Duration.ofSeconds(10)) })
// streams.cleanUp()
val description: TopologyDescription = topology.describe() val description: TopologyDescription = topology.describe()
println(description) println(description)
@ -121,11 +124,11 @@ class KafkatorioTopology(
) { _: String, value: KafkatorioPacket, _: RecordContext -> ) { _: String, value: KafkatorioPacket, _: RecordContext ->
// println("[$key] sending event:${value.eventType} to topic:${value.data.objectName()}") // println("[$key] sending event:${value.eventType} to topic:${value.data.objectName()}")
when (value) { when (value) {
is FactorioEvent -> is FactorioEvent ->
"kafkatorio.${value.packetType.name}.${value.data.objectName.name}" "kafkatorio.${value.packetType.name}.${value.data.objectName.name}"
is FactorioConfigurationUpdate -> is FactorioConfigurationUpdate ->
"kafkatorio.${value.packetType.name}.FactorioConfigurationUpdate" "kafkatorio.${value.packetType.name}.FactorioConfigurationUpdate"
is FactorioPrototypes -> is FactorioPrototypes ->
"kafkatorio.${value.packetType.name}.all" "kafkatorio.${value.packetType.name}.all"
} }
} }
@ -167,7 +170,6 @@ class KafkatorioTopology(
jsonMapper.serde() jsonMapper.serde()
) )
) )
// .to( // .to(
// tilePrototypesStreamName, // tilePrototypesStreamName,
// ) // )
@ -187,6 +189,12 @@ class KafkatorioTopology(
// ) // )
} }
@Serializable
data class MapTileWithPrototype(
val position: MapTilePosition,
val prototype: MapTilePrototype,
)
@Serializable @Serializable
data class MapChunkDataPosition( data class MapChunkDataPosition(
val position: MapChunkPosition, val position: MapChunkPosition,
@ -197,24 +205,10 @@ class KafkatorioTopology(
data class MapChunkData( data class MapChunkData(
val chunkPosition: MapChunkDataPosition, val chunkPosition: MapChunkDataPosition,
val tiles: Set<MapTile>, val tiles: Set<MapTile>,
val tilePrototypes: Set<MapTilePrototype>,
) )
// : TopicRecord<MapChunkDataPosition>
{
// @kotlinx.serialization.Transient private fun mapChunksStream(tilePrototypesTable: KTable<String, MapTilePrototype>) {
// override val topicKey by ::chunkPosition
// @kotlinx.serialization.Transient
// val surfaceIndex: Int by chunkPosition::surfaceIndex
// @kotlinx.serialization.Transient
// val leftTopTile = chunkPosition.position.leftTopTile
// @kotlinx.serialization.Transient
// val rightBottom = chunkPosition.position.rightBottomTile
// @kotlinx.serialization.Transient
// val leftBottom = MapTilePosition(leftTopTile.x, rightBottom.x)
}
private fun mapChunksStream() {
val luaTilesUpdatesStream: KStream<String, MapTiles> = builder.stream( val luaTilesUpdatesStream: KStream<String, MapTiles> = builder.stream(
"kafkatorio.${KafkatorioPacket.PacketType.EVENT}.${FactorioObjectData.ObjectName.LuaTiles}", "kafkatorio.${KafkatorioPacket.PacketType.EVENT}.${FactorioObjectData.ObjectName.LuaTiles}",
@ -253,10 +247,10 @@ class KafkatorioTopology(
data class TileUpdateRecord( data class TileUpdateRecord(
val surfaceIndex: Int, val surfaceIndex: Int,
val tilePosition: MapTilePosition, val tilePosition: MapTilePosition,
val tile: MapTile val tile: MapTile,
val tilePrototype: MapTilePrototype?,
) : TopicRecord<TileUpdateRecordKey> { ) : TopicRecord<TileUpdateRecordKey> {
override val topicKey: TileUpdateRecordKey = override val topicKey: TileUpdateRecordKey = TileUpdateRecordKey(surfaceIndex, tilePosition)
TileUpdateRecordKey(surfaceIndex, tilePosition)
} }
val allTileUpdatesStream: KStream<TileUpdateRecordKey, TileUpdateRecord> = val allTileUpdatesStream: KStream<TileUpdateRecordKey, TileUpdateRecord> =
@ -268,10 +262,27 @@ class KafkatorioTopology(
TileUpdateRecord( TileUpdateRecord(
mapTiles.surfaceIndex, mapTiles.surfaceIndex,
tile.position, tile.position,
tile tile,
null
) )
} }
} }
.toTable(
"all-tile-updates-table",
materializedWith(jsonMapper.serde(), jsonMapper.serde())
)
.join(
tilePrototypesTable,
"enrich-tiles-with-prototypes",
materializedWith(jsonMapper.serde(), jsonMapper.serde()),
{ it.tile.prototypeName },
) { v1: TileUpdateRecord, v2: MapTilePrototype ->
v1.copy(tilePrototype = v2)
}
.toStream()
.filter { _, value ->
value.tilePrototype != null
}
val chunksTable: KTable<MapChunkDataPosition, MapChunkData> = val chunksTable: KTable<MapChunkDataPosition, MapChunkData> =
allTileUpdatesStream allTileUpdatesStream
@ -280,19 +291,26 @@ class KafkatorioTopology(
value.tilePosition.toMapChunkPosition(), value.tilePosition.toMapChunkPosition(),
value.surfaceIndex, value.surfaceIndex,
) )
key to MapChunkData(key, setOf(value.tile)) key to MapChunkData(
key,
setOf(value.tile),
setOfNotNull(value.tilePrototype)
)
} }
// group all tiles by chunk position // group all tiles by chunk position
.groupByKey( .groupByKey(
groupedAs("group-tile-updates-per-chunk-position", jsonMapper.serde(), jsonMapper.serde()) groupedAs("group-tile-updates-per-chunk-position", jsonMapper.serde(), jsonMapper.serde())
) )
.reduce { tileA, tileB -> .reduce { tileA, tileB ->
tileA.copy(tiles = tileA.tiles + tileB.tiles) tileA.copy(
tiles = tileA.tiles + tileB.tiles,
tilePrototypes = tileA.tilePrototypes + tileB.tilePrototypes
)
} }
.suppress( .suppress(
Suppressed.untilTimeLimit( Suppressed.untilTimeLimit(
Duration.ofSeconds(30), Duration.ofSeconds(30),
Suppressed.BufferConfig.maxRecords(30) Suppressed.BufferConfig.maxRecords(32*32*2)
) )
) )
@ -309,11 +327,15 @@ class KafkatorioTopology(
} }
} }
// @Suppress("KotlinConstantConditions")
private fun saveMapTilesPng(key: MapChunkDataPosition, chunk: MapChunkData) { private fun saveMapTilesPng(key: MapChunkDataPosition, chunk: MapChunkData) {
val tilePrototypes: Map<String, MapTilePrototype?> =
chunk.tilePrototypes.associateBy { it.name }.withDefault { null }
val chunkOriginX = chunk.chunkPosition.position.leftTopTile.x val chunkOriginX = chunk.chunkPosition.position.leftTopTile.x
val chunkOriginY = chunk.chunkPosition.position.rightBottomTile.y // val chunkOriginY = chunk.chunkPosition.position.rightBottomTile.y
val chunkOriginY = chunk.chunkPosition.position.leftTopTile.y
val chunkImage = val chunkImage =
ImmutableImage.filled( ImmutableImage.filled(
@ -325,9 +347,8 @@ class KafkatorioTopology(
chunk.tiles.forEach { tile -> chunk.tiles.forEach { tile ->
val prototypeColour = tilePrototypesStore val prototypeColour = tilePrototypes
.get(tile.prototypeName) .getValue(tile.prototypeName)
?.value()
?.mapColour ?.mapColour
?.toHexadecimal() ?.toHexadecimal()

View file

@ -1,6 +1,8 @@
package dev.adamko.kafkatorio.processor.tileserver package dev.adamko.kafkatorio.processor.tileserver
import org.http4k.core.HttpHandler import org.http4k.core.HttpHandler
import org.http4k.core.then
import org.http4k.filter.CachingFilters
import org.http4k.routing.ResourceLoader import org.http4k.routing.ResourceLoader
import org.http4k.routing.RoutingHttpHandler import org.http4k.routing.RoutingHttpHandler
import org.http4k.routing.bind import org.http4k.routing.bind
@ -10,7 +12,14 @@ import org.http4k.routing.static
class WebMapTileServer { class WebMapTileServer {
private val routes: RoutingHttpHandler = routes( private val routes: RoutingHttpHandler = routes(
"/tiles" bind static(ResourceLoader.Classpath("/kafkatorio-web-map")) "/tiles" bind CachingFilters.Response.NoCache()
.then(
static(
ResourceLoader.Directory(
"""D:\Users\Adam\Projects\games\kafkatorio\modules\events-server\src\main\resources\kafkatorio-web-map\"""
)
)
)
) )
fun build(): HttpHandler { fun build(): HttpHandler {

View file

@ -30,11 +30,13 @@ fun createFactorioMap() = Maps {
// DefaultTileLayers.OpenStreetMap.addTo(this) // DefaultTileLayers.OpenStreetMap.addTo(this)
L.tileLayer( L.tileLayer(
"""http://localhost:9073/tiles/s1/z1/x{x}/y{y}.png""" """http://localhost:9073/tiles/s1/z{z}/x{x}/y{y}.png"""
) { ) {
attribution = "kafkatorio" attribution = "kafkatorio"
tms = true tms = true
minZoom = 1 minZoom = 1
// maxZoom = 1
maxNativeZoom = 1
}.addTo(this) }.addTo(this)
with(options) { with(options) {