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.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>(
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
authors:
 | 
			
		||||
  - 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)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val changeTimeRange: ChangelogSlice
 | 
			
		||||
  val fullTimeSlice: ChangelogSlice
 | 
			
		||||
    get() = ChangelogSlice(changes.minOf { it.time }, changes.maxOf { it.time })
 | 
			
		||||
 | 
			
		||||
  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 current = start
 | 
			
		||||
    while (!current.isAfter(end)) {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user