diff options
Diffstat (limited to 'src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt')
-rw-r--r-- | src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt | 188 |
1 files changed, 90 insertions, 98 deletions
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt index 51671d4..e9ec148 100644 --- a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt +++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt @@ -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) + 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) } - throw IllegalArgumentException() + else -> return null } - return getRegion(parcel) + + 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 setOwnerBlock(parcel: ParcelId, owner: PlayerProfile?) { - val b = getBottomBlock(parcel) + 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 + } 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.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 |