summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/defaultimpl
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/io/dico/parcels2/defaultimpl')
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt122
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt12
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt20
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt47
4 files changed, 145 insertions, 56 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) }
}
}
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
index c154955..7755363 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
@@ -47,13 +47,23 @@ class ParcelImpl(override val world: ParcelWorld,
val globalAddedMap: AddedDataMap? get() = owner?.let { world.globalAddedData[it].addedMap }
- override val since: DateTime? get() = data.since
+ override val lastClaimTime: DateTime? get() = data.lastClaimTime
+
+ override var ownerSignOutdated: Boolean
+ get() = data.ownerSignOutdated
+ set(value) {
+ if (data.ownerSignOutdated != value) {
+ world.storage.setParcelOwnerSignOutdated(this, value)
+ data.ownerSignOutdated = value
+ }
+ }
override var owner: PlayerProfile?
get() = data.owner
set(value) {
if (data.owner != value) {
world.storage.setParcelOwner(this, value)
+ world.blockManager.setOwnerBlock(this, value)
data.owner = value
}
}
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt
index 70d428d..0c1dadc 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt
@@ -1,8 +1,11 @@
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
+import kotlinx.coroutines.experimental.Unconfined
+import kotlinx.coroutines.experimental.launch
import org.bukkit.Bukkit
import org.bukkit.WorldCreator
+import org.joda.time.DateTime
class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
inline val options get() = plugin.options
@@ -49,9 +52,24 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
if (parcelWorld != null) continue
val generator: ParcelGenerator = getWorldGenerator(worldName)!!
- val bukkitWorld = Bukkit.getWorld(worldName) ?: WorldCreator(worldName).generator(generator).createWorld()
+ val worldExists = Bukkit.getWorld(worldName) == null
+ val bukkitWorld =
+ if (worldExists) Bukkit.getWorld(worldName)!!
+ else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
+
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
plugin.globalAddedData, ::DefaultParcelContainer, plugin.worktimeLimiter)
+
+ if (!worldExists) {
+ val time = DateTime.now()
+ plugin.storage.setWorldCreationTime(parcelWorld.id, time)
+ parcelWorld.creationTime = time
+ } else {
+ launch(context = Unconfined) {
+ parcelWorld.creationTime = plugin.storage.getWorldCreationTime(parcelWorld.id).await() ?: DateTime.now()
+ }
+ }
+
_worlds[worldName] = parcelWorld
}
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt
index 4a168f5..a54e519 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt
@@ -7,21 +7,21 @@ import io.dico.parcels2.blockvisitor.WorktimeLimiter
import io.dico.parcels2.options.RuntimeWorldOptions
import io.dico.parcels2.storage.Storage
import org.bukkit.World
+import org.joda.time.DateTime
import java.util.UUID
-class ParcelWorldImpl private
-constructor(override val world: World,
- override val generator: ParcelGenerator,
- override var options: RuntimeWorldOptions,
- override val storage: Storage,
- override val globalAddedData: GlobalAddedDataManager,
- containerFactory: ParcelContainerFactory,
- blockManager: ParcelBlockManager)
+class ParcelWorldImpl(override val world: World,
+ override val generator: ParcelGenerator,
+ override var options: RuntimeWorldOptions,
+ override val storage: Storage,
+ override val globalAddedData: GlobalAddedDataManager,
+ containerFactory: ParcelContainerFactory,
+ worktimeLimiter: WorktimeLimiter)
: ParcelWorld,
ParcelWorldId,
- ParcelContainer, // missing delegation
- ParcelLocator, // missing delegation
- ParcelBlockManager by blockManager {
+ ParcelContainer, /* missing delegation */
+ ParcelLocator /* missing delegation */ {
+
override val id: ParcelWorldId get() = this
override val uid: UUID? get() = world.uid
@@ -33,10 +33,14 @@ constructor(override val world: World,
override val name: String = world.name!!
override val container: ParcelContainer = containerFactory(this)
- override val locator: ParcelLocator = generator.makeParcelLocator(container)
- override val blockManager: ParcelBlockManager = blockManager
+ override val locator: ParcelLocator
+ override val blockManager: ParcelBlockManager
init {
+ val pair = generator.makeParcelLocatorAndBlockManager(id, container, worktimeLimiter)
+ locator = pair.first
+ blockManager = pair.second
+
enforceOptions()
}
@@ -55,24 +59,13 @@ constructor(override val world: World,
world.setGameRuleValue("doTileDrops", "${options.doTileDrops}")
}
+ // Updated by ParcelProviderImpl
+ override var creationTime: DateTime? = null
+
/*
Interface delegation needs to be implemented manually because JetBrains has yet to fix it.
*/
- companion object {
- // Use this to be able to delegate blockManager and assign it to a property too, at least.
- operator fun invoke(world: World,
- generator: ParcelGenerator,
- options: RuntimeWorldOptions,
- storage: Storage,
- globalAddedData: GlobalAddedDataManager,
- containerFactory: ParcelContainerFactory,
- worktimeLimiter: WorktimeLimiter): ParcelWorldImpl {
- val blockManager = generator.makeParcelBlockManager(worktimeLimiter)
- return ParcelWorldImpl(world, generator, options, storage, globalAddedData, containerFactory, blockManager)
- }
- }
-
// ParcelLocator interface
override fun getParcelAt(x: Int, z: Int): Parcel? {
return locator.getParcelAt(x, z)