diff --git a/.abstruse.yml b/.abstruse.yml new file mode 100644 index 0000000..657aa34 --- /dev/null +++ b/.abstruse.yml @@ -0,0 +1,13 @@ +image: openjdk + +matrix: + - env: SCRIPT=shadowJar + +install: + - gradle dependencies + +script: + - if [[ "SCRIPT" ]]; then gradle $SCRIPT; fi + +cache: + - .gradle \ No newline at end of file diff --git a/README.md b/README.md index a281f65..12a682e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# chunkmaster +# chunkmaster ![](https://abstruse.trivernis.net/badge/1) This plugin can be used to pre-generate the region of a world around the spawn chunk(s). The generation automatically pauses when a player joins the server (assuming the server was empty before) diff --git a/build.gradle b/build.gradle index 66a32f9..2887247 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ idea { } group "net.trivernis" -version "0.15-beta" +version "0.16-beta" sourceCompatibility = 1.8 @@ -55,7 +55,7 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compileOnly "com.destroystokyo.paper:paper-api:1.14.4-R0.1-SNAPSHOT" compileOnly "org.dynmap:dynmap-api:2.0" - compile group: 'org.xerial', name: 'sqlite-jdbc', version: '3.28.0' + compileOnly group: 'org.xerial', name: 'sqlite-jdbc', version: '3.28.0' compile "io.papermc:paperlib:1.0.2" compile "org.bstats:bstats-bukkit:1.5" } diff --git a/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt b/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt index f1d6db4..285b8d9 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/Chunkmaster.kt @@ -9,7 +9,6 @@ import org.bstats.bukkit.Metrics import org.bukkit.plugin.java.JavaPlugin import org.bukkit.scheduler.BukkitTask import org.dynmap.DynmapAPI -import org.dynmap.DynmapCommonAPI import java.lang.Exception class Chunkmaster: JavaPlugin() { diff --git a/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt b/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt index deaa7c3..baef0b9 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdGenerate.kt @@ -5,7 +5,6 @@ import net.trivernis.chunkmaster.lib.Subcommand import org.bukkit.command.Command import org.bukkit.command.CommandSender import org.bukkit.entity.Player -import kotlin.math.pow class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand { override val name = "generate" @@ -24,16 +23,17 @@ class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand { .map {it.name}.toMutableList() } else if (args.size == 2) { if (args[0].toIntOrNull() != null) { - return units.filter {it.indexOf(args[1]) == 0}.toMutableList() + return shapes.filter {it.indexOf(args[1]) == 0}.toMutableList() } } else if (args.size > 2) { if (args[1].toIntOrNull() != null) { - return units.filter {it.indexOf(args[2]) == 0}.toMutableList() + return shapes.filter {it.indexOf(args[2]) == 0}.toMutableList() } } return emptyList().toMutableList() } - val units = listOf("blockradius", "radius", "diameter") + + val shapes = listOf("circle", "square") /** @@ -41,80 +41,73 @@ class CmdGenerate(private val chunkmaster: Chunkmaster): Subcommand { */ override fun execute(sender: CommandSender, args: List): Boolean { var worldName = "" - var stopAfter = -1 + var blockRadius = -1 + var shape = "square" + if (sender is Player) { - if (args.isNotEmpty()) { - if (args[0].toIntOrNull() != null) { - stopAfter = args[0].toInt() - worldName = sender.world.name - } else { - worldName = args[0] - } - if (args.size > 1) { - if (args[1].toIntOrNull() != null) { - stopAfter = args[1].toInt() - } else if (args[1] in units && args[0].toIntOrNull() != null) { - stopAfter = getStopAfter(stopAfter, args[1]) - } else { - worldName = args[1] - } - } - if (args.size > 2 && args[2] in units && args[1].toIntOrNull() != null) { - stopAfter = getStopAfter(stopAfter, args[2]) - } + worldName = sender.world.name + } + if (args.isEmpty()) { + if (sender is Player) { + return createTask(sender, worldName, blockRadius, shape) } else { - worldName = sender.world.name + sender.sendMessage(chunkmaster.langManager.getLocalized("WORLD_NAME_REQUIRED")) + return false } - } else { - if (args.isNotEmpty()) { - worldName = args[0] - if (args.size > 1) { - if (args[1].toIntOrNull() != null) { - stopAfter = args[1].toInt() - } - } - if (args.size > 2 && args[2] in units) { - stopAfter = getStopAfter(stopAfter, args[2]) - } - } else { + } + if (args[0].toIntOrNull() != null) { + if (sender !is Player) { sender.sendMessage(chunkmaster.langManager.getLocalized("WORLD_NAME_REQUIRED")) return false } + blockRadius = args[0].toInt() + } else { + worldName = args[0] } - return createTask(sender, worldName, stopAfter) - } - /** - * Returns stopAfter for a given unit - */ - private fun getStopAfter(number: Int, unit: String): Int { - if (unit in units) { - return when (unit) { - "radius" -> { - ((number * 2)+1).toDouble().pow(2.0).toInt() - } - "diameter" -> { - number.toDouble().pow(2.0).toInt() - } - "blockradius" -> { - ((number.toDouble()+1)/8).pow(2.0).toInt() - } - else -> number + if (args.size == 1) { + return createTask(sender, worldName, blockRadius, shape) + } + + when { + args[1].toIntOrNull() != null -> blockRadius = args[1].toInt() + args[1] in shapes -> shape = args[1] + else -> { + sender.sendMessage(chunkmaster.langManager.getLocalized("INVALID_ARGUMENT", 2, args[1])) + return false } } - return number + if (args.size == 2) { + return createTask(sender, worldName, blockRadius, shape) + } + if (args[2] in shapes) { + shape = args[2] + } else { + sender.sendMessage(chunkmaster.langManager.getLocalized("INVALID_ARGUMENT", 3, args[2])) + return false + } + + return createTask(sender, worldName, blockRadius, shape) } /** * Creates the task with the given arguments. */ - private fun createTask(sender: CommandSender, worldName: String, stopAfter: Int): Boolean { + private fun createTask(sender: CommandSender, worldName: String, blockRadius: Int, shape: String): Boolean { val world = chunkmaster.server.getWorld(worldName) val allTasks = chunkmaster.generationManager.allTasks return if (world != null && (allTasks.find { it.generationTask.world == world }) == null) { - chunkmaster.generationManager.addTask(world, stopAfter) + chunkmaster.generationManager.addTask(world, if (blockRadius > 0) blockRadius/16 else -1 , shape) sender.sendMessage(chunkmaster.langManager - .getLocalized("TASK_CREATION_SUCCESS", worldName, if (stopAfter > 0) "$stopAfter chunks" else "WorldBorder")) + .getLocalized("TASK_CREATION_SUCCESS", + worldName, + if (blockRadius > 0) { + chunkmaster.langManager.getLocalized("TASK_UNIT_RADIUS", blockRadius) + } else{ + chunkmaster.langManager.getLocalized("TASK_UNIT_WORLDBORDER") + }, + shape + )) true } else if (world == null){ sender.sendMessage(chunkmaster.langManager.getLocalized("WORLD_NOT_FOUND", worldName)); diff --git a/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdList.kt b/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdList.kt index 86f98c3..98472cb 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdList.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/commands/CmdList.kt @@ -1,7 +1,5 @@ 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 net.trivernis.chunkmaster.lib.generation.TaskEntry @@ -50,8 +48,8 @@ class CmdList(private val chunkmaster: Chunkmaster): Subcommand { */ 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) + "%)." + val percentage = if (genTask.radius > 0) + " (%.1f".format(genTask.shape.progress()*100) + "%)." else "" return "\n" + chunkmaster.langManager.getLocalized("TASKS_ENTRY", diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/SqliteManager.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/SqliteManager.kt index 00dcd5b..47419f5 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/SqliteManager.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/SqliteManager.kt @@ -20,7 +20,8 @@ class SqliteManager(private val chunkmaster: Chunkmaster) { 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("stop_after", "integer DEFAULT -1") + Pair("radius", "integer DEFAULT -1"), + Pair("shape", "text NOT NULL DEFAULT 'square'") ) ), Pair( diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/DynmapApiWrapper.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/DynmapApiWrapper.kt new file mode 100644 index 0000000..209cef8 --- /dev/null +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/DynmapApiWrapper.kt @@ -0,0 +1,30 @@ +package net.trivernis.chunkmaster.lib.dynmap + +import org.dynmap.DynmapAPI + +class DynmapApiWrapper(private val dynmapAPI: DynmapAPI) { + + /** + * Returns a marker set by name + */ + fun getMarkerSet(name: String): ExtendedMarkerSet? { + val set = dynmapAPI.markerAPI?.getMarkerSet(name) + return if (set != null) { + ExtendedMarkerSet(set) + } else { + null + } + } + + fun getCreateMarkerSet(id: String, name: String): ExtendedMarkerSet? { + var set = dynmapAPI.markerAPI?.getMarkerSet(id) + if (set == null) { + set = dynmapAPI.markerAPI?.createMarkerSet(id, name, null, true) + } + return if (set != null) { + ExtendedMarkerSet(set) + } else { + null + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/ExtendedMarkerSet.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/ExtendedMarkerSet.kt new file mode 100644 index 0000000..c5dab40 --- /dev/null +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/ExtendedMarkerSet.kt @@ -0,0 +1,95 @@ +package net.trivernis.chunkmaster.lib.dynmap + +import org.bukkit.Location +import org.dynmap.markers.AreaMarker +import org.dynmap.markers.Marker +import org.dynmap.markers.MarkerSet +import org.dynmap.markers.PolyLineMarker + +class ExtendedMarkerSet(private val markerSet: MarkerSet) { + /** + * Creates or updates an area marker depending on if it exists + * @param id - the unique id of the area marker + * @param label - the label that is displayed when clicking on the marker + * @param l1 - the top left corner + * @param l2 - the bottom right corner + */ + fun creUpdateAreMarker(id: String, label: String, l1: Location, l2: Location, style: MarkerStyle?): AreaMarker { + var marker = markerSet.findAreaMarker(id) + + if (marker != null) { + marker.setCornerLocations( + doubleArrayOf(l1.x, l2.x), + doubleArrayOf(l1.z, l2.z) + ) + } else { + marker = markerSet.createAreaMarker( + id, + label, + false, + l1.world.name, + doubleArrayOf(l1.x, l2.x), + doubleArrayOf(l1.z, l2.z), + true + ) + } + if (style != null) { + marker.boostFlag = style.boostFlag + if (style.lineStyle != null) { + marker.setLineStyle(style.lineStyle.weight, style.lineStyle.opacity, style.lineStyle.color) + } + if (style.fillStyle != null) { + marker.setFillStyle(style.fillStyle.opacity, style.fillStyle.color) + } + } + return marker + } + + + fun creUpdatePolyLineMarker(id: String, label: String, edges: List, style: MarkerStyle?): PolyLineMarker? { + var marker = markerSet.findPolyLineMarker(id) + val xList = edges.map { it.x } + val yList = edges.map { it.y } + val zList = edges.map { it.z } + if (marker != null) { + marker.setCornerLocations(xList.toDoubleArray(), yList.toDoubleArray(), zList.toDoubleArray()) + } else { + marker = markerSet.createPolyLineMarker(id, label, false, edges.first().world.name, xList.toDoubleArray(), yList.toDoubleArray(), zList.toDoubleArray(), true) + } + if (style != null) { + if (style.lineStyle != null) { + marker.setLineStyle(style.lineStyle.weight, style.lineStyle.opacity, style.lineStyle.color) + } + } + return marker + } + + /** + * Returns the area marker for an id + * @param id - the id of the marker + */ + fun findAreaMarker(id: String): AreaMarker? { + return markerSet.findAreaMarker(id) + } + + /** + * Returns the polylinemarker for an id + */ + fun findPolyLineMarker(id: String): PolyLineMarker? { + return markerSet.findPolyLineMarker(id) + } + + /** + * Deletes an area marker + * @param id - the id of the marker + */ + fun deleteAreaMarker(id: String) { + val marker = this.findAreaMarker(id) + marker?.deleteMarker() + } + + fun deletePolyLineMarker(id: String) { + val marker = this.findPolyLineMarker(id) + marker?.deleteMarker() + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/FillStyle.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/FillStyle.kt new file mode 100644 index 0000000..5f82a8f --- /dev/null +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/FillStyle.kt @@ -0,0 +1,3 @@ +package net.trivernis.chunkmaster.lib.dynmap + +data class FillStyle(val opacity: Double, val color: Int) \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/LineStyle.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/LineStyle.kt new file mode 100644 index 0000000..4bc467d --- /dev/null +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/LineStyle.kt @@ -0,0 +1,3 @@ +package net.trivernis.chunkmaster.lib.dynmap + +data class LineStyle(val weight: Int, val opacity: Double, val color: Int) \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/MarkerStyle.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/MarkerStyle.kt new file mode 100644 index 0000000..4260002 --- /dev/null +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/dynmap/MarkerStyle.kt @@ -0,0 +1,5 @@ +package net.trivernis.chunkmaster.lib.dynmap + +import org.dynmap.markers.MarkerIcon + +data class MarkerStyle(val icon: MarkerIcon?, val lineStyle: LineStyle?, val fillStyle: FillStyle?, val boostFlag: Boolean = false) \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt index f822620..509d910 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationManager.kt @@ -2,7 +2,8 @@ package net.trivernis.chunkmaster.lib.generation import io.papermc.lib.PaperLib import net.trivernis.chunkmaster.Chunkmaster -import org.bukkit.Chunk +import net.trivernis.chunkmaster.lib.shapes.Circle +import net.trivernis.chunkmaster.lib.shapes.Spiral import org.bukkit.Server import org.bukkit.World @@ -33,7 +34,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server /** * Adds a generation task */ - fun addTask(world: World, stopAfter: Int = -1): Int { + fun addTask(world: World, radius: Int = -1, shape: String = "square"): Int { val foundTask = allTasks.find { it.generationTask.world == world } if (foundTask == null) { val centerChunk = if (worldCenters[world.name] == null) { @@ -42,12 +43,12 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server val center = worldCenters[world.name]!! ChunkCoordinates(center.first, center.second) } - val generationTask = createGenerationTask(world, centerChunk, centerChunk, stopAfter) + val generationTask = createGenerationTask(world, centerChunk, centerChunk, radius, shape) chunkmaster.sqliteManager.executeStatement( """ - INSERT INTO generation_tasks (center_x, center_z, last_x, last_z, world, stop_after) - values (?, ?, ?, ?, ?, ?) + INSERT INTO generation_tasks (center_x, center_z, last_x, last_z, world, radius, shape) + values (?, ?, ?, ?, ?, ?, ?) """, HashMap( mapOf( @@ -56,7 +57,8 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server 3 to centerChunk.x, 4 to centerChunk.z, 5 to world.name, - 6 to stopAfter + 6 to radius, + 7 to shape ) ), null @@ -99,14 +101,15 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server center: ChunkCoordinates, last: ChunkCoordinates, id: Int, - stopAfter: Int = -1, - delay: Long = 200L + radius: Int = -1, + delay: Long = 200L, + shape: String = "square" ) { if (!paused) { chunkmaster.logger.info(chunkmaster.langManager.getLocalized("RESUME_FOR_WORLD", world.name)) - val generationTask = createGenerationTask(world, center, last, stopAfter) + val generationTask = createGenerationTask(world, center, last, radius, shape) val task = server.scheduler.runTaskTimer( - chunkmaster, generationTask, delay, // 10 sec delay + chunkmaster, generationTask, delay, chunkmaster.config.getLong("generation.period") ) tasks.add(RunningTaskEntry(id, task, generationTask)) @@ -161,7 +164,7 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server if (!server.onlinePlayers.isEmpty()) { this.pauseAll() } - }, 600) + }, 20) } /** @@ -197,9 +200,10 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server val world = server.getWorld(res.getString("world")) val center = ChunkCoordinates(res.getInt("center_x"), res.getInt("center_z")) val last = ChunkCoordinates(res.getInt("last_x"), res.getInt("last_z")) - val stopAfter = res.getInt("stop_after") + val radius = res.getInt("radius") + val shape = res.getString("shape") if (this.tasks.find { it.id == id } == null) { - resumeTask(world!!, center, last, id, stopAfter, 200L + count) + resumeTask(world!!, center, last, id, radius, 200L + count, shape) } } catch (error: NullPointerException) { chunkmaster.logger.severe(chunkmaster.langManager.getLocalized("TASK_LOAD_FAILED", res.getInt("id"))) @@ -284,12 +288,10 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server for (task in tasks) { try { val genTask = task.generationTask - val speed = task.generationSpeed!! - val percentage = if (genTask.stopAfter > 0) "(${"%.2f".format( - (genTask.count.toDouble() / genTask.stopAfter.toDouble()) * 100 - )}%)" else "" - val eta = if (genTask.stopAfter > 0 && speed > 0) { - val etaSeconds = (genTask.stopAfter - genTask.count).toDouble()/speed + val (speed, chunkSpeed) = task.generationSpeed + val percentage = if (genTask.radius > 0) "(${"%.2f".format(genTask.shape.progress() * 100)}%)" else "" + val eta = if (genTask.radius > 0 && speed!! > 0) { + val etaSeconds = (genTask.shape.progress())/speed val hours: Int = (etaSeconds/3600).toInt() val minutes: Int = ((etaSeconds % 3600) / 60).toInt() val seconds: Int = (etaSeconds % 60).toInt() @@ -304,10 +306,11 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server genTask.count, percentage, eta, - speed, - genTask.lastChunk.x, - genTask.lastChunk.z)) + chunkSpeed!!, + genTask.lastChunkCoords.x, + genTask.lastChunkCoords.z)) saveProgressToDatabase(genTask.lastChunkCoords, task.id) + genTask.updateLastChunkMarker() } catch (error: Exception) { chunkmaster.logger.warning(chunkmaster.langManager.getLocalized("TASK_SAVE_FAILED", error.toString())) } @@ -336,12 +339,19 @@ class GenerationManager(private val chunkmaster: Chunkmaster, private val server world: World, center: ChunkCoordinates, start: ChunkCoordinates, - stopAfter: Int + radius: Int, + shapeName: String ): GenerationTask { + val shape = when (shapeName) { + "circle" -> Circle(Pair(center.x, center.z), Pair(center.x, center.z), radius) + "square" -> Spiral(Pair(center.x, center.z), Pair(center.x, center.z), radius) + else -> Spiral(Pair(center.x, center.z), Pair(center.x, center.z), radius) + } + return if (PaperLib.isPaper()) { - GenerationTaskPaper(chunkmaster, world, center, start, stopAfter) + GenerationTaskPaper(chunkmaster, world, start, radius, shape) } else { - GenerationTaskSpigot(chunkmaster, world, center, start, stopAfter) + GenerationTaskSpigot(chunkmaster, world, start, radius, shape) } } } \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt index 8436a92..539a8da 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTask.kt @@ -1,25 +1,26 @@ package net.trivernis.chunkmaster.lib.generation import net.trivernis.chunkmaster.Chunkmaster -import net.trivernis.chunkmaster.lib.Spiral +import net.trivernis.chunkmaster.lib.dynmap.* +import net.trivernis.chunkmaster.lib.shapes.Shape import org.bukkit.Chunk -import org.bukkit.Location import org.bukkit.World -import kotlin.math.* /** * Interface for generation tasks. */ -abstract class GenerationTask(plugin: Chunkmaster, private val centerChunk: ChunkCoordinates, startChunk: ChunkCoordinates) : +abstract class GenerationTask( + plugin: Chunkmaster, + startChunk: ChunkCoordinates, + val shape: Shape +) : Runnable { - abstract val stopAfter: Int + abstract val radius: Int abstract val world: World - abstract val count: Int + abstract var count: Int abstract var endReached: Boolean - protected val spiral: Spiral = - Spiral(Pair(centerChunk.x, centerChunk.z), Pair(startChunk.x, startChunk.z)) protected val loadedChunks: HashSet = HashSet() var lastChunkCoords = ChunkCoordinates(startChunk.x, startChunk.z) protected set @@ -27,13 +28,22 @@ abstract class GenerationTask(plugin: Chunkmaster, private val centerChunk: Chun protected val msptThreshold = plugin.config.getLong("generation.mspt-pause-threshold") protected val maxLoadedChunks = plugin.config.getInt("generation.max-loaded-chunks") protected val chunksPerStep = plugin.config.getInt("generation.chunks-per-step") - protected val dynmapIntegration = plugin.config.getBoolean("dynmap") - protected val dynmap = plugin.dynmapApi - protected var endReachedCallback: ((GenerationTask) -> Unit)? = null - private set - private val markerId = "chunkmaster_genarea" - private val markerName = "Chunkmaster Generation Area" + private var endReachedCallback: ((GenerationTask) -> Unit)? = null + + private val dynmapIntegration = plugin.config.getBoolean("dynmap") + private val dynmap = plugin.dynmapApi + private val markerSet: ExtendedMarkerSet? = if (dynmap != null) { + DynmapApiWrapper(dynmap).getCreateMarkerSet("chunkmaster", "Chunkmaster") + } else { + null + } + private val markerAreaStyle = MarkerStyle(null, LineStyle(2, 1.0, 0x0022FF), FillStyle(.0, 0)) + private val markerAreaId = "chunkmaster_genarea" + private val markerAreaName = "Chunkmaster Generation Area" + private val markerLastStyle = MarkerStyle(null, LineStyle(2, 1.0, 0x0077FF), FillStyle(.5, 0x0077FF)) + private val markerLastId = "chunkmaster_lastchunk" + private val markerLastName = "Chunkmaster Last Chunk" private val ignoreWorldborder = plugin.config.getBoolean("generation.ignore-worldborder") abstract override fun run() @@ -41,27 +51,16 @@ abstract class GenerationTask(plugin: Chunkmaster, private val centerChunk: Chun val nextChunkCoordinates: ChunkCoordinates get() { - val nextChunkCoords = spiral.next() + val nextChunkCoords = shape.next() return ChunkCoordinates(nextChunkCoords.first, nextChunkCoords.second) } - val lastChunk: Chunk - get() { - return world.getChunkAt(lastChunkCoords.x, lastChunkCoords.z) - } - - val nextChunk: Chunk - get() { - val next = nextChunkCoordinates - return world.getChunkAt(next.x, next.z) - } - /** * Checks if the World border or the maximum chunk setting for the task is reached. */ protected fun borderReached(): Boolean { return (!world.worldBorder.isInside(lastChunkCoords.getCenterLocation(world)) && !ignoreWorldborder) - || (stopAfter in 1..count) + || shape.endReached() } /** @@ -83,56 +82,57 @@ abstract class GenerationTask(plugin: Chunkmaster, private val centerChunk: Chun /** * Updates the dynmap marker for the generation radius */ - protected fun updateDynmapMarker(clear: Boolean = false) { - val markerSet = dynmap?.markerAPI?.getMarkerSet("markers") - var marker = markerSet?.findAreaMarker(markerId) + protected fun updateGenerationAreaMarker(clear: Boolean = false) { if (clear) { - marker?.deleteMarker() - } else if (dynmapIntegration && stopAfter > 0) { - val (topLeft, bottomRight) = this.getAreaCorners() - if (marker != null) { - marker.setCornerLocations( - doubleArrayOf((topLeft.x * 16).toDouble(), (bottomRight.x * 16).toDouble()), - doubleArrayOf((topLeft.z * 16).toDouble(), (bottomRight.z * 16).toDouble()) - ) - } else { - marker = markerSet?.createAreaMarker( - markerId, - markerName, - false, - world.name, - doubleArrayOf((topLeft.x * 16).toDouble(), (bottomRight.x * 16).toDouble()), - doubleArrayOf((topLeft.z * 16).toDouble(), (bottomRight.z * 16).toDouble()), - true - ) - } - marker?.setFillStyle(.0, 0) - marker?.setLineStyle(2, 1.0, 0x0000FF) + markerSet?.deletePolyLineMarker(markerAreaId) + } else if (dynmapIntegration && radius > 0) { + markerSet?.creUpdatePolyLineMarker( + markerAreaId, + markerAreaName, + this.shape.getShapeEdgeLocations().map { ChunkCoordinates(it.first, it.second).getCenterLocation(this.world) }, + markerAreaStyle + ) } } /** - * Returns an approximation of cornders of the generation area + * Updates the dynmap marker for the generation radius */ - protected fun getAreaCorners(): Pair { - val width = sqrt(stopAfter.toFloat()) - return Pair( - ChunkCoordinates(centerChunk.x - floor(width/2).toInt(), centerChunk.z - floor(width/2).toInt()), - ChunkCoordinates(centerChunk.x + ceil(width/2).toInt(), centerChunk.z + ceil(width/2).toInt()) - ) + fun updateLastChunkMarker(clear: Boolean = false) { + if (clear) { + markerSet?.deleteAreaMarker(markerLastId) + } else if (dynmapIntegration) { + markerSet?.creUpdateAreMarker( + markerLastId, + markerLastName, + this.lastChunkCoords.getCenterLocation(world).chunk.getBlock(0, 0, 0).location, + this.lastChunkCoords.getCenterLocation(world).chunk.getBlock(15, 0, 15).location, + markerLastStyle + ) + } } /** * Handles the invocation of the end reached callback and additional logic */ - protected fun setEndReached() { + private fun setEndReached() { endReached = true + count = shape.count endReachedCallback?.invoke(this) - updateDynmapMarker(true) - if (dynmapIntegration) { - val (topLeft, bottomRight) = this.getAreaCorners() - dynmap?.triggerRenderOfVolume(topLeft.getCenterLocation(world), bottomRight.getCenterLocation(world)) + updateGenerationAreaMarker(true) + updateLastChunkMarker(true) + } + + /** + * Performs a check if the border has been reached + */ + protected fun borderReachedCheck(): Boolean { + val done = borderReached() + if (done) { + unloadLoadedChunks() + setEndReached() } + return done } /** diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskPaper.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskPaper.kt index a8e20bc..5e8d92f 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskPaper.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskPaper.kt @@ -1,45 +1,44 @@ package net.trivernis.chunkmaster.lib.generation import net.trivernis.chunkmaster.Chunkmaster +import net.trivernis.chunkmaster.lib.shapes.Shape import org.bukkit.Chunk import org.bukkit.World import java.util.concurrent.CompletableFuture class GenerationTaskPaper( - private val plugin: Chunkmaster, override val world: World, - centerChunk: ChunkCoordinates, private val startChunk: ChunkCoordinates, - override val stopAfter: Int = -1 -) : GenerationTask(plugin, centerChunk, startChunk) { + private val plugin: Chunkmaster, + override val world: World, + startChunk: ChunkCoordinates, + override val radius: Int = -1, + shape: Shape +) : GenerationTask(plugin, startChunk, shape) { private val maxPendingChunks = plugin.config.getInt("generation.max-pending-chunks") private val pendingChunks = HashSet>() override var count = 0 - private set override var endReached: Boolean = false init { - updateDynmapMarker() + updateGenerationAreaMarker() } /** - * Runs the generation task. Every Iteration the next chunk will be generated if - * it hasn't been generated already. - * After 10 chunks have been generated, they will all be unloaded and saved. + * Runs the generation task. Every Iteration the next chunks will be generated if + * they haven't been generated already + * After a configured number of chunks chunks have been generated, they will all be unloaded and saved. */ override fun run() { - if (plugin.mspt < msptThreshold) { // pause when tps < 2 + if (plugin.mspt < msptThreshold) { if (loadedChunks.size > maxLoadedChunks) { unloadLoadedChunks() - } else if (pendingChunks.size < maxPendingChunks) { // if more than 10 chunks are pending, wait. - if (borderReached()) { - setEndReached() - return - } + } else if (pendingChunks.size < maxPendingChunks) { + if (borderReachedCheck()) return var chunk = nextChunkCoordinates - for (i in 1 until chunkSkips) { + for (i in 0 until chunkSkips) { if (world.isChunkGenerated(chunk.x, chunk.z)) { chunk = nextChunkCoordinates } else { @@ -48,7 +47,8 @@ class GenerationTaskPaper( } if (!world.isChunkGenerated(chunk.x, chunk.z)) { - for (i in 0 until minOf(chunksPerStep, (stopAfter - count) - 1)) { + for (i in 0 until chunksPerStep) { + if (borderReached()) break if (!world.isChunkGenerated(chunk.x, chunk.z)) { pendingChunks.add(world.getChunkAtAsync(chunk.x, chunk.z, true)) } @@ -59,7 +59,7 @@ class GenerationTaskPaper( } } lastChunkCoords = chunk - count = spiral.count // set the count to the more accurate spiral count + count = shape.count } } checkChunksLoaded() @@ -70,7 +70,8 @@ class GenerationTaskPaper( * This unloads all chunks that were generated but not unloaded yet. */ override fun cancel() { - updateDynmapMarker(true) + updateGenerationAreaMarker(true) + updateLastChunkMarker(true) unloadAllChunks() } diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskSpigot.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskSpigot.kt index bf5a36f..5dfbd10 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskSpigot.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/GenerationTaskSpigot.kt @@ -1,54 +1,52 @@ package net.trivernis.chunkmaster.lib.generation import net.trivernis.chunkmaster.Chunkmaster +import net.trivernis.chunkmaster.lib.shapes.Shape import org.bukkit.World import java.lang.Exception class GenerationTaskSpigot( - private val plugin: Chunkmaster, override val world: World, - centerChunk: ChunkCoordinates, private val startChunk: ChunkCoordinates, - override val stopAfter: Int = -1 -) : GenerationTask(plugin, centerChunk, startChunk) { + private val plugin: Chunkmaster, + override val world: World, + startChunk: ChunkCoordinates, + override val radius: Int = -1, + shape: Shape +) : GenerationTask(plugin, startChunk, shape) { override var count = 0 - private set override var endReached: Boolean = false init { - updateDynmapMarker() + updateGenerationAreaMarker() } /** - * Runs the generation task. Every Iteration the next chunk will be generated if - * it hasn't been generated already. - * After 10 chunks have been generated, they will all be unloaded and saved. + * Runs the generation task. Every Iteration the next chunks will be generated if + * they haven't been generated already + * After a configured number of chunks chunks have been generated, they will all be unloaded and saved. */ override fun run() { - if (plugin.mspt < msptThreshold) { // pause when tps < 2 + if (plugin.mspt < msptThreshold) { if (loadedChunks.size > maxLoadedChunks) { unloadLoadedChunks() } else { - if (borderReached()) { - setEndReached() - return - } + if (borderReachedCheck()) return var chunk = nextChunkCoordinates - - if (!world.isChunkGenerated(chunk.x, chunk.z)) { - for (i in 0 until minOf(chunksPerStep, stopAfter - count)) { - val chunkInstance = world.getChunkAt(chunk.x, chunk.z) - chunkInstance.load(true) - loadedChunks.add(chunkInstance) - chunk = nextChunkCoordinates - } + for (i in 0 until chunksPerStep) { + if (borderReached()) break val chunkInstance = world.getChunkAt(chunk.x, chunk.z) chunkInstance.load(true) loadedChunks.add(chunkInstance) + chunk = nextChunkCoordinates } + val chunkInstance = world.getChunkAt(chunk.x, chunk.z) + chunkInstance.load(true) + loadedChunks.add(chunkInstance) + lastChunkCoords = chunk - count = spiral.count // set the count to the more accurate spiral count + count = shape.count } } } @@ -67,6 +65,7 @@ class GenerationTaskSpigot( } } } - updateDynmapMarker(true) + updateGenerationAreaMarker(true) + updateLastChunkMarker(true) } } \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/RunningTaskEntry.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/RunningTaskEntry.kt index a5f35c0..d28d8bb 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/RunningTaskEntry.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/generation/RunningTaskEntry.kt @@ -8,25 +8,34 @@ class RunningTaskEntry( override val generationTask: GenerationTask ) : TaskEntry { - private var lastProgress: Pair? = null + private var lastProgress: Pair? = null + private var lastChunkCount: Pair? = null /** * Returns the generation Speed */ - val generationSpeed: Double? + val generationSpeed: Pair get() { var generationSpeed: Double? = null + var chunkGenerationSpeed: Double? = null if (lastProgress != null) { - val chunkDiff = generationTask.count - lastProgress!!.second + val progressDiff = generationTask.shape.progress() - lastProgress!!.second val timeDiff = (System.currentTimeMillis() - lastProgress!!.first).toDouble()/1000 - generationSpeed = chunkDiff.toDouble()/timeDiff + generationSpeed = progressDiff/timeDiff } - lastProgress = Pair(System.currentTimeMillis(), generationTask.count) - return generationSpeed + 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.count) + lastProgress = Pair(System.currentTimeMillis(), generationTask.shape.progress()) + lastChunkCount = Pair(System.currentTimeMillis(), generationTask.count) } diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Circle.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Circle.kt new file mode 100644 index 0000000..be03db5 --- /dev/null +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Circle.kt @@ -0,0 +1,130 @@ +package net.trivernis.chunkmaster.lib.shapes + +import net.trivernis.chunkmaster.lib.dynmap.ExtendedMarkerSet +import net.trivernis.chunkmaster.lib.dynmap.MarkerStyle +import java.util.* +import kotlin.collections.ArrayList +import kotlin.collections.HashSet +import kotlin.math.PI +import kotlin.math.pow +import kotlin.math.sqrt +import kotlin.system.exitProcess + +class Circle(center: Pair, start: Pair, radius: Int): Shape(center, start, radius) { + private var r = 0 + private var coords = Stack>() + private var previousCoords = HashSet>() + + override fun endReached(): Boolean { + if ((radius + 1) in 1..r) return true + return radius > 0 && coords.isEmpty() && r >= radius + } + + override fun progress(): Double { + return (PI * r.toFloat().pow(2))/(PI* radius.toFloat().pow(2)) + } + + override fun currentRadius(): Int { + return r + } + + /** + * Returns the edge locations of the shape to be used + * with dynmap markers + */ + override fun getShapeEdgeLocations(): List> { + val locations = this.getCircleCoordinates(this.radius) + locations.add(locations.first()) + return locations.map{ Pair(it.first + center.first, it.second + center.second) } + } + + /** + * Returns the next coordinate of the circle until the end is reached + */ + override fun next(): Pair { + if (endReached()) { + return currentPos + } + if (count == 0 && currentPos != center) { + val tmpCircle = Circle(center, center, radius) + while (tmpCircle.next() != currentPos); + this.count = tmpCircle.count + this.r = tmpCircle.r + } + if (count == 0) { + count++ + return center + } + if (coords.isEmpty()) { + r++ + val tmpCoords = HashSet>() + tmpCoords.addAll(getCircleCoordinates((r*2)-1).map { Pair(it.first / 2, it.second / 2) }) + tmpCoords.addAll(getCircleCoordinates(r)) + tmpCoords.removeAll(previousCoords) + previousCoords.clear() + coords.addAll(tmpCoords) + previousCoords.addAll(tmpCoords) + } + count++ + val coord = coords.pop() + currentPos = Pair(coord.first + center.first, coord.second + center.second) + return currentPos + } + + /** + * Returns the int coordinates for a circle + * Some coordinates might already be present in the list + * @param r - the radius + */ + private fun getCircleCoordinates(r: Int): ArrayList> { + val coords = ArrayList>() + val segCoords = getSegment(r) + coords.addAll(segCoords.reversed()) + for (step in 1..7) { + val tmpSeg = ArrayList>() + for (pos in segCoords) { + val coord = when (step) { + 1 -> Pair(pos.first, -pos.second) + 2 ->Pair(pos.second, -pos.first) + 3 -> Pair(-pos.second, -pos.first) + 4 -> Pair(-pos.first, -pos.second) + 5 -> Pair(-pos.first, pos.second) + 6 -> Pair(-pos.second, pos.first) + 7 -> Pair(pos.second, pos.first) + else -> pos + } + if (coord !in coords) { + tmpSeg.add(coord) + } + } + if (step % 2 == 0) { + coords.addAll(tmpSeg.reversed()) + } else { + coords.addAll(tmpSeg) + } + } + + return coords + } + + /** + * Returns the int coordinates for a circles segment + * @param r - the radius + */ + private fun getSegment(r: Int): ArrayList> { + var d = -r + var x = r + var y = 0 + val coords = ArrayList>() + while (y <= x) { + coords.add(Pair(x, y)) + d += 2 * y + 1 + y += 1 + if (d > 0) { + x -= 1 + d -= 2 * x + } + } + return coords + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Shape.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Shape.kt new file mode 100644 index 0000000..22d3902 --- /dev/null +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Shape.kt @@ -0,0 +1,37 @@ +package net.trivernis.chunkmaster.lib.shapes + +import net.trivernis.chunkmaster.lib.dynmap.ExtendedMarkerSet +import net.trivernis.chunkmaster.lib.dynmap.MarkerStyle +import javax.xml.stream.Location + +abstract class Shape(protected val center: Pair, start: Pair, radius: Int) { + protected var currentPos = start + protected var radius = radius + private set + var count = 0 + + /** + * Returns the next value + */ + abstract fun next(): Pair + + /** + * If the shape can provide a next value + */ + abstract fun endReached(): Boolean + + /** + * Returns the progress of the shape + */ + abstract fun progress(): Double + + /** + * Returns the current radius + */ + abstract fun currentRadius(): Int + + /** + * returns a poly marker for the shape + */ + abstract fun getShapeEdgeLocations(): List> +} \ No newline at end of file diff --git a/src/main/kotlin/net/trivernis/chunkmaster/lib/Spiral.kt b/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Spiral.kt similarity index 54% rename from src/main/kotlin/net/trivernis/chunkmaster/lib/Spiral.kt rename to src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Spiral.kt index 15b063f..75ee564 100644 --- a/src/main/kotlin/net/trivernis/chunkmaster/lib/Spiral.kt +++ b/src/main/kotlin/net/trivernis/chunkmaster/lib/shapes/Spiral.kt @@ -1,20 +1,34 @@ -package net.trivernis.chunkmaster.lib +package net.trivernis.chunkmaster.lib.shapes +import kotlin.math.PI import kotlin.math.abs +import kotlin.math.pow +import kotlin.math.sqrt -class Spiral(private val center: Pair, start: Pair) { - private var currentPos = start +class Spiral(center: Pair, start: Pair, radius: Int): Shape(center, start, radius) { private var direction = 0 - var count = 0 + + override fun endReached(): Boolean { + val distances = getDistances(center, currentPos) + return radius > 0 && (distances.first > radius || distances.second > radius) + } + + override fun progress(): Double { + return (currentRadius()*2).toDouble().pow(2) / (radius * 2).toDouble().pow(2) + } + + override fun currentRadius(): Int { + val distances = getDistances(center, currentPos) + return distances.first.coerceAtLeast(distances.second) + } /** * Returns the next value in the spiral */ - fun next(): Pair { + override fun next(): Pair { if (count == 0 && currentPos != center) { - // simulate the spiral to get the correct direction - // TODO: Improve performance of this workaround (replace it with acutal stuff) - val simSpiral = Spiral(center, center) + // simulate the spiral to get the correct direction and count + val simSpiral = Spiral(center, center, radius) while (simSpiral.next() != currentPos); direction = simSpiral.direction count = simSpiral.count @@ -55,6 +69,17 @@ class Spiral(private val center: Pair, start: Pair) { return currentPos } + /** + * Returns the edges to be used with dynmap markers + */ + override fun getShapeEdgeLocations(): List> { + val a = Pair(this.radius + center.first, this.radius + center.second) + val b = Pair(this.radius + center.first, -this.radius + center.second) + val c = Pair(-this.radius + center.first, -this.radius + center.second) + val d = Pair(-this.radius + center.first, this.radius + center.second) + return listOf(a, b, c, d, a) + } + /** * Returns the distances between 2 coordinates */ diff --git a/src/main/resources/i18n/DEFAULT.i18n.properties b/src/main/resources/i18n/DEFAULT.i18n.properties index fac0f79..3b9bb3c 100644 --- a/src/main/resources/i18n/DEFAULT.i18n.properties +++ b/src/main/resources/i18n/DEFAULT.i18n.properties @@ -11,8 +11,11 @@ TASK_SAVE_FAILED = §cException when saving tasks: %s WORLD_NAME_REQUIRED = §cYou need to provide a world name! WORLD_NOT_FOUND = §cWorld §2%s §cnot found! TASK_ALREADY_EXISTS = §cA task for '%s' already exists! -TASK_CREATION_SUCCESS = §9Generation Task for world §2%s §9 until §2%s §9successfully created! +TASK_CREATION_SUCCESS = §9Generation Task for world §2%s§9 §2%s§9 and shape %s successfully created! +TASK_UNIT_WORLDBORDER = until world border +TASK_UNIT_RADIUS = with a radius of %s TASK_ID_REQUIRED = §cYou need to provide a task id! +INVALID_ARGUMENT = §cInvalid argument at %s: %s! PAUSED_TASKS_HEADER = Currently Paused Generation Tasks TASKS_ENTRY = - §9#%d§r - §2%s§r - §2%d chunks %s§r diff --git a/src/main/resources/i18n/de.i18n.properties b/src/main/resources/i18n/de.i18n.properties index 1307e88..e30787d 100644 --- a/src/main/resources/i18n/de.i18n.properties +++ b/src/main/resources/i18n/de.i18n.properties @@ -11,8 +11,11 @@ TASK_SAVE_FAILED = §cFehler beim Speichern der Aufgaben: %s WORLD_NAME_REQUIRED = §cDu musst einen Weltennamen angeben! WORLD_NOT_FOUND = §c Die Welt §2%s §cwurde nicht gefunden! TASK_ALREADY_EXISTS = §cEs existiert bereits eine Aufgabe für §2%s§c! -TASK_CREATION_SUCCESS = §9Generierungs-Aufgabe §2%s §9 bis §2%s §9wurde erfolgreich erstellt! +TASK_CREATION_SUCCESS = §9Generierungs-Aufgabe §2%s§9 §2%s§9 in der Form %s wurde erfolgreich erstellt! +TASK_UNIT_WORLDBORDER = bis zur World-Border +TASK_UNIT_RADIUS = mit einem Radius von %s TASK_ID_REQUIRED = §cDu musst eine Aufgaben-Id angeben! +INVALID_ARGUMENT = §cFalscher Parameter an Stelle %s: %s! PAUSED_TASKS_HEADER = §lPausierte Generierungsaufgaben§r diff --git a/src/main/resources/i18n/en.i18n.properties b/src/main/resources/i18n/en.i18n.properties index fac0f79..3b9bb3c 100644 --- a/src/main/resources/i18n/en.i18n.properties +++ b/src/main/resources/i18n/en.i18n.properties @@ -11,8 +11,11 @@ TASK_SAVE_FAILED = §cException when saving tasks: %s WORLD_NAME_REQUIRED = §cYou need to provide a world name! WORLD_NOT_FOUND = §cWorld §2%s §cnot found! TASK_ALREADY_EXISTS = §cA task for '%s' already exists! -TASK_CREATION_SUCCESS = §9Generation Task for world §2%s §9 until §2%s §9successfully created! +TASK_CREATION_SUCCESS = §9Generation Task for world §2%s§9 §2%s§9 and shape %s successfully created! +TASK_UNIT_WORLDBORDER = until world border +TASK_UNIT_RADIUS = with a radius of %s TASK_ID_REQUIRED = §cYou need to provide a task id! +INVALID_ARGUMENT = §cInvalid argument at %s: %s! PAUSED_TASKS_HEADER = Currently Paused Generation Tasks TASKS_ENTRY = - §9#%d§r - §2%s§r - §2%d chunks %s§r diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8bf099a..15dbfb0 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ main: net.trivernis.chunkmaster.Chunkmaster name: Chunkmaster -version: '0.15-beta' +version: '0.16-beta' description: Chunk commands plugin. author: Trivernis website: trivernis.net @@ -13,7 +13,7 @@ commands: description: Main command permission: chunkmaster.chunkmaster usage: | - / generate [, ] - generates chunks starting from the spawn until the chunk-count is reached + / generate [] [] - generates chunks starting from the spawn until the chunk-count is reached / cancel - cancels the generation task with the task-id / list - lists all running and paused generation tasks / pause - pauses all generation tasks