diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/database/SqliteManager.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/database/SqliteManager.kt index bd16d7b..f2ed67c 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/database/SqliteManager.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/database/SqliteManager.kt @@ -1,189 +1,189 @@ -package net.trivernis.chunkmaster.lib.database - -import net.trivernis.chunkmaster.Chunkmaster -import org.apache.commons.lang.exception.ExceptionUtils -import java.sql.Connection -import java.sql.DriverManager -import java.sql.ResultSet - -class SqliteManager(private val chunkmaster: Chunkmaster) { - private val tables = listOf( - Pair( - "generation_tasks", - listOf( - Pair("id", "integer PRIMARY KEY AUTOINCREMENT"), - Pair("center_x", "integer NOT NULL DEFAULT 0"), - Pair("center_z", "integer NOT NULL DEFAULT 0"), - Pair("last_x", "integer NOT NULL DEFAULT 0"), - Pair("last_z", "integer NOT NULL DEFAULT 0"), - Pair("world", "text UNIQUE NOT NULL DEFAULT 'world'"), - Pair("radius", "integer DEFAULT -1"), - Pair("shape", "text NOT NULL DEFAULT 'square'"), - Pair("state", "text NOT NULL DEFAULT 'GENERATING'") - ) - ), - Pair( - "world_properties", - listOf( - Pair("name", "text PRIMARY KEY"), - Pair("center_x", "integer NOT NULL DEFAULT 0"), - Pair("center_z", "integer NOT NULL DEFAULT 0") - ) - ), - Pair( - "pending_chunks", - listOf( - Pair("id", "integer PRIMARY KEY AUTOINCREMENT"), - Pair("task_id", "integer NOT NULL"), - Pair("chunk_x", "integer NOT NULL"), - Pair("chunk_z", "integer NOT NULL") - ) - ) - ) - private val needUpdate = HashSet>>() - private val needCreation = HashSet() - private var connection: Connection? = null - private var activeTasks = 0 - - val worldProperties = WorldProperties(this) - val pendingChunks = PendingChunks(this) - val generationTasks = GenerationTasks(this) - - /** - * Returns the connection to the database - */ - fun getConnection(): Connection? { - if (this.connection != null) { - return this.connection - } - try { - Class.forName("org.sqlite.JDBC") - this.connection = DriverManager.getConnection( - "jdbc:sqlite:${chunkmaster.dataFolder.absolutePath}/" + - "${chunkmaster.config.getString("database.filename")}" - ) - return this.connection - } catch (e: Exception) { - chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("DATABASE_CONNECTION_ERROR")) - chunkmaster.logger.severe(e.message) - } - return null - } - - /** - * Checks for and performs an update - */ - fun init() { - this.checkUpdate() - this.performUpdate() - } - - /** - * Checks which tables need an update or creation. - */ - private fun checkUpdate() { - val meta = getConnection()!!.metaData - - for (table in tables) { - val resTables = meta.getTables(null, null, table.first, null) - - if (resTables.next()) { // table exists - for (column in table.second) { - val resColumn = meta.getColumns(null, null, table.first, column.first) - if (!resColumn.next()) { - needUpdate.add(Pair(table.first, column)) - } - resColumn.close() - } - } else { - needCreation.add(table.first) - } - resTables.close() - } - } - - /** - * Executes a sql statement on the database. - */ - fun executeStatement(sql: String, values: HashMap, callback: ((ResultSet?) -> Unit)?) { - val connection = getConnection() - activeTasks++ - if (connection != null) { - try { - //println("'$sql' with values $values") - val statement = connection.prepareStatement(sql) - for (parameterValue in values) { - statement.setObject(parameterValue.key, parameterValue.value) - } - statement.execute() - val res: ResultSet? = statement.resultSet - if (callback != null) { - callback(res) - } - statement.close() - } catch (e: Exception) { - chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("SQL_ERROR", e.toString())) - chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) - } finally { - activeTasks-- - if (activeTasks == 0) { - connection.close() - this.connection = null - } - } - } else { - chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("NO_DATABASE_CONNECTION")) - } - } - - /** - * Creates or updates tables that needed an update. - */ - private fun performUpdate() { - for (table in needCreation) { - try { - var tableDef = "CREATE TABLE IF NOT EXISTS $table (" - - for (column in tables.find { it.first == table }!!.second) { - tableDef += "${column.first} ${column.second}," - } - tableDef = tableDef.substringBeforeLast(",") + ");" - chunkmaster.logger.finest( - chunkmaster.langManager.getLocalized( - "CREATE_TABLE_DEFINITION", - table, - tableDef - ) - ) - executeStatement(tableDef, HashMap(), null) - } catch (e: Exception) { - chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("TABLE_CREATE_ERROR", table)) - chunkmaster.logger.severe(e.message) - chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) - } - } - for (table in needUpdate) { - val updateSql = "ALTER TABLE ${table.first} ADD COLUMN ${table.second.first} ${table.second.second}" - try { - executeStatement(updateSql, HashMap(), null) - chunkmaster.logger.finest( - chunkmaster.langManager.getLocalized( - "UPDATE_TABLE_DEFINITION", - table.first, - updateSql - ) - ) - } catch (e: Exception) { - chunkmaster.logger.severe( - chunkmaster.langManager.getLocalized( - "UPDATE_TABLE_FAILED", - table.first, - updateSql - ) - ) - chunkmaster.logger.severe(e.message) - chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) - } - } - } +package net.trivernis.chunkmaster.lib.database + +import net.trivernis.chunkmaster.Chunkmaster +import org.apache.commons.lang.exception.ExceptionUtils +import java.sql.Connection +import java.sql.DriverManager +import java.sql.ResultSet + +class SqliteManager(private val chunkmaster: Chunkmaster) { + private val tables = listOf( + Pair( + "generation_tasks", + listOf( + Pair("id", "integer PRIMARY KEY AUTOINCREMENT"), + Pair("center_x", "integer NOT NULL DEFAULT 0"), + Pair("center_z", "integer NOT NULL DEFAULT 0"), + Pair("last_x", "integer NOT NULL DEFAULT 0"), + Pair("last_z", "integer NOT NULL DEFAULT 0"), + Pair("world", "text UNIQUE NOT NULL DEFAULT 'world'"), + Pair("radius", "integer DEFAULT -1"), + Pair("shape", "text NOT NULL DEFAULT 'square'"), + Pair("state", "text NOT NULL DEFAULT 'GENERATING'") + ) + ), + Pair( + "world_properties", + listOf( + Pair("name", "text PRIMARY KEY"), + Pair("center_x", "integer NOT NULL DEFAULT 0"), + Pair("center_z", "integer NOT NULL DEFAULT 0") + ) + ), + Pair( + "pending_chunks", + listOf( + Pair("id", "integer PRIMARY KEY AUTOINCREMENT"), + Pair("task_id", "integer NOT NULL"), + Pair("chunk_x", "integer NOT NULL"), + Pair("chunk_z", "integer NOT NULL") + ) + ) + ) + private val needUpdate = HashSet>>() + private val needCreation = HashSet() + private var connection: Connection? = null + private var activeTasks = 0 + + val worldProperties = WorldProperties(this) + val pendingChunks = PendingChunks(this) + val generationTasks = GenerationTasks(this) + + /** + * Returns the connection to the database + */ + fun getConnection(): Connection? { + if (this.connection != null) { + return this.connection + } + try { + Class.forName("org.sqlite.JDBC") + this.connection = DriverManager.getConnection( + "jdbc:sqlite:${chunkmaster.dataFolder.absolutePath}/" + + "${chunkmaster.config.getString("database.filename")}" + ) + return this.connection + } catch (e: Exception) { + chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("DATABASE_CONNECTION_ERROR")) + chunkmaster.logger.severe(e.message) + } + return null + } + + /** + * Checks for and performs an update + */ + fun init() { + this.checkUpdate() + this.performUpdate() + } + + /** + * Checks which tables need an update or creation. + */ + private fun checkUpdate() { + val meta = getConnection()!!.metaData + + for (table in tables) { + val resTables = meta.getTables(null, null, table.first, null) + + if (resTables.next()) { // table exists + for (column in table.second) { + val resColumn = meta.getColumns(null, null, table.first, column.first) + if (!resColumn.next()) { + needUpdate.add(Pair(table.first, column)) + } + resColumn.close() + } + } else { + needCreation.add(table.first) + } + resTables.close() + } + } + + /** + * Executes a sql statement on the database. + */ + fun executeStatement(sql: String, values: HashMap, callback: ((ResultSet?) -> Unit)?) { + val connection = getConnection() + activeTasks++ + if (connection != null) { + try { + //println("'$sql' with values $values") + val statement = connection.prepareStatement(sql) + for (parameterValue in values) { + statement.setObject(parameterValue.key, parameterValue.value) + } + statement.execute() + val res: ResultSet? = statement.resultSet + if (callback != null) { + callback(res) + } + statement.close() + } catch (e: Exception) { + chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("SQL_ERROR", e.toString())) + chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) + } finally { + activeTasks-- + if (activeTasks == 0) { + connection.close() + this.connection = null + } + } + } else { + chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("NO_DATABASE_CONNECTION")) + } + } + + /** + * Creates or updates tables that needed an update. + */ + private fun performUpdate() { + for (table in needCreation) { + try { + var tableDef = "CREATE TABLE IF NOT EXISTS $table (" + + for (column in tables.find { it.first == table }!!.second) { + tableDef += "${column.first} ${column.second}," + } + tableDef = tableDef.substringBeforeLast(",") + ");" + chunkmaster.logger.finest( + chunkmaster.langManager.getLocalized( + "CREATE_TABLE_DEFINITION", + table, + tableDef + ) + ) + executeStatement(tableDef, HashMap(), null) + } catch (e: Exception) { + chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("TABLE_CREATE_ERROR", table)) + chunkmaster.logger.severe(e.message) + chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) + } + } + for (table in needUpdate) { + val updateSql = "ALTER TABLE ${table.first} ADD COLUMN ${table.second.first} ${table.second.second}" + try { + executeStatement(updateSql, HashMap(), null) + chunkmaster.logger.finest( + chunkmaster.langManager.getLocalized( + "UPDATE_TABLE_DEFINITION", + table.first, + updateSql + ) + ) + } catch (e: Exception) { + chunkmaster.logger.severe( + chunkmaster.langManager.getLocalized( + "UPDATE_TABLE_FAILED", + table.first, + updateSql + ) + ) + chunkmaster.logger.severe(e.message) + chunkmaster.logger.info(ExceptionUtils.getStackTrace(e)) + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/taskentry/RunningTaskEntry.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/taskentry/RunningTaskEntry.kt index 684155c..6db86d3 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/taskentry/RunningTaskEntry.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/taskentry/RunningTaskEntry.kt @@ -1,69 +1,69 @@ -package net.trivernis.chunkmaster.lib.generation.taskentry - -import net.trivernis.chunkmaster.lib.generation.GenerationTask - -class RunningTaskEntry( - override val id: Int, - override val generationTask: GenerationTask -) : TaskEntry { - - private var lastProgress: Pair? = null - private var lastChunkCount: Pair? = null - private var thread = Thread(generationTask) - - /** - * Returns the generation Speed - */ - val generationSpeed: Pair - get() { - var generationSpeed: Double? = null - var chunkGenerationSpeed: Double? = null - if (lastProgress != null) { - val progressDiff = generationTask.shape.progress() - lastProgress!!.second - val timeDiff = (System.currentTimeMillis() - lastProgress!!.first).toDouble() / 1000 - generationSpeed = progressDiff / timeDiff - } - if (lastChunkCount != null) { - val chunkDiff = generationTask.count - lastChunkCount!!.second - val timeDiff = (System.currentTimeMillis() - lastChunkCount!!.first).toDouble() / 1000 - chunkGenerationSpeed = chunkDiff / timeDiff - } - lastProgress = Pair(System.currentTimeMillis(), generationTask.shape.progress()) - lastChunkCount = Pair(System.currentTimeMillis(), generationTask.count) - return Pair(generationSpeed, chunkGenerationSpeed) - } - - init { - lastProgress = Pair(System.currentTimeMillis(), generationTask.shape.progress()) - lastChunkCount = Pair(System.currentTimeMillis(), generationTask.count) - } - - fun start() { - thread.start() - } - - fun cancel(timeout: Long): Boolean { - if (generationTask.isRunning) { - generationTask.cancel() - thread.interrupt() - } - return try { - joinThread(timeout) - } catch (e: InterruptedException) { - true - } - } - - private fun joinThread(timeout: Long): Boolean { - var threadStopped = false - - for (i in 0..100) { - if (!thread.isAlive || !generationTask.isRunning) { - threadStopped = true - break - } - Thread.sleep(timeout / 100) - } - return threadStopped - } +package net.trivernis.chunkmaster.lib.generation.taskentry + +import net.trivernis.chunkmaster.lib.generation.GenerationTask + +class RunningTaskEntry( + override val id: Int, + override val generationTask: GenerationTask +) : TaskEntry { + + private var lastProgress: Pair? = null + private var lastChunkCount: Pair? = null + private var thread = Thread(generationTask) + + /** + * Returns the generation Speed + */ + val generationSpeed: Pair + get() { + var generationSpeed: Double? = null + var chunkGenerationSpeed: Double? = null + if (lastProgress != null) { + val progressDiff = generationTask.shape.progress() - lastProgress!!.second + val timeDiff = (System.currentTimeMillis() - lastProgress!!.first).toDouble() / 1000 + generationSpeed = progressDiff / timeDiff + } + if (lastChunkCount != null) { + val chunkDiff = generationTask.count - lastChunkCount!!.second + val timeDiff = (System.currentTimeMillis() - lastChunkCount!!.first).toDouble() / 1000 + chunkGenerationSpeed = chunkDiff / timeDiff + } + lastProgress = Pair(System.currentTimeMillis(), generationTask.shape.progress()) + lastChunkCount = Pair(System.currentTimeMillis(), generationTask.count) + return Pair(generationSpeed, chunkGenerationSpeed) + } + + init { + lastProgress = Pair(System.currentTimeMillis(), generationTask.shape.progress()) + lastChunkCount = Pair(System.currentTimeMillis(), generationTask.count) + } + + fun start() { + thread.start() + } + + fun cancel(timeout: Long): Boolean { + if (generationTask.isRunning) { + generationTask.cancel() + thread.interrupt() + } + return try { + joinThread(timeout) + } catch (e: InterruptedException) { + true + } + } + + private fun joinThread(timeout: Long): Boolean { + var threadStopped = false + + for (i in 0..100) { + if (!thread.isAlive || !generationTask.isRunning) { + threadStopped = true + break + } + Thread.sleep(timeout / 100) + } + return threadStopped + } } \ No newline at end of file diff --git a/src/main/resources/i18n/zh.i18n.properties b/src/main/resources/i18n/zh.i18n.properties index 18a6d97..17fa4a0 100644 --- a/src/main/resources/i18n/zh.i18n.properties +++ b/src/main/resources/i18n/zh.i18n.properties @@ -1,11 +1,12 @@ RESUME_FOR_WORLD = 正在恢复执行 '%s' 世界的区块生成任务... TASK_FINISHED = 任务 #%d 在生成 %d 个区块后完成. -TASK_CANCELED = 已取消任务 #%s. +TASK_CANCELLED = 已取消任务 #%s. TASK_LOAD_FAILED = §c加载任务 #%d 失败. TASK_LOAD_SUCCESS = %d 个已保存的任务加载完成. TASK_NOT_FOUND = §c任务 %s 未找到! CREATE_DELAYED_LOAD = 正在创建延迟执行的区块生成任务... -TASK_PERIODIC_REPORT = 任务 #%d 正在 '%s' 世界执行. 进度: %d 区块 %s %s, 速度: %.1f 区块 / 秒, 最新生成的区块: %d, %d +TASK_PERIODIC_REPORT = 任务 #%d 正在 '%s' 世界执行. 状态: %s. 进度: %d 区块 %s %s, 速度: %.1f 区块 / 秒, 最新生成的区块: %d, %d +TASK_PERIODIC_REPORT_CORRECTING = 任务 #%d 正在为世界 '%s' 生成缺失的区块. 进度: %d 区块 %s TASK_SAVE_FAILED = §c保存任务时发生错误: %s WORLD_NAME_REQUIRED = §c你需要提供世界名称! @@ -18,7 +19,7 @@ TASK_ID_REQUIRED = §c你需要提供任务 ID! INVALID_ARGUMENT = §c在 %s: %s 存在无效的变量! PAUSED_TASKS_HEADER = 当前暂停的区块生成任务 -TASKS_ENTRY = - §9#%d§r - §2%s§r - §2%d 区块 %s§r +TASKS_ENTRY = - §9#%d§r - §2%s§r - §2%s§r - §2%s 区块 %s§r RUNNING_TASKS_HEADER = 当前运行的区块生成任务 NO_GENERATION_TASKS = 无区块生成任务. @@ -44,7 +45,7 @@ DB_INIT_FINISHED = 数据库初始化完成. DB_INIT_EROR = 初始化数据库时发生错误: %s. DATABASE_CONNECTION_ERROR = §c连接数据库失败! -SQL_ERROR = §cSQL %s 发生错误! +SQL_ERROR = §cSQL 发生错误: %s ! NO_DATABASE_CONNECTION = §c无法执行 SQL 语句: 无数据库连接. CREATE_TABLE_DEFINITION = 已创建表 %s ,定义 %s. TABLE_CREATE_ERROR = §c创建表 %s 失败. @@ -73,3 +74,7 @@ STATS_WORLD_NAME = §l%s§r STATS_ENTITY_COUNT = - §2%d§r 实体 STATS_LOADED_CHUNKS = - §2%d§r 已载入区块 STATS_PLUGIN_LOADED_CHUNKS = - §2%d§r 被 Chunk Master 载入的区块 + +SAVING_CHUNKS = 正在保存 %d 已载入的区块... +CANCEL_FAIL = 取消任务 #%d 操作超时! +NO_AUTOSTART = 自动启动被设置为 §2关闭§r. 正在暂停...