mirror of
				https://github.com/GayPizzaSpecifications/foundation.git
				synced 2025-11-04 03:39:37 +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