Changes I made before breaking my local repository. Hoping this works.
This commit is contained in:
@@ -1,73 +1,73 @@
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.Parcel
|
||||
import io.dico.parcels2.ParcelContainer
|
||||
import io.dico.parcels2.ParcelId
|
||||
import io.dico.parcels2.ParcelWorld
|
||||
|
||||
class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
|
||||
private var parcels: Array<Array<Parcel>>
|
||||
|
||||
init {
|
||||
parcels = initArray(world.options.axisLimit, world)
|
||||
}
|
||||
|
||||
fun resizeIfSizeChanged() {
|
||||
if (parcels.size != world.options.axisLimit * 2 + 1) {
|
||||
resize(world.options.axisLimit)
|
||||
}
|
||||
}
|
||||
|
||||
fun resize(axisLimit: Int) {
|
||||
parcels = initArray(axisLimit, world, this)
|
||||
}
|
||||
|
||||
fun initArray(axisLimit: Int, world: ParcelWorld, cur: DefaultParcelContainer? = null): Array<Array<Parcel>> {
|
||||
val arraySize = 2 * axisLimit + 1
|
||||
return Array(arraySize) {
|
||||
val x = it - axisLimit
|
||||
Array(arraySize) {
|
||||
val z = it - axisLimit
|
||||
cur?.getParcelById(x, z) ?: ParcelImpl(world, x, z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getParcelById(x: Int, z: Int): Parcel? {
|
||||
return parcels.getOrNull(x + world.options.axisLimit)?.getOrNull(z + world.options.axisLimit)
|
||||
}
|
||||
|
||||
override fun getParcelById(id: ParcelId): Parcel? {
|
||||
if (!world.id.equals(id.worldId)) throw IllegalArgumentException()
|
||||
return when (id) {
|
||||
is Parcel -> id
|
||||
else -> getParcelById(id.x, id.z)
|
||||
}
|
||||
}
|
||||
|
||||
override fun nextEmptyParcel(): Parcel? {
|
||||
return walkInCircle().find { it.owner == null }
|
||||
}
|
||||
|
||||
private fun walkInCircle(): Iterable<Parcel> = Iterable {
|
||||
iterator {
|
||||
val center = world.options.axisLimit
|
||||
yield(parcels[center][center])
|
||||
for (radius in 0..center) {
|
||||
var x = center - radius;
|
||||
var z = center - radius
|
||||
repeat(radius * 2) { yield(parcels[x++][z]) }
|
||||
repeat(radius * 2) { yield(parcels[x][z++]) }
|
||||
repeat(radius * 2) { yield(parcels[x--][z]) }
|
||||
repeat(radius * 2) { yield(parcels[x][z--]) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllParcels(): Iterator<Parcel> = iterator {
|
||||
for (array in parcels) {
|
||||
yieldAll(array.iterator())
|
||||
}
|
||||
}
|
||||
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.Parcel
|
||||
import io.dico.parcels2.ParcelContainer
|
||||
import io.dico.parcels2.ParcelId
|
||||
import io.dico.parcels2.ParcelWorld
|
||||
|
||||
class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
|
||||
private var parcels: Array<Array<Parcel>>
|
||||
|
||||
init {
|
||||
parcels = initArray(world.options.axisLimit, world)
|
||||
}
|
||||
|
||||
fun resizeIfSizeChanged() {
|
||||
if (parcels.size != world.options.axisLimit * 2 + 1) {
|
||||
resize(world.options.axisLimit)
|
||||
}
|
||||
}
|
||||
|
||||
fun resize(axisLimit: Int) {
|
||||
parcels = initArray(axisLimit, world, this)
|
||||
}
|
||||
|
||||
fun initArray(axisLimit: Int, world: ParcelWorld, cur: DefaultParcelContainer? = null): Array<Array<Parcel>> {
|
||||
val arraySize = 2 * axisLimit + 1
|
||||
return Array(arraySize) {
|
||||
val x = it - axisLimit
|
||||
Array(arraySize) {
|
||||
val z = it - axisLimit
|
||||
cur?.getParcelById(x, z) ?: ParcelImpl(world, x, z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getParcelById(x: Int, z: Int): Parcel? {
|
||||
return parcels.getOrNull(x + world.options.axisLimit)?.getOrNull(z + world.options.axisLimit)
|
||||
}
|
||||
|
||||
override fun getParcelById(id: ParcelId): Parcel? {
|
||||
if (!world.id.equals(id.worldId)) throw IllegalArgumentException()
|
||||
return when (id) {
|
||||
is Parcel -> id
|
||||
else -> getParcelById(id.x, id.z)
|
||||
}
|
||||
}
|
||||
|
||||
override fun nextEmptyParcel(): Parcel? {
|
||||
return walkInCircle().find { it.owner == null }
|
||||
}
|
||||
|
||||
private fun walkInCircle(): Iterable<Parcel> = Iterable {
|
||||
iterator {
|
||||
val center = world.options.axisLimit
|
||||
yield(parcels[center][center])
|
||||
for (radius in 0..center) {
|
||||
var x = center - radius;
|
||||
var z = center - radius
|
||||
repeat(radius * 2) { yield(parcels[x++][z]) }
|
||||
repeat(radius * 2) { yield(parcels[x][z++]) }
|
||||
repeat(radius * 2) { yield(parcels[x--][z]) }
|
||||
repeat(radius * 2) { yield(parcels[x][z--]) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllParcels(): Iterator<Parcel> = iterator {
|
||||
for (array in parcels) {
|
||||
yieldAll(array.iterator())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,378 +1,378 @@
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.blockvisitor.RegionTraverser
|
||||
import io.dico.parcels2.options.DefaultGeneratorOptions
|
||||
import io.dico.parcels2.util.math.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.bukkit.*
|
||||
import org.bukkit.block.Biome
|
||||
import org.bukkit.block.BlockFace
|
||||
import org.bukkit.block.Skull
|
||||
import org.bukkit.block.data.type.Slab
|
||||
import org.bukkit.block.data.type.WallSign
|
||||
import java.util.Random
|
||||
|
||||
private val airType = Bukkit.createBlockData(Material.AIR)
|
||||
|
||||
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) {
|
||||
val world = Bukkit.getWorld(worldName)
|
||||
maxHeight = world.maxHeight
|
||||
_world = world
|
||||
return world
|
||||
}
|
||||
return _world!!
|
||||
}
|
||||
|
||||
private var maxHeight = 0
|
||||
val sectionSize = o.parcelSize + o.pathSize
|
||||
val pathOffset = (if (o.pathSize % 2 == 0) o.pathSize + 2 else o.pathSize + 1) / 2
|
||||
val makePathMain = o.pathSize > 2
|
||||
val makePathAlt = o.pathSize > 4
|
||||
|
||||
private inline fun <T> generate(
|
||||
chunkX: Int,
|
||||
chunkZ: Int,
|
||||
floor: T, wall:
|
||||
T, pathMain: T,
|
||||
pathAlt: T,
|
||||
fill: T,
|
||||
setter: (Int, Int, Int, T) -> Unit
|
||||
) {
|
||||
|
||||
val floorHeight = o.floorHeight
|
||||
val parcelSize = o.parcelSize
|
||||
val sectionSize = sectionSize
|
||||
val pathOffset = pathOffset
|
||||
val makePathMain = makePathMain
|
||||
val makePathAlt = makePathAlt
|
||||
|
||||
// parcel bottom x and z
|
||||
// umod is unsigned %: the result is always >= 0
|
||||
val pbx = ((chunkX shl 4) - o.offsetX) umod sectionSize
|
||||
val pbz = ((chunkZ shl 4) - o.offsetZ) umod sectionSize
|
||||
|
||||
var curHeight: Int
|
||||
var x: Int
|
||||
var z: Int
|
||||
for (cx in 0..15) {
|
||||
for (cz in 0..15) {
|
||||
x = (pbx + cx) % sectionSize - pathOffset
|
||||
z = (pbz + cz) % sectionSize - pathOffset
|
||||
curHeight = floorHeight
|
||||
|
||||
val type = when {
|
||||
(x in 0 until parcelSize && z in 0 until parcelSize) -> floor
|
||||
(x in -1..parcelSize && z in -1..parcelSize) -> {
|
||||
curHeight++
|
||||
wall
|
||||
}
|
||||
(makePathAlt && x in -2 until parcelSize + 2 && z in -2 until parcelSize + 2) -> pathAlt
|
||||
(makePathMain) -> pathMain
|
||||
else -> {
|
||||
curHeight++
|
||||
wall
|
||||
}
|
||||
}
|
||||
|
||||
for (y in 0 until curHeight) {
|
||||
setter(cx, y, cz, fill)
|
||||
}
|
||||
setter(cx, curHeight, cz, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateChunkData(world: World?, random: Random?, chunkX: Int, chunkZ: Int, biome: BiomeGrid?): ChunkData {
|
||||
val out = Bukkit.createChunkData(world)
|
||||
generate(chunkX, chunkZ, o.floorType, o.wallType, o.pathMainType, o.pathAltType, o.fillType) { x, y, z, type ->
|
||||
out.setBlock(x, y, z, type)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
override fun populate(world: World?, random: Random?, chunk: Chunk?) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun getFixedSpawnLocation(world: World?, random: Random?): Location {
|
||||
val fix = if (o.parcelSize.even) 0.5 else 0.0
|
||||
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
|
||||
}
|
||||
|
||||
override fun makeParcelLocatorAndBlockManager(
|
||||
parcelProvider: ParcelProvider,
|
||||
container: ParcelContainer,
|
||||
coroutineScope: CoroutineScope,
|
||||
jobDispatcher: JobDispatcher
|
||||
): Pair<ParcelLocator, ParcelBlockManager> {
|
||||
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? {
|
||||
val sectionSize = sectionSize
|
||||
val parcelSize = o.parcelSize
|
||||
val absX = x - o.offsetX - pathOffset
|
||||
val absZ = z - o.offsetZ - pathOffset
|
||||
val modX = absX umod sectionSize
|
||||
val modZ = absZ umod sectionSize
|
||||
if (modX in 0 until parcelSize && modZ in 0 until parcelSize) {
|
||||
return mapper((absX - modX) / sectionSize + 1, (absZ - modZ) / sectionSize + 1)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
|
||||
return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(worldId, idx, idz) }
|
||||
}
|
||||
|
||||
|
||||
private fun checkParcelId(parcel: ParcelId): ParcelId {
|
||||
if (!parcel.worldId.equals(worldId)) {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
return parcel
|
||||
}
|
||||
|
||||
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 origin = getRegionOrigin(parcel)
|
||||
return Region(
|
||||
Vec3i(origin.x, 0, origin.z),
|
||||
Vec3i(o.parcelSize, maxHeight, o.parcelSize)
|
||||
)
|
||||
}
|
||||
|
||||
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 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 - 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 {
|
||||
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.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 if (!skull.setOwner(owner.name)) {
|
||||
skullBlock.type = Material.AIR
|
||||
return
|
||||
}
|
||||
|
||||
skull.rotation = BlockFace.SOUTH
|
||||
skull.update()
|
||||
}
|
||||
}
|
||||
|
||||
private fun trySubmitBlockVisitor(vararg parcels: ParcelId, function: JobFunction): Job? {
|
||||
parcels.forEach { checkParcelId(it) }
|
||||
return parcelProvider.trySubmitBlockVisitor(Permit(), parcels, function)
|
||||
}
|
||||
|
||||
override fun setBiome(parcel: ParcelId, biome: Biome) = trySubmitBlockVisitor(checkParcelId(parcel)) {
|
||||
val world = world
|
||||
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) {
|
||||
markSuspensionPoint()
|
||||
world.setBiome(x, z, biome)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearParcel(parcel: ParcelId) = trySubmitBlockVisitor(checkParcelId(parcel)) {
|
||||
val region = getRegion(parcel)
|
||||
val blocks = parcelTraverser.traverseRegion(region)
|
||||
val blockCount = region.blockCount.toDouble()
|
||||
val world = world
|
||||
val floorHeight = o.floorHeight
|
||||
val airType = airType
|
||||
val floorType = o.floorType
|
||||
val fillType = o.fillType
|
||||
|
||||
for ((index, vec) in blocks.withIndex()) {
|
||||
markSuspensionPoint()
|
||||
val y = vec.y
|
||||
val blockType = when {
|
||||
y > floorHeight -> airType
|
||||
y == floorHeight -> floorType
|
||||
else -> fillType
|
||||
}
|
||||
world[vec].blockData = blockType
|
||||
setProgress((index + 1) / blockCount)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
return (0 until matchesOnDimensionX).flatMap { idOffsetX ->
|
||||
(0 until matchesOnDimensionZ).map { idOffsetZ -> Vec2i(firstIdX + idOffsetX, firstIdZ + idOffsetZ) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.blockvisitor.RegionTraverser
|
||||
import io.dico.parcels2.options.DefaultGeneratorOptions
|
||||
import io.dico.parcels2.util.math.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.bukkit.*
|
||||
import org.bukkit.block.Biome
|
||||
import org.bukkit.block.BlockFace
|
||||
import org.bukkit.block.Skull
|
||||
import org.bukkit.block.data.type.Slab
|
||||
import org.bukkit.block.data.type.WallSign
|
||||
import java.util.Random
|
||||
|
||||
private val airType = Bukkit.createBlockData(Material.AIR)
|
||||
|
||||
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) {
|
||||
val world = Bukkit.getWorld(worldName)
|
||||
maxHeight = world.maxHeight
|
||||
_world = world
|
||||
return world
|
||||
}
|
||||
return _world!!
|
||||
}
|
||||
|
||||
private var maxHeight = 0
|
||||
val sectionSize = o.parcelSize + o.pathSize
|
||||
val pathOffset = (if (o.pathSize % 2 == 0) o.pathSize + 2 else o.pathSize + 1) / 2
|
||||
val makePathMain = o.pathSize > 2
|
||||
val makePathAlt = o.pathSize > 4
|
||||
|
||||
private inline fun <T> generate(
|
||||
chunkX: Int,
|
||||
chunkZ: Int,
|
||||
floor: T, wall:
|
||||
T, pathMain: T,
|
||||
pathAlt: T,
|
||||
fill: T,
|
||||
setter: (Int, Int, Int, T) -> Unit
|
||||
) {
|
||||
|
||||
val floorHeight = o.floorHeight
|
||||
val parcelSize = o.parcelSize
|
||||
val sectionSize = sectionSize
|
||||
val pathOffset = pathOffset
|
||||
val makePathMain = makePathMain
|
||||
val makePathAlt = makePathAlt
|
||||
|
||||
// parcel bottom x and z
|
||||
// umod is unsigned %: the result is always >= 0
|
||||
val pbx = ((chunkX shl 4) - o.offsetX) umod sectionSize
|
||||
val pbz = ((chunkZ shl 4) - o.offsetZ) umod sectionSize
|
||||
|
||||
var curHeight: Int
|
||||
var x: Int
|
||||
var z: Int
|
||||
for (cx in 0..15) {
|
||||
for (cz in 0..15) {
|
||||
x = (pbx + cx) % sectionSize - pathOffset
|
||||
z = (pbz + cz) % sectionSize - pathOffset
|
||||
curHeight = floorHeight
|
||||
|
||||
val type = when {
|
||||
(x in 0 until parcelSize && z in 0 until parcelSize) -> floor
|
||||
(x in -1..parcelSize && z in -1..parcelSize) -> {
|
||||
curHeight++
|
||||
wall
|
||||
}
|
||||
(makePathAlt && x in -2 until parcelSize + 2 && z in -2 until parcelSize + 2) -> pathAlt
|
||||
(makePathMain) -> pathMain
|
||||
else -> {
|
||||
curHeight++
|
||||
wall
|
||||
}
|
||||
}
|
||||
|
||||
for (y in 0 until curHeight) {
|
||||
setter(cx, y, cz, fill)
|
||||
}
|
||||
setter(cx, curHeight, cz, type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateChunkData(world: World?, random: Random?, chunkX: Int, chunkZ: Int, biome: BiomeGrid?): ChunkData {
|
||||
val out = Bukkit.createChunkData(world)
|
||||
generate(chunkX, chunkZ, o.floorType, o.wallType, o.pathMainType, o.pathAltType, o.fillType) { x, y, z, type ->
|
||||
out.setBlock(x, y, z, type)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
override fun populate(world: World?, random: Random?, chunk: Chunk?) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun getFixedSpawnLocation(world: World?, random: Random?): Location {
|
||||
val fix = if (o.parcelSize.even) 0.5 else 0.0
|
||||
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
|
||||
}
|
||||
|
||||
override fun makeParcelLocatorAndBlockManager(
|
||||
parcelProvider: ParcelProvider,
|
||||
container: ParcelContainer,
|
||||
coroutineScope: CoroutineScope,
|
||||
jobDispatcher: JobDispatcher
|
||||
): Pair<ParcelLocator, ParcelBlockManager> {
|
||||
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? {
|
||||
val sectionSize = sectionSize
|
||||
val parcelSize = o.parcelSize
|
||||
val absX = x - o.offsetX - pathOffset
|
||||
val absZ = z - o.offsetZ - pathOffset
|
||||
val modX = absX umod sectionSize
|
||||
val modZ = absZ umod sectionSize
|
||||
if (modX in 0 until parcelSize && modZ in 0 until parcelSize) {
|
||||
return mapper((absX - modX) / sectionSize + 1, (absZ - modZ) / sectionSize + 1)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@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)
|
||||
}
|
||||
|
||||
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
|
||||
return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(worldId, idx, idz) }
|
||||
}
|
||||
|
||||
|
||||
private fun checkParcelId(parcel: ParcelId): ParcelId {
|
||||
if (!parcel.worldId.equals(worldId)) {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
return parcel
|
||||
}
|
||||
|
||||
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 origin = getRegionOrigin(parcel)
|
||||
return Region(
|
||||
Vec3i(origin.x, 0, origin.z),
|
||||
Vec3i(o.parcelSize, maxHeight, o.parcelSize)
|
||||
)
|
||||
}
|
||||
|
||||
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 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 - 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 {
|
||||
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.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 if (!skull.setOwner(owner.name)) {
|
||||
skullBlock.type = Material.AIR
|
||||
return
|
||||
}
|
||||
|
||||
skull.rotation = BlockFace.SOUTH
|
||||
skull.update()
|
||||
}
|
||||
}
|
||||
|
||||
private fun trySubmitBlockVisitor(vararg parcels: ParcelId, function: JobFunction): Job? {
|
||||
parcels.forEach { checkParcelId(it) }
|
||||
return parcelProvider.trySubmitBlockVisitor(Permit(), parcels, function)
|
||||
}
|
||||
|
||||
override fun setBiome(parcel: ParcelId, biome: Biome) = trySubmitBlockVisitor(checkParcelId(parcel)) {
|
||||
val world = world
|
||||
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) {
|
||||
markSuspensionPoint()
|
||||
world.setBiome(x, z, biome)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearParcel(parcel: ParcelId) = trySubmitBlockVisitor(checkParcelId(parcel)) {
|
||||
val region = getRegion(parcel)
|
||||
val blocks = parcelTraverser.traverseRegion(region)
|
||||
val blockCount = region.blockCount.toDouble()
|
||||
val world = world
|
||||
val floorHeight = o.floorHeight
|
||||
val airType = airType
|
||||
val floorType = o.floorType
|
||||
val fillType = o.fillType
|
||||
|
||||
for ((index, vec) in blocks.withIndex()) {
|
||||
markSuspensionPoint()
|
||||
val y = vec.y
|
||||
val blockType = when {
|
||||
y > floorHeight -> airType
|
||||
y == floorHeight -> floorType
|
||||
else -> fillType
|
||||
}
|
||||
world[vec].blockData = blockType
|
||||
setProgress((index + 1) / blockCount)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
return (0 until matchesOnDimensionX).flatMap { idOffsetX ->
|
||||
(0 until matchesOnDimensionZ).map { idOffsetZ -> Vec2i(firstIdX + idOffsetX, firstIdZ + idOffsetZ) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +1,28 @@
|
||||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.util.ext.alsoIfTrue
|
||||
import java.util.Collections
|
||||
|
||||
class GlobalPrivilegesManagerImpl(val plugin: ParcelsPlugin) : GlobalPrivilegesManager {
|
||||
private val map = mutableMapOf<PlayerProfile, GlobalPrivileges>()
|
||||
|
||||
override fun get(owner: PlayerProfile.Real): GlobalPrivileges {
|
||||
return map[owner] ?: GlobalPrivilegesImpl(owner).also { map[owner] = it }
|
||||
}
|
||||
|
||||
private inner class GlobalPrivilegesImpl(override val keyOfOwner: PlayerProfile.Real) : PrivilegesHolder(), GlobalPrivileges {
|
||||
override var privilegeOfStar: Privilege
|
||||
get() = super<GlobalPrivileges>.privilegeOfStar
|
||||
set(value) = run { super<GlobalPrivileges>.privilegeOfStar = value }
|
||||
|
||||
override fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
|
||||
return super.setRawStoredPrivilege(key, privilege).alsoIfTrue {
|
||||
plugin.storage.setGlobalPrivilege(keyOfOwner, key, privilege)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.util.ext.alsoIfTrue
|
||||
import java.util.Collections
|
||||
|
||||
class GlobalPrivilegesManagerImpl(val plugin: ParcelsPlugin) : GlobalPrivilegesManager {
|
||||
private val map = mutableMapOf<PlayerProfile, GlobalPrivileges>()
|
||||
|
||||
override fun get(owner: PlayerProfile.Real): GlobalPrivileges {
|
||||
return map[owner] ?: GlobalPrivilegesImpl(owner).also { map[owner] = it }
|
||||
}
|
||||
|
||||
private inner class GlobalPrivilegesImpl(override val keyOfOwner: PlayerProfile.Real) : PrivilegesHolder(), GlobalPrivileges {
|
||||
override var privilegeOfStar: Privilege
|
||||
get() = super<GlobalPrivileges>.privilegeOfStar
|
||||
set(value) = run { super<GlobalPrivileges>.privilegeOfStar = value }
|
||||
|
||||
override fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
|
||||
return super.setRawStoredPrivilege(key, privilege).alsoIfTrue {
|
||||
plugin.storage.setGlobalPrivilege(keyOfOwner, key, privilege)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +1,88 @@
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.dicore.Formatting
|
||||
import io.dico.parcels2.Privilege
|
||||
import io.dico.parcels2.PrivilegeKey
|
||||
import io.dico.parcels2.RawPrivileges
|
||||
import io.dico.parcels2.filterProfilesWithPrivilegeTo
|
||||
|
||||
object InfoBuilder {
|
||||
val infoStringColor1 = Formatting.GREEN
|
||||
val infoStringColor2 = Formatting.AQUA
|
||||
|
||||
inline fun StringBuilder.appendField(field: StringBuilder.() -> Unit, value: StringBuilder.() -> Unit) {
|
||||
append(infoStringColor1)
|
||||
field()
|
||||
append(": ")
|
||||
append(infoStringColor2)
|
||||
value()
|
||||
append(' ')
|
||||
}
|
||||
|
||||
inline fun StringBuilder.appendField(name: String, value: StringBuilder.() -> Unit) {
|
||||
appendField({ append(name) }, value)
|
||||
}
|
||||
|
||||
inline fun StringBuilder.appendFieldWithCount(name: String, count: Int, value: StringBuilder.() -> Unit) {
|
||||
appendField({
|
||||
append(name)
|
||||
append('(')
|
||||
append(infoStringColor2)
|
||||
append(count)
|
||||
append(infoStringColor1)
|
||||
append(')')
|
||||
}, value)
|
||||
}
|
||||
|
||||
fun StringBuilder.appendProfilesWithPrivilege(fieldName: String, local: RawPrivileges, global: RawPrivileges?, privilege: Privilege) {
|
||||
val map = linkedMapOf<PrivilegeKey, Privilege>()
|
||||
local.filterProfilesWithPrivilegeTo(map, privilege)
|
||||
val localCount = map.size
|
||||
global?.filterProfilesWithPrivilegeTo(map, privilege)
|
||||
appendPrivilegeProfiles(fieldName, map, localCount)
|
||||
}
|
||||
|
||||
fun StringBuilder.appendPrivilegeProfiles(fieldName: String, map: LinkedHashMap<PrivilegeKey, Privilege>, localCount: Int) {
|
||||
if (map.isEmpty()) return
|
||||
|
||||
appendFieldWithCount(fieldName, map.size) {
|
||||
// first [localCount] entries are local
|
||||
val separator = "$infoStringColor1, $infoStringColor2"
|
||||
val iterator = map.iterator()
|
||||
|
||||
if (localCount != 0) {
|
||||
appendPrivilegeEntry(false, iterator.next().toPair())
|
||||
repeat(localCount - 1) {
|
||||
append(separator)
|
||||
appendPrivilegeEntry(false, iterator.next().toPair())
|
||||
}
|
||||
|
||||
} else if (iterator.hasNext()) {
|
||||
// ensure there is never a leading or trailing separator
|
||||
appendPrivilegeEntry(true, iterator.next().toPair())
|
||||
}
|
||||
|
||||
iterator.forEach { next ->
|
||||
append(separator)
|
||||
appendPrivilegeEntry(true, next.toPair())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun StringBuilder.appendPrivilegeEntry(global: Boolean, pair: Pair<PrivilegeKey, Privilege>) {
|
||||
val (key, priv) = pair
|
||||
|
||||
append(key.notNullName)
|
||||
|
||||
// suffix. Maybe T should be M for mod or something. T means they have CAN_MANAGE privilege.
|
||||
append(
|
||||
when {
|
||||
global && priv == Privilege.CAN_MANAGE -> " (G) (T)"
|
||||
global -> " (G)"
|
||||
priv == Privilege.CAN_MANAGE -> " (T)"
|
||||
else -> ""
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.dicore.Formatting
|
||||
import io.dico.parcels2.Privilege
|
||||
import io.dico.parcels2.PrivilegeKey
|
||||
import io.dico.parcels2.RawPrivileges
|
||||
import io.dico.parcels2.filterProfilesWithPrivilegeTo
|
||||
|
||||
object InfoBuilder {
|
||||
val infoStringColor1 = Formatting.GREEN
|
||||
val infoStringColor2 = Formatting.AQUA
|
||||
|
||||
inline fun StringBuilder.appendField(field: StringBuilder.() -> Unit, value: StringBuilder.() -> Unit) {
|
||||
append(infoStringColor1)
|
||||
field()
|
||||
append(": ")
|
||||
append(infoStringColor2)
|
||||
value()
|
||||
append(' ')
|
||||
}
|
||||
|
||||
inline fun StringBuilder.appendField(name: String, value: StringBuilder.() -> Unit) {
|
||||
appendField({ append(name) }, value)
|
||||
}
|
||||
|
||||
inline fun StringBuilder.appendFieldWithCount(name: String, count: Int, value: StringBuilder.() -> Unit) {
|
||||
appendField({
|
||||
append(name)
|
||||
append('(')
|
||||
append(infoStringColor2)
|
||||
append(count)
|
||||
append(infoStringColor1)
|
||||
append(')')
|
||||
}, value)
|
||||
}
|
||||
|
||||
fun StringBuilder.appendProfilesWithPrivilege(fieldName: String, local: RawPrivileges, global: RawPrivileges?, privilege: Privilege) {
|
||||
val map = linkedMapOf<PrivilegeKey, Privilege>()
|
||||
local.filterProfilesWithPrivilegeTo(map, privilege)
|
||||
val localCount = map.size
|
||||
global?.filterProfilesWithPrivilegeTo(map, privilege)
|
||||
appendPrivilegeProfiles(fieldName, map, localCount)
|
||||
}
|
||||
|
||||
fun StringBuilder.appendPrivilegeProfiles(fieldName: String, map: LinkedHashMap<PrivilegeKey, Privilege>, localCount: Int) {
|
||||
if (map.isEmpty()) return
|
||||
|
||||
appendFieldWithCount(fieldName, map.size) {
|
||||
// first [localCount] entries are local
|
||||
val separator = "$infoStringColor1, $infoStringColor2"
|
||||
val iterator = map.iterator()
|
||||
|
||||
if (localCount != 0) {
|
||||
appendPrivilegeEntry(false, iterator.next().toPair())
|
||||
repeat(localCount - 1) {
|
||||
append(separator)
|
||||
appendPrivilegeEntry(false, iterator.next().toPair())
|
||||
}
|
||||
|
||||
} else if (iterator.hasNext()) {
|
||||
// ensure there is never a leading or trailing separator
|
||||
appendPrivilegeEntry(true, iterator.next().toPair())
|
||||
}
|
||||
|
||||
iterator.forEach { next ->
|
||||
append(separator)
|
||||
appendPrivilegeEntry(true, next.toPair())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun StringBuilder.appendPrivilegeEntry(global: Boolean, pair: Pair<PrivilegeKey, Privilege>) {
|
||||
val (key, priv) = pair
|
||||
|
||||
append(key.notNullName)
|
||||
|
||||
// suffix. Maybe T should be M for mod or something. T means they have CAN_MANAGE privilege.
|
||||
append(
|
||||
when {
|
||||
global && priv == Privilege.CAN_MANAGE -> " (G) (T)"
|
||||
global -> " (G)"
|
||||
priv == Privilege.CAN_MANAGE -> " (T)"
|
||||
else -> ""
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,223 +1,223 @@
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.blockvisitor.Schematic
|
||||
import io.dico.parcels2.util.schedule
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.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
|
||||
override val worlds: Map<String, ParcelWorld> get() = _worlds
|
||||
private val _worlds: MutableMap<String, ParcelWorld> = hashMapOf()
|
||||
private val _generators: MutableMap<String, ParcelGenerator> = hashMapOf()
|
||||
private var _worldsLoaded = false
|
||||
private var _dataIsLoaded = false
|
||||
|
||||
// disabled while !_dataIsLoaded. getParcelById() will work though for data loading.
|
||||
override fun getWorld(name: String): ParcelWorld? = _worlds[name]?.takeIf { _dataIsLoaded }
|
||||
|
||||
override fun getWorldById(id: ParcelWorldId): ParcelWorld? {
|
||||
if (id is ParcelWorld) return id
|
||||
return _worlds[id.name] ?: id.bukkitWorld?.let { getWorld(it) }
|
||||
}
|
||||
|
||||
override fun getParcelById(id: ParcelId): Parcel? {
|
||||
if (id is Parcel) return id
|
||||
return getWorldById(id.worldId)?.container?.getParcelById(id.x, id.z)
|
||||
}
|
||||
|
||||
override fun getWorldGenerator(worldName: String): ParcelGenerator? {
|
||||
return _worlds[worldName]?.generator
|
||||
?: _generators[worldName]
|
||||
?: options.worlds[worldName]?.generator?.newInstance(worldName)?.also { _generators[worldName] = it }
|
||||
}
|
||||
|
||||
override fun loadWorlds() {
|
||||
if (_worldsLoaded) throw IllegalStateException()
|
||||
_worldsLoaded = true
|
||||
loadWorlds0()
|
||||
}
|
||||
|
||||
private fun loadWorlds0() {
|
||||
if (Bukkit.getWorlds().isEmpty()) {
|
||||
plugin.schedule(::loadWorlds0)
|
||||
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
|
||||
|
||||
val generator: ParcelGenerator = getWorldGenerator(worldName)!!
|
||||
val worldExists = Bukkit.getWorld(worldName) != null
|
||||
val bukkitWorld =
|
||||
if (worldExists) Bukkit.getWorld(worldName)!!
|
||||
else {
|
||||
logger.info("Creating world $worldName")
|
||||
WorldCreator(worldName).generator(generator).createWorld()
|
||||
}
|
||||
|
||||
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 {
|
||||
GlobalScope.launch(context = Dispatchers.Unconfined) {
|
||||
parcelWorld.creationTime = plugin.storage.getWorldCreationTime(parcelWorld.id).await() ?: DateTime.now()
|
||||
}
|
||||
}
|
||||
|
||||
_worlds[worldName] = parcelWorld
|
||||
}
|
||||
|
||||
loadStoredData(newlyCreatedWorlds.toSet())
|
||||
}
|
||||
|
||||
private fun loadStoredData(newlyCreatedWorlds: Collection<ParcelWorld> = emptyList()) {
|
||||
plugin.launch(Dispatchers.Default) {
|
||||
val migration = plugin.options.migration
|
||||
if (migration.enabled) {
|
||||
migration.instance?.newInstance()?.apply {
|
||||
logger.warn("Migrating database now...")
|
||||
migrateTo(plugin.storage).join()
|
||||
logger.warn("Migration completed")
|
||||
|
||||
if (migration.disableWhenComplete) {
|
||||
migration.enabled = false
|
||||
plugin.saveOptions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Loading all parcel data...")
|
||||
|
||||
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()
|
||||
while (true) {
|
||||
val (profile, data) = channel2.receiveOrNull() ?: break
|
||||
if (profile !is PrivilegeKey) {
|
||||
logger.error("Received profile that is not a privilege key: ${profile.javaClass}, $profile")
|
||||
continue
|
||||
}
|
||||
(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) {
|
||||
val world: ParcelWorld
|
||||
try {
|
||||
|
||||
world = ParcelWorldImpl(
|
||||
worldName,
|
||||
worldOptions,
|
||||
worldOptions.generator.newGenerator(this, worldName),
|
||||
plugin.storage,
|
||||
plugin.globalPrivileges,
|
||||
::DefaultParcelContainer)
|
||||
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
continue
|
||||
}
|
||||
|
||||
_worlds[worldName] = world
|
||||
}
|
||||
|
||||
plugin.functionHelper.schedule(10) {
|
||||
println("Parcels generating parcelProvider now")
|
||||
for ((name, world) in _worlds) {
|
||||
if (Bukkit.getWorld(name) == null) {
|
||||
val bworld = WorldCreator(name).generator(world.generator).createWorld()
|
||||
val spawn = world.generator.getFixedSpawnLocation(bworld, null)
|
||||
bworld.setSpawnLocation(spawn.x.floor(), spawn.y.floor(), spawn.z.floor())
|
||||
}
|
||||
}
|
||||
|
||||
val channel = plugin.storage.transmitAllParcelData()
|
||||
val job = plugin.functionHelper.launchLazilyOnMainThread {
|
||||
do {
|
||||
val pair = channel.receiveOrNull() ?: break
|
||||
val parcel = getParcelById(pair.first) ?: continue
|
||||
pair.second?.let { parcel.copyDataIgnoringDatabase(it) }
|
||||
} while (true)
|
||||
}
|
||||
job.start()
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.blockvisitor.Schematic
|
||||
import io.dico.parcels2.util.schedule
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.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
|
||||
override val worlds: Map<String, ParcelWorld> get() = _worlds
|
||||
private val _worlds: MutableMap<String, ParcelWorld> = hashMapOf()
|
||||
private val _generators: MutableMap<String, ParcelGenerator> = hashMapOf()
|
||||
private var _worldsLoaded = false
|
||||
private var _dataIsLoaded = false
|
||||
|
||||
// disabled while !_dataIsLoaded. getParcelById() will work though for data loading.
|
||||
override fun getWorld(name: String): ParcelWorld? = _worlds[name]?.takeIf { _dataIsLoaded }
|
||||
|
||||
override fun getWorldById(id: ParcelWorldId): ParcelWorld? {
|
||||
if (id is ParcelWorld) return id
|
||||
return _worlds[id.name] ?: id.bukkitWorld?.let { getWorld(it) }
|
||||
}
|
||||
|
||||
override fun getParcelById(id: ParcelId): Parcel? {
|
||||
if (id is Parcel) return id
|
||||
return getWorldById(id.worldId)?.container?.getParcelById(id.x, id.z)
|
||||
}
|
||||
|
||||
override fun getWorldGenerator(worldName: String): ParcelGenerator? {
|
||||
return _worlds[worldName]?.generator
|
||||
?: _generators[worldName]
|
||||
?: options.worlds[worldName]?.generator?.newInstance(worldName)?.also { _generators[worldName] = it }
|
||||
}
|
||||
|
||||
override fun loadWorlds() {
|
||||
if (_worldsLoaded) throw IllegalStateException()
|
||||
_worldsLoaded = true
|
||||
loadWorlds0()
|
||||
}
|
||||
|
||||
private fun loadWorlds0() {
|
||||
if (Bukkit.getWorlds().isEmpty()) {
|
||||
plugin.schedule(::loadWorlds0)
|
||||
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
|
||||
|
||||
val generator: ParcelGenerator = getWorldGenerator(worldName)!!
|
||||
val worldExists = Bukkit.getWorld(worldName) != null
|
||||
val bukkitWorld =
|
||||
if (worldExists) Bukkit.getWorld(worldName)!!
|
||||
else {
|
||||
logger.info("Creating world $worldName")
|
||||
WorldCreator(worldName).generator(generator).createWorld()
|
||||
}
|
||||
|
||||
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 {
|
||||
GlobalScope.launch(context = Dispatchers.Unconfined) {
|
||||
parcelWorld.creationTime = plugin.storage.getWorldCreationTime(parcelWorld.id).await() ?: DateTime.now()
|
||||
}
|
||||
}
|
||||
|
||||
_worlds[worldName] = parcelWorld
|
||||
}
|
||||
|
||||
loadStoredData(newlyCreatedWorlds.toSet())
|
||||
}
|
||||
|
||||
private fun loadStoredData(newlyCreatedWorlds: Collection<ParcelWorld> = emptyList()) {
|
||||
plugin.launch(Dispatchers.Default) {
|
||||
val migration = plugin.options.migration
|
||||
if (migration.enabled) {
|
||||
migration.instance?.newInstance()?.apply {
|
||||
logger.warn("Migrating database now...")
|
||||
migrateTo(plugin.storage).join()
|
||||
logger.warn("Migration completed")
|
||||
|
||||
if (migration.disableWhenComplete) {
|
||||
migration.enabled = false
|
||||
plugin.saveOptions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Loading all parcel data...")
|
||||
|
||||
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()
|
||||
while (true) {
|
||||
val (profile, data) = channel2.receiveOrNull() ?: break
|
||||
if (profile !is PrivilegeKey) {
|
||||
logger.error("Received profile that is not a privilege key: ${profile.javaClass}, $profile")
|
||||
continue
|
||||
}
|
||||
(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) {
|
||||
val world: ParcelWorld
|
||||
try {
|
||||
|
||||
world = ParcelWorldImpl(
|
||||
worldName,
|
||||
worldOptions,
|
||||
worldOptions.generator.newGenerator(this, worldName),
|
||||
plugin.storage,
|
||||
plugin.globalPrivileges,
|
||||
::DefaultParcelContainer)
|
||||
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
continue
|
||||
}
|
||||
|
||||
_worlds[worldName] = world
|
||||
}
|
||||
|
||||
plugin.functionHelper.schedule(10) {
|
||||
println("Parcels generating parcelProvider now")
|
||||
for ((name, world) in _worlds) {
|
||||
if (Bukkit.getWorld(name) == null) {
|
||||
val bworld = WorldCreator(name).generator(world.generator).createWorld()
|
||||
val spawn = world.generator.getFixedSpawnLocation(bworld, null)
|
||||
bworld.setSpawnLocation(spawn.x.floor(), spawn.y.floor(), spawn.z.floor())
|
||||
}
|
||||
}
|
||||
|
||||
val channel = plugin.storage.transmitAllParcelData()
|
||||
val job = plugin.functionHelper.launchLazilyOnMainThread {
|
||||
do {
|
||||
val pair = channel.receiveOrNull() ?: break
|
||||
val parcel = getParcelById(pair.first) ?: continue
|
||||
pair.second?.let { parcel.copyDataIgnoringDatabase(it) }
|
||||
} while (true)
|
||||
}
|
||||
job.start()
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,75 +1,75 @@
|
||||
@file:Suppress("CanBePrimaryConstructorProperty", "UsePropertyAccessSyntax")
|
||||
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
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(
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
override val name: String = world.name!!
|
||||
override val container: ParcelContainer = containerFactory(this)
|
||||
override val locator: ParcelLocator
|
||||
override val blockManager: ParcelBlockManager
|
||||
|
||||
init {
|
||||
val (locator, blockManager) = generator.makeParcelLocatorAndBlockManager(plugin.parcelProvider, container, plugin, plugin.jobDispatcher)
|
||||
this.locator = locator
|
||||
this.blockManager = blockManager
|
||||
enforceOptions()
|
||||
}
|
||||
|
||||
fun enforceOptions() {
|
||||
if (options.dayTime) {
|
||||
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false)
|
||||
world.setTime(6000)
|
||||
}
|
||||
|
||||
if (options.noWeather) {
|
||||
world.setStorm(false)
|
||||
world.setThundering(false)
|
||||
world.weatherDuration = Int.MAX_VALUE
|
||||
}
|
||||
|
||||
world.setGameRule(GameRule.DO_TILE_DROPS, options.doTileDrops)
|
||||
}
|
||||
|
||||
// Accessed by ParcelProviderImpl
|
||||
override var creationTime: DateTime? = null
|
||||
|
||||
|
||||
override fun getParcelAt(x: Int, z: Int): Parcel? = locator.getParcelAt(x, z)
|
||||
|
||||
override fun getParcelIdAt(x: Int, z: Int): ParcelId? = locator.getParcelIdAt(x, z)
|
||||
|
||||
override fun getParcelById(x: Int, z: Int): Parcel? = container.getParcelById(x, z)
|
||||
|
||||
override fun getParcelById(id: ParcelId): Parcel? = container.getParcelById(id)
|
||||
|
||||
override fun nextEmptyParcel(): Parcel? = container.nextEmptyParcel()
|
||||
|
||||
override fun toString() = parcelWorldIdToString()
|
||||
}
|
||||
@file:Suppress("CanBePrimaryConstructorProperty", "UsePropertyAccessSyntax")
|
||||
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
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(
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
override val name: String = world.name!!
|
||||
override val container: ParcelContainer = containerFactory(this)
|
||||
override val locator: ParcelLocator
|
||||
override val blockManager: ParcelBlockManager
|
||||
|
||||
init {
|
||||
val (locator, blockManager) = generator.makeParcelLocatorAndBlockManager(plugin.parcelProvider, container, plugin, plugin.jobDispatcher)
|
||||
this.locator = locator
|
||||
this.blockManager = blockManager
|
||||
enforceOptions()
|
||||
}
|
||||
|
||||
fun enforceOptions() {
|
||||
if (options.dayTime) {
|
||||
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false)
|
||||
world.setTime(6000)
|
||||
}
|
||||
|
||||
if (options.noWeather) {
|
||||
world.setStorm(false)
|
||||
world.setThundering(false)
|
||||
world.weatherDuration = Int.MAX_VALUE
|
||||
}
|
||||
|
||||
world.setGameRule(GameRule.DO_TILE_DROPS, options.doTileDrops)
|
||||
}
|
||||
|
||||
// Accessed by ParcelProviderImpl
|
||||
override var creationTime: DateTime? = null
|
||||
|
||||
|
||||
override fun getParcelAt(x: Int, z: Int): Parcel? = locator.getParcelAt(x, z)
|
||||
|
||||
override fun getParcelIdAt(x: Int, z: Int): ParcelId? = locator.getParcelIdAt(x, z)
|
||||
|
||||
override fun getParcelById(x: Int, z: Int): Parcel? = container.getParcelById(x, z)
|
||||
|
||||
override fun getParcelById(id: ParcelId): Parcel? = container.getParcelById(id)
|
||||
|
||||
override fun nextEmptyParcel(): Parcel? = container.nextEmptyParcel()
|
||||
|
||||
override fun toString() = parcelWorldIdToString()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user