Archived
0

10/10 commit messages btw

This commit is contained in:
Dico
2018-09-28 21:16:14 +01:00
parent bb6ae7d370
commit 67cb73e4c7
31 changed files with 602 additions and 352 deletions

View File

@@ -64,7 +64,7 @@ class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
}
}
fun allParcels(): Sequence<Parcel> = sequence {
fun getAllParcels(): Iterator<Parcel> = iterator {
for (array in parcels) {
yieldAll(array.iterator())
}

View File

@@ -1,22 +1,14 @@
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.blockvisitor.*
import io.dico.parcels2.blockvisitor.RegionTraverser
import io.dico.parcels2.options.DefaultGeneratorOptions
import io.dico.parcels2.util.math.Region
import io.dico.parcels2.util.math.Vec2i
import io.dico.parcels2.util.math.Vec3i
import io.dico.parcels2.util.math.even
import io.dico.parcels2.util.math.umod
import io.dico.parcels2.util.math.get
import io.dico.parcels2.util.math.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
import kotlinx.coroutines.launch
import org.bukkit.*
import org.bukkit.block.Biome
import org.bukkit.block.BlockFace
import org.bukkit.block.Skull
import org.bukkit.block.data.BlockData
import org.bukkit.block.data.type.Slab
import org.bukkit.block.data.type.WallSign
import java.util.Random
@@ -118,12 +110,13 @@ class DefaultParcelGenerator(
}
override fun makeParcelLocatorAndBlockManager(
worldId: ParcelWorldId,
parcelProvider: ParcelProvider,
container: ParcelContainer,
coroutineScope: CoroutineScope,
jobDispatcher: JobDispatcher
): Pair<ParcelLocator, ParcelBlockManager> {
return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, coroutineScope, jobDispatcher)
val impl = ParcelLocatorAndBlockManagerImpl(parcelProvider, container, coroutineScope, jobDispatcher)
return impl to impl
}
private inline fun <T> convertBlockLocationToId(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
@@ -139,11 +132,25 @@ class DefaultParcelGenerator(
return null
}
private inner class ParcelLocatorImpl(
val worldId: ParcelWorldId,
val container: ParcelContainer
) : ParcelLocator {
override val world: World = this@DefaultParcelGenerator.world
@Suppress("DEPRECATION")
private inner class ParcelLocatorAndBlockManagerImpl(
val parcelProvider: ParcelProvider,
val container: ParcelContainer,
coroutineScope: CoroutineScope,
override val jobDispatcher: JobDispatcher
) : ParcelBlockManagerBase(), ParcelLocator, CoroutineScope by coroutineScope {
override val world: World get() = this@DefaultParcelGenerator.world
val worldId = parcelProvider.getWorld(world)?.id ?: ParcelWorldId(world)
override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight)
private val cornerWallType = when {
o.wallType is Slab -> (o.wallType.clone() as Slab).apply { type = Slab.Type.DOUBLE }
o.wallType.material.name.endsWith("CARPET") -> {
Bukkit.createBlockData(Material.getMaterial(o.wallType.material.name.substringBefore("CARPET") + "WOOL"))
}
else -> null
}
override fun getParcelAt(x: Int, z: Int): Parcel? {
return convertBlockLocationToId(x, z, container::getParcelById)
@@ -152,112 +159,113 @@ class DefaultParcelGenerator(
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(worldId, idx, idz) }
}
}
@Suppress("DEPRECATION")
private inner class ParcelBlockManagerImpl(
val worldId: ParcelWorldId,
coroutineScope: CoroutineScope,
override val jobDispatcher: JobDispatcher
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
override val world: World = this@DefaultParcelGenerator.world
override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight)
/*override*/ fun getBottomBlock(parcel: ParcelId): Vec2i = Vec2i(
sectionSize * (parcel.x - 1) + pathOffset + o.offsetX,
sectionSize * (parcel.z - 1) + pathOffset + o.offsetZ
)
private fun checkParcelId(parcel: ParcelId): ParcelId {
if (!parcel.worldId.equals(worldId)) {
throw IllegalArgumentException()
}
return parcel
}
override fun getHomeLocation(parcel: ParcelId): Location {
val bottom = getBottomBlock(parcel)
val x = bottom.x + (o.parcelSize - 1) / 2.0
val z = bottom.z - 2
return Location(world, x + 0.5, o.floorHeight + 1.0, z + 0.5, 0F, 0F)
override fun getRegionOrigin(parcel: ParcelId): Vec2i {
checkParcelId(parcel)
return Vec2i(
sectionSize * (parcel.x - 1) + pathOffset + o.offsetX,
sectionSize * (parcel.z - 1) + pathOffset + o.offsetZ
)
}
override fun getRegion(parcel: ParcelId): Region {
val bottom = getBottomBlock(parcel)
val origin = getRegionOrigin(parcel)
return Region(
Vec3i(bottom.x, 0, bottom.z),
Vec3i(origin.x, 0, origin.z),
Vec3i(o.parcelSize, maxHeight, o.parcelSize)
)
}
private fun getRegionConsideringWorld(parcel: ParcelId): Region {
if (parcel.worldId != worldId) {
(parcel.worldId as? ParcelWorld)?.let {
return it.blockManager.getRegion(parcel)
}
throw IllegalArgumentException()
}
return getRegion(parcel)
override fun getHomeLocation(parcel: ParcelId): Location {
val origin = getRegionOrigin(parcel)
val x = origin.x + (o.parcelSize - 1) / 2.0
val z = origin.z - 2
return Location(world, x + 0.5, o.floorHeight + 1.0, z + 0.5, 0F, 0F)
}
override fun setOwnerBlock(parcel: ParcelId, owner: PlayerProfile?) {
val b = getBottomBlock(parcel)
override fun getParcelForInfoBlockInteraction(block: Vec3i, type: Material, face: BlockFace): Parcel? {
if (block.y != o.floorHeight + 1) return null
val expectedParcelOrigin = when (type) {
Material.WALL_SIGN -> Vec2i(block.x + 1, block.z + 2)
o.wallType.material, cornerWallType?.material -> {
if (face != BlockFace.NORTH || world[block + Vec3i.convert(BlockFace.NORTH)].type == Material.WALL_SIGN) {
return null
}
Vec2i(block.x + 1, block.z + 1)
}
else -> return null
}
return getParcelAt(expectedParcelOrigin.x, expectedParcelOrigin.z)
?.takeIf { expectedParcelOrigin == getRegionOrigin(it.id) }
?.also { parcel ->
if (type != Material.WALL_SIGN && parcel.owner != null) {
updateParcelInfo(parcel.id, parcel.owner)
parcel.isOwnerSignOutdated = false
}
}
}
override fun isParcelInfoSectionLoaded(parcel: ParcelId): Boolean {
val wallBlockChunk = getRegionOrigin(parcel).add(-1, -1).toChunk()
return world.isChunkLoaded(wallBlockChunk.x, wallBlockChunk.z)
}
override fun updateParcelInfo(parcel: ParcelId, owner: PlayerProfile?) {
val b = getRegionOrigin(parcel)
val wallBlock = world.getBlockAt(b.x - 1, o.floorHeight + 1, b.z - 1)
val signBlock = world.getBlockAt(b.x - 2, o.floorHeight + 1, b.z - 1)
val signBlock = world.getBlockAt(b.x - 1, o.floorHeight + 1, b.z - 2)
val skullBlock = world.getBlockAt(b.x - 1, o.floorHeight + 2, b.z - 1)
if (owner == null) {
wallBlock.blockData = o.wallType
signBlock.type = Material.AIR
skullBlock.type = Material.AIR
} else {
val wallBlockType: BlockData = if (o.wallType is Slab)
(o.wallType.clone() as Slab).apply { type = Slab.Type.DOUBLE }
else
o.wallType
wallBlock.blockData = wallBlockType
cornerWallType?.let { wallBlock.blockData = it }
signBlock.blockData = (Bukkit.createBlockData(Material.WALL_SIGN) as WallSign).apply { facing = BlockFace.NORTH }
val sign = signBlock.state as org.bukkit.block.Sign
sign.setLine(0, "${parcel.x},${parcel.z}")
sign.setLine(2, owner.name)
sign.setLine(2, owner.name ?: "")
sign.update()
skullBlock.type = Material.AIR
skullBlock.type = Material.PLAYER_HEAD
val skull = skullBlock.state as Skull
if (owner is PlayerProfile.Real) {
skull.owningPlayer = Bukkit.getOfflinePlayer(owner.uuid)
} else {
skull.owner = owner.name
} else if (!skull.setOwner(owner.name)) {
skullBlock.type = Material.AIR
return
}
skull.rotation = BlockFace.WEST
skull.rotation = BlockFace.SOUTH
skull.update()
}
}
private fun getParcel(parcelId: ParcelId): Parcel? {
// todo dont rely on this cast
val world = worldId as? ParcelWorld ?: return null
return world.getParcelById(parcelId)
private fun trySubmitBlockVisitor(vararg parcels: ParcelId, function: JobFunction): Job? {
parcels.forEach { checkParcelId(it) }
return parcelProvider.trySubmitBlockVisitor(Permit(), parcels, function)
}
override fun submitBlockVisitor(vararg parcelIds: ParcelId, task: JobFunction): Job {
val parcels = parcelIds.mapNotNull { getParcel(it) }
if (parcels.isEmpty()) return jobDispatcher.dispatch(task)
if (parcels.any { it.hasBlockVisitors }) throw IllegalArgumentException("This parcel already has a block visitor")
val worker = jobDispatcher.dispatch(task)
for (parcel in parcels) {
launch(start = UNDISPATCHED) {
parcel.withBlockVisitorPermit {
worker.awaitCompletion()
}
}
}
return worker
}
override fun setBiome(parcel: ParcelId, biome: Biome): Job = submitBlockVisitor(parcel) {
override fun setBiome(parcel: ParcelId, biome: Biome) = trySubmitBlockVisitor(checkParcelId(parcel)) {
val world = world
val b = getBottomBlock(parcel)
val b = getRegionOrigin(parcel)
val parcelSize = o.parcelSize
for (x in b.x until b.x + parcelSize) {
for (z in b.z until b.z + parcelSize) {
@@ -267,7 +275,7 @@ class DefaultParcelGenerator(
}
}
override fun clearParcel(parcel: ParcelId): Job = submitBlockVisitor(parcel) {
override fun clearParcel(parcel: ParcelId) = trySubmitBlockVisitor(checkParcelId(parcel)) {
val region = getRegion(parcel)
val blocks = parcelTraverser.traverseRegion(region)
val blockCount = region.blockCount.toDouble()
@@ -291,22 +299,6 @@ class DefaultParcelGenerator(
}
}
override fun swapParcels(parcel1: ParcelId, parcel2: ParcelId): Job = submitBlockVisitor(parcel1, parcel2) {
var region1 = getRegionConsideringWorld(parcel1)
var region2 = getRegionConsideringWorld(parcel2)
val size = region1.size.clampMax(region2.size)
if (size != region1.size) {
region1 = region1.withSize(size)
region2 = region2.withSize(size)
}
val schematicOf1 = delegateWork(0.25) { Schematic().apply { load(world, region1) } }
val schematicOf2 = delegateWork(0.25) { Schematic().apply { load(world, region2) } }
delegateWork(0.25) { with(schematicOf1) { paste(world, region2.origin) } }
delegateWork(0.25) { with(schematicOf2) { paste(world, region1.origin) } }
}
override fun getParcelsWithOwnerBlockIn(chunk: Chunk): Collection<Vec2i> {
/*
* Get the offsets for the world out of the way

View File

@@ -3,59 +3,84 @@ package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.Privilege.*
import io.dico.parcels2.util.ext.alsoIfTrue
import io.dico.parcels2.util.isServerThread
import io.dico.parcels2.util.math.Vec2i
import org.bukkit.Material
import org.joda.time.DateTime
import java.util.concurrent.atomic.AtomicInteger
import java.lang.IllegalStateException
class ParcelImpl(
class ParcelImpl (
override val world: ParcelWorld,
override val x: Int,
override val z: Int
) : Parcel, ParcelId {
override val id: ParcelId = this
override val id: ParcelId get() = this
override val pos get() = Vec2i(x, z)
override var data: ParcelDataHolder = ParcelDataHolder(); private set
override val hasBlockVisitors get() = blockVisitors.get() > 0
override var data = ParcelDataHolder(); private set
override val worldId: ParcelWorldId get() = world.id
override fun copyDataIgnoringDatabase(data: ParcelData) {
this.data = ((data as? Parcel)?.data ?: data) as ParcelDataHolder
}
override fun copyData(newData: ParcelDataHolder, callerIsDatabase: Boolean) {
if (callerIsDatabase) {
data = newData
return
}
val ownerChanged = owner != newData.owner
if (ownerChanged) {
updateOwnerSign(true, false, true)
}
val ownerSignWasOutdated = if (callerIsDatabase) newData.isOwnerSignOutdated else isOwnerSignOutdated
val ownerChanged = owner != newData.owner
data = newData
if (ownerChanged && isServerThread()) {
updateOwnerSign(true, false, updateDatabase = callerIsDatabase)
} else {
newData.isOwnerSignOutdated = ownerChanged || ownerSignWasOutdated
}
override fun copyData(data: ParcelData) {
copyDataIgnoringDatabase(data)
world.storage.setParcelData(this, data)
}
override fun dispose() {
copyDataIgnoringDatabase(ParcelDataHolder())
world.storage.setParcelData(this, null)
}
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
updateOwnerSign(true, false, true)
}
}
override val lastClaimTime: DateTime?
get() = data.lastClaimTime
override var ownerSignOutdated: Boolean
get() = data.ownerSignOutdated
override var isOwnerSignOutdated: Boolean
get() = data.isOwnerSignOutdated
set(value) {
if (data.ownerSignOutdated != value) {
if (data.isOwnerSignOutdated != value) {
world.storage.setParcelOwnerSignOutdated(this, value)
data.ownerSignOutdated = value
data.isOwnerSignOutdated = value
}
}
override fun updateOwnerSign(force: Boolean) {
updateOwnerSign(false, force, true)
}
private fun updateOwnerSign(ownerChanged: Boolean, force: Boolean, updateDatabase: Boolean) {
if (!ownerChanged && !isOwnerSignOutdated && !force) return
val update = force || world.blockManager.isParcelInfoSectionLoaded(this)
if (update) world.blockManager.updateParcelInfo(this, owner)
if (updateDatabase) isOwnerSignOutdated = !update
else data.isOwnerSignOutdated = !update
}
override val privilegeMap: PrivilegeMap
get() = data.privilegeMap
@@ -106,7 +131,24 @@ class ParcelImpl(
}
}
override val hasBlockVisitors: Boolean
get() = permit != null
private var permit: Permit? = null
fun acquireBlockVisitorPermit(with: Permit): Boolean {
if (permit === with) return true
if (permit != null) return false
permit = with
return true
}
fun releaseBlockVisitorPermit(with: Permit) {
if (permit !== with) throw IllegalStateException()
permit = null
}
/*
private var blockVisitors = AtomicInteger(0)
override suspend fun withBlockVisitorPermit(block: suspend () -> Unit) {
@@ -116,9 +158,9 @@ class ParcelImpl(
} finally {
blockVisitors.getAndDecrement()
}
}
}*/
override fun toString() = toStringExt()
override fun toString() = parcelIdToString()
override val infoString: String
get() = getInfoString()

View File

@@ -1,8 +1,10 @@
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.blockvisitor.Schematic
import io.dico.parcels2.util.schedule
import kotlinx.coroutines.Unconfined
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.bukkit.Bukkit
import org.bukkit.WorldCreator
@@ -44,10 +46,11 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
private fun loadWorlds0() {
if (Bukkit.getWorlds().isEmpty()) {
plugin.schedule(::loadWorlds0)
plugin.logger.warning("Scheduling to load worlds in the next tick, \nbecause no bukkit worlds are loaded yet")
plugin.logger.warning("Scheduling to load worlds in the next tick because no bukkit worlds are loaded yet")
return
}
val newlyCreatedWorlds = mutableListOf<ParcelWorld>()
for ((worldName, worldOptions) in options.worlds.entries) {
var parcelWorld = _worlds[worldName]
if (parcelWorld != null) continue
@@ -56,19 +59,20 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
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") }
else {
logger.info("Creating world $worldName")
WorldCreator(worldName).generator(generator).createWorld()
}
parcelWorld = ParcelWorldImpl(
bukkitWorld, generator, worldOptions.runtime, plugin.storage,
plugin.globalPrivileges, ::DefaultParcelContainer, plugin, plugin.jobDispatcher
)
parcelWorld = ParcelWorldImpl(plugin, bukkitWorld, generator, worldOptions.runtime,::DefaultParcelContainer)
if (!worldExists) {
val time = DateTime.now()
plugin.storage.setWorldCreationTime(parcelWorld.id, time)
parcelWorld.creationTime = time
newlyCreatedWorlds.add(parcelWorld)
} else {
launch(context = Unconfined) {
GlobalScope.launch(context = Dispatchers.Unconfined) {
parcelWorld.creationTime = plugin.storage.getWorldCreationTime(parcelWorld.id).await() ?: DateTime.now()
}
}
@@ -76,11 +80,11 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
_worlds[worldName] = parcelWorld
}
loadStoredData()
loadStoredData(newlyCreatedWorlds.toSet())
}
private fun loadStoredData() {
plugin.launch {
private fun loadStoredData(newlyCreatedWorlds: Collection<ParcelWorld> = emptyList()) {
plugin.launch(Dispatchers.Default) {
val migration = plugin.options.migration
if (migration.enabled) {
migration.instance?.newInstance()?.apply {
@@ -96,11 +100,14 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
}
logger.info("Loading all parcel data...")
val channel = plugin.storage.transmitAllParcelData()
while (true) {
val (id, data) = channel.receiveOrNull() ?: break
val parcel = getParcelById(id) ?: continue
data?.let { parcel.copyDataIgnoringDatabase(it) }
val job1 = launch {
val channel = plugin.storage.transmitAllParcelData()
while (true) {
val (id, data) = channel.receiveOrNull() ?: break
val parcel = getParcelById(id) ?: continue
data?.let { parcel.copyData(it, callerIsDatabase = true) }
}
}
val channel2 = plugin.storage.transmitAllGlobalPrivileges()
@@ -113,11 +120,61 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
(plugin.globalPrivileges[profile] as PrivilegesHolder).copyPrivilegesFrom(data)
}
job1.join()
logger.info("Loading data completed")
_dataIsLoaded = true
}
}
override fun acquireBlockVisitorPermit(parcelId: ParcelId, with: Permit): Boolean {
val parcel = getParcelById(parcelId) as? ParcelImpl ?: return true
return parcel.acquireBlockVisitorPermit(with)
}
override fun releaseBlockVisitorPermit(parcelId: ParcelId, with: Permit) {
val parcel = getParcelById(parcelId) as? ParcelImpl ?: return
parcel.releaseBlockVisitorPermit(with)
}
override fun trySubmitBlockVisitor(permit: Permit, vararg parcelIds: ParcelId, function: JobFunction): Job? {
val withPermit = parcelIds.filter { acquireBlockVisitorPermit(it, permit) }
if (withPermit.size != parcelIds.size) {
withPermit.forEach { releaseBlockVisitorPermit(it, permit) }
return null
}
val job = plugin.jobDispatcher.dispatch(function)
plugin.launch {
job.awaitCompletion()
withPermit.forEach { releaseBlockVisitorPermit(it, permit) }
}
return job
}
override fun swapParcels(parcelId1: ParcelId, parcelId2: ParcelId): Job? {
val blockManager1 = getWorldById(parcelId1.worldId)?.blockManager ?: return null
val blockManager2 = getWorldById(parcelId2.worldId)?.blockManager ?: return null
return trySubmitBlockVisitor(Permit(), parcelId1, parcelId2) {
var region1 = blockManager1.getRegion(parcelId1)
var region2 = blockManager2.getRegion(parcelId2)
val size = region1.size.clampMax(region2.size)
if (size != region1.size) {
region1 = region1.withSize(size)
region2 = region2.withSize(size)
}
val schematicOf1 = delegateWork(0.25) { Schematic().apply { load(blockManager1.world, region1) } }
val schematicOf2 = delegateWork(0.25) { Schematic().apply { load(blockManager2.world, region2) } }
delegateWork(0.25) { with(schematicOf1) { paste(blockManager2.world, region2.origin) } }
delegateWork(0.25) { with(schematicOf2) { paste(blockManager1.world, region1.origin) } }
}
}
/*
fun loadWorlds(options: Options) {
for ((worldName, worldOptions) in options.worlds.entries) {

View File

@@ -3,30 +3,27 @@
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.blockvisitor.JobDispatcher
import io.dico.parcels2.options.RuntimeWorldOptions
import io.dico.parcels2.storage.Storage
import kotlinx.coroutines.CoroutineScope
import org.bukkit.GameRule
import org.bukkit.World
import org.joda.time.DateTime
import java.util.UUID
class ParcelWorldImpl(override val world: World,
override val generator: ParcelGenerator,
override var options: RuntimeWorldOptions,
override val storage: Storage,
override val globalPrivileges: GlobalPrivilegesManager,
containerFactory: ParcelContainerFactory,
coroutineScope: CoroutineScope,
jobDispatcher: JobDispatcher)
: ParcelWorld,
ParcelWorldId,
ParcelContainer, /* missing delegation */
ParcelLocator /* missing delegation */ {
class ParcelWorldImpl(
val plugin: ParcelsPlugin,
override val world: World,
override val generator: ParcelGenerator,
override var options: RuntimeWorldOptions,
containerFactory: ParcelContainerFactory
) : ParcelWorld, ParcelWorldId, ParcelContainer, ParcelLocator {
override val id: ParcelWorldId get() = this
override val uid: UUID? get() = world.uid
override val storage get() = plugin.storage
override val globalPrivileges get() = plugin.globalPrivileges
init {
if (generator.world != world) {
throw IllegalArgumentException()
@@ -39,52 +36,40 @@ class ParcelWorldImpl(override val world: World,
override val blockManager: ParcelBlockManager
init {
val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, jobDispatcher)
locator = pair.first
blockManager = pair.second
val (locator, blockManager) = generator.makeParcelLocatorAndBlockManager(plugin.parcelProvider, container, plugin, plugin.jobDispatcher)
this.locator = locator
this.blockManager = blockManager
enforceOptions()
}
fun enforceOptions() {
if (options.dayTime) {
world.setGameRuleValue("doDaylightCycle", "false")
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false)
world.setTime(6000)
}
if (options.noWeather) {
world.setStorm(false)
world.setThundering(false)
world.weatherDuration = Integer.MAX_VALUE
world.weatherDuration = Int.MAX_VALUE
}
world.setGameRuleValue("doTileDrops", "${options.doTileDrops}")
world.setGameRule(GameRule.DO_TILE_DROPS, options.doTileDrops)
}
// Updated by ParcelProviderImpl
// Accessed by ParcelProviderImpl
override var creationTime: DateTime? = null
/*
Interface delegation needs to be implemented manually because JetBrains has yet to fix it.
*/
// ParcelLocator interface
override fun getParcelAt(x: Int, z: Int): Parcel? {
return locator.getParcelAt(x, z)
}
override fun getParcelAt(x: Int, z: Int): Parcel? = locator.getParcelAt(x, z)
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
return locator.getParcelIdAt(x, z)
}
override fun getParcelIdAt(x: Int, z: Int): ParcelId? = locator.getParcelIdAt(x, z)
// ParcelContainer interface
override fun getParcelById(x: Int, z: Int): Parcel? {
return container.getParcelById(x, z)
}
override fun getParcelById(x: Int, z: Int): Parcel? = container.getParcelById(x, z)
override fun nextEmptyParcel(): Parcel? {
return container.nextEmptyParcel()
}
override fun getParcelById(id: ParcelId): Parcel? = container.getParcelById(id)
override fun toString() = toStringExt()
override fun nextEmptyParcel(): Parcel? = container.nextEmptyParcel()
override fun toString() = parcelWorldIdToString()
}