Performance and stability improvements

- improved performance of paper generation task
- improved stability of spigot generation task
- Updated Readme
- added configuration parameters for max pending chunks and max loaded chunks
pull/1/head
Trivernis 5 years ago
parent c49036e35b
commit 5a5fe74d9c

@ -22,11 +22,24 @@ All features can be accessed with the command `/chunkmaster` or the aliases `/ch
```yaml
generation:
# The maximum amount of chunks that are loaded before unloading and saving them.
# Higher values mean higher generation speed but greater memory usage.
# The value should be a positive integer.
max-loaded-chunks: 10
# Paper Only
# The maximum amount of requested chunks with the asynchronous paper chunk
# loading method. Higher values mean faster generation but more memory usage
# (and probably bigger performance impact).
# The value should be a positive integer.
max-pending-chunks: 10
# The period (in ticks) in which a generation step is run.
# Higher values mean less performance impact but slower generation.
# The value should be a positive integer.
period: 2
# Paper Only
# The number of already generated chunks that will be skipped for each step.
# Notice that these still have a performance impact because the server needs to check
# if the chunk is generated.
@ -47,4 +60,10 @@ generation:
# process is minimal.
# The value should be a boolean <true/false>
pause-on-join: true
```
```
## Spigot and Paper
The plugin works on spigot and paper servers but is significantly faster on paper servers
(because it profits from asynchronous chunk loading an the better implementation of the
isChunkGenerated method).

@ -56,9 +56,11 @@ class Chunkmaster: JavaPlugin() {
private fun configure() {
dataFolder.mkdir()
config.addDefault("generation.period", 2L)
config.addDefault("generation.chunks-skips-per-step", 4)
config.addDefault("generation.chunks-skips-per-step", 10)
config.addDefault("generation.mspt-pause-threshold", 500L)
config.addDefault("generation.pause-on-join", true)
config.addDefault("generation.max-pending-chunks", 10)
config.addDefault("generation.max-loaded-chunks", 10)
config.options().copyDefaults(true)
saveConfig()
}

@ -1,4 +1,10 @@
package net.trivernis.chunkmaster.lib.generation
data class ChunkCoordinates(val x: Int, val z: Int) {
import org.bukkit.Location
import org.bukkit.World
class ChunkCoordinates(val x: Int, val z: Int) {
fun getCenterLocation(world: World): Location {
return Location(world, ((x*16) + 8).toDouble(), 1.0, ((x*16) + 8).toDouble())
}
}

@ -13,14 +13,15 @@ abstract class GenerationTask(plugin: Chunkmaster, centerChunk: Chunk, startChun
abstract val stopAfter: Int
abstract val world: World
abstract val count: Int
abstract val lastChunk: Chunk
abstract val endReached: Boolean
protected val spiral: Spiral =
Spiral(Pair(centerChunk.x, centerChunk.z), Pair(startChunk.x, startChunk.z))
protected val loadedChunks: HashSet<Chunk> = HashSet()
protected var lastChunkCoords = ChunkCoordinates(startChunk.x, startChunk.z)
protected val chunkSkips = plugin.config.getInt("generation.chunks-skips-per-step")
protected val msptThreshold = plugin.config.getLong("generation.mspt-pause-threshold")
protected val maxLoadedChunks = plugin.config.getInt("generation.max-loaded-chunks")
abstract override fun run()
abstract fun cancel()
@ -30,13 +31,21 @@ abstract class GenerationTask(plugin: Chunkmaster, centerChunk: Chunk, startChun
val nextChunkCoords = spiral.next()
return ChunkCoordinates(nextChunkCoords.first, nextChunkCoords.second)
}
var lastChunk: Chunk = startChunk
get() {
return world.getChunkAt(lastChunkCoords.x, lastChunkCoords.z)
}
private set
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(lastChunk.getBlock(8, 0, 8).location) || (stopAfter in 1..count)
return !world.worldBorder.isInside(lastChunkCoords.getCenterLocation(world)) || (stopAfter in 1..count)
}
}

@ -12,20 +12,15 @@ class GenerationTaskPaper(
override val stopAfter: Int = -1
) : GenerationTask(plugin, centerChunk, startChunk) {
private val maxPendingChunks = plugin.config.getInt("generation.max-pending-chunks")
private val pendingChunks = HashSet<CompletableFuture<Chunk>>()
override var count = 0
private set
override var lastChunk: Chunk = startChunk
get() {
return world.getChunkAt(lastChunkCoords.x, lastChunkCoords.z)
}
private set
override var endReached: Boolean = false
private set
private var lastChunkCoords = ChunkCoordinates(startChunk.x, startChunk.z)
/**
* Runs the generation task. Every Iteration the next chunk will be generated if
* it hasn't been generated already.
@ -33,13 +28,14 @@ class GenerationTaskPaper(
*/
override fun run() {
if (plugin.mspt < msptThreshold) { // pause when tps < 2
if (loadedChunks.size > 10) {
if (loadedChunks.size > maxLoadedChunks) {
for (chunk in loadedChunks) {
if (chunk.isLoaded) {
chunk.unload(true)
}
}
} else if (pendingChunks.size < 10) { // if more than 10 chunks are pending, wait.
loadedChunks.clear()
} else if (pendingChunks.size < maxPendingChunks) { // if more than 10 chunks are pending, wait.
if (borderReached()) {
endReached = true
return

@ -13,8 +13,6 @@ class GenerationTaskSpigot(
override var count = 0
private set
override var lastChunk: Chunk = startChunk
private set
override var endReached: Boolean = false
private set
@ -25,33 +23,27 @@ class GenerationTaskSpigot(
*/
override fun run() {
if (plugin.mspt < msptThreshold) { // pause when tps < 2
if (loadedChunks.size > 10) {
if (loadedChunks.size > maxLoadedChunks) {
for (chunk in loadedChunks) {
if (chunk.isLoaded) {
chunk.unload(true)
}
}
loadedChunks.clear()
} else {
if (borderReached()) {
endReached = true
return
}
var chunk = nextChunk
for (i in 1 until chunkSkips) {
if (world.isChunkGenerated(chunk.x, chunk.z)) {
chunk = nextChunk
} else {
break
}
}
val chunk = nextChunkCoordinates
if (!world.isChunkGenerated(chunk.x, chunk.z)) {
chunk.load(true)
loadedChunks.add(chunk)
val chunkInstance = world.getChunkAt(chunk.x, chunk.z)
chunkInstance.load(true)
loadedChunks.add(chunkInstance)
}
lastChunk = chunk
lastChunkCoords = chunk
count = spiral.count // set the count to the more accurate spiral count
}
}

Loading…
Cancel
Save