Heimdall: It's back!

This commit is contained in:
2023-01-28 19:35:10 -08:00
parent 086f7dba10
commit 7289e5cb9f
87 changed files with 2617 additions and 2 deletions

View File

@ -0,0 +1,30 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.tool.state.BlockExpanse
import gay.pizza.foundation.heimdall.tool.state.BlockStateMap
import gay.pizza.foundation.heimdall.tool.state.ChangelogSlice
import gay.pizza.foundation.heimdall.tool.util.BlockColorKey
import gay.pizza.foundation.heimdall.tool.util.defaultBlockColorMap
import java.awt.Color
import java.awt.image.BufferedImage
class BlockDiversityRenderer(val expanse: BlockExpanse, quadPixelSize: Int = defaultQuadPixelSize) :
BlockGridRenderer(quadPixelSize) {
private val blockColorKey = BlockColorKey(defaultBlockColorMap)
override fun render(slice: ChangelogSlice, map: BlockStateMap): BufferedImage = buildPixelQuadImage(expanse) { graphics, x, z ->
val maybeYBlocks = map.getVerticalSection(x, z)
if (maybeYBlocks == null) {
setPixelQuad(graphics, x, z, Color.white)
return@buildPixelQuadImage
}
val maxBlockState = maybeYBlocks.maxByOrNull { it.key }?.value
if (maxBlockState == null) {
setPixelQuad(graphics, x, z, Color.white)
return@buildPixelQuadImage
}
val color = blockColorKey.map(maxBlockState.type)
setPixelQuad(graphics, x, z, color)
}
}

View File

@ -0,0 +1,47 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.tool.state.BlockExpanse
import java.awt.Color
import java.awt.Graphics2D
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, color: Color) {
if (globalQuadPixelNoop) {
return
}
drawSquare(graphics, x * quadPixelSize, z * quadPixelSize, quadPixelSize.toLong(), color)
}
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()))
}
protected fun buildPixelQuadImage(
expanse: BlockExpanse,
callback: BufferedImage.(Graphics2D, Long, Long) -> Unit
): BufferedImage {
val widthInBlocks = expanse.size.x
val heightInBlocks = expanse.size.z
val widthInPixels = widthInBlocks.toInt() * quadPixelSize
val heightInPixels = heightInBlocks.toInt() * quadPixelSize
val bufferedImage =
BufferedImage(widthInPixels, heightInPixels, BufferedImage.TYPE_3BYTE_BGR)
val graphics = bufferedImage.createGraphics()
for (x in 0 until widthInBlocks) {
for (z in 0 until heightInBlocks) {
callback(bufferedImage, graphics, x, z)
}
}
graphics.dispose()
return bufferedImage
}
companion object {
const val defaultQuadPixelSize = 4
var globalQuadPixelNoop = false
}
}

View File

@ -0,0 +1,26 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.tool.state.BlockExpanse
import gay.pizza.foundation.heimdall.tool.util.ColorGradient
import gay.pizza.foundation.heimdall.tool.util.FloatClamp
import java.awt.Color
import java.awt.image.BufferedImage
abstract class BlockHeatMapRenderer(quadPixelSize: Int = defaultQuadPixelSize) : BlockGridRenderer(quadPixelSize) {
protected fun buildHeatMapImage(
expanse: BlockExpanse,
clamp: FloatClamp,
calculate: (Long, Long) -> Long?
): BufferedImage =
buildPixelQuadImage(expanse) { graphics, x, z ->
val value = calculate(x, z)
val color = if (value != null) {
val floatValue = clamp.convert(value)
ColorGradient.HeatMap.getColorAtValue(floatValue)
} else {
Color.white
}
setPixelQuad(graphics, x, z, color)
}
}

View File

