summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt')
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt122
1 files changed, 95 insertions, 27 deletions
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt
index 7e75f52..244d38c 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt
@@ -1,14 +1,13 @@
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
-import io.dico.parcels2.blockvisitor.RegionTraversal
+import io.dico.parcels2.blockvisitor.RegionTraverser
import io.dico.parcels2.blockvisitor.Worker
import io.dico.parcels2.blockvisitor.WorktimeLimiter
import io.dico.parcels2.options.DefaultGeneratorOptions
import io.dico.parcels2.util.*
import org.bukkit.*
import org.bukkit.block.Biome
-import org.bukkit.block.Block
import org.bukkit.block.BlockFace
import org.bukkit.block.Skull
import org.bukkit.block.data.BlockData
@@ -18,11 +17,13 @@ import java.util.Random
private val airType = Bukkit.createBlockData(Material.AIR)
-class DefaultParcelGenerator(val name: String, private val o: DefaultGeneratorOptions) : ParcelGenerator() {
+private const val chunkSize = 16
+
+class DefaultParcelGenerator(override val worldName: String, private val o: DefaultGeneratorOptions) : ParcelGenerator() {
private var _world: World? = null
override val world: World
get() {
- if (_world == null) _world = Bukkit.getWorld(name)!!.also {
+ if (_world == null) _world = Bukkit.getWorld(worldName)!!.also {
maxHeight = it.maxHeight
return it
}
@@ -103,12 +104,10 @@ class DefaultParcelGenerator(val name: String, private val o: DefaultGeneratorOp
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
}
- override fun makeParcelBlockManager(worktimeLimiter: WorktimeLimiter): ParcelBlockManager {
- return ParcelBlockManagerImpl(worktimeLimiter)
- }
-
- override fun makeParcelLocator(container: ParcelContainer): ParcelLocator {
- return ParcelLocatorImpl(container)
+ override fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
+ container: ParcelContainer,
+ worktimeLimiter: WorktimeLimiter): Pair<ParcelLocator, ParcelBlockManager> {
+ return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, worktimeLimiter)
}
private inline fun <T> convertBlockLocationToId(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
@@ -124,22 +123,26 @@ class DefaultParcelGenerator(val name: String, private val o: DefaultGeneratorOp
return null
}
- private inner class ParcelLocatorImpl(val container: ParcelContainer) : ParcelLocator {
+ private inner class ParcelLocatorImpl(val worldId: ParcelWorldId,
+ val container: ParcelContainer) : ParcelLocator {
override val world: World = this@DefaultParcelGenerator.world
+
override fun getParcelAt(x: Int, z: Int): Parcel? {
return convertBlockLocationToId(x, z, container::getParcelById)
}
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
- return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(world.name, world.uid, idx, idz) }
+ return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(worldId, idx, idz) }
}
}
@Suppress("DEPRECATION")
- private inner class ParcelBlockManagerImpl(override val worktimeLimiter: WorktimeLimiter) : ParcelBlockManager {
+ private inner class ParcelBlockManagerImpl(val worldId: ParcelWorldId,
+ override val worktimeLimiter: WorktimeLimiter) : ParcelBlockManagerBase() {
override val world: World = this@DefaultParcelGenerator.world
+ override val parcelTraverser: RegionTraverser = RegionTraverser.upToAndDownUntil(o.floorHeight)
- override fun getBottomBlock(parcel: ParcelId): Vec2i = Vec2i(
+ /*override*/ fun getBottomBlock(parcel: ParcelId): Vec2i = Vec2i(
sectionSize * (parcel.x - 1) + pathOffset + o.offsetX,
sectionSize * (parcel.z - 1) + pathOffset + o.offsetZ
)
@@ -151,6 +154,11 @@ class DefaultParcelGenerator(val name: String, private val o: DefaultGeneratorOp
return Location(world, x + 0.5, o.floorHeight + 1.0, z + 0.5, 0F, 0F)
}
+ override fun getRegion(parcel: ParcelId): Region {
+ val bottom = getBottomBlock(parcel)
+ return Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight + 1, o.parcelSize))
+ }
+
override fun setOwnerBlock(parcel: ParcelId, owner: PlayerProfile?) {
val b = getBottomBlock(parcel)
@@ -203,9 +211,8 @@ class DefaultParcelGenerator(val name: String, private val o: DefaultGeneratorOp
}
override fun clearParcel(parcel: ParcelId): Worker = worktimeLimiter.submit {
- val bottom = getBottomBlock(parcel)
- val region = Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight + 1, o.parcelSize))
- val blocks = RegionTraversal.DOWNWARD.regionTraverser(region)
+ val region = getRegion(parcel)
+ val blocks = parcelTraverser.traverseRegion(region)
val blockCount = region.blockCount.toDouble()
val world = world
@@ -227,17 +234,78 @@ class DefaultParcelGenerator(val name: String, private val o: DefaultGeneratorOp
}
}
- override fun doBlockOperation(parcel: ParcelId, direction: RegionTraversal, operation: (Block) -> Unit): Worker = worktimeLimiter.submit {
- val bottom = getBottomBlock(parcel)
- val region = Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight + 1, o.parcelSize))
- val blocks = direction.regionTraverser(region)
- val blockCount = region.blockCount.toDouble()
- val world = world
+ override fun getParcelsWithOwnerBlockIn(chunk: Chunk): Collection<Vec2i> {
+ /*
+ * Get the offsets for the world out of the way
+ * to simplify the calculation that follows.
+ */
+
+ val x = chunk.x.shl(4) - (o.offsetX + pathOffset)
+ val z = chunk.z.shl(4) - (o.offsetZ + pathOffset)
+
+ /* Locations of wall corners (where owner blocks are placed) are defined as:
+ *
+ * x umod sectionSize == sectionSize-1
+ *
+ * This check needs to be made for all 16 slices of the chunk in 2 dimensions
+ * How to optimize this?
+ * Let's take the expression
+ *
+ * x umod sectionSize
+ *
+ * And call it modX
+ * x can be shifted (chunkSize -1) times to attempt to get a modX of 0.
+ * This means that if the modX is 1, and sectionSize == (chunkSize-1), there would be a match at the last shift.
+ * To check that there are any matches, we can see if the following holds:
+ *
+ * modX >= ((sectionSize-1) - (chunkSize-1))
+ *
+ * Which can be simplified to:
+ * modX >= sectionSize - chunkSize
+ *
+ * if sectionSize == chunkSize, this expression can be simplified to
+ * modX >= 0
+ * which is always true. This is expected.
+ * To get the total number of matches on a dimension, we can evaluate the following:
+ *
+ * (modX - (sectionSize - chunkSize) + sectionSize) / sectionSize
+ *
+ * We add sectionSize to the lhs because, if the other part of the lhs is 0, we need at least 1.
+ * This can be simplified to:
+ *
+ * (modX + chunkSize) / sectionSize
+ */
+
+ val sectionSize = sectionSize
+
+ val modX = x umod sectionSize
+ val matchesOnDimensionX = (modX + chunkSize) / sectionSize
+ if (matchesOnDimensionX <= 0) return emptyList()
+
+ val modZ = z umod sectionSize
+ val matchesOnDimensionZ = (modZ + chunkSize) / sectionSize
+ if (matchesOnDimensionZ <= 0) return emptyList()
+
+ /*
+ * Now we need to find the first id within the matches,
+ * and then return the subsequent matches in a rectangle following it.
+ *
+ * On each dimension, get the distance to the first match, which is equal to (sectionSize-1 - modX)
+ * and add it to the coordinate value
+ */
+ val firstX = x + (sectionSize - 1 - modX)
+ val firstZ = z + (sectionSize - 1 - modZ)
+
+ val firstIdX = (firstX + 1) / sectionSize + 1
+ val firstIdZ = (firstZ + 1) / sectionSize + 1
+
+ if (matchesOnDimensionX == 1 && matchesOnDimensionZ == 1) {
+ // fast-path optimization
+ return listOf(Vec2i(firstIdX, firstIdZ))
+ }
- for ((index, vec) in blocks.withIndex()) {
- markSuspensionPoint()
- operation(world[vec])
- setProgress((index + 1) / blockCount)
+ return (0 until matchesOnDimensionX).flatMap { idOffsetX ->
+ (0 until matchesOnDimensionZ).map { idOffsetZ -> Vec2i(firstIdX + idOffsetX, firstIdZ + idOffsetZ) }
}
}