From dcd90c09add292300b163edf44c26ddf99f1199b Mon Sep 17 00:00:00 2001 From: Dico Date: Tue, 25 Sep 2018 08:40:02 +0100 Subject: Work on RegionTraverser (wasted a lotta time but we'll get there) --- build.gradle.kts | 7 +- .../io/dico/parcels2/blockvisitor/Attachables.kt | 108 ++++---- .../dico/parcels2/blockvisitor/RegionTraverser.kt | 303 ++++++++++++++++++--- .../io/dico/parcels2/blockvisitor/Schematic.kt | 34 ++- .../io/dico/parcels2/command/CommandsDebug.kt | 17 ++ .../parcels2/defaultimpl/DefaultParcelGenerator.kt | 2 +- .../dico/parcels2/listener/ParcelEntityTracker.kt | 5 +- .../io/dico/parcels2/listener/ParcelListeners.kt | 9 +- .../io/dico/parcels2/util/MainThreadDispatcher.kt | 14 +- src/main/kotlin/io/dico/parcels2/util/Vec3i.kt | 22 ++ 10 files changed, 406 insertions(+), 115 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7fb3ede..06f2041 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,8 +17,11 @@ plugins { id("com.github.johnrengelman.plugin-shadow") version "2.0.3" } + + allprojects { apply() + apply(plugin = "idea") repositories { mavenCentral() @@ -68,7 +71,7 @@ dependencies { // not on sk89q maven repo yet compileClasspath(files("$rootDir/debug/plugins/worldedit-bukkit-7.0.0-beta-01.jar")) - compileClasspath(files("$rootDir/debug/lib/spigot-1.13.1.jar")) + //compileClasspath(files("$rootDir/debug/lib/spigot-1.13.1.jar")) compile("org.jetbrains.exposed:exposed:0.10.5") { isTransitive = false } compile("joda-time:joda-time:2.10") @@ -91,7 +94,7 @@ tasks { javaParameters = true suppressWarnings = true jvmTarget = "1.8" - //freeCompilerArgs = listOf("-XXLanguage:+InlineClasses", "-Xuse-experimental=kotlin.Experimental") + freeCompilerArgs = listOf("-XXLanguage:+InlineClasses", "-Xuse-experimental=kotlin.Experimental") } } diff --git a/src/main/kotlin/io/dico/parcels2/blockvisitor/Attachables.kt b/src/main/kotlin/io/dico/parcels2/blockvisitor/Attachables.kt index 9403f34..84d8a58 100644 --- a/src/main/kotlin/io/dico/parcels2/blockvisitor/Attachables.kt +++ b/src/main/kotlin/io/dico/parcels2/blockvisitor/Attachables.kt @@ -1,67 +1,61 @@ package io.dico.parcels2.blockvisitor +import io.dico.parcels2.util.Vec3i +import io.dico.parcels2.util.ext.getMaterialsWithWoodTypePrefix +import io.dico.parcels2.util.ext.getMaterialsWithWoolColorPrefix import org.bukkit.Material import org.bukkit.Material.* +import org.bukkit.block.BlockFace +import org.bukkit.block.data.BlockData +import org.bukkit.block.data.Directional import java.util.EnumSet -val attachables: Set = EnumSet.of( - ACACIA_DOOR, - ACTIVATOR_RAIL, - BIRCH_DOOR, - BROWN_MUSHROOM, - CACTUS, - CAKE, - WHITE_CARPET, ORANGE_CARPET, MAGENTA_CARPET, LIGHT_BLUE_CARPET, YELLOW_CARPET, LIME_CARPET, PINK_CARPET, GRAY_CARPET, LIGHT_GRAY_CARPET, CYAN_CARPET, PURPLE_CARPET, BLUE_CARPET, BROWN_CARPET, GREEN_CARPET, RED_CARPET, BLACK_CARPET, - CARROT, - COCOA, - WHEAT, - DARK_OAK_DOOR, - DEAD_BUSH, - DETECTOR_RAIL, - REPEATER, - TALL_GRASS, TALL_SEAGRASS, - DRAGON_EGG, - FIRE, - FLOWER_POT, - OAK_PRESSURE_PLATE, BIRCH_PRESSURE_PLATE, SPRUCE_PRESSURE_PLATE, JUNGLE_PRESSURE_PLATE, ACACIA_PRESSURE_PLATE, DARK_OAK_PRESSURE_PLATE, +private val attachables = EnumSet.of( + REPEATER, COMPARATOR, + *getMaterialsWithWoodTypePrefix("PRESSURE_PLATE"), STONE_PRESSURE_PLATE, LIGHT_WEIGHTED_PRESSURE_PLATE, HEAVY_WEIGHTED_PRESSURE_PLATE, - IRON_DOOR, - OAK_DOOR, BIRCH_DOOR, SPRUCE_DOOR, JUNGLE_DOOR, ACACIA_DOOR, DARK_OAK_DOOR, - OAK_BUTTON, BIRCH_BUTTON, SPRUCE_BUTTON, JUNGLE_BUTTON, ACACIA_BUTTON, DARK_OAK_BUTTON, - STONE_BUTTON, - OAK_TRAPDOOR, BIRCH_TRAPDOOR, SPRUCE_TRAPDOOR, JUNGLE_TRAPDOOR, ACACIA_TRAPDOOR, DARK_OAK_TRAPDOOR, - IRON_TRAPDOOR, + *getMaterialsWithWoodTypePrefix("BUTTON"), + STONE_BUTTON, LEVER, + *getMaterialsWithWoodTypePrefix("DOOR"), IRON_DOOR, + ACTIVATOR_RAIL, POWERED_RAIL, DETECTOR_RAIL, RAIL, + PISTON, STICKY_PISTON, + REDSTONE_TORCH, REDSTONE_WALL_TORCH, REDSTONE_WIRE, + TRIPWIRE, TRIPWIRE_HOOK, + + BROWN_MUSHROOM, RED_MUSHROOM, CACTUS, CARROT, COCOA, + WHEAT, DEAD_BUSH, CHORUS_FLOWER, DANDELION, SUGAR_CANE, + TALL_GRASS, TALL_SEAGRASS, NETHER_WART, MELON_STEM, + PUMPKIN_STEM, SUNFLOWER, POTATO, LILY_PAD, VINE, + *getMaterialsWithWoodTypePrefix("SAPLING"), + + SAND, RED_SAND, DRAGON_EGG, ANVIL, + *getMaterialsWithWoolColorPrefix("CONCRETE_POWDER"), + + *getMaterialsWithWoolColorPrefix("CARPET"), + CAKE, FIRE, + FLOWER_POT, LADDER, - LEVER, - MELON_STEM, - NETHER_WART, - PISTON, - STICKY_PISTON, - NETHER_PORTAL, - POTATO, - POWERED_RAIL, - PUMPKIN_STEM, - RAIL, - COMPARATOR, - REDSTONE_TORCH, - REDSTONE_WIRE, - RED_MUSHROOM, - SUNFLOWER, + // NETHER_PORTAL, fuck nether portals FLOWER_POT, - CHORUS_FLOWER, - OAK_SAPLING, BIRCH_SAPLING, SPRUCE_SAPLING, JUNGLE_SAPLING, ACACIA_SAPLING, DARK_OAK_SAPLING, - SIGN, SNOW, - SPRUCE_DOOR, - STONE_BUTTON, - SUGAR_CANE, - TORCH, - TRIPWIRE, - TRIPWIRE_HOOK, - VINE, - WHITE_BANNER, ORANGE_BANNER, MAGENTA_BANNER, LIGHT_BLUE_BANNER, YELLOW_BANNER, LIME_BANNER, PINK_BANNER, GRAY_BANNER, LIGHT_GRAY_BANNER, CYAN_BANNER, PURPLE_BANNER, BLUE_BANNER, BROWN_BANNER, GREEN_BANNER, RED_BANNER, BLACK_BANNER, - WHITE_WALL_BANNER, ORANGE_WALL_BANNER, MAGENTA_WALL_BANNER, LIGHT_BLUE_WALL_BANNER, YELLOW_WALL_BANNER, LIME_WALL_BANNER, PINK_WALL_BANNER, GRAY_WALL_BANNER, LIGHT_GRAY_WALL_BANNER, CYAN_WALL_BANNER, PURPLE_WALL_BANNER, BLUE_WALL_BANNER, BROWN_WALL_BANNER, GREEN_WALL_BANNER, RED_WALL_BANNER, BLACK_WALL_BANNER, - WALL_SIGN, - LILY_PAD, - DANDELION -) \ No newline at end of file + TORCH, WALL_TORCH, + *getMaterialsWithWoolColorPrefix("BANNER"), + *getMaterialsWithWoolColorPrefix("WALL_BANNER"), + SIGN, WALL_SIGN +) + +fun isAttachable(type: Material) = attachables.contains(type) + +fun supportingBlock(data: BlockData): Vec3i = when (data) { + //is MultipleFacing -> // fuck it xD this is good enough + + is Directional -> Vec3i.convert(when (data.material) { + // exceptions + COCOA -> data.facing + OAK_DOOR, BIRCH_DOOR, SPRUCE_DOOR, JUNGLE_DOOR, ACACIA_DOOR, DARK_OAK_DOOR, IRON_DOOR -> BlockFace.DOWN + + else -> data.facing.oppositeFace + }) + + else -> Vec3i.down +} diff --git a/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt index 3899db9..563d7a1 100644 --- a/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt +++ b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt @@ -2,64 +2,291 @@ package io.dico.parcels2.blockvisitor import io.dico.parcels2.util.Region import io.dico.parcels2.util.Vec3i +import io.dico.parcels2.util.ext.clampMax -abstract class RegionTraverser { - fun traverseRegion(region: Region): Iterable = Iterable { iterator { build(region) } } +private typealias Scope = SequenceScope - protected abstract suspend fun SequenceScope.build(region: Region) +sealed class RegionTraverser { + fun traverseRegion(region: Region, worldHeight: Int = 256): Iterable = + Iterable { iterator { build(validify(region, worldHeight)) } } - companion object { - val upward = create { traverseUpward(it) } - val downward = create { traverseDownward(it) } - val forClearing get() = downward - val forFilling get() = upward - - inline fun create(crossinline builder: suspend SequenceScope.(Region) -> Unit) = object : RegionTraverser() { - override suspend fun SequenceScope.build(region: Region) { - builder(region) - } + private fun validify(region: Region, worldHeight: Int): Region { + if (region.origin.y < 0) { + val origin = region.origin withY 0 + val size = region.size.withY((region.size.y + region.origin.y).clampMax(worldHeight)) + return Region(origin, size) } - private suspend fun SequenceScope.traverseDownward(region: Region) { - val origin = region.origin - val size = region.size - repeat(size.y) { y -> - repeat(size.z) { z -> - repeat(size.x) { x -> - yield(origin.add(x, size.y - y - 1, z)) - } - } - } + if (region.origin.y + region.size.y > worldHeight) { + val size = region.size.withY(worldHeight - region.origin.y) + return Region(region.origin, size) } - private suspend fun SequenceScope.traverseUpward(region: Region) { - val origin = region.origin - val size = region.size - repeat(size.y) { y -> - repeat(size.z) { z -> - repeat(size.x) { x -> - yield(origin.add(x, size.y - y - 1, z)) - } - } - } + return region + } + + protected abstract suspend fun Scope.build(region: Region) + + companion object { + val upward = Directional(TraverseDirection(1, 1, 1), TraverseOrder(Dimension.Y, Dimension.X)) + val downward = Directional(TraverseDirection(1, -1, 1), TraverseOrder(Dimension.Y, Dimension.X)) + val toClear get() = downward + val toFill get() = upward + + fun convergingTo(y: Int) = Slicing(y, upward, downward, true) + + fun separatingFrom(y: Int) = Slicing(y, downward, upward, false) + } + + class Directional( + val direction: TraverseDirection, + val order: TraverseOrder + ) : RegionTraverser() { + override suspend fun Scope.build(region: Region) { + //traverserLogic(region, order, direction) } + } + + class Slicing( + val bottomSectionMaxY: Int, + val bottomTraverser: RegionTraverser, + val topTraverser: RegionTraverser, + val bottomFirst: Boolean = true + ) : RegionTraverser() { + private fun slice(region: Region, atY: Int): Pair { if (atY < region.size.y + 1) { val first = Region(region.origin, region.size.withY(atY + 1)) - val second = Region(region.origin.withY(atY), region.size.addY(-atY-1)) + val second = Region(region.origin.withY(atY), region.size.addY(-atY - 1)) return first to second } return region to null } - fun upToAndDownUntil(y: Int) = create { region -> - val (bottom, top) = slice(region, y) - traverseUpward(bottom) - top?.let { traverseDownward(it) } + override suspend fun Scope.build(region: Region) { + val (bottom, top) = slice(region, bottomSectionMaxY) + + if (bottomFirst) { + with(bottomTraverser) { build(bottom) } + top?.let { with(topTraverser) { build(it) } } + } else { + top?.let { with(topTraverser) { build(it) } } + with(bottomTraverser) { build(bottom) } + } + } + } + +} + +enum class Dimension { + X, + Y, + Z; + + fun extract(block: Vec3i) = + when (this) { + X -> block.x + Y -> block.y + Z -> block.z } + companion object { + private val values = values() + operator fun get(ordinal: Int) = values[ordinal] } +} + +inline class TraverseOrder(val orderNum: Int) { + private constructor(first: Dimension, swap: Boolean) + : this(if (swap) first.ordinal + 3 else first.ordinal) + + @Suppress("NOTHING_TO_INLINE") + private inline fun element(index: Int) = Dimension[(orderNum + index) % 3] + + private val swap inline get() = orderNum >= 3 + + /** + * The slowest changing dimension + */ + val primary: Dimension get() = element(0) + + /** + * Second slowest changing dimension + */ + val secondary: Dimension get() = element(if (swap) 2 else 1) + + /** + * Dimension that changes every block + */ + val tertiary: Dimension get() = element(if (swap) 1 else 2) + + /** + * All 3 dimensions in this order + */ + fun toArray() = arrayOf(primary, secondary, tertiary) + companion object { + private fun isSwap(primary: Dimension, secondary: Dimension) = secondary.ordinal != (primary.ordinal + 1) % 3 + + operator fun invoke(primary: Dimension, secondary: Dimension): TraverseOrder { + // tertiary is implicit + if (primary == secondary) throw IllegalArgumentException() + return TraverseOrder(primary, isSwap(primary, secondary)) + } + } + fun add(vec: Vec3i, dp: Int, ds: Int, dt: Int): Vec3i = + // optimize this, will be called lots + when (orderNum) { + 0 -> vec.add(dp, ds, dt) // xyz + 1 -> vec.add(dt, dp, ds) // yzx + 2 -> vec.add(ds, dt, dp) // zxy + 3 -> vec.add(dp, dt, ds) // xzy + 4 -> vec.add(ds, dp, dt) // yxz + 5 -> vec.add(dt, ds, dp) // zyx + else -> error("Invalid orderNum $orderNum") + } } + +class AltTraverser(val size: Vec3i, + val order: TraverseOrder, + val direction: TraverseDirection) { + + + suspend fun Scope.build() { + doPrimary() + } + + private suspend fun Scope.doPrimary() { + val dimension = order.primary + direction.directionOf(dimension).traverse(dimension.extract(size)) { value -> + + } + } + + private fun Dimension.setValue(value: Int) { + + } + +} + +enum class Increment(val offset: Int) { + UP(1), + DOWN(-1); + + companion object { + fun convert(bool: Boolean) = if (bool) UP else DOWN + } + + inline fun traverse(size: Int, op: (Int) -> Unit) { + when (this) { + UP -> repeat(size, op) + DOWN -> repeat(size) { op(size - it - 1) } + } + } + +} + +inline class TraverseDirection(val bits: Int) { + + fun directionOf(dimension: Dimension) = Increment.convert((1 shl dimension.ordinal) and bits != 0) + + companion object { + operator fun invoke(x: Int, y: Int, z: Int) = invoke(Vec3i(x, y, z)) + + operator fun invoke(block: Vec3i): TraverseDirection { + if (block.x == 0 || block.y == 0 || block.z == 0) throw IllegalArgumentException() + var bits = 0 + if (block.x > 0) bits = bits or 1 + if (block.y > 0) bits = bits or 2 + if (block.z > 0) bits = bits or 3 + return TraverseDirection(bits) + } + } + +} + +/* +private typealias Scope = SequenceScope +private typealias ScopeAction = suspend Scope.(Int, Int, Int) -> Unit + +@Suppress("NON_EXHAUSTIVE_WHEN") +suspend fun Scope.traverserLogic( + region: Region, + order: TraverseOrder, + direction: TraverseDirection +) = with(direction) { + val (primary, secondary, tertiary) = order.toArray() + val (origin, size) = region + + when (order.primary) { + Dimension.X -> + when (order.secondary) { + Dimension.Y -> { + directionOf(primary).traverse(primary.extract(size)) { p -> + directionOf(secondary).traverse(secondary.extract(size)) { s -> + directionOf(tertiary).traverse(tertiary.extract(size)) { t -> + yield(origin.add(p, s, t)) + } + } + } + } + Dimension.Z -> { + directionOf(primary).traverse(primary.extract(size)) { p -> + directionOf(secondary).traverse(secondary.extract(size)) { s -> + directionOf(tertiary).traverse(tertiary.extract(size)) { t -> + yield(origin.add(p, t, s)) + } + } + } + } + } + + Dimension.Y -> + when (order.secondary) { + Dimension.X -> { + directionOf(primary).traverse(primary.extract(size)) { p -> + directionOf(secondary).traverse(secondary.extract(size)) { s -> + directionOf(tertiary).traverse(tertiary.extract(size)) { t -> + yield(origin.add(s, p, t)) + } + } + } + } + Dimension.Z -> { + directionOf(primary).traverse(primary.extract(size)) { p -> + directionOf(secondary).traverse(secondary.extract(size)) { s -> + directionOf(tertiary).traverse(tertiary.extract(size)) { t -> + yield(origin.add(t, p, s)) + } + } + } + } + } + + Dimension.Z -> + when (order.secondary) { + Dimension.X -> { + directionOf(primary).traverse(primary.extract(size)) { p -> + directionOf(secondary).traverse(secondary.extract(size)) { s -> + directionOf(tertiary).traverse(tertiary.extract(size)) { t -> + yield(origin.add(s, t, p)) + } + } + } + } + Dimension.Y -> { + directionOf(primary).traverse(primary.extract(size)) { p -> + directionOf(secondary).traverse(secondary.extract(size)) { s -> + directionOf(tertiary).traverse(tertiary.extract(size)) { t -> + yield(origin.add(t, s, p)) + } + } + } + } + } + } +} + +*/ \ No newline at end of file diff --git a/src/main/kotlin/io/dico/parcels2/blockvisitor/Schematic.kt b/src/main/kotlin/io/dico/parcels2/blockvisitor/Schematic.kt index 7e109c8..8d2084b 100644 --- a/src/main/kotlin/io/dico/parcels2/blockvisitor/Schematic.kt +++ b/src/main/kotlin/io/dico/parcels2/blockvisitor/Schematic.kt @@ -3,9 +3,13 @@ package io.dico.parcels2.blockvisitor import io.dico.parcels2.util.Region import io.dico.parcels2.util.Vec3i import io.dico.parcels2.util.get +import org.bukkit.Bukkit +import org.bukkit.Material import org.bukkit.World import org.bukkit.block.data.BlockData +private val air = Bukkit.createBlockData(Material.AIR) + // TODO order paste such that attachables are placed after the block they depend on class Schematic { val size: Vec3i get() = _size!! @@ -15,15 +19,17 @@ class Schematic { field = value } - private var _data: Array? = null + private var blockDatas: Array? = null //private var extra: Map Unit>? = null private var isLoaded = false; private set + private val traverser: RegionTraverser = RegionTraverser.upward fun getLoadTask(world: World, region: Region): TimeLimitedTask = { - val size = region.size.also { _size = it } - val data = arrayOfNulls(region.blockCount).also { _data = it } + _size = region.size + + val data = arrayOfNulls(region.blockCount).also { blockDatas = it } //val extra = mutableMapOf Unit>().also { extra = it } - val blocks = RegionTraverser.downward.traverseRegion(region) + val blocks = traverser.traverseRegion(region) for ((index, vec) in blocks.withIndex()) { markSuspensionPoint() @@ -39,14 +45,26 @@ class Schematic { fun getPasteTask(world: World, position: Vec3i): TimeLimitedTask = { if (!isLoaded) throw IllegalStateException() val region = Region(position, _size!!) - val blocks = RegionTraverser.downward.traverseRegion(region) - val data = _data!! + val blocks = traverser.traverseRegion(region, worldHeight = world.maxHeight) + val blockDatas = blockDatas!! + + val postponed = mutableListOf>() for ((index, vec) in blocks.withIndex()) { markSuspensionPoint() val block = world[vec] - if (block.y > 255) continue - data[index]?.let { block.blockData = it } + val type = blockDatas[index] ?: air + if (type !== air && isAttachable(type.material)) { + + + postponed += vec to type + } else { + block.blockData = type + } + } + + for ((vec, data) in postponed) { + } } diff --git a/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt b/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt index b646450..916fccd 100644 --- a/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt +++ b/src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt @@ -10,6 +10,8 @@ import io.dico.parcels2.blockvisitor.RegionTraverser import io.dico.parcels2.doBlockOperation import org.bukkit.Bukkit import org.bukkit.Material +import org.bukkit.block.BlockFace +import org.bukkit.block.data.Directional import org.bukkit.entity.Player import java.util.Random @@ -55,4 +57,19 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) { } } + @Cmd("directionality", aliases = ["dir"]) + fun cmdDirectionality(sender: Player, context: ExecutionContext, material: Material): Any? { + val senderLoc = sender.location + val block = senderLoc.add(senderLoc.direction.setY(0).normalize().multiply(2).toLocation(sender.world)).block + + val blockData = Bukkit.createBlockData(material) + if (blockData is Directional) { + blockData.facing = BlockFace.SOUTH + } + + block.blockData = blockData + return if (blockData is Directional) "The block is facing south" else "The block is not directional, however it implements " + + blockData.javaClass.interfaces!!.contentToString() + } + } \ No newline at end of file diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt index 84324f7..8c8f303 100644 --- a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt +++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt @@ -162,7 +162,7 @@ class DefaultParcelGenerator( override val worktimeLimiter: WorktimeLimiter ) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope { override val world: World = this@DefaultParcelGenerator.world - override val parcelTraverser: RegionTraverser = RegionTraverser.upToAndDownUntil(o.floorHeight) + override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight) /*override*/ fun getBottomBlock(parcel: ParcelId): Vec2i = Vec2i( sectionSize * (parcel.x - 1) + pathOffset + o.offsetX, diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt index 3785770..198e0e7 100644 --- a/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt +++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt @@ -33,7 +33,7 @@ class ParcelEntityTracker(val parcelProvider: ParcelProvider) { remove() val newParcel = parcelProvider.getParcelAt(entity.location) - if (newParcel !== parcel && !(newParcel != null && newParcel.hasBlockVisitors)) { + if (newParcel !== parcel && (newParcel == null || !newParcel.hasBlockVisitors)) { entity.remove() } @@ -41,14 +41,13 @@ class ParcelEntityTracker(val parcelProvider: ParcelProvider) { } val newParcel = parcelProvider.getParcelAt(entity.location) - if (newParcel !== parcel && !(newParcel != null && newParcel.hasBlockVisitors)) { + if (newParcel !== parcel && (newParcel == null || !newParcel.hasBlockVisitors)) { remove() entity.remove() } } } - @Suppress("RedundantLambdaArrow") fun swapParcels(parcel1: Parcel, parcel2: Parcel) { map.editLoop { -> if (value === parcel1) { diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt index 9805f40..9d91cda 100644 --- a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt +++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt @@ -196,11 +196,10 @@ class ParcelListeners( when (event.action) { Action.RIGHT_CLICK_BLOCK -> run { val type = clickedBlock.type - val interactable = Interactables.listedMaterials.containsKey(type) - && (parcel.effectiveInteractableConfig.isInteractable(type) || (parcel != null && parcel.canBuild(user))) - if (!interactable) { - val interactableClassName = Interactables[type]!!.name - user.sendParcelMessage(nopermit = true, message = "You cannot interact with $interactableClassName in this parcel") + + val interactableClass = Interactables[type] + if (interactableClass != null && (parcel.effectiveInteractableConfig.isInteractable(type) || (parcel != null && parcel.canBuild(user)))) { + user.sendParcelMessage(nopermit = true, message = "You cannot interact with ${interactableClass.name} in this parcel") event.isCancelled = true return@l } diff --git a/src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt b/src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt index b1d18ab..ce1bf0f 100644 --- a/src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt +++ b/src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt @@ -1,11 +1,14 @@ package io.dico.parcels2.util +import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Delay import kotlinx.coroutines.Runnable +import kotlinx.coroutines.timeunit.TimeUnit import org.bukkit.plugin.Plugin import kotlin.coroutines.CoroutineContext -abstract class MainThreadDispatcher : CoroutineDispatcher() { +abstract class MainThreadDispatcher : CoroutineDispatcher(), Delay { abstract val mainThread: Thread abstract fun runOnMainThread(task: Runnable) } @@ -27,5 +30,14 @@ fun MainThreadDispatcher(plugin: Plugin): MainThreadDispatcher { if (Thread.currentThread() === mainThread) task.run() else plugin.server.scheduler.runTaskLater(plugin, task, 0) } + + override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation) { + val task = Runnable { + with (continuation) { resumeUndispatched(Unit) } + } + + val millis = TimeUnit.MILLISECONDS.convert(time, unit) + plugin.server.scheduler.runTaskLater(plugin, task, (millis + 25) / 50 - 1) + } } } \ No newline at end of file diff --git a/src/main/kotlin/io/dico/parcels2/util/Vec3i.kt b/src/main/kotlin/io/dico/parcels2/util/Vec3i.kt index ded1e0c..36a51c1 100644 --- a/src/main/kotlin/io/dico/parcels2/util/Vec3i.kt +++ b/src/main/kotlin/io/dico/parcels2/util/Vec3i.kt @@ -2,6 +2,7 @@ package io.dico.parcels2.util import org.bukkit.World import org.bukkit.block.Block +import org.bukkit.block.BlockFace data class Vec3d( val x: Double, @@ -32,6 +33,27 @@ data class Vec3i( infix fun withY(o: Int) = Vec3i(x, o, z) infix fun withZ(o: Int) = Vec3i(x, y, o) fun add(ox: Int, oy: Int, oz: Int) = Vec3i(x + ox, y + oy, z + oz) + fun neg() = Vec3i(-x, -y, -z) + + companion object { + private operator fun invoke(face: BlockFace) = Vec3i(face.modX, face.modY, face.modZ) + val down = Vec3i(BlockFace.DOWN) + val up = Vec3i(BlockFace.UP) + val north = Vec3i(BlockFace.NORTH) + val east = Vec3i(BlockFace.EAST) + val south = Vec3i(BlockFace.SOUTH) + val west = Vec3i(BlockFace.WEST) + + fun convert(face: BlockFace) = when (face) { + BlockFace.DOWN -> down + BlockFace.UP -> up + BlockFace.NORTH -> north + BlockFace.EAST -> east + BlockFace.SOUTH -> south + BlockFace.WEST -> west + else -> Vec3i(face) + } + } } @Suppress("NOTHING_TO_INLINE") -- cgit v1.2.3