Bug fixes, config file, more commands
- fixed chunk skips skipping not-generated chunks - changed command structure to /chunkmaster <operation> - added config options - updated readmepull/4/head v0.9-beta
parent
f726f3e15c
commit
52ba24390f
@ -1,17 +1,50 @@
|
||||
# chunkmaster
|
||||
|
||||
This plugin can be used to pre-generate the region of a world around the spawn chunk. The plugin provides the commands
|
||||
|
||||
- `/generate [world] [stopAt]` - Pre-generates chunks in the current world until the world border or the stopAt chunk count is reached.
|
||||
- `/listgentasks` - Lists all running generation tasks (and their ids)
|
||||
- `/removegentask [taskId]` - Removes a generation task (stops it permanently)
|
||||
|
||||
This plugin can be used to pre-generate the region of a world around the spawn chunk.
|
||||
The generation automatically pauses when a player joins the server (assuming the server was empty before)
|
||||
and resumes when the server is empty again. The generation also auto-resumes after a server
|
||||
restart. The plugin tracks the ticks per second and pauses the generation when the tps
|
||||
is lower than 2.
|
||||
|
||||
## Future Features
|
||||
## Commands
|
||||
|
||||
All features can be accessed with the command `/chunkmaster` or the aliases `/chm`, `chunkm`, `cmaster`.
|
||||
|
||||
- `/chunkmaster generate [world] [chunk count]` Starts the generation until the specified chunk count or the world border is reached.
|
||||
- `/chunkmaster list` Lists all running generation tasks
|
||||
- `/chunkmaster cancel <Task id>` Cancels the generation task with the specified id (if it is running).
|
||||
- `/chunkmaster pause` Pauses all generation tasks until the resume command is executed.
|
||||
- `/chunkmaster resume` Resumes all paused generation tasks.
|
||||
- `/chunkmaster reload` Reloads the configuration file.
|
||||
|
||||
## Config
|
||||
|
||||
```yaml
|
||||
generation:
|
||||
|
||||
# The period (in ticks) in which a generation step is run.
|
||||
# Higher values mean less performance impact but slower generation.
|
||||
# The value should be a positive integer.
|
||||
period: 2
|
||||
|
||||
# The number of already generated chunks that will be skipped for each step.
|
||||
# Notice that these still have a performance impact because the server needs to check
|
||||
# if the chunk is generated.
|
||||
# Higher values mean faster generation but greater performance impact.
|
||||
# The value should be a positive integer.
|
||||
chunks-skips-per-step: 5
|
||||
|
||||
# The maximum milliseconds per tick the server is allowed to have
|
||||
# during the cunk generation process.
|
||||
# If the mspt is greather than this, the chunk generation task pauses.
|
||||
# The value should be a positive integer greater than 50.
|
||||
mspt-pause-threshold: 500
|
||||
|
||||
- pause generation tasks until restarted by command
|
||||
- configure the tps pause limit
|
||||
# If the chunk generation process should pause on player join.
|
||||
# Notice that playing on a server that constantly generates chunks can be
|
||||
# very laggy and can cause it to crash.
|
||||
# You could configure the values above so that the performance impact of the generation
|
||||
# process is minimal.
|
||||
# The value should be a boolean <true/false>
|
||||
pause-on-join: true
|
||||
```
|
@ -0,0 +1,28 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.md_5.bungee.api.ChatColor
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import net.trivernis.chunkmaster.lib.Subcommand
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CmdCancel(private val chunkmaster: Chunkmaster): Subcommand {
|
||||
override val name = "cancel"
|
||||
|
||||
override fun execute(sender: CommandSender, args: List<String>): Boolean {
|
||||
return if (args.isNotEmpty() && args[0].toIntOrNull() != null) {
|
||||
if (chunkmaster.generationManager.removeTask(args[0].toInt())) {
|
||||
sender.sendMessage("Task ${args[0]} canceled.")
|
||||
true
|
||||
} else {
|
||||
sender.spigot().sendMessage(*ComponentBuilder("Task ${args[0]} not found!")
|
||||
.color(ChatColor.RED).create())
|
||||
false
|
||||
}
|
||||
} else {
|
||||
sender.spigot().sendMessage(*ComponentBuilder("You need to provide a task id to cancel.")
|
||||
.color(ChatColor.RED).create())
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.md_5.bungee.api.ChatColor
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import net.trivernis.chunkmaster.lib.Subcommand
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand {
|
||||
override val name = "generate"
|
||||
|
||||
override fun execute(sender: CommandSender, args: List<String>): Boolean {
|
||||
var worldName = ""
|
||||
var stopAfter = -1
|
||||
if (sender is Player) {
|
||||
if (args.isNotEmpty()) {
|
||||
if (args[0].toIntOrNull() != null) {
|
||||
stopAfter = args[0].toInt()
|
||||
} else {
|
||||
worldName = args[0]
|
||||
}
|
||||
if (args.size > 1 && args[1].toIntOrNull() != null) {
|
||||
stopAfter = args[1].toInt()
|
||||
}
|
||||
} else {
|
||||
worldName = sender.world.name
|
||||
}
|
||||
} else {
|
||||
if (args.isNotEmpty()) {
|
||||
worldName = args[0]
|
||||
if (args.size > 1 && args[1].toIntOrNull() != null) {
|
||||
stopAfter = args[1].toInt()
|
||||
}
|
||||
} else {
|
||||
sender.spigot().sendMessage(
|
||||
*ComponentBuilder("You need to provide a world name").color(ChatColor.RED).create())
|
||||
return false
|
||||
}
|
||||
}
|
||||
val world = chunkmaster.server.getWorld(worldName)
|
||||
return if (world != null) {
|
||||
chunkmaster.generationManager.addTask(world, stopAfter)
|
||||
sender.spigot().sendMessage(*ComponentBuilder("Generation task for world ").color(ChatColor.BLUE)
|
||||
.append(worldName).color(ChatColor.GREEN).append(" until ").color(ChatColor.BLUE)
|
||||
.append(if (stopAfter > 0) "$stopAfter chunks" else "WorldBorder").color(ChatColor.GREEN)
|
||||
.append(" successfully created").color(ChatColor.BLUE).create())
|
||||
true
|
||||
} else {
|
||||
sender.spigot().sendMessage(*ComponentBuilder("World ").color(ChatColor.RED)
|
||||
.append(worldName).color(ChatColor.GREEN).append(" not found!").color(ChatColor.RED).create())
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.md_5.bungee.api.ChatColor
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import net.trivernis.chunkmaster.lib.Subcommand
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CmdList(private val chunkmaster: Chunkmaster): Subcommand {
|
||||
override val name = "list"
|
||||
|
||||
override fun execute(sender: CommandSender, args: List<String>): Boolean {
|
||||
val runningTasks = chunkmaster.generationManager.tasks
|
||||
if (runningTasks.isEmpty()) {
|
||||
sender.spigot().sendMessage(*ComponentBuilder("There are no running generation tasks.")
|
||||
.color(ChatColor.BLUE).create())
|
||||
} else {
|
||||
val response = ComponentBuilder("Currently running generation tasks:").color(ChatColor.WHITE)
|
||||
for (task in runningTasks) {
|
||||
response.append("\n - #${task.id}: ${task.generationTask.world.name}, Progress ${task.generationTask.count}")
|
||||
.color(ChatColor.BLUE)
|
||||
}
|
||||
sender.spigot().sendMessage(*response.create())
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.md_5.bungee.api.ChatColor
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import net.trivernis.chunkmaster.lib.Subcommand
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CmdPause(private val chunkmaster: Chunkmaster) : Subcommand {
|
||||
override val name: String = "pause"
|
||||
|
||||
override fun execute(sender: CommandSender, args: List<String>): Boolean {
|
||||
return if (!chunkmaster.generationManager.paused) {
|
||||
chunkmaster.generationManager.pauseAll()
|
||||
sender.spigot().sendMessage(
|
||||
*ComponentBuilder("Paused all generation tasks.")
|
||||
.color(ChatColor.BLUE).create()
|
||||
)
|
||||
true
|
||||
} else {
|
||||
sender.spigot().sendMessage(
|
||||
*ComponentBuilder("The generation process is already paused.").color(ChatColor.RED).create()
|
||||
)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.md_5.bungee.api.ChatColor
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import net.trivernis.chunkmaster.lib.Subcommand
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CmdResume(private val chunkmaster: Chunkmaster): Subcommand {
|
||||
override val name = "resume"
|
||||
|
||||
override fun execute(sender: CommandSender, args: List<String>): Boolean {
|
||||
return if (chunkmaster.generationManager.paused) {
|
||||
chunkmaster.generationManager.resumeAll()
|
||||
sender.spigot().sendMessage(
|
||||
*ComponentBuilder("Resumed all generation tasks.").color(ChatColor.BLUE).create())
|
||||
true
|
||||
} else {
|
||||
sender.spigot().sendMessage(
|
||||
*ComponentBuilder("There are no paused generation tasks.").color(ChatColor.RED).create())
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.md_5.bungee.api.ChatColor
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import net.trivernis.chunkmaster.lib.Subcommand
|
||||
import org.bukkit.Server
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.command.TabCompleter
|
||||
|
||||
class CommandChunkmaster(private val chunkmaster: Chunkmaster, private val server: Server): CommandExecutor,
|
||||
TabCompleter {
|
||||
private val commands = HashMap<String, Subcommand>()
|
||||
|
||||
init {
|
||||
registerCommands()
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab complete for commands
|
||||
*/
|
||||
override fun onTabComplete(sender: CommandSender, command: Command, alias: String, args: Array<out String>):
|
||||
MutableList<String> {
|
||||
return commands.keys.filter { it.indexOf(args[0]) == 0 }.toMutableList()
|
||||
}
|
||||
|
||||
/**
|
||||
* /chunkmaster command to handle all commands
|
||||
*/
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
if (args.isNotEmpty()) {
|
||||
when (args[0]) {
|
||||
"reload" -> {
|
||||
chunkmaster.reloadConfig()
|
||||
sender.sendMessage("Configuration file reloaded.")
|
||||
}
|
||||
else -> {
|
||||
if (sender.hasPermission("chunkmaster.${args[0]}")) {
|
||||
return if (commands.containsKey(args[0])) {
|
||||
commands[args[0]]!!.execute(sender, args.slice(1 until args.size))
|
||||
} else {
|
||||
sender.spigot().sendMessage(*ComponentBuilder("Subcommand ").color(ChatColor.RED)
|
||||
.append(args[0]).color(ChatColor.GREEN).append(" not found").color(ChatColor.RED).create())
|
||||
false
|
||||
}
|
||||
} else {
|
||||
sender.spigot().sendMessage(*ComponentBuilder("You do not have permission!")
|
||||
.color(ChatColor.RED).create())
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun registerCommands() {
|
||||
val cmdGenerate = CmdGenerate(chunkmaster)
|
||||
commands[cmdGenerate.name] = cmdGenerate
|
||||
|
||||
val cmdPause = CmdPause(chunkmaster)
|
||||
commands[cmdPause.name] = cmdPause
|
||||
|
||||
val cmdResume = CmdResume(chunkmaster)
|
||||
commands[cmdResume.name] = cmdResume
|
||||
|
||||
val cmdCancel = CmdCancel(chunkmaster)
|
||||
commands[cmdCancel.name] = cmdCancel
|
||||
|
||||
val cmdList = CmdList(chunkmaster)
|
||||
commands[cmdList.name] = cmdList
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class CommandGenerate(private val chunkmaster: Chunkmaster): CommandExecutor {
|
||||
/**
|
||||
* Start world generation task on commmand
|
||||
*/
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
if (sender is Player) {
|
||||
return if (command.testPermission(sender)) {
|
||||
var stopAfter = -1
|
||||
|
||||
if (args.isNotEmpty() && args[0].toIntOrNull() != null) {
|
||||
stopAfter = args[0].toInt()
|
||||
}
|
||||
chunkmaster.generationManager.addTask(sender.world, stopAfter)
|
||||
sender.sendMessage("Added generation task for world \"${sender.world.name}\"" +
|
||||
"Stopping after $stopAfter chunks (-1 for world border).")
|
||||
true
|
||||
} else {
|
||||
sender.sendMessage("You do not have permission.")
|
||||
true
|
||||
}
|
||||
} else {
|
||||
return if (args.size >= 1) {
|
||||
val world = sender.server.getWorld(args[0])
|
||||
if (world != null) {
|
||||
var stopAfter = -1
|
||||
|
||||
if (args.size >=2 && args[1].toIntOrNull() != null) {
|
||||
stopAfter = args[1].toInt()
|
||||
}
|
||||
chunkmaster.generationManager.addTask(world, stopAfter)
|
||||
|
||||
sender.sendMessage("Added generation task for world \"${world.name}\"" +
|
||||
"Stopping after $stopAfter chunks (-1 for world border).")
|
||||
true
|
||||
} else {
|
||||
sender.sendMessage("World \"${args[0]}\" not found")
|
||||
false
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage("You need to specify a world")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.md_5.bungee.api.ChatColor
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CommandListGenTasks(private val chunkmaster: Chunkmaster): CommandExecutor {
|
||||
/**
|
||||
* Responds with a list of running generation tasks.
|
||||
*/
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
val runningTasks = chunkmaster.generationManager.tasks
|
||||
val response = ComponentBuilder("Currently running generation tasks").color(ChatColor.BLUE)
|
||||
for (task in runningTasks) {
|
||||
response.append("\n - #${task.id}: ${task.generationTask.world.name}, Progress ${task.generationTask.count}")
|
||||
}
|
||||
response.color(ChatColor.GREEN)
|
||||
sender.spigot().sendMessage(*response.create())
|
||||
return true
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package net.trivernis.chunkmaster.commands
|
||||
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import org.bukkit.command.Command
|
||||
import org.bukkit.command.CommandExecutor
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CommandRemoveGenTask(private val chunkmaster: Chunkmaster): CommandExecutor {
|
||||
/**
|
||||
* Stops the specified generation task and removes it from the autostart.
|
||||
*/
|
||||
override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean {
|
||||
return if (command.testPermission(sender) && args.size == 1) {
|
||||
chunkmaster.generationManager.removeTask(args[0].toInt())
|
||||
sender.sendMessage("Task ${args[1].toInt()} canceled.")
|
||||
true
|
||||
} else {
|
||||
sender.sendMessage("Invalid argument.")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package net.trivernis.chunkmaster.lib
|
||||
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
interface Subcommand {
|
||||
val name: String
|
||||
fun execute(sender: CommandSender, args: List<String>): Boolean
|
||||
}
|
Loading…
Reference in New Issue