Gjallarhorn: Initial Player Position Code

This commit is contained in:
Kenneth Endfinger 2022-01-17 22:24:47 -05:00
parent 54cd41e925
commit d4a06ea84a
No known key found for this signature in database
GPG Key ID: C4E68E5647420E10
9 changed files with 77 additions and 19 deletions

View File

@ -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")

View File

@ -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)
}
}

View File

@ -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()))
}

View File

@ -21,6 +21,6 @@ abstract class BlockHeatMapRenderer(quadPixelSize: Int = defaultQuadPixelSize) :
Color.white
}
setPixelQuad(graphics, x, z, color.rgb)
setPixelQuad(graphics, x, z, color)
}
}

View File

@ -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)

View File

@ -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<T> {
fun render(map: BlockMap): T
fun render(slice: ChangelogSlice, map: BlockMap): T
}

View File

@ -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)
}
}
}
}

View File

@ -3,7 +3,6 @@ package cloud.kubelet.foundation.gjallarhorn.state
class BlockMapTimelapse<T> :
BlockMapRenderPoolDelegate<T> {
override fun onSinglePlaybackComplete(pool: BlockMapRenderPool<T>, slice: ChangelogSlice, tracker: BlockLogTracker) {
throw UnsupportedOperationException()
}
override fun onAllPlaybackComplete(
@ -24,7 +23,7 @@ class BlockMapTimelapse<T> :
for ((slice, tracker) in trackers) {
pool.submitRenderJob(slice) {
val map = tracker.buildBlockMap(globalBlockExpanse.offset)
renderer.render(map)
renderer.render(slice, map)
}
}
}

View File

@ -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<Instant> = from..to
val relativeChangeRange: ClosedRange<Instant> = 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<ChangelogSlice> {
val half = relative.dividedBy(2)