summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDico <dico.karssiens@gmail.com>2018-09-25 08:40:02 +0100
committerDico <dico.karssiens@gmail.com>2018-09-25 08:40:02 +0100
commitdcd90c09add292300b163edf44c26ddf99f1199b (patch)
tree7f4dac848950910dd4535cb1a946b84f6aa5aa0a
parent98395542a507e40a9058d2ed6332853ec20b23fc (diff)
Work on RegionTraverser (wasted a lotta time but we'll get there)
-rw-r--r--build.gradle.kts7
-rw-r--r--src/main/kotlin/io/dico/parcels2/blockvisitor/Attachables.kt108
-rw-r--r--src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt303
-rw-r--r--src/main/kotlin/io/dico/parcels2/blockvisitor/Schematic.kt34
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/CommandsDebug.kt17
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt5
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt9
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt14
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/Vec3i.kt22
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<JavaPlugin>()
+ 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<Material> = 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<Vec3i> = Iterable { iterator<Vec3i> { build(region) } }
+private typealias Scope = SequenceScope<Vec3i>
- protected abstract suspend fun SequenceScope<Vec3i>.build(region: Region)
+sealed class RegionTraverser {
+ fun traverseRegion(region: Region, worldHeight: Int = 256): Iterable<Vec3i> =
+ Iterable { iterator<Vec3i> { 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<Vec3i>.(Region) -> Unit) = object : RegionTraverser() {
- override suspend fun SequenceScope<Vec3i>.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<Vec3i>.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<Vec3i>.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<Region, Region?> {
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<Vec3i>
+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<BlockData?>? = null
+ private var blockDatas: Array<BlockData?>? = null
//private var extra: Map<Vec3i, (Block) -> 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<BlockData>(region.blockCount).also { _data = it }
+ _size = region.size
+
+ val data = arrayOfNulls<BlockData>(region.blockCount).also { blockDatas = it }
//val extra = mutableMapOf<Vec3i, (Block) -> 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<Pair<Vec3i, BlockData>>()
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<Unit>) {
+ 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")