Merge pull request #20 from Trivernis/develop

Release Beta 0.14
pull/23/head
Trivernis 5 years ago committed by GitHub
commit 407edff2df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,6 +2,7 @@ package net.trivernis.chunkmaster
import io.papermc.lib.PaperLib import io.papermc.lib.PaperLib
import net.trivernis.chunkmaster.commands.* import net.trivernis.chunkmaster.commands.*
import net.trivernis.chunkmaster.lib.LanguageManager
import net.trivernis.chunkmaster.lib.generation.GenerationManager import net.trivernis.chunkmaster.lib.generation.GenerationManager
import net.trivernis.chunkmaster.lib.SqliteManager import net.trivernis.chunkmaster.lib.SqliteManager
import org.bstats.bukkit.Metrics import org.bstats.bukkit.Metrics
@ -12,6 +13,7 @@ import java.lang.Exception
class Chunkmaster: JavaPlugin() { class Chunkmaster: JavaPlugin() {
lateinit var sqliteManager: SqliteManager lateinit var sqliteManager: SqliteManager
lateinit var generationManager: GenerationManager lateinit var generationManager: GenerationManager
lateinit var langManager: LanguageManager
private lateinit var tpsTask: BukkitTask private lateinit var tpsTask: BukkitTask
var mspt = 20 // keep track of the milliseconds per tick var mspt = 20 // keep track of the milliseconds per tick
private set private set
@ -25,6 +27,8 @@ class Chunkmaster: JavaPlugin() {
val metrics = Metrics(this) val metrics = Metrics(this)
langManager = LanguageManager(this)
langManager.loadProperties()
initDatabase() initDatabase()
generationManager = GenerationManager(this, server) generationManager = GenerationManager(this, server)
generationManager.init() generationManager.init()
@ -52,7 +56,7 @@ class Chunkmaster: JavaPlugin() {
* Stop all tasks and close database connection on disable * Stop all tasks and close database connection on disable
*/ */
override fun onDisable() { override fun onDisable() {
logger.info("Stopping all generation tasks...") logger.info(langManager.getLocalized("STOPPING_ALL_TASKS"))
generationManager.stopAll() generationManager.stopAll()
} }
@ -70,6 +74,7 @@ class Chunkmaster: JavaPlugin() {
config.addDefault("generation.max-loaded-chunks", 10) config.addDefault("generation.max-loaded-chunks", 10)
config.addDefault("generation.ignore-worldborder", false) config.addDefault("generation.ignore-worldborder", false)
config.addDefault("database.filename", "chunkmaster.db") config.addDefault("database.filename", "chunkmaster.db")
config.addDefault("language", "en")
config.options().copyDefaults(true) config.options().copyDefaults(true)
saveConfig() saveConfig()
} }
@ -78,13 +83,13 @@ class Chunkmaster: JavaPlugin() {
* Initializes the database * Initializes the database
*/ */
private fun initDatabase() { private fun initDatabase() {
logger.info("Initializing Database...") logger.info(langManager.getLocalized("DB_INIT"))
try { try {
this.sqliteManager = SqliteManager( this) this.sqliteManager = SqliteManager( this)
sqliteManager.init() sqliteManager.init()
logger.info("Database fully initialized.") logger.info(langManager.getLocalized("DB_INIT_FINISHED"))
} catch(e: Exception) { } catch(e: Exception) {
logger.warning("Failed to init database: ${e.message}") logger.warning(langManager.getLocalized("DB_INIT_EROR", e.message!!))
} }
} }
} }

@ -32,16 +32,14 @@ class CmdCancel(private val chunkmaster: Chunkmaster): Subcommand {
override fun execute(sender: CommandSender, args: List<String>): Boolean { override fun execute(sender: CommandSender, args: List<String>): Boolean {
return if (args.isNotEmpty() && args[0].toIntOrNull() != null) { return if (args.isNotEmpty() && args[0].toIntOrNull() != null) {
if (chunkmaster.generationManager.removeTask(args[0].toInt())) { if (chunkmaster.generationManager.removeTask(args[0].toInt())) {
sender.sendMessage("Task ${args[0]} canceled.") sender.sendMessage(chunkmaster.langManager.getLocalized("TASK_CANCELED", args[0]))
true true
} else { } else {
sender.spigot().sendMessage(*ComponentBuilder("Task ${args[0]} not found!") sender.sendMessage(chunkmaster.langManager.getLocalized("TASK_NOT_FOUND", args[0]))
.color(ChatColor.RED).create())
false false
} }
} else { } else {
sender.spigot().sendMessage(*ComponentBuilder("You need to provide a task id to cancel.") sender.sendMessage(chunkmaster.langManager.getLocalized("TASK_ID_REQUIRED"));
.color(ChatColor.RED).create())
false false
} }
} }

@ -1,7 +1,5 @@
package net.trivernis.chunkmaster.commands 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.Chunkmaster
import net.trivernis.chunkmaster.lib.Subcommand import net.trivernis.chunkmaster.lib.Subcommand
import org.bukkit.command.Command import org.bukkit.command.Command
@ -79,8 +77,7 @@ class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand {
stopAfter = getStopAfter(stopAfter, args[2]) stopAfter = getStopAfter(stopAfter, args[2])
} }
} else { } else {
sender.spigot().sendMessage( sender.sendMessage(chunkmaster.langManager.getLocalized("WORLD_NAME_REQUIRED"))
*ComponentBuilder("You need to provide a world name").color(ChatColor.RED).create())
return false return false
} }
} }
@ -116,17 +113,14 @@ class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand {
val allTasks = chunkmaster.generationManager.allTasks val allTasks = chunkmaster.generationManager.allTasks
return if (world != null && (allTasks.find { it.generationTask.world == world }) == null) { return if (world != null && (allTasks.find { it.generationTask.world == world }) == null) {
chunkmaster.generationManager.addTask(world, stopAfter) chunkmaster.generationManager.addTask(world, stopAfter)
sender.spigot().sendMessage(*ComponentBuilder("Generation task for world ").color(ChatColor.BLUE) sender.sendMessage(chunkmaster.langManager
.append(worldName).color(ChatColor.GREEN).append(" until ").color(ChatColor.BLUE) .getLocalized("TASK_CREATION_SUCCESS", worldName, if (stopAfter > 0) "$stopAfter chunks" else "WorldBorder"))
.append(if (stopAfter > 0) "$stopAfter chunks" else "WorldBorder").color(ChatColor.GREEN)
.append(" successfully created").color(ChatColor.BLUE).create())
true true
} else if (world == null){ } else if (world == null){
sender.spigot().sendMessage(*ComponentBuilder("World ").color(ChatColor.RED) sender.sendMessage(chunkmaster.langManager.getLocalized("WORLD_NOT_FOUND", worldName));
.append(worldName).color(ChatColor.GREEN).append(" not found!").color(ChatColor.RED).create())
false false
} else { } else {
sender.spigot().sendMessage(*ComponentBuilder("Task already exists!").color(ChatColor.RED).create()) sender.sendMessage(chunkmaster.langManager.getLocalized("TASK_ALREADY_EXISTS", worldName))
return false return false
} }
} }

