Work on a couple of the todos
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
for ((index, vec) in blocks.withIndex()) {
|
||||
markSuspensionPoint()
|
||||
operation(world[vec])
|
||||
setProgress((index + 1) / blockCount)
|
||||
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))
|
||||
}
|
||||
|
||||
return (0 until matchesOnDimensionX).flatMap { idOffsetX ->
|
||||
(0 until matchesOnDimensionZ).map { idOffsetZ -> Vec2i(firstIdX + idOffsetX, firstIdZ + idOffsetZ) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user