diff --git a/build.gradle.kts b/build.gradle.kts index cafe112..711f991 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,6 +21,7 @@ repositories { dependencies { implementation(kotlin("stdlib-jdk8")) implementation(kotlin("reflect")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7") implementation("commons-codec:commons-codec:1.14") compileOnly("com.comphenix.protocol", "ProtocolLib", "4.5.0") compileOnly("org.spigotmc", "spigot-api", "1.15.2-R0.1-SNAPSHOT") diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/CommandManager.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/CommandManager.kt index 61f65c9..accaa4b 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/CommandManager.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/CommandManager.kt @@ -5,6 +5,7 @@ import de.moritzruth.spigot_ttt.game.InfoCommand import de.moritzruth.spigot_ttt.game.ReviveCommand import de.moritzruth.spigot_ttt.game.StartCommand import de.moritzruth.spigot_ttt.game.items.AddItemSpawnCommand +import de.moritzruth.spigot_ttt.worlds.WorldCommand object CommandManager { fun initializeCommands() { @@ -15,5 +16,6 @@ object CommandManager { ResourcepackCommand() ReloadTTTConfigCommand() InfoCommand() + WorldCommand() } } diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/TTTPlugin.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/TTTPlugin.kt index afbd442..645937e 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/TTTPlugin.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/TTTPlugin.kt @@ -1,6 +1,7 @@ package de.moritzruth.spigot_ttt import de.moritzruth.spigot_ttt.game.GameManager +import de.moritzruth.spigot_ttt.worlds.WorldManager import org.bukkit.ChatColor import org.bukkit.plugin.java.JavaPlugin @@ -12,6 +13,8 @@ class TTTPlugin: JavaPlugin() { override fun onEnable() { saveDefaultConfig() + WorldManager.removeNeglectedWorlds() + CommandManager.initializeCommands() GameManager.initialize() diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/utils/ConfigurationFile.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/utils/ConfigurationFile.kt index edadbb6..3b73890 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/utils/ConfigurationFile.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/utils/ConfigurationFile.kt @@ -2,18 +2,18 @@ package de.moritzruth.spigot_ttt.utils import de.moritzruth.spigot_ttt.plugin import org.bukkit.configuration.file.YamlConfiguration -import java.nio.file.Paths +import java.io.File -class ConfigurationFile(name: String): YamlConfiguration() { - private val filePath = Paths.get(plugin.dataFolder.absolutePath, "$name.yml").toAbsolutePath().toString() +class ConfigurationFile(private val file: File): YamlConfiguration() { + constructor(name: String) : this(plugin.dataFolder.resolve("$name.yml")) init { try { - load(filePath) + load(file) } catch (e: Exception) {} } fun save() { - save(filePath) + save(file) } } diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/utils/CreateTabCompleter.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/utils/CreateTabCompleter.kt index e30ac2c..462b464 100644 --- a/src/main/kotlin/de/moritzruth/spigot_ttt/utils/CreateTabCompleter.kt +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/utils/CreateTabCompleter.kt @@ -4,12 +4,15 @@ import org.bukkit.command.CommandSender import org.bukkit.command.TabCompleter fun createTabCompleter(fn: (sender: CommandSender, index: Int) -> List?) = + createTabCompleter { sender, index, _ -> fn(sender, index) } + +fun createTabCompleter(fn: (sender: CommandSender, index: Int, args: List) -> List?) = TabCompleter { sender, _, _, args -> val index = args.count() val completions = if (index == 0) emptyList() - else fn(sender, index) ?: emptyList() + else fn(sender, index, args.toList()) ?: emptyList() completions.filter { it.startsWith(args.last(), true) } } diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/TTTWorld.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/TTTWorld.kt new file mode 100644 index 0000000..3f2aea5 --- /dev/null +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/TTTWorld.kt @@ -0,0 +1,73 @@ +package de.moritzruth.spigot_ttt.worlds + +import de.moritzruth.spigot_ttt.plugin +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import org.bukkit.WorldCreator + +class TTTWorld(val sourceWorld: WorldManager.SourceWorld) { + var state: State = State.NOT_COPIED; private set + enum class State { + NOT_COPIED, + COPYING, + COPIED, + LOADED, + UNLOADING + } + + val id = WorldManager.tttWorlds.count() + val actualWorldName = "${WORLD_PREFIX}${id}" + private val worldDir = plugin.server.worldContainer.resolve("./$actualWorldName") + + init { + WorldManager.tttWorlds.add(this) + } + + suspend fun copy() { + if (state != State.NOT_COPIED) throw IllegalStateException("The world was already copied") + state = State.COPYING + + coroutineScope { + launch(Dispatchers.IO) { + sourceWorld.dir.copyRecursively(worldDir) + } + } + } + + fun load() { + if (state != State.COPIED) throw IllegalStateException("The world was not copied yet or already loaded") + plugin.server.createWorld(WorldCreator.name(actualWorldName)) + } + + suspend fun save() { + if (state != State.LOADED) throw IllegalStateException("The world must be loaded") + + coroutineScope { + launch(Dispatchers.IO) { + val tempWorldDir = WorldManager.worldsDir.resolve("./${sourceWorld.name}_$id") + worldDir.copyRecursively(tempWorldDir) + sourceWorld.dir.deleteRecursively() + tempWorldDir.renameTo(sourceWorld.dir) + state = State.NOT_COPIED + } + } + } + + suspend fun unloadAndRemove() { + if (state != State.LOADED) throw IllegalStateException("The world must be loaded") + state = State.UNLOADING + plugin.server.unloadWorld(actualWorldName, false) + + coroutineScope { + launch(Dispatchers.IO) { + worldDir.deleteRecursively() + state = State.NOT_COPIED + } + } + } + + companion object { + const val WORLD_PREFIX = "tempworld_" + } +} diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/WorldCommand.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/WorldCommand.kt new file mode 100644 index 0000000..9851f79 --- /dev/null +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/WorldCommand.kt @@ -0,0 +1,29 @@ +package de.moritzruth.spigot_ttt.worlds + +import de.moritzruth.spigot_ttt.plugin +import de.moritzruth.spigot_ttt.utils.createTabCompleter +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender + +class WorldCommand: CommandExecutor { + init { + val command = plugin.getCommand("world")!! + command.setExecutor(this) + command.tabCompleter = createTabCompleter { _, index, args -> + return@createTabCompleter when(index) { + 0 -> listOf("load", "save", "join", "list") + 1 -> when(args[0].toLowerCase()) { + "load" -> WorldManager.sourceWorlds.map { it.name } + "save", "join" -> WorldManager.tttWorlds.map { it.id.toString() } + else -> null + } + else -> null + } + } + } + + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { + TODO("Not yet implemented") + } +} diff --git a/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/WorldManager.kt b/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/WorldManager.kt new file mode 100644 index 0000000..75fac20 --- /dev/null +++ b/src/main/kotlin/de/moritzruth/spigot_ttt/worlds/WorldManager.kt @@ -0,0 +1,24 @@ +package de.moritzruth.spigot_ttt.worlds + +import de.moritzruth.spigot_ttt.plugin +import de.moritzruth.spigot_ttt.utils.ConfigurationFile +import java.io.File + +object WorldManager { + data class SourceWorld(val dir: File) { + val name: String = dir.name + val config = ConfigurationFile(dir.resolve("config.yml")) + } + + val worldsDir = plugin.dataFolder.resolve("./worlds").also { it.mkdirs() } + val sourceWorlds = worldsDir.listFiles(File::isDirectory)!!.map { SourceWorld(it) } + + val tttWorlds = mutableSetOf() + + fun removeNeglectedWorlds() { + plugin.server.worldContainer.listFiles { file -> + file.isDirectory && file.name.startsWith(TTTWorld.WORLD_PREFIX) && + tttWorlds.find { it.actualWorldName == file.name } != null + }!!.forEach { it.deleteRecursively() } + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9b2b5f3..0d53983 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -23,12 +23,12 @@ commands: description: Add an item spawn revive: - usage: /revive [player] ['here'] + usage: /revive [Player] ['here'] permission: ttt.revive description: Revive yourself or another player at the world spawn or at your location info: - usage: /info [player] + usage: /info [Player] permission: ttt.info description: Show information about all players or a specific player @@ -45,3 +45,8 @@ commands: permission: ttt.reload aliases: - rt + + world: + usage: /world load OR /world <'join'|'save'> OR /world list + description: Perform world operations + permission: ttt.world