mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-03 13:31:32 +00:00
Implement world reassembly from a Heimdall backup.
This commit is contained in:
@ -10,6 +10,7 @@ import gay.pizza.foundation.heimdall.plugin.buffer.BufferFlushThread
|
||||
import gay.pizza.foundation.heimdall.plugin.buffer.EventBuffer
|
||||
import gay.pizza.foundation.heimdall.plugin.event.*
|
||||
import gay.pizza.foundation.heimdall.plugin.export.ExportAllChunksCommand
|
||||
import gay.pizza.foundation.heimdall.plugin.load.ImportWorldLoadCommand
|
||||
import gay.pizza.foundation.heimdall.plugin.model.HeimdallConfig
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
||||
import org.bukkit.event.EventHandler
|
||||
@ -45,6 +46,9 @@ class FoundationHeimdallPlugin : JavaPlugin(), Listener {
|
||||
val exportChunksCommand = getCommand("export_all_chunks") ?: throw Exception("Failed to get export_all_chunks command")
|
||||
exportChunksCommand.setExecutor(ExportAllChunksCommand(this))
|
||||
|
||||
val importWorldLoadCommand = getCommand("import_world_load") ?: throw Exception("Failed to get import_world_load command")
|
||||
importWorldLoadCommand.setExecutor(ImportWorldLoadCommand(this))
|
||||
|
||||
val foundation = FoundationCoreLoader.get(server)
|
||||
val configPath = copyDefaultConfig<FoundationHeimdallPlugin>(
|
||||
slF4JLogger,
|
||||
|
@ -0,0 +1,37 @@
|
||||
package gay.pizza.foundation.heimdall.plugin.load
|
||||
|
||||
import gay.pizza.foundation.heimdall.load.WorldLoadFormat
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.plugin.Plugin
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.inputStream
|
||||
|
||||
class ImportWorldLoadCommand(private val plugin: Plugin) : CommandExecutor {
|
||||
override fun onCommand(
|
||||
sender: CommandSender,
|
||||
command: Command,
|
||||
label: String,
|
||||
args: Array<out String>
|
||||
): Boolean {
|
||||
if (args.size != 1) {
|
||||
sender.sendMessage("Usage: import_world_load <path>")
|
||||
return true
|
||||
}
|
||||
val pathString = args[0]
|
||||
val path = Paths.get(pathString)
|
||||
if (!path.exists()) {
|
||||
sender.sendMessage("Path '${path}' not found.")
|
||||
}
|
||||
val format = Json.decodeFromStream(WorldLoadFormat.serializer(), path.inputStream())
|
||||
val reassembler = WorldReassembler(plugin, sender.server, format) { message ->
|
||||
sender.sendMessage(message)
|
||||
}
|
||||
reassembler.loadInBackground()
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package gay.pizza.foundation.heimdall.plugin.load
|
||||
|
||||
import gay.pizza.foundation.heimdall.load.WorldLoadFormat
|
||||
import gay.pizza.foundation.heimdall.load.WorldLoadWorld
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.Server
|
||||
import org.bukkit.plugin.Plugin
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
class WorldReassembler(val plugin: Plugin, val server: Server, val format: WorldLoadFormat, val feedback: (String) -> Unit) {
|
||||
fun loadInBackground() {
|
||||
server.scheduler.runTaskAsynchronously(plugin) { ->
|
||||
for (world in server.worlds) {
|
||||
val id = world.uid
|
||||
var load: WorldLoadWorld? = format.worlds[id.toString().lowercase()]
|
||||
if (load == null) {
|
||||
load = format.worlds.values.firstOrNull { it.name == world.name }
|
||||
}
|
||||
|
||||
if (load == null) {
|
||||
feedback("Unable to match world ${world.uid} (${world.name}) to a loadable world, skipping")
|
||||
continue
|
||||
}
|
||||
|
||||
val blocksToMake = mutableListOf<Pair<Location, Material>>()
|
||||
|
||||
for ((x, zBlocks) in load.blocks) {
|
||||
for ((z, yBlocks) in zBlocks) {
|
||||
for ((y, block) in yBlocks) {
|
||||
val material: Material? = Material.matchMaterial(block.type)
|
||||
|
||||
if (material == null) {
|
||||
feedback("Unknown Material '${block.type}' at $x $y $z")
|
||||
continue
|
||||
}
|
||||
|
||||
blocksToMake.add(Location(world, x.toDouble(), y.toDouble(), z.toDouble()) to material)
|
||||
}
|
||||
}
|
||||
}
|
||||
blocksToMake.sortBy { it.first.x }
|
||||
|
||||
feedback("Will place ${blocksToMake.size} blocks in ${world.name}")
|
||||
|
||||
val count = AtomicLong()
|
||||
var ticks = 0L
|
||||
blocksToMake.chunked(1000) { section ->
|
||||
val copy = section.toList()
|
||||
val runnable = object : BukkitRunnable() {
|
||||
override fun run() {
|
||||
for ((location, material) in copy) {
|
||||
val block = world.getBlockAt(location)
|
||||
block.type = material
|
||||
count.incrementAndGet()
|
||||
}
|
||||
feedback("Placed ${count.get()} blocks in ${world.name}")
|
||||
}
|
||||
}
|
||||
runnable.runTaskLater(plugin, ticks)
|
||||
ticks += 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,3 +13,7 @@ commands:
|
||||
description: Export All Chunks
|
||||
usage: /export_all_chunks
|
||||
permission: heimdall.command.export_all_chunks
|
||||
import_world_load:
|
||||
description: Import World Load
|
||||
usage: /import_world_load
|
||||
permission: heimdall.command.import_world_load
|
||||
|
Reference in New Issue
Block a user