mirror of
				https://github.com/GayPizzaSpecifications/foundation.git
				synced 2025-11-04 03:39:37 +00:00 
			
		
		
		
	Implement Chunk Export
This commit is contained in:
		@ -6,6 +6,7 @@ import cloud.kubelet.foundation.heimdall.buffer.BufferFlushThread
 | 
				
			|||||||
import cloud.kubelet.foundation.heimdall.buffer.EventBuffer
 | 
					import cloud.kubelet.foundation.heimdall.buffer.EventBuffer
 | 
				
			||||||
import cloud.kubelet.foundation.heimdall.event.*
 | 
					import cloud.kubelet.foundation.heimdall.event.*
 | 
				
			||||||
import cloud.kubelet.foundation.heimdall.model.HeimdallConfig
 | 
					import cloud.kubelet.foundation.heimdall.model.HeimdallConfig
 | 
				
			||||||
 | 
					import cloud.kubelet.foundation.heimdall.export.ExportChunksCommand
 | 
				
			||||||
import com.charleskorn.kaml.Yaml
 | 
					import com.charleskorn.kaml.Yaml
 | 
				
			||||||
import com.zaxxer.hikari.HikariConfig
 | 
					import com.zaxxer.hikari.HikariConfig
 | 
				
			||||||
import com.zaxxer.hikari.HikariDataSource
 | 
					import com.zaxxer.hikari.HikariDataSource
 | 
				
			||||||
@ -38,6 +39,9 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
 | 
				
			|||||||
  private val legacyComponentSerializer = LegacyComponentSerializer.builder().build()
 | 
					  private val legacyComponentSerializer = LegacyComponentSerializer.builder().build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  override fun onEnable() {
 | 
					  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 foundation = server.pluginManager.getPlugin("Foundation") as FoundationCorePlugin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val configPath = Util.copyDefaultConfig<FoundationHeimdallPlugin>(
 | 
					    val configPath = Util.copyDefaultConfig<FoundationHeimdallPlugin>(
 | 
				
			||||||
 | 
				
			|||||||
@ -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)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -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
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package cloud.kubelet.foundation.heimdall.export
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					data class ExportedBlock(
 | 
				
			||||||
 | 
					  val type: String
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -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>
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -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>
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
@ -8,3 +8,8 @@ depend:
 | 
				
			|||||||
  - Foundation
 | 
					  - Foundation
 | 
				
			||||||
authors:
 | 
					authors:
 | 
				
			||||||
  - kubelet
 | 
					  - kubelet
 | 
				
			||||||
 | 
					commands:
 | 
				
			||||||
 | 
					  export_all_chunks:
 | 
				
			||||||
 | 
					    description: Export All Chunks
 | 
				
			||||||
 | 
					    usage: /export_all_chunks
 | 
				
			||||||
 | 
					    permission: foundation.heimdall.command.export_all_chunks
 | 
				
			||||||
 | 
				
			|||||||
@ -20,11 +20,12 @@ class BlockChangelog(
 | 
				
			|||||||
    slice.isTimeWithinSliceRange(it.time)
 | 
					    slice.isTimeWithinSliceRange(it.time)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  val changeTimeRange: ChangelogSlice
 | 
					  val fullTimeSlice: ChangelogSlice
 | 
				
			||||||
    get() = ChangelogSlice(changes.minOf { it.time }, changes.maxOf { it.time })
 | 
					    get() = ChangelogSlice(changes.minOf { it.time }, changes.maxOf { it.time })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fun calculateChangelogSlices(interval: Duration, limit: Int? = null): List<ChangelogSlice> {
 | 
					  fun calculateChangelogSlices(interval: Duration, limit: Int? = null): List<ChangelogSlice> {
 | 
				
			||||||
    val (start, end) = changeTimeRange
 | 
					    val start = fullTimeSlice.rootStartTime
 | 
				
			||||||
 | 
					    val end = fullTimeSlice.sliceEndTime
 | 
				
			||||||
    var intervals = mutableListOf<Instant>()
 | 
					    var intervals = mutableListOf<Instant>()
 | 
				
			||||||
    var current = start
 | 
					    var current = start
 | 
				
			||||||
    while (!current.isAfter(end)) {
 | 
					    while (!current.isAfter(end)) {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user