@ -4,6 +4,7 @@ import net.md_5.bungee.api.ChatColor
import net.md_5.bungee.api.chat.ComponentBuilder import net.md_5.bungee.api.chat.ComponentBuilder
import net.trivernis.chunkmaster.Chunkmaster import net.trivernis.chunkmaster.Chunkmaster
import net.trivernis.chunkmaster.lib.Subcommand import net.trivernis.chunkmaster.lib.Subcommand
import net.trivernis.chunkmaster.lib.generation.TaskEntry
import org.bukkit.command.Command import org.bukkit.command.Command
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
@ -27,37 +28,33 @@ class CmdList(private val chunkmaster: Chunkmaster): Subcommand {
val pausedTasks = chunkmaster.generationManager.pausedTasks val pausedTasks = chunkmaster.generationManager.pausedTasks
if (runningTasks.isEmpty() && pausedTasks.isEmpty()) { if (runningTasks.isEmpty() && pausedTasks.isEmpty()) {
sender.spigot().sendMessage(*ComponentBuilder("There are no generation tasks.") sender.sendMessage(chunkmaster.langManager.getLocalized("NO_GENERATION_TASKS"))
.color(ChatColor.BLUE).create())
} else if (runningTasks.isEmpty()) { } else if (runningTasks.isEmpty()) {
val response = ComponentBuilder("Currently paused generation tasks:").color(ChatColor.WHITE).bold(true) var response = chunkmaster.langManager.getLocalized("PAUSED_TASKS_HEADER")
for (taskEntry in pausedTasks) { for (taskEntry in pausedTasks) {
val genTask = taskEntry.generationTask response += getGenerationEntry(taskEntry)
response.append("\n - ").color(ChatColor.WHITE).bold(false)
response.append("#${taskEntry.id}").color(ChatColor.BLUE).append(" - ").color(ChatColor.WHITE)
response.append(genTask.world.name).color(ChatColor.GREEN).append(" - Progress: ").color(ChatColor.WHITE)
response.append("${genTask.count} chunks").color(ChatColor.BLUE)
if (genTask.stopAfter > 0) {
response.append(" (${(genTask.count.toDouble()/genTask.stopAfter.toDouble())*100}%).")
}
} }
sender.spigot().sendMessage(*response.create()) sender.sendMessage(response)
} else { } else {
val response = ComponentBuilder("Currently running generation tasks:").color(ChatColor.WHITE).bold(true) var response = chunkmaster.langManager.getLocalized("RUNNING_TASKS_HEADER")
for (task in runningTasks) { for (task in runningTasks) {
val genTask = task.generationTask response += getGenerationEntry(task)
response.append("\n - ").color(ChatColor.WHITE).bold(false)
.append("#${task.id}").color(ChatColor.BLUE).append(" - ").color(ChatColor.WHITE)
.append(genTask.world.name).color(ChatColor.GREEN).append(" - Progress: ").color(ChatColor.WHITE)
.append("${genTask.count} chunks").color(ChatColor.BLUE)
if (genTask.stopAfter > 0) {
response.append(" (${(genTask.count.toDouble()/genTask.stopAfter.toDouble())*100}%).")
}
} }
sender.spigot().sendMessage(*response.create()) sender.sendMessage(response)
} }
return true return true
} }
/**
* Returns the report string for one generation task
*/
private fun getGenerationEntry(task: TaskEntry): String {
val genTask = task.generationTask
val percentage = if (genTask.stopAfter > 0)
" (%.1f".format((genTask.count.toDouble()/genTask.stopAfter.toDouble())*100) + "%)."
else
""
return "\n" + chunkmaster.langManager.getLocalized("TASKS_ENTRY",
task.id, genTask.world.name, genTask.count, percentage)
}
} }

