Working version
parent
9bf9c61b0d
commit
1343dbf249
@ -1,18 +1,63 @@
|
||||
package net.trivernis.chunkmaster
|
||||
|
||||
import net.trivernis.chunkmaster.commands.CommandGenerate
|
||||
import net.trivernis.chunkmaster.lib.GenerationManager
|
||||
import net.trivernis.chunkmaster.lib.Spiral
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import java.lang.Exception
|
||||
import java.sql.Connection
|
||||
import java.sql.DriverManager
|
||||
import kotlin.math.log
|
||||
|
||||
class Chunkmaster: JavaPlugin() {
|
||||
lateinit var sqliteConnection: Connection
|
||||
var dbname: String? = null
|
||||
lateinit var generationManager: GenerationManager
|
||||
|
||||
override fun onEnable() {
|
||||
configure()
|
||||
initDatabase()
|
||||
generationManager = GenerationManager(this, server)
|
||||
generationManager.init()
|
||||
getCommand("generate")?.setExecutor(CommandGenerate(this))
|
||||
server.pluginManager.registerEvents(ChunkmasterEvents(this, server), this)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
|
||||
logger.info("Stopping all generation tasks...")
|
||||
generationManager.stopAll()
|
||||
sqliteConnection.close()
|
||||
}
|
||||
|
||||
private fun configure() {
|
||||
dataFolder.mkdir()
|
||||
config.options().copyDefaults(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the database
|
||||
*/
|
||||
private fun initDatabase() {
|
||||
logger.info("Initializing Database...")
|
||||
try {
|
||||
Class.forName("org.sqlite.JDBC")
|
||||
sqliteConnection = DriverManager.getConnection("jdbc:sqlite:${dataFolder.absolutePath}/chunkmaster.db")
|
||||
logger.info("Database connection established.")
|
||||
val createTableStatement = sqliteConnection.prepareStatement("""
|
||||
CREATE TABLE IF NOT EXISTS generation_tasks (
|
||||
id integer PRIMARY KEY AUTOINCREMENT,
|
||||
center_x integer NOT NULL DEFAULT 0,
|
||||
center_z integer NOT NULL DEFAULT 0,
|
||||
last_x integer NOT NULL DEFAULT 0,
|
||||
last_z integer NOT NULL DEFAULT 0,
|
||||
world text UNIQUE NOT NULL DEFAULT 'world'
|
||||
);
|
||||
""".trimIndent())
|
||||
createTableStatement.execute()
|
||||
createTableStatement.close()
|
||||
logger.info("Database tables created.")
|
||||
} catch(e: Exception) {
|
||||
logger.warning("Failed to init database: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.trivernis.chunkmaster
|
||||
|
||||
import org.bukkit.Server
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
|
||||
class ChunkmasterEvents(private val chunkmaster: Chunkmaster, private val server: Server): Listener {
|
||||
|
||||
/**
|
||||
* Autostart generation tasks
|
||||
*/
|
||||
fun onPlayerQuit(event: PlayerQuitEvent) {
|
||||
if (server.onlinePlayers.size == 1 && server.onlinePlayers.contains(event.player)) {
|
||||
chunkmaster.generationManager.startAll()
|
||||
chunkmaster.logger.info("Server is empty. Starting chunk generation tasks.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Autostop generation tasks
|
||||
*/
|
||||
fun onPlayerJoin(event: PlayerJoinEvent) {
|
||||
if (server.onlinePlayers.size == 1 || server.onlinePlayers.isEmpty()) {
|
||||
chunkmaster.generationManager.stopAll()
|
||||
chunkmaster.logger.info("Stopping generation tasks because of player join.")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
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)) {
|
||||
chunkmaster.generationManager.addTask(sender.world)
|
||||
sender.sendMessage("Added generation task for world \"${sender.world.name}\"")
|
||||
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) {
|
||||
chunkmaster.generationManager.addTask(world)
|
||||
true
|
||||
} else {
|
||||
sender.sendMessage("World \"${args[0]}\" not found")
|
||||
false
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage("You need to specify a world")
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,127 @@
|
||||
package net.trivernis.chunkmaster.lib
|
||||
|
||||
class GenerationManager {
|
||||
//TODO: Implement
|
||||
import javafx.concurrent.Task
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import org.bukkit.Chunk
|
||||
import org.bukkit.Server
|
||||
import org.bukkit.World
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.lang.Exception
|
||||
import java.lang.NullPointerException
|
||||
|
||||
class GenerationManager(private val chunkmaster: Chunkmaster, private val server: Server) {
|
||||
|
||||
private val tasks: HashSet<TaskEntry> = HashSet()
|
||||
|
||||
/**
|
||||
* Adds a generation task
|
||||
*/
|
||||
fun addTask(world: World): Int {
|
||||
val centerChunk = world.getChunkAt(world.spawnLocation)
|
||||
val generationTask = GenerationTask(chunkmaster, world, centerChunk, centerChunk)
|
||||
val task = server.scheduler.runTaskTimer(chunkmaster, generationTask, 10, 2)
|
||||
val insertStatement = chunkmaster.sqliteConnection.prepareStatement("""
|
||||
INSERT INTO generation_tasks (center_x, center_z, last_x, last_z, world)
|
||||
values (?, ?, ?, ?, ?)
|
||||
""")
|
||||
insertStatement.setInt(1, centerChunk.x)
|
||||
insertStatement.setInt(2, centerChunk.z)
|
||||
insertStatement.setInt(3, centerChunk.x)
|
||||
insertStatement.setInt(4, centerChunk.z)
|
||||
insertStatement.setString(5, world.name)
|
||||
insertStatement.execute()
|
||||
val getIdStatement = chunkmaster.sqliteConnection.prepareStatement("""
|
||||
SELECT id FROM generation_tasks ORDER BY id DESC LIMIT 1
|
||||
""".trimIndent())
|
||||
getIdStatement.execute()
|
||||
val result = getIdStatement.resultSet
|
||||
result.next()
|
||||
val id: Int = result.getInt("id")
|
||||
tasks.add(TaskEntry(id, task, generationTask))
|
||||
insertStatement.close()
|
||||
getIdStatement.close()
|
||||
return id
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes a generation task
|
||||
*/
|
||||
fun resumeTask(world: World, center: Chunk, last: Chunk, id: Int) {
|
||||
chunkmaster.logger.info("Resuming chunk generation task for world \"${world.name}\"")
|
||||
val generationTask = GenerationTask(chunkmaster, world, center, last)
|
||||
val task = server.scheduler.runTaskTimer(chunkmaster, generationTask, 10, 2)
|
||||
tasks.add(TaskEntry(id, task, generationTask))
|
||||
}
|
||||
|
||||
/**
|
||||
* Init
|
||||
* Loads tasks from the database and resumes them
|
||||
*/
|
||||
fun init() {
|
||||
chunkmaster.logger.info("Creating task to load chunk generation Tasks later...")
|
||||
server.scheduler.runTaskLater(chunkmaster, Runnable {
|
||||
startAll() // run startAll after 10 seconds
|
||||
}, 200)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all generation tasks
|
||||
*/
|
||||
fun stopAll() {
|
||||
saveProgress()
|
||||
for (task in tasks) {
|
||||
task.generationTask.cancel()
|
||||
task.task.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts all generation tasks.
|
||||
*/
|
||||
fun startAll() {
|
||||
chunkmaster.logger.info("Loading saved chunk generation tasks...")
|
||||
val savedTasksStatement = chunkmaster.sqliteConnection.prepareStatement("SELECT * FROM generation_tasks")
|
||||
savedTasksStatement.execute()
|
||||
val res = savedTasksStatement.resultSet
|
||||
while (res.next()) {
|
||||
try {
|
||||
val id = res.getInt("id")
|
||||
val world = server.getWorld(res.getString("world"))
|
||||
val center = world!!.getChunkAt(res.getInt("center_x"), res.getInt("center_z"))
|
||||
val last = world.getChunkAt(res.getInt("last_x"), res.getInt("last_z"))
|
||||
resumeTask(world, center, last, id)
|
||||
} catch (error: NullPointerException) {
|
||||
server.consoleSender.sendMessage("Failed to load Task ${res.getInt("id")}.")
|
||||
}
|
||||
}
|
||||
savedTasksStatement.close()
|
||||
server.scheduler.runTaskTimer(chunkmaster, Runnable {
|
||||
saveProgress() // save progress every 30 seconds
|
||||
}, 600, 600)
|
||||
chunkmaster.logger.info("${tasks.size} saved tasks loaded.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the task progress
|
||||
*/
|
||||
private fun saveProgress() {
|
||||
for (task in tasks) {
|
||||
try {
|
||||
val genTask = task.generationTask
|
||||
server.consoleSender.sendMessage("Task #${task.id} running for \"${genTask.world.name}\"." +
|
||||
"Progress ${task.generationTask.count} chunks. Last Chunk: ${genTask.lastChunk.x}, ${genTask.lastChunk.z}")
|
||||
val updateStatement = chunkmaster.sqliteConnection.prepareStatement("""
|
||||
UPDATE generation_tasks SET last_x = ?, last_z = ?
|
||||
WHERE id = ?
|
||||
""".trimIndent())
|
||||
updateStatement.setInt(1, genTask.lastChunk.x)
|
||||
updateStatement.setInt(2, genTask.lastChunk.z)
|
||||
updateStatement.setInt(3, task.id)
|
||||
updateStatement.execute()
|
||||
updateStatement.close()
|
||||
} catch (error: Exception) {
|
||||
server.consoleSender.sendMessage("Exception when saving task progress ${error.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package net.trivernis.chunkmaster.lib
|
||||
|
||||
import net.trivernis.chunkmaster.Chunkmaster
|
||||
import org.bukkit.Chunk
|
||||
import org.bukkit.World
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
|
||||
class GenerationTask(private val plugin: Chunkmaster, val world: World,
|
||||
private val centerChunk: Chunk, val startChunk: Chunk): Runnable {
|
||||
private val spiral: Spiral = Spiral(Pair(centerChunk.x, centerChunk.z), Pair(startChunk.x, startChunk.z))
|
||||
private val loadedChunks: HashSet<Chunk> = HashSet()
|
||||
var count = 0
|
||||
get() = field
|
||||
var lastChunk: Chunk = startChunk
|
||||
get() = field
|
||||
|
||||
override fun run() {
|
||||
if (loadedChunks.size > 10) {
|
||||
for (chunk in loadedChunks) {
|
||||
if (chunk.isLoaded) {
|
||||
chunk.unload(true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val nextChunkCoords = spiral.next()
|
||||
val chunk = world.getChunkAt(nextChunkCoords.first, nextChunkCoords.second)
|
||||
|
||||
if (!world.isChunkGenerated(chunk.x, chunk.z)) {
|
||||
chunk.load(true)
|
||||
loadedChunks.add(chunk)
|
||||
}
|
||||
lastChunk = chunk
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
fun cancel() {
|
||||
for (chunk in loadedChunks) {
|
||||
if (chunk.isLoaded) {
|
||||
chunk.unload(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package net.trivernis.chunkmaster.lib
|
||||
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
|
||||
data class TaskEntry(val id: Int, val task: BukkitTask, val generationTask: GenerationTask) {
|
||||
}
|
Loading…
Reference in New Issue