diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/ChunkExportLoaderCommand.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/ChunkExportLoaderCommand.kt index 55c10bc..c452fb4 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/ChunkExportLoaderCommand.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/commands/ChunkExportLoaderCommand.kt @@ -1,17 +1,23 @@ package cloud.kubelet.foundation.gjallarhorn.commands import cloud.kubelet.foundation.gjallarhorn.export.ChunkExportLoader +import cloud.kubelet.foundation.gjallarhorn.export.CombinedChunkFormat import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse import cloud.kubelet.foundation.gjallarhorn.state.BlockLogTracker import cloud.kubelet.foundation.gjallarhorn.state.ChangelogSlice +import cloud.kubelet.foundation.gjallarhorn.state.SparseBlockStateMap import cloud.kubelet.foundation.gjallarhorn.util.savePngFile import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.requireObject import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.options.flag 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 kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream +import kotlinx.serialization.json.encodeToStream import org.jetbrains.exposed.sql.Database class ChunkExportLoaderCommand : CliktCommand("Chunk Export Loader", name = "chunk-export-loader") { @@ -21,17 +27,35 @@ class ChunkExportLoaderCommand : CliktCommand("Chunk Export Loader", name = "chu 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 { it.id } + private val loadCombinedFormat by option("--load-combined-format").flag() + private val saveCombinedFormat by option("--save-combined-format").flag() override fun run() { - val tracker = BlockLogTracker(isConcurrent = true) - val loader = ChunkExportLoader(tracker = tracker) - loader.loadAllChunksForWorld(exportDirectoryPath, world, fast = true, limit = chunkLoadLimit) - if (render != null) { + val format: CombinedChunkFormat + + val combinedFormatFile = exportDirectoryPath.resolve("combined.json").toFile() + format = if (loadCombinedFormat) { + Json.decodeFromStream(CombinedChunkFormat.serializer(), combinedFormatFile.inputStream()) + } else { + val tracker = BlockLogTracker(isConcurrent = true) + val loader = ChunkExportLoader(tracker = tracker) + loader.loadAllChunksForWorld(exportDirectoryPath, world, fast = true, limit = chunkLoadLimit) val expanse = BlockExpanse.zeroOffsetAndMax(tracker.calculateZeroBlockOffset(), tracker.calculateMaxBlock()) val map = tracker.buildBlockMap(expanse.offset) - val renderer = render!!.createNewRenderer(expanse, db) - val image = renderer.render(ChangelogSlice.none, map) + CombinedChunkFormat(expanse, map) + } + + if (render != null) { + val renderer = render!!.createNewRenderer(format.expanse, db) + val image = renderer.render(ChangelogSlice.none, format.map) image.savePngFile("full.png") } + + if (saveCombinedFormat) { + if (combinedFormatFile.exists()) { + combinedFormatFile.delete() + } + Json.encodeToStream(CombinedChunkFormat.serializer(), format, combinedFormatFile.outputStream()) + } } } diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/export/ChunkExportLoader.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/export/ChunkExportLoader.kt index 5616c7d..1bb3d3a 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/export/ChunkExportLoader.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/export/ChunkExportLoader.kt @@ -1,9 +1,6 @@ package cloud.kubelet.foundation.gjallarhorn.export -import cloud.kubelet.foundation.gjallarhorn.state.BlockCoordinate -import cloud.kubelet.foundation.gjallarhorn.state.BlockLogTracker -import cloud.kubelet.foundation.gjallarhorn.state.BlockState -import cloud.kubelet.foundation.gjallarhorn.state.SparseBlockStateMap +import cloud.kubelet.foundation.gjallarhorn.state.* import cloud.kubelet.foundation.heimdall.export.ExportedChunk import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/export/CombinedChunkFormat.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/export/CombinedChunkFormat.kt new file mode 100644 index 0000000..f181f1a --- /dev/null +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/export/CombinedChunkFormat.kt @@ -0,0 +1,10 @@ +package cloud.kubelet.foundation.gjallarhorn.export + +import cloud.kubelet.foundation.gjallarhorn.state.BlockExpanse +import cloud.kubelet.foundation.gjallarhorn.state.SparseBlockStateMap + +@kotlinx.serialization.Serializable +class CombinedChunkFormat( + val expanse: BlockExpanse, + val map: SparseBlockStateMap +) diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinate.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinate.kt index 95210df..7c569b5 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinate.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinate.kt @@ -1,7 +1,9 @@ package cloud.kubelet.foundation.gjallarhorn.state import java.util.* +import kotlinx.serialization.Serializable +@Serializable data class BlockCoordinate( val x: Long, val y: Long, diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinateSparseMap.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinateSparseMap.kt index c4b353b..cd6f33b 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinateSparseMap.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockCoordinateSparseMap.kt @@ -5,10 +5,10 @@ import cloud.kubelet.foundation.gjallarhorn.util.minOfAll import java.util.* import kotlin.math.absoluteValue -open class BlockCoordinateSparseMap : BlockCoordinateStore { - private var internalBlocks = TreeMap>>() +open class BlockCoordinateSparseMap(blocks: Map>> = mutableMapOf()) : BlockCoordinateStore { + private var internalBlocks = blocks - val blocks: TreeMap>> + val blocks: Map>> get() = internalBlocks override fun get(position: BlockCoordinate): T? = internalBlocks[position.x]?.get(position.z)?.get(position.z) @@ -16,11 +16,11 @@ open class BlockCoordinateSparseMap : BlockCoordinateStore { override fun getXSection(x: Long): Map>? = internalBlocks[x] override fun put(position: BlockCoordinate, value: T) { - internalBlocks.getOrPut(position.x) { - TreeMap() - }.getOrPut(position.z) { - TreeMap() - }[position.y] = value + (((internalBlocks as MutableMap).getOrPut(position.x) { + mutableMapOf() + } as MutableMap).getOrPut(position.z) { + mutableMapOf() + } as MutableMap)[position.y] = value } override fun createOrModify(position: BlockCoordinate, create: () -> T, modify: (T) -> Unit) { @@ -52,11 +52,11 @@ open class BlockCoordinateSparseMap : BlockCoordinateStore { } fun applyCoordinateOffset(offset: BlockCoordinate) { - val root = TreeMap>>() + val root = mutableMapOf>>() internalBlocks = internalBlocks.map { xSection -> - val zSectionMap = TreeMap>() + val zSectionMap = mutableMapOf>() (xSection.key + offset.x) to xSection.value.map { zSection -> - val ySectionMap = TreeMap() + val ySectionMap = mutableMapOf() (zSection.key + offset.z) to zSection.value.mapKeys { (it.key + offset.y) }.toMap(ySectionMap) diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockExpanse.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockExpanse.kt index c1b0a17..8769b4f 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockExpanse.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockExpanse.kt @@ -1,6 +1,9 @@ package cloud.kubelet.foundation.gjallarhorn.state -class BlockExpanse( +import kotlinx.serialization.Serializable + +@Serializable +data class BlockExpanse( val offset: BlockCoordinate, val size: BlockCoordinate ) { diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockState.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockState.kt index 78a20e0..58a9666 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockState.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockState.kt @@ -1,8 +1,10 @@ package cloud.kubelet.foundation.gjallarhorn.state +import kotlinx.serialization.Serializable import java.util.concurrent.ConcurrentHashMap -class BlockState(val type: String) { +@Serializable(BlockStateSerializer::class) +data class BlockState(val type: String) { companion object { private val cache = ConcurrentHashMap() diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockStateSerializer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockStateSerializer.kt new file mode 100644 index 0000000..473ab6a --- /dev/null +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/BlockStateSerializer.kt @@ -0,0 +1,20 @@ +package cloud.kubelet.foundation.gjallarhorn.state + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +class BlockStateSerializer : KSerializer { + override val descriptor: SerialDescriptor + get() = String.serializer().descriptor + + override fun deserialize(decoder: Decoder): BlockState { + return BlockState.cached(decoder.decodeString()) + } + + override fun serialize(encoder: Encoder, value: BlockState) { + encoder.encodeString(value.type) + } +} diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/SparseBlockStateMap.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/SparseBlockStateMap.kt index dbf74b8..e442e3a 100644 --- a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/SparseBlockStateMap.kt +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/SparseBlockStateMap.kt @@ -1,3 +1,7 @@ package cloud.kubelet.foundation.gjallarhorn.state -class SparseBlockStateMap : BlockCoordinateSparseMap() +import kotlinx.serialization.Serializable + +@Serializable(SparseBlockStateMapSerializer::class) +class SparseBlockStateMap(blocks: Map>> = mutableMapOf()) : + BlockCoordinateSparseMap(blocks) diff --git a/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/SparseBlockStateMapSerializer.kt b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/SparseBlockStateMapSerializer.kt new file mode 100644 index 0000000..0de601e --- /dev/null +++ b/tool-gjallarhorn/src/main/kotlin/cloud/kubelet/foundation/gjallarhorn/state/SparseBlockStateMapSerializer.kt @@ -0,0 +1,23 @@ +package cloud.kubelet.foundation.gjallarhorn.state + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.builtins.MapSerializer +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +class SparseBlockStateMapSerializer : KSerializer { + private val internal = MapSerializer(Long.serializer(), MapSerializer(Long.serializer(), MapSerializer(Long.serializer(), BlockState.serializer()))) + override val descriptor: SerialDescriptor + get() = internal.descriptor + + override fun deserialize(decoder: Decoder): SparseBlockStateMap { + val data = internal.deserialize(decoder) + return SparseBlockStateMap(data) + } + + override fun serialize(encoder: Encoder, value: SparseBlockStateMap) { + internal.serialize(encoder, value.blocks) + } +}