@ -22,15 +22,10 @@ class CmdPause(private val chunkmaster: Chunkmaster) : Subcommand {
override fun execute(sender: CommandSender, args: List<String>): Boolean { override fun execute(sender: CommandSender, args: List<String>): Boolean {
return if (!chunkmaster.generationManager.paused) { return if (!chunkmaster.generationManager.paused) {
chunkmaster.generationManager.pauseAll() chunkmaster.generationManager.pauseAll()
sender.spigot().sendMessage( sender.sendMessage(chunkmaster.langManager.getLocalized("PAUSE_SUCCESS"))
*ComponentBuilder("Paused all generation tasks.")
.color(ChatColor.BLUE).create()
)
true true
} else { } else {
sender.spigot().sendMessage( sender.sendMessage(chunkmaster.langManager.getLocalized("ALREADY_PAUSED"))
*ComponentBuilder("The generation process is already paused.").color(ChatColor.RED).create()
)
false false
} }
} }

@ -23,12 +23,11 @@ class CmdReload(private val chunkmaster: Chunkmaster): Subcommand {
* Reload command to reload the config and restart the tasks. * Reload command to reload the config and restart the tasks.
*/ */
override fun execute(sender: CommandSender, args: List<String>): Boolean { override fun execute(sender: CommandSender, args: List<String>): Boolean {
sender.spigot().sendMessage(*ComponentBuilder("Reloading config and restarting tasks...") sender.sendMessage(chunkmaster.langManager.getLocalized("CONFIG_RELOADING"))
.color(ChatColor.YELLOW).create())
chunkmaster.generationManager.stopAll() chunkmaster.generationManager.stopAll()
chunkmaster.reloadConfig() chunkmaster.reloadConfig()
chunkmaster.generationManager.startAll() chunkmaster.generationManager.startAll()
sender.spigot().sendMessage(*ComponentBuilder("Config reload complete!").color(ChatColor.GREEN).create()) sender.sendMessage(chunkmaster.langManager.getLocalized("CONFIG_RELOADED"))
return true return true
} }
} }

@ -22,12 +22,10 @@ class CmdResume(private val chunkmaster: Chunkmaster): Subcommand {
override fun execute(sender: CommandSender, args: List<String>): Boolean { override fun execute(sender: CommandSender, args: List<String>): Boolean {
return if (chunkmaster.generationManager.paused) { return if (chunkmaster.generationManager.paused) {
chunkmaster.generationManager.resumeAll() chunkmaster.generationManager.resumeAll()
sender.spigot().sendMessage( sender.sendMessage(chunkmaster.langManager.getLocalized("RESUME_SUCCESS"))
*ComponentBuilder("Resumed all generation tasks.").color(ChatColor.BLUE).create())
true true
} else { } else {
sender.spigot().sendMessage( sender.sendMessage(chunkmaster.langManager.getLocalized("NOT_PAUSED"))
*ComponentBuilder("There are no paused generation tasks.").color(ChatColor.RED).create())
false false
} }
} }

@ -3,13 +3,14 @@ package net.trivernis.chunkmaster.commands
import io.papermc.lib.PaperLib import io.papermc.lib.PaperLib
import net.md_5.bungee.api.ChatColor import net.md_5.bungee.api.ChatColor
import net.md_5.bungee.api.chat.ComponentBuilder import net.md_5.bungee.api.chat.ComponentBuilder
import net.trivernis.chunkmaster.Chunkmaster
import net.trivernis.chunkmaster.lib.Subcommand import net.trivernis.chunkmaster.lib.Subcommand
import org.bukkit.Material import org.bukkit.Material
import org.bukkit.command.Command import org.bukkit.command.Command
import org.bukkit.command.CommandSender import org.bukkit.command.CommandSender
import org.bukkit.entity.Player import org.bukkit.entity.Player
class CmdTpChunk: Subcommand { class CmdTpChunk(private val chunkmaster: Chunkmaster): Subcommand {
override val name = "tpchunk" override val name = "tpchunk"
override fun onTabComplete( override fun onTabComplete(
@ -37,15 +38,13 @@ class CmdTpChunk: Subcommand {
} else { } else {
sender.teleport(location) sender.teleport(location)
} }
sender.spigot().sendMessage(*ComponentBuilder("You have been teleportet to chunk") sender.sendMessage(chunkmaster.langManager.getLocalized("TELEPORTED", args[0], args[1]))
.color(ChatColor.YELLOW).append("${args[0]}, ${args[1]}").color(ChatColor.BLUE).create())
return true return true
} else { } else {
return false return false
} }
} else { } else {
sender.spigot().sendMessage(*ComponentBuilder("This command can only be executed by a player!") sender.sendMessage(chunkmaster.langManager.getLocalized("TP_ONLY_PLAYER"))
.color(ChatColor.RED).create())
return false return false
} }
} }