@ -0,0 +1,20 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.tool.state.BlockExpanse
import gay.pizza.foundation.heimdall.tool.state.BlockStateMap
import gay.pizza.foundation.heimdall.tool.state.SparseBlockStateMap
import gay.pizza.foundation.heimdall.tool.state.ChangelogSlice
import gay.pizza.foundation.heimdall.tool.util.FloatClamp
import java.awt.image.BufferedImage
class BlockHeightMapRenderer(val expanse: BlockExpanse, quadPixelSize: Int = defaultQuadPixelSize) :
BlockHeatMapRenderer(quadPixelSize) {
override fun render(slice: ChangelogSlice, map: BlockStateMap): BufferedImage {
val blockMap = map as SparseBlockStateMap
val yMin = blockMap.blocks.minOf { xSection -> xSection.value.minOf { zSection -> zSection.value.minOf { it.key } } }
val yMax = blockMap.blocks.maxOf { xSection -> xSection.value.maxOf { zSection -> zSection.value.maxOf { it.key } } }
val clamp = FloatClamp(yMin, yMax)
return buildHeatMapImage(expanse, clamp) { x, z -> blockMap.blocks[x]?.get(z)?.maxOf { it.key } }
}
}

View File

@ -0,0 +1,5 @@
package gay.pizza.foundation.heimdall.tool.render
import java.awt.image.BufferedImage
interface BlockImageRenderer : BlockMapRenderer<BufferedImage>

View File

@ -0,0 +1,8 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.tool.state.BlockStateMap
import gay.pizza.foundation.heimdall.tool.state.ChangelogSlice
interface BlockMapRenderer<T> {
fun render(slice: ChangelogSlice, map: BlockStateMap): T
}

View File

@ -0,0 +1,20 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.tool.state.BlockExpanse
import gay.pizza.foundation.heimdall.tool.state.BlockStateMap
import gay.pizza.foundation.heimdall.tool.state.SparseBlockStateMap
import gay.pizza.foundation.heimdall.tool.state.ChangelogSlice
import gay.pizza.foundation.heimdall.tool.util.FloatClamp
import java.awt.image.BufferedImage
class BlockVerticalFillMapRenderer(val expanse: BlockExpanse, quadPixelSize: Int = defaultQuadPixelSize) :
BlockHeatMapRenderer(quadPixelSize) {
override fun render(slice: ChangelogSlice, map: BlockStateMap): BufferedImage {
val blockMap = map as SparseBlockStateMap
val yMin = blockMap.blocks.minOf { xSection -> xSection.value.minOf { zSection -> zSection.value.size } }
val yMax = blockMap.blocks.maxOf { xSection -> xSection.value.maxOf { zSection -> zSection.value.size } }
val clamp = FloatClamp(yMin.toLong(), yMax.toLong())
return buildHeatMapImage(expanse, clamp) { x, z -> blockMap.blocks[x]?.get(z)?.maxOf { it.key } }
}
}

View File

@ -0,0 +1,20 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.tool.render.ui.GraphicalRenderSession
import gay.pizza.foundation.heimdall.tool.state.BlockExpanse
import gay.pizza.foundation.heimdall.tool.state.BlockStateMap
import gay.pizza.foundation.heimdall.tool.state.ChangelogSlice
import java.awt.image.BufferedImage
import javax.swing.WindowConstants
class LaunchGraphicalRenderSession(val expanse: BlockExpanse) : BlockImageRenderer {
override fun render(slice: ChangelogSlice, map: BlockStateMap): BufferedImage {
val session = GraphicalRenderSession(expanse, map)
session.isVisible = true
session.defaultCloseOperation = WindowConstants.HIDE_ON_CLOSE
while (session.isVisible) {
Thread.sleep(1000)
}
return BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR)
}
}

View File

