mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-03 05:30:55 +00:00
Gjallarhorn: Initial Player Position Code
This commit is contained in:
@ -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")
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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()))
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,6 @@ abstract class BlockHeatMapRenderer(quadPixelSize: Int = defaultQuadPixelSize) :
|
||||
Color.white
|
||||
}
|
||||
|
||||
setPixelQuad(graphics, x, z, color.rgb)
|
||||
setPixelQuad(graphics, x, z, color)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Reference in New Issue
Block a user