@ -44,17 +44,11 @@ class CommandChunkmaster(private val chunkmaster: Chunkmaster, private val serve
return if (commands.containsKey(args[0])) { return if (commands.containsKey(args[0])) {
commands[args[0]]!!.execute(sender, args.slice(1 until args.size)) commands[args[0]]!!.execute(sender, args.slice(1 until args.size))
} else { } else {
sender.spigot().sendMessage( sender.sendMessage(chunkmaster.langManager.getLocalized("SUBCOMMAND_NOT_FOUND", args[0]))
*ComponentBuilder("Subcommand ").color(ChatColor.RED)
.append(args[0]).color(ChatColor.GREEN).append(" not found").color(ChatColor.RED).create()
)
false false
} }
} else { } else {
sender.spigot().sendMessage( sender.sendMessage(chunkmaster.langManager.getLocalized("NO_PERMISSION"))
*ComponentBuilder("You do not have permission!")
.color(ChatColor.RED).create()
)
} }
return true return true
} else { } else {
@ -84,7 +78,7 @@ class CommandChunkmaster(private val chunkmaster: Chunkmaster, private val serve
val cmdReload = CmdReload(chunkmaster) val cmdReload = CmdReload(chunkmaster)
commands[cmdReload.name] = cmdReload commands[cmdReload.name] = cmdReload
val cmdTpChunk = CmdTpChunk() val cmdTpChunk = CmdTpChunk(chunkmaster)
commands[cmdTpChunk.name] = cmdTpChunk commands[cmdTpChunk.name] = cmdTpChunk
} }
} }

@ -0,0 +1,61 @@
package net.trivernis.chunkmaster.lib
import net.trivernis.chunkmaster.Chunkmaster
import java.io.BufferedReader
import java.io.File
import java.lang.Exception
import java.util.Properties
class LanguageManager(private val plugin: Chunkmaster) {
private val langProps = Properties()
private val languageFolder = "${plugin.dataFolder.absolutePath}/i18n"
private var langFileLoaded = false
/**
* Loads the default properties file and then the language specific ones.
* If no lang-specific file is found in the plugins directory under i18n an attempt is made to
* load the file from inside the jar in i18n.
*/
fun loadProperties() {
val language = plugin.config.getString("language")
val langFile = "$languageFolder/$language.i18n.properties"
val file = File(langFile)
val loader = Thread.currentThread().contextClassLoader
val defaultStream = this.javaClass.getResourceAsStream("/i18n/DEFAULT.i18n.properties")
if (defaultStream != null) {
langProps.load(defaultStream)
defaultStream.close()
} else {
plugin.logger.severe("Couldn't load default language properties.")
}
if (file.exists()) {
try {
val inputStream = loader.getResourceAsStream(langFile)
if (inputStream != null) {
langProps.load(inputStream)
langFileLoaded = true
inputStream.close()
}
} catch (e: Exception) {
plugin.logger.warning("Language file $langFile could not be loaded!")
plugin.logger.fine(e.toString())
}
} else {
val inputStream = this.javaClass.getResourceAsStream("/i18n/$language.i18n.properties")
if (inputStream != null) {
langProps.load(inputStream)
langFileLoaded = true
inputStream.close()
} else {
plugin.logger.warning("Language File $langFile could not be found!")
}
}
}
/**
* Returns a localized message with replacements
*/
fun getLocalized(key: String, vararg replacements: Any): String {
val localizedString = langProps.getProperty(key)
return String.format(localizedString, *replacements)
}
}

