Implement Chunk Export

This commit is contained in:
Kenneth Endfinger
2022-02-16 23:48:51 -05:00
parent eb5cb1a229
commit ac2e99052d
8 changed files with 141 additions and 2 deletions

View File

@ -6,6 +6,7 @@ import cloud.kubelet.foundation.heimdall.buffer.BufferFlushThread
import cloud.kubelet.foundation.heimdall.buffer.EventBuffer
import cloud.kubelet.foundation.heimdall.event.*
import cloud.kubelet.foundation.heimdall.model.HeimdallConfig
import cloud.kubelet.foundation.heimdall.export.ExportChunksCommand
import com.charleskorn.kaml.Yaml
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
@ -38,6 +39,9 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
private val legacyComponentSerializer = LegacyComponentSerializer.builder().build()
override fun onEnable() {
val exportChunksCommand = getCommand("export_all_chunks") ?: throw Exception("Failed to get export_all_chunks command")
exportChunksCommand.setExecutor(ExportChunksCommand(this))
val foundation = server.pluginManager.getPlugin("Foundation") as FoundationCorePlugin
val configPath = Util.copyDefaultConfig<FoundationHeimdallPlugin>(

View File

@ -0,0 +1,84 @@
package cloud.kubelet.foundation.heimdall.export
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.encodeToStream
import org.bukkit.Chunk
import org.bukkit.ChunkSnapshot
import org.bukkit.Server
import org.bukkit.World
import org.bukkit.plugin.Plugin
import java.io.File
import java.util.concurrent.atomic.AtomicBoolean
import java.util.zip.GZIPOutputStream
class ChunkExporter(private val plugin: Plugin, private val server: Server, val world: World) {
private val json = Json {
ignoreUnknownKeys = true
}
fun exportLoadedChunksAsync() {
exportChunkListAsync(world.loadedChunks.toList())
}
private fun exportChunkListAsync(chunks: List<Chunk>) {
val listOfChunks = chunks.toMutableList()
doExportChunkList(listOfChunks, AtomicBoolean(false))
}
private fun doExportChunkList(chunks: MutableList<Chunk>, check: AtomicBoolean) {
check.set(false)
val chunk = chunks.removeFirstOrNull()
if (chunk == null) {
plugin.slF4JLogger.info("Chunk Export Complete")
return
}
val snapshot = chunk.chunkSnapshot
server.scheduler.runTaskAsynchronously(plugin) { ->
saveChunkSnapshotAndScheduleNext(snapshot, chunks, check)
}
}
private fun saveChunkSnapshotAndScheduleNext(snapshot: ChunkSnapshot, chunks: MutableList<Chunk>, check: AtomicBoolean) {
exportChunkSnapshot(snapshot)
if (!check.getAndSet(true)) {
plugin.server.scheduler.runTask(plugin) { -> doExportChunkList(chunks, check) }
}
}
private fun exportChunkSnapshot(snapshot: ChunkSnapshot) {
val sections = mutableListOf<ExportedChunkSection>()
val yRange = world.minHeight until world.maxHeight
val chunkRange = 0..15
for (x in chunkRange) {
for (z in chunkRange) {
sections.add(exportChunkSection(snapshot, yRange, x, z))
}
}
val exported = ExportedChunk(snapshot.x, snapshot.z, sections)
saveChunkSnapshot(snapshot, exported)
}
private fun saveChunkSnapshot(snapshot: ChunkSnapshot, chunk: ExportedChunk) {
val file = File("exported_chunks/${snapshot.worldName}_chunk_${snapshot.x}_${snapshot.z}.json.gz")
if (!file.parentFile.exists()) {
file.parentFile.mkdirs()
}
val fileOutputStream = file.outputStream()
val gzipOutputStream = GZIPOutputStream(fileOutputStream)
json.encodeToStream(ExportedChunk.serializer(), chunk, gzipOutputStream)
gzipOutputStream.close()
}
private fun exportChunkSection(snapshot: ChunkSnapshot, yRange: IntRange, x: Int, z: Int): ExportedChunkSection {
val blocks = mutableListOf<ExportedBlock>()
for (y in yRange) {
val blockData = snapshot.getBlockData(x, y, z)
val block = ExportedBlock(blockData.material.key.toString())
blocks.add(block)
}
return ExportedChunkSection(x, z, blocks)
}
}

View File

@ -0,0 +1,17 @@
package cloud.kubelet.foundation.heimdall.export
import org.bukkit.command.Command
import org.bukkit.command.CommandExecutor
import org.bukkit.command.CommandSender
import org.bukkit.plugin.Plugin
class ExportChunksCommand(private val plugin: Plugin) : CommandExecutor {
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
plugin.slF4JLogger.info("Exporting All Chunks")
for (world in sender.server.worlds) {
val export = ChunkExporter(plugin, sender.server, world)
export.exportLoadedChunksAsync()
}
return true
}
}

View File

@ -0,0 +1,8 @@
package cloud.kubelet.foundation.heimdall.export
import kotlinx.serialization.Serializable
@Serializable
data class ExportedBlock(
val type: String
)

View File

@ -0,0 +1,10 @@
package cloud.kubelet.foundation.heimdall.export
import kotlinx.serialization.Serializable
@Serializable
data class ExportedChunk(
val x: Int,
val z: Int,
val sections: List<ExportedChunkSection>
)

View File

@ -0,0 +1,10 @@
package cloud.kubelet.foundation.heimdall.export
import kotlinx.serialization.Serializable
@Serializable
data class ExportedChunkSection(
val x: Int,
val z: Int,
val blocks: List<ExportedBlock>
)

View File

@ -8,3 +8,8 @@ depend:
- Foundation
authors:
- kubelet
commands:
export_all_chunks:
description: Export All Chunks
usage: /export_all_chunks
permission: foundation.heimdall.command.export_all_chunks