Gjallarhorn: Implement trimming at the changelog level, resulting in really fast renderings.

This commit is contained in:
Kenneth Endfinger 2022-01-10 02:13:13 -05:00
parent dcec7cab54
commit 3ac24f6912
No known key found for this signature in database
GPG Key ID: C4E68E5647420E10
4 changed files with 24 additions and 23 deletions

View File

@ -4,7 +4,9 @@ import cloud.kubelet.foundation.gjallarhorn.render.BlockDiversityRenderer
import cloud.kubelet.foundation.gjallarhorn.render.BlockHeightMapRenderer import cloud.kubelet.foundation.gjallarhorn.render.BlockHeightMapRenderer
import cloud.kubelet.foundation.gjallarhorn.render.BlockImageRenderer import cloud.kubelet.foundation.gjallarhorn.render.BlockImageRenderer
import cloud.kubelet.foundation.gjallarhorn.state.* import cloud.kubelet.foundation.gjallarhorn.state.*
import cloud.kubelet.foundation.gjallarhorn.util.compose
import cloud.kubelet.foundation.gjallarhorn.util.savePngFile import cloud.kubelet.foundation.gjallarhorn.util.savePngFile
import cloud.kubelet.foundation.heimdall.view.BlockChangeView
import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.requireObject import com.github.ajalt.clikt.core.requireObject
import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.flag
@ -13,6 +15,9 @@ import com.github.ajalt.clikt.parameters.options.required
import com.github.ajalt.clikt.parameters.types.enum import com.github.ajalt.clikt.parameters.types.enum
import com.github.ajalt.clikt.parameters.types.int import com.github.ajalt.clikt.parameters.types.int
import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greaterEq
import org.jetbrains.exposed.sql.SqlExpressionBuilder.lessEq
import org.jetbrains.exposed.sql.and
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.awt.Color import java.awt.Color
import java.awt.Font import java.awt.Font
@ -45,8 +50,19 @@ class BlockChangeTimelapseCommand : CliktCommand("Block Change Timelapse", name
override fun run() { override fun run() {
val threadPoolExecutor = ScheduledThreadPoolExecutor(16) val threadPoolExecutor = ScheduledThreadPoolExecutor(16)
val changelog = BlockChangelog.query(db)
val timelapse = BlockMapTimelapse<BufferedImage>(maybeBuildTrim()) val trim = maybeBuildTrim()
val filter = compose(
combine = { a, b -> a and b },
{ trim?.first?.x != null } to { BlockChangeView.x greaterEq trim!!.first.x },
{ trim?.first?.z != null } to { BlockChangeView.z greaterEq trim!!.first.z },
{ trim?.second?.x != null } to { BlockChangeView.x lessEq trim!!.second.x },
{ trim?.second?.z != null } to { BlockChangeView.z lessEq trim!!.second.z }
)
val changelog = BlockChangelog.query(db, filter)
logger.info("Block Changelog: ${changelog.changes.size} changes")
val timelapse = BlockMapTimelapse<BufferedImage>()
var slices = timelapse.calculateChangelogSlices(changelog, timelapseMode.interval, timelapseIntervalLimit) var slices = timelapse.calculateChangelogSlices(changelog, timelapseMode.interval, timelapseIntervalLimit)
if (timelapseSpeedChangeThreshold != null && timelapseSpeedChangeMinimumIntervalSeconds != null) { if (timelapseSpeedChangeThreshold != null && timelapseSpeedChangeMinimumIntervalSeconds != null) {

View File

@ -17,17 +17,6 @@ class BlockLogTracker(private val mode: BlockTrackMode = BlockTrackMode.RemoveOn
} }
} }
fun trimOutsideXAndZRange(min: BlockCoordinate, max: BlockCoordinate) {
val blockPositionsToRemove = blocks.keys.filter {
it.x < min.x ||
it.z < min.z ||
it.x > max.x ||
it.z > max.z
}.toList()
blockPositionsToRemove.forEach { blocks.remove(it) }
}
fun calculateZeroBlockOffset(): BlockCoordinate { fun calculateZeroBlockOffset(): BlockCoordinate {
val x = blocks.keys.minOf { it.x } val x = blocks.keys.minOf { it.x }
val y = blocks.keys.minOf { it.y } val y = blocks.keys.minOf { it.y }
@ -48,7 +37,7 @@ class BlockLogTracker(private val mode: BlockTrackMode = BlockTrackMode.RemoveOn
} }
fun isEmpty() = blocks.isEmpty() fun isEmpty() = blocks.isEmpty()
fun isNotEmpty() = blocks.isNotEmpty() fun isNotEmpty() = !isEmpty()
fun buildBlockMap(offset: BlockCoordinate = BlockCoordinate.zero): BlockMap { fun buildBlockMap(offset: BlockCoordinate = BlockCoordinate.zero): BlockMap {
val map = BlockMap() val map = BlockMap()

View File

@ -60,7 +60,6 @@ class BlockMapRenderPool<T>(
val sliced = changelog.slice(slice) val sliced = changelog.slice(slice)
val tracker = BlockLogTracker(blockTrackMode) val tracker = BlockLogTracker(blockTrackMode)
tracker.replay(sliced) tracker.replay(sliced)
delegate.postProcessTracker(tracker)
if (tracker.isNotEmpty()) { if (tracker.isNotEmpty()) {
trackers[slice] = tracker trackers[slice] = tracker
} }
@ -70,7 +69,6 @@ class BlockMapRenderPool<T>(
} }
interface RenderPoolDelegate<T> { interface RenderPoolDelegate<T> {
fun postProcessTracker(tracker: BlockLogTracker)
fun buildRenderJobs(pool: BlockMapRenderPool<T>, trackers: MutableMap<BlockChangelogSlice, BlockLogTracker>) fun buildRenderJobs(pool: BlockMapRenderPool<T>, trackers: MutableMap<BlockChangelogSlice, BlockLogTracker>)
} }

View File

@ -4,7 +4,7 @@ import java.time.Duration
import java.time.Instant import java.time.Instant
import java.util.stream.Stream import java.util.stream.Stream
class BlockMapTimelapse<T>(val trim: Pair<BlockCoordinate, BlockCoordinate>? = null) : class BlockMapTimelapse<T> :
BlockMapRenderPool.RenderPoolDelegate<T> { BlockMapRenderPool.RenderPoolDelegate<T> {
fun calculateChangelogSlices( fun calculateChangelogSlices(
changelog: BlockChangelog, interval: Duration, limit: Int? = null changelog: BlockChangelog, interval: Duration, limit: Int? = null
@ -46,6 +46,10 @@ class BlockMapTimelapse<T>(val trim: Pair<BlockCoordinate, BlockCoordinate>? = n
pool: BlockMapRenderPool<T>, pool: BlockMapRenderPool<T>,
trackers: MutableMap<BlockChangelogSlice, BlockLogTracker> trackers: MutableMap<BlockChangelogSlice, BlockLogTracker>
) { ) {
if (trackers.isEmpty()) {
return
}
val allBlockOffsets = trackers.map { it.value.calculateZeroBlockOffset() } val allBlockOffsets = trackers.map { it.value.calculateZeroBlockOffset() }
val globalBlockOffset = BlockCoordinate.maxOf(allBlockOffsets) val globalBlockOffset = BlockCoordinate.maxOf(allBlockOffsets)
val allBlockMaxes = trackers.map { it.value.calculateMaxBlock() } val allBlockMaxes = trackers.map { it.value.calculateMaxBlock() }
@ -60,10 +64,4 @@ class BlockMapTimelapse<T>(val trim: Pair<BlockCoordinate, BlockCoordinate>? = n
} }
} }
} }
override fun postProcessTracker(tracker: BlockLogTracker) {
if (trim != null) {
tracker.trimOutsideXAndZRange(trim.first, trim.second)
}
}
} }