@ -36,7 +36,7 @@ class SqliteManager(private val chunkmaster: Chunkmaster) {
return DriverManager.getConnection("jdbc:sqlite:${chunkmaster.dataFolder.absolutePath}/" + return DriverManager.getConnection("jdbc:sqlite:${chunkmaster.dataFolder.absolutePath}/" +
"${chunkmaster.config.getString("database.filename")}") "${chunkmaster.config.getString("database.filename")}")
} catch (e: Exception) { } catch (e: Exception) {
chunkmaster.logger.severe("Could not get database connection.") chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("DATABASE_CONNECTION_ERROR"))
chunkmaster.logger.severe(e.message) chunkmaster.logger.severe(e.message)
} }
return null return null
@ -92,13 +92,13 @@ class SqliteManager(private val chunkmaster: Chunkmaster) {
} }
statement.close() statement.close()
} catch (e: Exception) { } catch (e: Exception) {
chunkmaster.logger.severe("An error occured on sql $sql. ${e.message}") chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("SQL_ERROR", e.message!!))
chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) chunkmaster.logger.info(ExceptionUtils.getStackTrace(e))
} finally { } finally {
connection.close() connection.close()
} }
} else { } else {
chunkmaster.logger.severe("Could not execute sql $sql. No database connection established.") chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("NO_DATABASE_CONNECTION"))
} }
} }
@ -114,10 +114,10 @@ class SqliteManager(private val chunkmaster: Chunkmaster) {
tableDef += "${column.first} ${column.second}," tableDef += "${column.first} ${column.second},"
} }
tableDef = tableDef.substringBeforeLast(",") + ");" tableDef = tableDef.substringBeforeLast(",") + ");"
chunkmaster.logger.info("Creating table $table with definition $tableDef") chunkmaster.logger.finest(chunkmaster.langManager.getLocalized("CREATE_TABLE_DEFINITION", table, tableDef))
executeStatement(tableDef, HashMap(), null) executeStatement(tableDef, HashMap(), null)
} catch (e: Exception) { } catch (e: Exception) {
chunkmaster.logger.severe("Error creating table $table.") chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("TABLE_CREATE_ERROR", table))
chunkmaster.logger.severe(e.message) chunkmaster.logger.severe(e.message)
chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) chunkmaster.logger.info(ExceptionUtils.getStackTrace(e))
} }
@ -126,9 +126,9 @@ class SqliteManager(private val chunkmaster: Chunkmaster) {
val updateSql = "ALTER TABLE ${table.first} ADD COLUMN ${table.second.first} ${table.second.second}" val updateSql = "ALTER TABLE ${table.first} ADD COLUMN ${table.second.first} ${table.second.second}"
try { try {
executeStatement(updateSql, HashMap(), null) executeStatement(updateSql, HashMap(), null)
chunkmaster.logger.info("Updated table ${table.first} with sql $updateSql") chunkmaster.logger.finest(chunkmaster.langManager.getLocalized("UPDATE_TABLE_DEFINITION", table.first, updateSql))
} catch (e: Exception) { } catch (e: Exception) {
chunkmaster.logger.severe("Failed to update table ${table.first} with sql $updateSql") chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("UPDATE_TABLE_FAILED", table.first, updateSql))
chunkmaster.logger.severe(e.message) chunkmaster.logger.severe(e.message)
chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) chunkmaster.logger.info(ExceptionUtils.getStackTrace(e))
} }

@ -5,6 +5,6 @@ import org.bukkit.World
class ChunkCoordinates(val x: Int, val z: Int) { class ChunkCoordinates(val x: Int, val z: Int) {
fun getCenterLocation(world: World): Location { fun getCenterLocation(world: World): Location {
return Location(world, ((x*16) + 8).toDouble(), 1.0, ((x*16) + 8).toDouble()) return Location(world, ((x*16) + 8).toDouble(), 1.0, ((z*16) + 8).toDouble())
} }
} }

