mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-02 21:20:55 +00:00
Gjallarhorn: First attempt at a graphical render system.
This commit is contained in:
parent
1afb1c7148
commit
6bcddb15b5
@ -104,7 +104,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, db) },
|
||||
createRendererFunction = { expanse -> render.createNewRenderer(expanse, db) },
|
||||
threadPoolExecutor = threadPoolExecutor
|
||||
) { slice, result ->
|
||||
val speed = slice.sliceRelativeDuration.toSeconds().toDouble() / timelapseMode.interval.toSeconds().toDouble()
|
||||
|
@ -10,6 +10,7 @@ import com.github.ajalt.clikt.core.requireObject
|
||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||
import com.github.ajalt.clikt.parameters.options.option
|
||||
import com.github.ajalt.clikt.parameters.types.enum
|
||||
import com.github.ajalt.clikt.parameters.types.int
|
||||
import com.github.ajalt.clikt.parameters.types.path
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
|
||||
@ -18,17 +19,17 @@ class ChunkExportLoaderCommand : CliktCommand("Chunk Export Loader", name = "chu
|
||||
|
||||
private val exportDirectoryPath by argument("export-directory-path").path()
|
||||
private val world by argument("world")
|
||||
|
||||
private val chunkLoadLimit by option("--chunk-limit", help = "Chunk Limit").int()
|
||||
private val render by option("--render", help = "Render Top Down Image").enum<ImageRenderType> { it.id }
|
||||
|
||||
override fun run() {
|
||||
val tracker = BlockLogTracker(isConcurrent = true)
|
||||
val loader = ChunkExportLoader(tracker = tracker)
|
||||
loader.loadAllChunksForWorld(exportDirectoryPath, world, fast = true)
|
||||
loader.loadAllChunksForWorld(exportDirectoryPath, world, fast = true, limit = chunkLoadLimit)
|
||||
if (render != null) {
|
||||
val expanse = BlockExpanse.zeroOffsetAndMax(tracker.calculateZeroBlockOffset(), tracker.calculateMaxBlock())
|
||||
val map = tracker.buildBlockMap(expanse.offset)
|
||||
val renderer = render!!.create(expanse, db)
|
||||
val renderer = render!!.createNewRenderer(expanse, db)
|
||||
val image = renderer.render(ChangelogSlice.none, map)
|
||||
image.savePngFile("full.png")
|
||||
}
|
||||
|
@ -1,18 +1,16 @@
|
||||
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.BlockImageRenderer
|
||||
import cloud.kubelet.foundation.gjallarhorn.render.PlayerLocationShareRenderer
|
||||
import cloud.kubelet.foundation.gjallarhorn.render.*
|
||||
import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
|
||||
@Suppress("unused")
|
||||
enum class ImageRenderType(
|
||||
val id: String,
|
||||
val create: (BlockExpanse, Database) -> BlockImageRenderer
|
||||
val createNewRenderer: (BlockExpanse, Database) -> BlockImageRenderer
|
||||
) {
|
||||
BlockDiversity("block-diversity", { expanse, _ -> BlockDiversityRenderer(expanse) }),
|
||||
HeightMap("height-map", { expanse, _ -> BlockHeightMapRenderer(expanse) }),
|
||||
PlayerPosition("player-position", { expanse, db -> PlayerLocationShareRenderer(expanse, db) })
|
||||
PlayerPosition("player-position", { expanse, db -> PlayerLocationShareRenderer(expanse, db) }),
|
||||
GraphicalSession("graphical", { expanse, _ -> LaunchGraphicalRenderSession(expanse) })
|
||||
}
|
||||
|
@ -14,8 +14,11 @@ import kotlin.io.path.inputStream
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
|
||||
class ChunkExportLoader(val map: SparseBlockStateMap? = null, val tracker: BlockLogTracker? = null) {
|
||||
fun loadAllChunksForWorld(path: Path, world: String, fast: Boolean = false) {
|
||||
val chunkFiles = path.listDirectoryEntries("${world}_chunk_*.json.gz")
|
||||
fun loadAllChunksForWorld(path: Path, world: String, fast: Boolean = false, limit: Int? = null) {
|
||||
var chunkFiles = path.listDirectoryEntries("${world}_chunk_*.json.gz")
|
||||
if (limit != null) {
|
||||
chunkFiles = chunkFiles.take(limit)
|
||||
}
|
||||
if (fast) {
|
||||
chunkFiles.parallelStream().forEach { loadChunkFile(it, id = chunkFiles.indexOf(it)) }
|
||||
} else {
|
||||
|
@ -0,0 +1,15 @@
|
||||
package cloud.kubelet.foundation.gjallarhorn.render
|
||||
|
||||
import cloud.kubelet.foundation.gjallarhorn.render.ui.GraphicalRenderSession
|
||||
import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse
|
||||
import cloud.kubelet.foundation.gjallarhorn.state.BlockStateMap
|
||||
import cloud.kubelet.foundation.gjallarhorn.state.ChangelogSlice
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
class LaunchGraphicalRenderSession(val expanse: BlockExpanse) : BlockImageRenderer {
|
||||
override fun render(slice: ChangelogSlice, map: BlockStateMap): BufferedImage {
|
||||
val session = GraphicalRenderSession(expanse, map)
|
||||
session.isVisible = true
|
||||
return BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR)
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cloud.kubelet.foundation.gjallarhorn.render.ui
|
||||
|
||||
import cloud.kubelet.foundation.gjallarhorn.render.BlockDiversityRenderer
|
||||
import cloud.kubelet.foundation.gjallarhorn.render.BlockHeightMapRenderer
|
||||
import cloud.kubelet.foundation.gjallarhorn.render.BlockVerticalFillMapRenderer
|
||||
import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse
|
||||
import cloud.kubelet.foundation.gjallarhorn.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)
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cloud.kubelet.foundation.gjallarhorn.render.ui
|
||||
|
||||
import cloud.kubelet.foundation.gjallarhorn.render.BlockImageRenderer
|
||||
import cloud.kubelet.foundation.gjallarhorn.state.BlockStateMap
|
||||
import cloud.kubelet.foundation.gjallarhorn.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)
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package cloud.kubelet.foundation.gjallarhorn.state
|
||||
|
||||
import cloud.kubelet.foundation.gjallarhorn.util.maxOfAll
|
||||
import cloud.kubelet.foundation.gjallarhorn.util.minOfAll
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
@ -23,10 +25,7 @@ class BlockLogTracker(private val mode: BlockTrackMode = BlockTrackMode.RemoveOn
|
||||
}
|
||||
|
||||
fun calculateZeroBlockOffset(): BlockCoordinate {
|
||||
val x = blocks.keys.minOf { it.x }
|
||||
val y = blocks.keys.minOf { it.y }
|
||||
val z = blocks.keys.minOf { it.z }
|
||||
|
||||
val (x, y, z) = blocks.keys.minOfAll(3) { listOf(it.x, it.y, it.z) }
|
||||
val xOffset = if (x < 0) x.absoluteValue else 0
|
||||
val yOffset = if (y < 0) y.absoluteValue else 0
|
||||
val zOffset = if (z < 0) z.absoluteValue else 0
|
||||
@ -35,9 +34,7 @@ class BlockLogTracker(private val mode: BlockTrackMode = BlockTrackMode.RemoveOn
|
||||
}
|
||||
|
||||
fun calculateMaxBlock(): BlockCoordinate {
|
||||
val x = blocks.keys.maxOf { it.x }
|
||||
val y = blocks.keys.maxOf { it.y }
|
||||
val z = blocks.keys.maxOf { it.z }
|
||||
val (x, y, z) = blocks.keys.maxOfAll(3) { listOf(it.x, it.y, it.z) }
|
||||
return BlockCoordinate(x, y, z)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package cloud.kubelet.foundation.gjallarhorn.util
|
||||
|
||||
fun <T> Sequence<T>.minOfAll(fieldCount: Int, block: (value: T) -> List<Long>): List<Long> {
|
||||
fun <T> Iterable<T>.minOfAll(fieldCount: Int, block: (value: T) -> List<Long>): List<Long> {
|
||||
val fieldRange = 0 until fieldCount
|
||||
val results = fieldRange.map { Long.MAX_VALUE }.toMutableList()
|
||||
for (item in this) {
|
||||
@ -16,7 +16,7 @@ fun <T> Sequence<T>.minOfAll(fieldCount: Int, block: (value: T) -> List<Long>):
|
||||
return results
|
||||
}
|
||||
|
||||
fun <T> Sequence<T>.maxOfAll(fieldCount: Int, block: (value: T) -> List<Long>): List<Long> {
|
||||
fun <T> Iterable<T>.maxOfAll(fieldCount: Int, block: (value: T) -> List<Long>): List<Long> {
|
||||
val fieldRange = 0 until fieldCount
|
||||
val results = fieldRange.map { Long.MIN_VALUE }.toMutableList()
|
||||
for (item in this) {
|
||||
@ -31,3 +31,9 @@ fun <T> Sequence<T>.maxOfAll(fieldCount: Int, block: (value: T) -> List<Long>):
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
fun <T> Sequence<T>.minOfAll(fieldCount: Int, block: (value: T) -> List<Long>): List<Long> =
|
||||
asIterable().minOfAll(fieldCount, block)
|
||||
|
||||
fun <T> Sequence<T>.maxOfAll(fieldCount: Int, block: (value: T) -> List<Long>): List<Long> =
|
||||
asIterable().maxOfAll(fieldCount, block)
|
||||
|
Loading…
Reference in New Issue
Block a user