From d4a06ea84a619cf0371fb5ab4e938be959ddb1f5 Mon Sep 17 00:00:00 2001 From: Kenneth Endfinger Date: Mon, 17 Jan 2022 22:24:47 -0500 Subject: [PATCH] Gjallarhorn: Initial Player Position Code --- .../commands/BlockChangeTimelapseCommand.kt | 10 ++-- .../render/BlockDiversityRenderer.kt | 9 ++-- .../gjallarhorn/render/BlockGridRenderer.kt | 8 +-- .../render/BlockHeatMapRenderer.kt | 2 +- .../render/BlockHeightMapRenderer.kt | 3 +- .../gjallarhorn/render/BlockMapRenderer.kt | 3 +- .../render/PlayerLocationShareRenderer.kt | 52 +++++++++++++++++++ .../gjallarhorn/state/BlockMapTimelapse.kt | 3 +- .../gjallarhorn/state/ChangelogSlice.kt | 6 ++- 9 files changed, 77 insertions(+), 19 deletions(-) create mode 100644 tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/PlayerLocationShareRenderer.kt diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/BlockChangeTimelapseCommand.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/BlockChangeTimelapseCommand.kt index 3cf45bf..36b26a3 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/BlockChangeTimelapseCommand.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/BlockChangeTimelapseCommand.kt @@ -2,6 +2,7 @@ package cloud.kubelet.foundation.gjallarhorn.commands import cloud.kubelet.foundation.gjallarhorn.render.BlockDiversityRenderer import cloud.kubelet.foundation.gjallarhorn.render.BlockHeightMapRenderer +import cloud.kubelet.foundation.gjallarhorn.render.PlayerLocationShareRenderer import cloud.kubelet.foundation.gjallarhorn.render.BlockImageRenderer import cloud.kubelet.foundation.gjallarhorn.state.* import cloud.kubelet.foundation.gjallarhorn.util.compose @@ -80,7 +81,7 @@ class BlockChangeTimelapseCommand : CliktCommand("Block Change Timelapse", name changelog = changelog, blockTrackMode = if (considerAirBlocks) BlockTrackMode.AirOnDelete else BlockTrackMode.RemoveOnDelete, delegate = timelapse, - createRendererFunction = { expanse -> render.create(expanse) }, + createRendererFunction = { expanse -> render.create(expanse, db) }, threadPoolExecutor = threadPoolExecutor ) { slice, result -> val speed = slice.relative.toSeconds().toDouble() / timelapseMode.interval.toSeconds().toDouble() @@ -120,10 +121,11 @@ class BlockChangeTimelapseCommand : CliktCommand("Block Change Timelapse", name @Suppress("unused") enum class RenderType( val id: String, - val create: (BlockExpanse) -> BlockImageRenderer + val create: (BlockExpanse, Database) -> BlockImageRenderer ) { - BlockDiversity("block-diversity", { expanse -> BlockDiversityRenderer(expanse) }), - HeightMap("height-map", { expanse -> BlockHeightMapRenderer(expanse) }) + BlockDiversity("block-diversity", { expanse, _ -> BlockDiversityRenderer(expanse) }), + HeightMap("height-map", { expanse, _ -> BlockHeightMapRenderer(expanse) }), + PlayerPosition("player-position", { expanse, db -> PlayerLocationShareRenderer(expanse, db) }) } @Suppress("unused") diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockDiversityRenderer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockDiversityRenderer.kt index dfbf14d..03bd2a0 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockDiversityRenderer.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockDiversityRenderer.kt @@ -2,6 +2,7 @@ package cloud.kubelet.foundation.gjallarhorn.render import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse import cloud.kubelet.foundation.gjallarhorn.state.BlockMap +import cloud.kubelet.foundation.gjallarhorn.state.ChangelogSlice import cloud.kubelet.foundation.gjallarhorn.util.BlockColorKey import cloud.kubelet.foundation.gjallarhorn.util.defaultBlockColorMap import java.awt.Color @@ -11,19 +12,19 @@ class BlockDiversityRenderer(val expanse: BlockExpanse, quadPixelSize: Int = def BlockGridRenderer(quadPixelSize) { private val blockColorKey = BlockColorKey(defaultBlockColorMap) - override fun render(map: BlockMap): BufferedImage = buildPixelQuadImage(expanse) { graphics, x, z -> + override fun render(slice: ChangelogSlice, map: BlockMap): BufferedImage = buildPixelQuadImage(expanse) { graphics, x, z -> val maybeYBlocks = map.blocks[x]?.get(z) if (maybeYBlocks == null) { - setPixelQuad(graphics, x, z, Color.white.rgb) + setPixelQuad(graphics, x, z, Color.white) return@buildPixelQuadImage } val maxBlockState = maybeYBlocks.maxByOrNull { it.key }?.value if (maxBlockState == null) { - setPixelQuad(graphics, x, z, Color.white.rgb) + setPixelQuad(graphics, x, z, Color.white) return@buildPixelQuadImage } val color = blockColorKey.map(maxBlockState.type) - setPixelQuad(graphics, x, z, color.rgb) + setPixelQuad(graphics, x, z, color) } } diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockGridRenderer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockGridRenderer.kt index 6247852..7fa333d 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockGridRenderer.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockGridRenderer.kt @@ -7,12 +7,12 @@ import java.awt.Rectangle import java.awt.image.BufferedImage abstract class BlockGridRenderer(val quadPixelSize: Int = defaultQuadPixelSize) : BlockImageRenderer { - protected fun setPixelQuad(graphics: Graphics2D, x: Long, z: Long, rgb: Int) { - drawSquare(graphics, x * quadPixelSize, z * quadPixelSize, quadPixelSize.toLong(), rgb) + protected fun setPixelQuad(graphics: Graphics2D, x: Long, z: Long, color: Color) { + drawSquare(graphics, x * quadPixelSize, z * quadPixelSize, quadPixelSize.toLong(), color) } - protected fun drawSquare(graphics: Graphics2D, x: Long, y: Long, side: Long, rgb: Int) { - graphics.color = Color(rgb) + protected fun drawSquare(graphics: Graphics2D, x: Long, y: Long, side: Long, color: Color) { + graphics.color = color graphics.fill(Rectangle(x.toInt(), y.toInt(), side.toInt(), side.toInt())) } diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeatMapRenderer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeatMapRenderer.kt index 31958b5..0ae7cb6 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeatMapRenderer.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeatMapRenderer.kt @@ -21,6 +21,6 @@ abstract class BlockHeatMapRenderer(quadPixelSize: Int = defaultQuadPixelSize) : Color.white } - setPixelQuad(graphics, x, z, color.rgb) + setPixelQuad(graphics, x, z, color) } } diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeightMapRenderer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeightMapRenderer.kt index 71f3cca..cc32bf3 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeightMapRenderer.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockHeightMapRenderer.kt @@ -2,12 +2,13 @@ package cloud.kubelet.foundation.gjallarhorn.render import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse import cloud.kubelet.foundation.gjallarhorn.state.BlockMap +import cloud.kubelet.foundation.gjallarhorn.state.ChangelogSlice import cloud.kubelet.foundation.gjallarhorn.util.FloatClamp import java.awt.image.BufferedImage class BlockHeightMapRenderer(val expanse: BlockExpanse, quadPixelSize: Int = defaultQuadPixelSize) : BlockHeatMapRenderer(quadPixelSize) { - override fun render(map: BlockMap): BufferedImage { + override fun render(slice: ChangelogSlice, map: BlockMap): BufferedImage { val yMin = map.blocks.minOf { xSection -> xSection.value.minOf { zSection -> zSection.value.minOf { it.key } } } val yMax = map.blocks.maxOf { xSection -> xSection.value.maxOf { zSection -> zSection.value.maxOf { it.key } } } val clamp = FloatClamp(yMin, yMax) diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockMapRenderer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockMapRenderer.kt index 0600549..eb34026 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockMapRenderer.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/BlockMapRenderer.kt @@ -1,7 +1,8 @@ package cloud.kubelet.foundation.gjallarhorn.render import cloud.kubelet.foundation.gjallarhorn.state.BlockMap +import cloud.kubelet.foundation.gjallarhorn.state.ChangelogSlice interface BlockMapRenderer { - fun render(map: BlockMap): T + fun render(slice: ChangelogSlice, map: BlockMap): T } diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/PlayerLocationShareRenderer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/PlayerLocationShareRenderer.kt new file mode 100644 index 0000000..e16b8f5 --- /dev/null +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/render/PlayerLocationShareRenderer.kt @@ -0,0 +1,52 @@ +package cloud.kubelet.foundation.gjallarhorn.render + +import cloud.kubelet.foundation.gjallarhorn.state.BlockCoordinate +import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse +import cloud.kubelet.foundation.gjallarhorn.state.BlockMap +import cloud.kubelet.foundation.gjallarhorn.state.ChangelogSlice +import cloud.kubelet.foundation.gjallarhorn.util.BlockColorKey +import cloud.kubelet.foundation.heimdall.table.PlayerPositionTable +import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.select +import org.jetbrains.exposed.sql.transactions.transaction +import java.awt.Color +import java.awt.image.BufferedImage + +class PlayerLocationShareRenderer( + val expanse: BlockExpanse, + val db: Database, + quadPixelSize: Int = defaultQuadPixelSize) : BlockGridRenderer(quadPixelSize) { + private val colorKey = BlockColorKey(mapOf()) + + override fun render(slice: ChangelogSlice, map: BlockMap): BufferedImage { + val start = slice.relativeChangeRange.start + val end = slice.relativeChangeRange.endInclusive + + val playersToUniquePositions = transaction(db) { + PlayerPositionTable.select { + (PlayerPositionTable.time greater start) and + (PlayerPositionTable.time lessEq end) + }.map { + val x = it[PlayerPositionTable.x].toLong() + val y = it[PlayerPositionTable.y].toLong() + val z = it[PlayerPositionTable.z].toLong() + val coordinate = expanse.offset.applyAsOffset(BlockCoordinate(x, y, z)) + it[PlayerPositionTable.player] to coordinate + }.distinct() + } + + val colorOfPlayers = playersToUniquePositions.map { it.first } + .distinct() + .associateWith { colorKey.map(it.toString()) } + + return buildPixelQuadImage(expanse) { g, x, z -> + val players = playersToUniquePositions.filter { it.second.x == x && it.second.z == z }.map { it.first }.distinct() + if (players.isNotEmpty()) { + setPixelQuad(g, x, z, colorOfPlayers[players.first()]!!) + } else { + setPixelQuad(g, x, z, Color.white) + } + } + } +} diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockMapTimelapse.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockMapTimelapse.kt index a3ac352..262f9c0 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockMapTimelapse.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockMapTimelapse.kt @@ -3,7 +3,6 @@ package cloud.kubelet.foundation.gjallarhorn.state class BlockMapTimelapse : BlockMapRenderPoolDelegate { override fun onSinglePlaybackComplete(pool: BlockMapRenderPool, slice: ChangelogSlice, tracker: BlockLogTracker) { - throw UnsupportedOperationException() } override fun onAllPlaybackComplete( @@ -24,7 +23,7 @@ class BlockMapTimelapse : for ((slice, tracker) in trackers) { pool.submitRenderJob(slice) { val map = tracker.buildBlockMap(globalBlockExpanse.offset) - renderer.render(map) + renderer.render(slice, map) } } } diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/ChangelogSlice.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/ChangelogSlice.kt index bea46f7..2b859ce 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/ChangelogSlice.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/ChangelogSlice.kt @@ -7,9 +7,11 @@ data class ChangelogSlice(val from: Instant, val to: Instant, val relative: Dura constructor(from: Instant, to: Instant) : this(from, to, Duration.ofMillis(to.toEpochMilli() - from.toEpochMilli())) val relativeChangeStart: Instant = to.minus(relative) + val range: ClosedRange = from..to + val relativeChangeRange: ClosedRange = relativeChangeStart..to - fun isTimeWithin(time: Instant) = time in from..to - fun isRelativeWithin(time: Instant) = time in relativeChangeStart..to + fun isTimeWithin(time: Instant) = time in range + fun isRelativeWithin(time: Instant) = time in relativeChangeRange fun split(): List { val half = relative.dividedBy(2)