diff --git a/foundation-chaos/src/main/kotlin/gay/pizza/foundation/chaos/modules/WorldSwapper.kt b/foundation-chaos/src/main/kotlin/gay/pizza/foundation/chaos/modules/WorldSwapper.kt index b611d40..f8e361f 100644 --- a/foundation-chaos/src/main/kotlin/gay/pizza/foundation/chaos/modules/WorldSwapper.kt +++ b/foundation-chaos/src/main/kotlin/gay/pizza/foundation/chaos/modules/WorldSwapper.kt @@ -1,7 +1,11 @@ package gay.pizza.foundation.chaos.modules import gay.pizza.foundation.chaos.randomPlayer +import org.bukkit.Chunk import org.bukkit.ChunkSnapshot +import org.bukkit.Material +import org.bukkit.block.Block +import org.bukkit.block.data.BlockData import org.bukkit.plugin.Plugin class WorldSwapper(val plugin: Plugin) : ChaosModule { @@ -9,38 +13,91 @@ class WorldSwapper(val plugin: Plugin) : ChaosModule { override fun name(): String = "World Swapper" override fun what(): String = "Swaps the world vertically on activation, and un-swaps it on deactivation." - var snapshot: ChunkSnapshot? = null + var chunkInversions = mutableListOf() override fun activate() { val player = plugin.server.randomPlayer() ?: return - val chunk = player.world.getChunkAt(player.location) - val localSnapshot = chunk.chunkSnapshot + val baseChunk = player.chunk + recordInvert(baseChunk) + player.teleport(player.location.toHighestLocation()) + val chunksToInvert = player.world.loadedChunks.filter { it != baseChunk }.toMutableList() - for (x in 0..15) { - for (z in 0..15) { - val heightRange = (chunk.world.minHeight + 1) until chunk.world.maxHeight - for (y in heightRange) { - val targetBlock = chunk.getBlock(x, y, z) - val inverseY = heightRange.random() - val nextBlock = localSnapshot.getBlockData(x, inverseY, z) - targetBlock.setBlockData(nextBlock, true) - } + println("Inverting ${chunksToInvert.size} chunks...") + fun scheduleOne() { + if (chunksToInvert.isEmpty()) { + return } + + val chunk = chunksToInvert.removeAt(0) + plugin.server.scheduler.runTaskLater(plugin, { -> + recordInvert(chunk) + scheduleOne() + }, 5) } - snapshot = localSnapshot + + scheduleOne() + } + + fun recordInvert(chunk: Chunk) { + chunkInversions.add(invertChunk(chunk)) } override fun deactivate() { - val localSnapshot = snapshot ?: return - val world = plugin.server.getWorld(localSnapshot.worldName) ?: return - val chunk = world.getChunkAt(localSnapshot.x, localSnapshot.z) + fun scheduleOne() { + if (chunkInversions.isEmpty()) { + return + } + val inversion = chunkInversions.removeAt(0) + plugin.server.scheduler.runTaskLater(plugin, { -> + inversion.revert() + scheduleOne() + }, 5) + } + + scheduleOne() + } + + fun invertChunk(chunk: Chunk): ChunkInversion { + val snapshot = chunk.chunkSnapshot for (x in 0..15) { for (z in 0..15) { - val heightRange = chunk.world.minHeight + 1 until chunk.world.maxHeight - for (y in heightRange) { - val originalBlock = localSnapshot.getBlockData(x, y, z) - chunk.getBlock(x, y, z).blockData = originalBlock + var sy = chunk.world.minHeight + var ey = chunk.world.maxHeight + while (sy != ey) { + sy++ + ey-- + val targetBlock = chunk.getBlock(x, sy, z) + val targetBlockData = targetBlock.blockData.clone() + val nextBlock = chunk.getBlock(x, ey, z) + val nextBlockData = nextBlock.blockData.clone() + invertSetBlockData(targetBlock, nextBlockData) + invertSetBlockData(nextBlock, targetBlockData) + } + } + } + return ChunkInversion(plugin, snapshot) + } + + private fun invertSetBlockData(block: Block, data: BlockData) { + block.setBlockData(data, false) + } + + class ChunkInversion( + val plugin: Plugin, + val snapshot: ChunkSnapshot + ) { + fun revert() { + val world = plugin.server.getWorld(snapshot.worldName) ?: return + val chunk = world.getChunkAt(snapshot.x, snapshot.z) + + for (x in 0..15) { + for (z in 0..15) { + val heightRange = chunk.world.minHeight + 1 until chunk.world.maxHeight + for (y in heightRange) { + val originalBlock = snapshot.getBlockData(x, y, z) + chunk.getBlock(x, y, z).blockData = originalBlock + } } } }