@ -47,18 +47,15 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
) )
var id = 0 var id = 0
chunkmaster.sqliteManager.executeStatement( chunkmaster.sqliteManager.executeStatement("""
""" SELECT id FROM generation_tasks ORDER BY id DESC LIMIT 1
SELECT id FROM generation_tasks ORDER BY id DESC LIMIT 1 """.trimIndent(), HashMap()) {
""".trimIndent(),
HashMap()
) {
it.next() it.next()
id = it.getInt("id") id = it.getInt("id")
} }
generationTask.onEndReached { generationTask.onEndReached {
chunkmaster.logger.info("Task #${id} finished after ${it.count} chunks.") chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_FINISHED", id, it.count))
removeTask(id) removeTask(id)
} }
@ -89,7 +86,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
stopAfter: Int = -1 stopAfter: Int = -1
) { ) {
if (!paused) { if (!paused) {
chunkmaster.logger.info("Resuming chunk generation task for world \"${world.name}\"") chunkmaster.logger.info(chunkmaster.langManager.getLocalized("RESUME_FOR_WORLD", world.name))
val generationTask = createGenerationTask(world, center, last, stopAfter) val generationTask = createGenerationTask(world, center, last, stopAfter)
val task = server.scheduler.runTaskTimer( val task = server.scheduler.runTaskTimer(
chunkmaster, generationTask, 200, // 10 sec delay chunkmaster, generationTask, 200, // 10 sec delay
@ -97,7 +94,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
) )
tasks.add(RunningTaskEntry(id, task, generationTask)) tasks.add(RunningTaskEntry(id, task, generationTask))
generationTask.onEndReached { generationTask.onEndReached {
chunkmaster.logger.info("Task #${id} finished after ${generationTask.count} chunks.") chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_FINISHED", id, generationTask.count))
removeTask(id) removeTask(id)
} }
} }
@ -114,11 +111,9 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
} }
if (taskEntry != null) { if (taskEntry != null) {
taskEntry.cancel() taskEntry.cancel()
chunkmaster.sqliteManager.executeStatement( chunkmaster.sqliteManager.executeStatement("""
"""
DELETE FROM generation_tasks WHERE id = ?; DELETE FROM generation_tasks WHERE id = ?;
""".trimIndent(), """.trimIndent(), HashMap(mapOf(1 to taskEntry.id)),
HashMap(mapOf(1 to taskEntry.id)),
null null
) )
@ -139,7 +134,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
* Loads tasks from the database and resumes them * Loads tasks from the database and resumes them
*/ */
fun init() { fun init() {
chunkmaster.logger.info("Creating task to load chunk generation Tasks later...") chunkmaster.logger.info(chunkmaster.langManager.getLocalized("CREATE_DELAYED_LOAD"))
server.scheduler.runTaskTimer(chunkmaster, Runnable { server.scheduler.runTaskTimer(chunkmaster, Runnable {
saveProgress() // save progress every 30 seconds saveProgress() // save progress every 30 seconds
}, 600, 600) }, 600, 600)
@ -162,7 +157,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
if (task.task.isCancelled) { if (task.task.isCancelled) {
removalSet.add(task) removalSet.add(task)
} }
chunkmaster.logger.info("Canceled task #${task.id}") chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_CANCELED", task.id))
} }
tasks.removeAll(removalSet) tasks.removeAll(removalSet)
} }
@ -171,8 +166,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
* Starts all generation tasks. * Starts all generation tasks.
*/ */
fun startAll() { fun startAll() {
chunkmaster.sqliteManager.executeStatement("SELECT * FROM generation_tasks", HashMap()) { chunkmaster.sqliteManager.executeStatement("SELECT * FROM generation_tasks", HashMap()) { res ->
val res = it
while (res.next()) { while (res.next()) {
try { try {
val id = res.getInt("id") val id = res.getInt("id")
@ -184,13 +178,13 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
resumeTask(world!!, center, last, id, stopAfter) resumeTask(world!!, center, last, id, stopAfter)
} }
} catch (error: NullPointerException) { } catch (error: NullPointerException) {
chunkmaster.logger.severe("Failed to load Task ${res.getInt("id")}.") chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("TASK_LOAD_FAILED", res.getInt("id")))
} }
} }
} }
if (tasks.isNotEmpty()) { if (tasks.isNotEmpty()) {
chunkmaster.logger.info("${tasks.size} saved tasks loaded.") chunkmaster.logger.info(chunkmaster.langManager.getLocalized("TASK_LOAD_SUCCESS", tasks.size))
} }
} }
@ -221,16 +215,30 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
for (task in tasks) { for (task in tasks) {
try { try {
val genTask = task.generationTask val genTask = task.generationTask
chunkmaster.logger.info( val speed = task.generationSpeed!!
"""Task #${task.id} running for "${genTask.world.name}". val percentage = if (genTask.stopAfter > 0) "(${"%.2f".format(
|Progress ${task.generationTask.count} chunks (genTask.count.toDouble() / genTask.stopAfter.toDouble()) * 100
|${if (task.generationTask.stopAfter > 0) "(${"%.2f".format( )}%)" else ""
(task.generationTask.count.toDouble() / val eta = if (genTask.stopAfter > 0 && speed > 0) {
task.generationTask.stopAfter.toDouble()) * 100 val etaSeconds = (genTask.stopAfter - genTask.count).toDouble()/speed
)}%)" else ""}. chunkmaster.logger.info(""+etaSeconds)
| Speed: ${"%.1f".format(task.generationSpeed)} chunks/sec, val hours: Int = (etaSeconds/3600).toInt()
|Last Chunk: ${genTask.lastChunk.x}, ${genTask.lastChunk.z}""".trimMargin("|").replace('\n', ' ') val minutes: Int = ((etaSeconds % 3600) / 60).toInt()
) val seconds: Int = (etaSeconds % 60).toInt()
", ETA: %d:%02d:%02d".format(hours, minutes, seconds)
} else {
""
}
chunkmaster.logger.info(chunkmaster.langManager.getLocalized(
"TASK_PERIODIC_REPORT",
task.id,
genTask.world.name,
genTask.count,
percentage,
eta,
speed,
genTask.lastChunk.x,
genTask.lastChunk.z))
chunkmaster.sqliteManager.executeStatement( chunkmaster.sqliteManager.executeStatement(
""" """
UPDATE generation_tasks SET last_x = ?, last_z = ? UPDATE generation_tasks SET last_x = ?, last_z = ?
@ -240,7 +248,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server
null null
) )
} catch (error: Exception) { } catch (error: Exception) {
chunkmaster.logger.warning("Exception when saving task progress ${error.message}") chunkmaster.logger.warning(chunkmaster.langManager.getLocalized("TASK_SAVE_FAILED", error.toString()))
} }
} }
} }