@ -0,0 +1,56 @@
package gay.pizza.foundation.heimdall.tool.render
import gay.pizza.foundation.heimdall.table.PlayerPositionTable
import gay.pizza.foundation.heimdall.tool.state.*
import gay.pizza.foundation.heimdall.tool.util.BlockColorKey
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
import java.util.*
class PlayerLocationShareRenderer(
val expanse: BlockExpanse,
val db: Database,
quadPixelSize: Int = defaultQuadPixelSize
) : BlockGridRenderer(quadPixelSize) {
private val colorKey = BlockColorKey(mapOf())
override fun render(slice: ChangelogSlice, map: BlockStateMap): BufferedImage {
val start = slice.sliceChangeRange.start
val end = slice.sliceChangeRange.endInclusive
val playerSparseMap = BlockCoordinateSparseMap<MutableList<UUID>>()
val allPlayerIds = HashSet<UUID>()
transaction(db) {
gay.pizza.foundation.heimdall.table.PlayerPositionTable.select {
(gay.pizza.foundation.heimdall.table.PlayerPositionTable.time greater start) and
(gay.pizza.foundation.heimdall.table.PlayerPositionTable.time lessEq end)
}.forEach {
val x = it[gay.pizza.foundation.heimdall.table.PlayerPositionTable.x].toLong()
val y = it[gay.pizza.foundation.heimdall.table.PlayerPositionTable.y].toLong()
val z = it[gay.pizza.foundation.heimdall.table.PlayerPositionTable.z].toLong()
val coordinate = expanse.offset.applyAsOffset(BlockCoordinate(x, y, z))
val player = it[gay.pizza.foundation.heimdall.table.PlayerPositionTable.player]
playerSparseMap.createOrModify(
coordinate,
create = { mutableListOf(player) },
modify = { players -> players.add(player) })
allPlayerIds.add(player)
}
}
val colorOfPlayers = allPlayerIds.associateWith { colorKey.map(it.toString()) }
return buildPixelQuadImage(expanse) { g, x, z ->
val players = playerSparseMap.getVerticalSection(x, z)?.flatMap { it.value }?.distinct()
if (players != null) {
setPixelQuad(g, x, z, colorOfPlayers[players.first()]!!)
} else {
setPixelQuad(g, x, z, Color.white)
}
}
}
}

View File

@ -0,0 +1,22 @@
package gay.pizza.foundation.heimdall.tool.render.ui
import gay.pizza.foundation.heimdall.tool.render.BlockDiversityRenderer
import gay.pizza.foundation.heimdall.tool.render.BlockHeightMapRenderer
import gay.pizza.foundation.heimdall.tool.render.BlockVerticalFillMapRenderer
import gay.pizza.foundation.heimdall.tool.state.BlockExpanse
import gay.pizza.foundation.heimdall.tool.state.BlockStateMap
import java.awt.Dimension
import javax.swing.JFrame
import javax.swing.JTabbedPane
class GraphicalRenderSession(val expanse: BlockExpanse, val map: BlockStateMap) : JFrame() {
init {
name = "Gjallarhorn Renderer"
size = Dimension(1024, 1024)
val pane = JTabbedPane()
pane.addTab("Block Diversity", LazyImageRenderer(map, BlockDiversityRenderer(expanse)))
pane.addTab("Height Map", LazyImageRenderer(map, BlockHeightMapRenderer(expanse)))
pane.addTab("Vertical Fill Map", LazyImageRenderer(map, BlockVerticalFillMapRenderer(expanse)))
add(pane)
}
}

View File

@ -0,0 +1,21 @@
package gay.pizza.foundation.heimdall.tool.render.ui
import gay.pizza.foundation.heimdall.tool.render.BlockImageRenderer
import gay.pizza.foundation.heimdall.tool.state.BlockStateMap
import gay.pizza.foundation.heimdall.tool.state.ChangelogSlice
import java.awt.Graphics
import javax.swing.JComponent
class LazyImageRenderer(val map: BlockStateMap, private val renderer: BlockImageRenderer) : JComponent() {
private val image by lazy {
renderer.render(ChangelogSlice.none, map)
}
override fun paint(g: Graphics?) {
g?.drawImage(image, 0, 0, this)
}
override fun paintComponent(g: Graphics?) {
g?.drawImage(image, 0, 0, this)
}
}