mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-04 05:51:32 +00:00
Gjallarhorn: Block Color Key and Render Pool Enhancements
This commit is contained in:
@ -2,13 +2,14 @@ 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.util.RandomColorKey
|
||||
import cloud.kubelet.foundation.gjallarhorn.util.BlockColorKey
|
||||
import cloud.kubelet.foundation.gjallarhorn.util.defaultBlockColorMap
|
||||
import java.awt.Color
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
class BlockDiversityRenderer(val expanse: BlockExpanse, quadPixelSize: Int = defaultQuadPixelSize) :
|
||||
BlockGridRenderer(quadPixelSize) {
|
||||
private val randomColorKey = RandomColorKey()
|
||||
private val blockColorKey = BlockColorKey(defaultBlockColorMap)
|
||||
|
||||
override fun render(map: BlockMap): BufferedImage = buildPixelQuadImage(expanse) { graphics, x, z ->
|
||||
val maybeYBlocks = map.blocks[x]?.get(z)
|
||||
@ -22,7 +23,7 @@ class BlockDiversityRenderer(val expanse: BlockExpanse, quadPixelSize: Int = def
|
||||
return@buildPixelQuadImage
|
||||
}
|
||||
|
||||
val color = randomColorKey.map(maxBlockState.type)
|
||||
val color = blockColorKey.map(maxBlockState.type)
|
||||
setPixelQuad(graphics, x, z, color.rgb)
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ import java.time.Instant
|
||||
data class BlockChangelogSlice(val from: Instant, val to: Instant, val relative: Duration) {
|
||||
constructor(from: Instant, to: Instant) : this(from, to, Duration.ofMillis(to.toEpochMilli() - from.toEpochMilli()))
|
||||
|
||||
fun changeResolutionTime(): Instant = to.minus(relative)
|
||||
val changeResolutionTime: Instant = to.minus(relative)
|
||||
|
||||
fun isTimeWithin(time: Instant) = time in from..to
|
||||
fun isRelativeWithin(time: Instant) = time in changeResolutionTime()..to
|
||||
fun isRelativeWithin(time: Instant) = time in changeResolutionTime..to
|
||||
|
||||
fun split(): List<BlockChangelogSlice> {
|
||||
val half = relative.dividedBy(2)
|
||||
|
@ -16,12 +16,12 @@ class BlockMapRenderPool<T>(
|
||||
private val playbackJobFutures = ConcurrentHashMap<BlockChangelogSlice, Future<*>>()
|
||||
private val renderJobFutures = ConcurrentHashMap<BlockChangelogSlice, Future<*>>()
|
||||
|
||||
fun submitPlaybackJob(slice: BlockChangelogSlice) {
|
||||
fun submitPlaybackJob(id: String, slice: BlockChangelogSlice) {
|
||||
val future = threadPoolExecutor.submit {
|
||||
try {
|
||||
runPlaybackSlice(slice)
|
||||
runPlaybackSlice(id, slice)
|
||||
} catch (e: Exception) {
|
||||
logger.error("Failed to run playback job for slice $slice", e)
|
||||
logger.error("Failed to run playback job for slice $id", e)
|
||||
}
|
||||
}
|
||||
playbackJobFutures[slice] = future
|
||||
@ -41,7 +41,7 @@ class BlockMapRenderPool<T>(
|
||||
|
||||
fun render(slices: List<BlockChangelogSlice>) {
|
||||
for (slice in slices) {
|
||||
submitPlaybackJob(slice)
|
||||
submitPlaybackJob((slices.indexOf(slice) + 1).toString(), slice)
|
||||
}
|
||||
|
||||
for (future in playbackJobFutures.values) {
|
||||
@ -55,16 +55,22 @@ class BlockMapRenderPool<T>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun runPlaybackSlice(slice: BlockChangelogSlice) {
|
||||
private fun runPlaybackSlice(id: String, slice: BlockChangelogSlice) {
|
||||
val start = System.currentTimeMillis()
|
||||
val sliced = changelog.slice(slice)
|
||||
val tracker = BlockLogTracker(blockTrackMode)
|
||||
tracker.replay(sliced)
|
||||
delegate.postProcessTracker(tracker)
|
||||
if (tracker.isNotEmpty()) {
|
||||
trackers[slice] = tracker
|
||||
}
|
||||
val end = System.currentTimeMillis()
|
||||
val timeInMilliseconds = end - start
|
||||
logger.info("Playback Completed for Slice $id in ${timeInMilliseconds}ms")
|
||||
}
|
||||
|
||||
interface RenderPoolDelegate<T> {
|
||||
fun postProcessTracker(tracker: BlockLogTracker)
|
||||
fun buildRenderJobs(pool: BlockMapRenderPool<T>, trackers: MutableMap<BlockChangelogSlice, BlockLogTracker>)
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package cloud.kubelet.foundation.gjallarhorn.state
|
||||
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.stream.Stream
|
||||
|
||||
class BlockMapTimelapse<T>(val trim: Pair<BlockCoordinate, BlockCoordinate>? = null) :
|
||||
BlockMapRenderPool.RenderPoolDelegate<T> {
|
||||
@ -28,35 +29,23 @@ class BlockMapTimelapse<T>(val trim: Pair<BlockCoordinate, BlockCoordinate>? = n
|
||||
minimumTimeInterval: Duration,
|
||||
slices: List<BlockChangelogSlice>
|
||||
): List<BlockChangelogSlice> {
|
||||
return slices.flatMap { slice ->
|
||||
return slices.parallelStream().flatMap { slice ->
|
||||
val count = changelog.countRelativeChangesInSlice(slice)
|
||||
if (count < targetChangeThreshold ||
|
||||
slice.relative < minimumTimeInterval
|
||||
) {
|
||||
return@flatMap listOf(slice)
|
||||
return@flatMap Stream.of(slice)
|
||||
}
|
||||
|
||||
val split = slice.split()
|
||||
return@flatMap splitChangelogSlicesWithThreshold(changelog, targetChangeThreshold, minimumTimeInterval, split)
|
||||
}
|
||||
return@flatMap splitChangelogSlicesWithThreshold(changelog, targetChangeThreshold, minimumTimeInterval, split).parallelStream()
|
||||
}.toList()
|
||||
}
|
||||
|
||||
override fun buildRenderJobs(
|
||||
pool: BlockMapRenderPool<T>,
|
||||
trackers: MutableMap<BlockChangelogSlice, BlockLogTracker>
|
||||
) {
|
||||
if (trim != null) {
|
||||
trackers.values.forEach { tracker ->
|
||||
tracker.trimOutsideXAndZRange(trim.first, trim.second)
|
||||
}
|
||||
}
|
||||
|
||||
for ((slice, tracker) in trackers.entries.toList()) {
|
||||
if (tracker.isEmpty()) {
|
||||
trackers.remove(slice)
|
||||
}
|
||||
}
|
||||
|
||||
val allBlockOffsets = trackers.map { it.value.calculateZeroBlockOffset() }
|
||||
val globalBlockOffset = BlockCoordinate.maxOf(allBlockOffsets)
|
||||
val allBlockMaxes = trackers.map { it.value.calculateMaxBlock() }
|
||||
@ -65,14 +54,16 @@ class BlockMapTimelapse<T>(val trim: Pair<BlockCoordinate, BlockCoordinate>? = n
|
||||
|
||||
val renderer = pool.rendererFactory(globalBlockExpanse)
|
||||
for ((slice, tracker) in trackers) {
|
||||
if (tracker.isEmpty()) {
|
||||
continue
|
||||
}
|
||||
|
||||
pool.submitRenderJob(slice) {
|
||||
val map = tracker.buildBlockMap(globalBlockExpanse.offset)
|
||||
renderer.render(map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun postProcessTracker(tracker: BlockLogTracker) {
|
||||
if (trim != null) {
|
||||
tracker.trimOutsideXAndZRange(trim.first, trim.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ package cloud.kubelet.foundation.gjallarhorn.util
|
||||
import java.awt.Color
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class RandomColorKey {
|
||||
private val colors = ConcurrentHashMap<String, Color>()
|
||||
class BlockColorKey(assigned: Map<String, Color>) {
|
||||
private val colors = ConcurrentHashMap(assigned)
|
||||
|
||||
fun map(key: String) = colors.computeIfAbsent(key) { findUniqueColor() }
|
||||
fun map(key: String): Color = colors.computeIfAbsent(key) { findUniqueColor() }
|
||||
|
||||
private fun findUniqueColor(): Color {
|
||||
var random = randomColor()
|
@ -0,0 +1,17 @@
|
||||
package cloud.kubelet.foundation.gjallarhorn.util
|
||||
|
||||
import java.awt.Color
|
||||
|
||||
val defaultBlockColorMap = mapOf<String, Color>(
|
||||
"minecraft:air" to Color.black,
|
||||
"minecraft:dirt" to Color.decode("#9b7653"),
|
||||
"minecraft:farmland" to Color.decode("#5d3f2a"),
|
||||
"minecraft:stone" to Color.decode("#787366"),
|
||||
"minecraft:cobblestone" to Color.decode("#c4bca7"),
|
||||
"minecraft:wheat" to Color.decode("#9e884c"),
|
||||
"minecraft:carrots" to Color.decode("#f89d40"),
|
||||
"minecraft:stone_brick_stairs" to Color.decode("#b8a18c"),
|
||||
"minecraft:dirt_path" to Color.decode("#8f743d"),
|
||||
"minecraft:deepslate_tiles" to Color.decode("#49494b"),
|
||||
"minecraft:spruce_planks" to Color.decode("#60492d")
|
||||
)
|
Reference in New Issue
Block a user