@ -4,13 +4,11 @@ import net.trivernis.chunkmaster.Chunkmaster
import net.trivernis.chunkmaster.lib.Spiral import net.trivernis.chunkmaster.lib.Spiral
import org.bukkit.Chunk import org.bukkit.Chunk
import org.bukkit.World import org.bukkit.World
/** /**
* Interface for generation tasks. * Interface for generation tasks.
*/ */
abstract class GenerationTask(plugin: Chunkmaster, centerChunk: ChunkCoordinates, startChunk: ChunkCoordinates) : abstract class GenerationTask(plugin: Chunkmaster, centerChunk: ChunkCoordinates, startChunk: ChunkCoordinates) :
Runnable { Runnable {
abstract val stopAfter: Int abstract val stopAfter: Int
abstract val world: World abstract val world: World
abstract val count: Int abstract val count: Int

@ -0,0 +1,48 @@
RESUME_FOR_WORLD = Resuming chunk generation task for world '%s'...
TASK_FINISHED = Task #%d finished after %d chunks.
TASK_CANCELED = Canceled task #%s.
TASK_LOAD_FAILED = \u00A7cFailed to load task #%d.
TASK_LOAD_SUCCESS = %d saved tasks loaded.
TASK_NOT_FOUND = \u00A7cTask %s not found!
CREATE_DELAYED_LOAD = Creating task to load chunk generation Tasks later...
TASK_PERIODIC_REPORT = Task #%d running for '%s'. Progress: %d chunks %s %s, Speed: %.1f ch/s, Last Chunk: %d, %d
TASK_SAVE_FAILED = \u00A7cException when saving tasks: %s
WORLD_NAME_REQUIRED = \u00A7cYou need to provide a world name!
WORLD_NOT_FOUND = \u00A7cWorld \u00A72%s \u00A7cnot found!
TASK_ALREADY_EXISTS = \u00A7cA task for '%s' already exists!
TASK_CREATION_SUCCESS = \u00A79Generation Task for world \u00A72%s \u00A79 until \u00A72%s \u00A79successfully created!
TASK_ID_REQUIRED = \u00A7cYou need to provide a task id!
PAUSED_TASKS_HEADER = Currently Paused Generation Tasks
TASKS_ENTRY = - \u00A79#%d\u00A7r - \u00A72%s\u00A7r - \u00A72%d chunks %s\u00A7r
RUNNING_TASKS_HEADER = Currently Running Generation Tasks
NO_GENERATION_TASKS = There are no generation tasks.
PAUSE_SUCCESS = \u00A79Paused all generation tasks.
ALREADY_PAUSED = \u00A7cThe generation process is already paused!
RESUME_SUCCESS = \u00A79Resumed all generation Tasks.
NOT_PAUSED = \u00A7cThe generation process is not paused!
CONFIG_RELOADING = Reloading the config file...
CONFIG_RELOADED = \u00A72The config file has been reloaded!
TELEPORTED = \u00A79You have been teleported to chunk \u00A72%s, %s
TP_ONLY_PLAYER = \u00A7cThis command can only be executed by a player!
NO_PERMISSION = \u00A7cYou do not have the permission for this command!
SUBCOMMAND_NOT_FOUND = \u00A7cSubcommand \u00A72%s \u00A7cnot found!
STOPPING_ALL_TASKS = Stopping all generation tasks...
DB_INIT = Initializing database...
DB_INIT_FINISHED = Database fully initialized.
DB_INIT_EROR = Failed to init database: %s.
DATABASE_CONNECTION_ERROR = \u00A7cCould not get the database connection!
SQL_ERROR = \u00A7cAn eror occured on sql %s!
NO_DATABASE_CONNECTION = \u00A7cCould not execute sql: No database connection.
CREATE_TABLE_DEFINITION = Created table %s with definition %s.
TABLE_CREATE_ERROR = \u00A7cError when creation table %s.
UPDATE_TABLE_DEFINITION = Updated table %s with sql %s.
UPDATE_TABLE_FAILED = Failed to update table %s with sql %s.

@ -0,0 +1,48 @@
RESUME_FOR_WORLD = Setze das Chunk-Generieren f\u00fcr Welt '%s' fort...
TASK_FINISHED = Aufgabe #%d wurde nach %d chunks beendet.
TASK_CANCELED = Aufgabe #%s wurde abgebrochen.
TASK_LOAD_FAILED = \u00A7cAufgabe #%d konnte nicht geladen werden.
TASK_LOAD_SUCCESS = %d gespeicherte Aufgaben wurden geladen.
TASK_NOT_FOUND = \u00A7cAufgabe %s konnte nicht gefunden werden!
CREATE_DELAYED_LOAD = Erstelle einen Bukkit-Task zum verz\u00f6gerten Laden von Aufgaben...
TASK_PERIODIC_REPORT = Aufgabe #%d f\u00fcr Welt '%s'. Fortschritt: %d chunks %s %s, Geschwindigkeit: %.1f ch/s, Letzer Chunk: %d, %d
TASK_SAVE_FAILED = \u00A7cFehler beim Speichern der Aufgaben: %s
WORLD_NAME_REQUIRED = \u00A7cDu musst einen Weltennamen angeben!
WORLD_NOT_FOUND = \u00A7c Die Welt \u00A72%s \u00A7cwurde nicht gefunden!
TASK_ALREADY_EXISTS = \u00A7cEs existiert bereits eine Aufgabe f\u00fcr \u00A72%s\u00A7c!
TASK_CREATION_SUCCESS = \u00A79Generierungs-Aufgabe \u00A72%s \u00A79 bis \u00A72%s \u00A79wurde erfolgreich erstellt!
TASK_ID_REQUIRED = \u00A7cDu musst eine Aufgaben-Id angeben!
PAUSED_TASKS_HEADER = \u00A7lPausierte Generierungsaufgaben\u00A7r
RUNNING_TASKS_HEADER = \u00A7lLaufende Generierungsaufgaben\u00A7r
NO_GENERATION_TASKS = Es gibt keine Aufgaben.
PAUSE_SUCCESS = \u00A79Alle Aufgaben wurden pausiert.
ALREADY_PAUSED = \u00A7cDas Generieren ist bereits pausiert.
RESUME_SUCCESS = \u00A79Alle Aufgaben wurden fortgesetzt.
NOT_PAUSED = \u00A7cEs gibt keine pausierten Aufgaben!
CONFIG_RELOADING = Die Konfigurationsdatei wird neu eingelesen...
CONFIG_RELOADED = \u00A72Die Konfigurationsdatei wurde neu geladen!
TELEPORTED = \u00A79Du wurdest zum Chunk \u00A72%s, %s \u00A79teleportiert
TP_ONLY_PLAYER = \u00A7cDieser Befehl kann nur von einem Spieler ausgef\u00fchrt werden.
NO_PERMISSION = \u00A7cDu hast nicht die Rechte für diesen Befehl!
SUBCOMMAND_NOT_FOUND = \u00A7cUnteraktion \u00A72%s \u00A7cwurde nicht gefunden!
STOPPING_ALL_TASKS = Stoppt alle Aufgaben...
DB_INIT = Initialisiere Datenbank...
DB_INIT_FINISHED = Die Datenbank wurde initialisiert.
DB_INIT_EROR = Fehler beim Initalisieren der Datenbank: %s.
DATABASE_CONNECTION_ERROR = \u00A7cDie Datenbankverbindung konnte nicht erzeugt werden.
SQL_ERROR = \u00A7cEin Fehler trat mit sql %s auf!
NO_DATABASE_CONNECTION = \u00A7cSql konnte nicht ausgef\u00fchrt werden: Keine Datenbankverbindung.
CREATE_TABLE_DEFINITION = Tabelle %s mit Definition %s wurde erstellt.
TABLE_CREATE_ERROR = \u00A7cFehler beim erstellen der Tabelle %s.
UPDATE_TABLE_DEFINITION = Tabelle %s wurde mit sql %s geupdated.
UPDATE_TABLE_FAILED = Fehler beim Updaten der Tabelle %s mit sql %s.

@ -0,0 +1,48 @@
RESUME_FOR_WORLD = Resuming chunk generation task for world '%s'...
TASK_FINISHED = Task #%d finished after %d chunks.
TASK_CANCELED = Canceled task #%s.
TASK_LOAD_FAILED = \u00A7cFailed to load task #%d.
TASK_LOAD_SUCCESS = %d saved tasks loaded.
TASK_NOT_FOUND = \u00A7cTask %s not found!
CREATE_DELAYED_LOAD = Creating task to load chunk generation Tasks later...
TASK_PERIODIC_REPORT = Task #%d running for '%s'. Progress: %d chunks %s %s, Speed: %.1f ch/s, Last Chunk: %d, %d
TASK_SAVE_FAILED = \u00A7cException when saving tasks: %s
WORLD_NAME_REQUIRED = \u00A7cYou need to provide a world name!
WORLD_NOT_FOUND = \u00A7cWorld \u00A72%s \u00A7cnot found!
TASK_ALREADY_EXISTS = \u00A7cA task for '%s' already exists!
TASK_CREATION_SUCCESS = \u00A79Generation Task for world \u00A72%s \u00A79 until \u00A72%s \u00A79successfully created!
TASK_ID_REQUIRED = \u00A7cYou need to provide a task id!
PAUSED_TASKS_HEADER = Currently Paused Generation Tasks
TASKS_ENTRY = - \u00A79#%d\u00A7r - \u00A72%s\u00A7r - \u00A72%d chunks %s\u00A7r
RUNNING_TASKS_HEADER = Currently Running Generation Tasks
NO_GENERATION_TASKS = There are no generation tasks.
PAUSE_SUCCESS = \u00A79Paused all generation tasks.
ALREADY_PAUSED = \u00A7cThe generation process is already paused!
RESUME_SUCCESS = \u00A79Resumed all generation Tasks.
NOT_PAUSED = \u00A7cThe generation process is not paused!
CONFIG_RELOADING = Reloading the config file...
CONFIG_RELOADED = \u00A72The config file has been reloaded!
TELEPORTED = \u00A79You have been teleported to chunk \u00A72%s, %s
TP_ONLY_PLAYER = \u00A7cThis command can only be executed by a player!
NO_PERMISSION = \u00A7cYou do not have the permission for this command!
SUBCOMMAND_NOT_FOUND = \u00A7cSubcommand \u00A72%s \u00A7cnot found!
STOPPING_ALL_TASKS = Stopping all generation tasks...
DB_INIT = Initializing database...
DB_INIT_FINISHED = Database fully initialized.
DB_INIT_EROR = Failed to init database: %s.
DATABASE_CONNECTION_ERROR = \u00A7cCould not get the database connection!
SQL_ERROR = \u00A7cAn eror occured on sql %s!
NO_DATABASE_CONNECTION = \u00A7cCould not execute sql: No database connection.
CREATE_TABLE_DEFINITION = Created table %s with definition %s.
TABLE_CREATE_ERROR = \u00A7cError when creation table %s.
UPDATE_TABLE_DEFINITION = Updated table %s with sql %s.
UPDATE_TABLE_FAILED = Failed to update table %s with sql %s.

@ -1,6 +1,6 @@
main: net.trivernis.chunkmaster.Chunkmaster main: net.trivernis.chunkmaster.Chunkmaster
name: Chunkmaster name: Chunkmaster
version: '0.13-beta' version: '0.14-beta'
description: Chunk commands plugin. description: Chunk commands plugin.
author: Trivernis author: Trivernis
website: trivernis.net website: trivernis.net

Loading…
Cancel
Save