Work on RegionTraverser (wasted a lotta time but we'll get there)
This commit is contained in:
@@ -17,8 +17,11 @@ plugins {
|
|||||||
id("com.github.johnrengelman.plugin-shadow") version "2.0.3"
|
id("com.github.johnrengelman.plugin-shadow") version "2.0.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
apply<JavaPlugin>()
|
apply<JavaPlugin>()
|
||||||
|
apply(plugin = "idea")
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -68,7 +71,7 @@ dependencies {
|
|||||||
|
|
||||||
// not on sk89q maven repo yet
|
// not on sk89q maven repo yet
|
||||||
compileClasspath(files("$rootDir/debug/plugins/worldedit-bukkit-7.0.0-beta-01.jar"))
|
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("org.jetbrains.exposed:exposed:0.10.5") { isTransitive = false }
|
||||||
compile("joda-time:joda-time:2.10")
|
compile("joda-time:joda-time:2.10")
|
||||||
@@ -91,7 +94,7 @@ tasks {
|
|||||||
javaParameters = true
|
javaParameters = true
|
||||||
suppressWarnings = true
|
suppressWarnings = true
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
//freeCompilerArgs = listOf("-XXLanguage:+InlineClasses", "-Xuse-experimental=kotlin.Experimental")
|
freeCompilerArgs = listOf("-XXLanguage:+InlineClasses", "-Xuse-experimental=kotlin.Experimental")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,67 +1,61 @@
|
|||||||
package io.dico.parcels2.blockvisitor
|
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.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
|
import java.util.EnumSet
|
||||||
|
|
||||||
val attachables: Set<Material> = EnumSet.of(
|
private val attachables = EnumSet.of(
|
||||||
ACACIA_DOOR,
|
REPEATER, COMPARATOR,
|
||||||
ACTIVATOR_RAIL,
|
*getMaterialsWithWoodTypePrefix("PRESSURE_PLATE"),
|
||||||
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,
|
|
||||||
STONE_PRESSURE_PLATE, LIGHT_WEIGHTED_PRESSURE_PLATE, HEAVY_WEIGHTED_PRESSURE_PLATE,
|
STONE_PRESSURE_PLATE, LIGHT_WEIGHTED_PRESSURE_PLATE, HEAVY_WEIGHTED_PRESSURE_PLATE,
|
||||||
IRON_DOOR,
|
*getMaterialsWithWoodTypePrefix("BUTTON"),
|
||||||
OAK_DOOR, BIRCH_DOOR, SPRUCE_DOOR, JUNGLE_DOOR, ACACIA_DOOR, DARK_OAK_DOOR,
|
STONE_BUTTON, LEVER,
|
||||||
OAK_BUTTON, BIRCH_BUTTON, SPRUCE_BUTTON, JUNGLE_BUTTON, ACACIA_BUTTON, DARK_OAK_BUTTON,
|
*getMaterialsWithWoodTypePrefix("DOOR"), IRON_DOOR,
|
||||||
STONE_BUTTON,
|
ACTIVATOR_RAIL, POWERED_RAIL, DETECTOR_RAIL, RAIL,
|
||||||
OAK_TRAPDOOR, BIRCH_TRAPDOOR, SPRUCE_TRAPDOOR, JUNGLE_TRAPDOOR, ACACIA_TRAPDOOR, DARK_OAK_TRAPDOOR,
|
PISTON, STICKY_PISTON,
|
||||||
IRON_TRAPDOOR,
|
REDSTONE_TORCH, REDSTONE_WALL_TORCH, REDSTONE_WIRE,
|
||||||
LADDER,
|
TRIPWIRE, TRIPWIRE_HOOK,
|
||||||
LEVER,
|
|
||||||
MELON_STEM,
|
BROWN_MUSHROOM, RED_MUSHROOM, CACTUS, CARROT, COCOA,
|
||||||
NETHER_WART,
|
WHEAT, DEAD_BUSH, CHORUS_FLOWER, DANDELION, SUGAR_CANE,
|
||||||
PISTON,
|
TALL_GRASS, TALL_SEAGRASS, NETHER_WART, MELON_STEM,
|
||||||
STICKY_PISTON,
|
PUMPKIN_STEM, SUNFLOWER, POTATO, LILY_PAD, VINE,
|
||||||
NETHER_PORTAL,
|
*getMaterialsWithWoodTypePrefix("SAPLING"),
|
||||||
POTATO,
|
|
||||||
POWERED_RAIL,
|
SAND, RED_SAND, DRAGON_EGG, ANVIL,
|
||||||
PUMPKIN_STEM,
|
*getMaterialsWithWoolColorPrefix("CONCRETE_POWDER"),
|
||||||
RAIL,
|
|
||||||
COMPARATOR,
|
*getMaterialsWithWoolColorPrefix("CARPET"),
|
||||||
REDSTONE_TORCH,
|
CAKE, FIRE,
|
||||||
REDSTONE_WIRE,
|
FLOWER_POT,
|
||||||
RED_MUSHROOM,
|
LADDER,
|
||||||
SUNFLOWER,
|
// NETHER_PORTAL, fuck nether portals
|
||||||
FLOWER_POT,
|
FLOWER_POT,
|
||||||
CHORUS_FLOWER,
|
|
||||||
OAK_SAPLING, BIRCH_SAPLING, SPRUCE_SAPLING, JUNGLE_SAPLING, ACACIA_SAPLING, DARK_OAK_SAPLING,
|
|
||||||
SIGN,
|
|
||||||
SNOW,
|
SNOW,
|
||||||
SPRUCE_DOOR,
|
TORCH, WALL_TORCH,
|
||||||
STONE_BUTTON,
|
*getMaterialsWithWoolColorPrefix("BANNER"),
|
||||||
SUGAR_CANE,
|
*getMaterialsWithWoolColorPrefix("WALL_BANNER"),
|
||||||
TORCH,
|
SIGN, WALL_SIGN
|
||||||
TRIPWIRE,
|
)
|
||||||
TRIPWIRE_HOOK,
|
|
||||||
VINE,
|
fun isAttachable(type: Material) = attachables.contains(type)
|
||||||
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,
|
fun supportingBlock(data: BlockData): Vec3i = when (data) {
|
||||||
WALL_SIGN,
|
//is MultipleFacing -> // fuck it xD this is good enough
|
||||||
LILY_PAD,
|
|
||||||
DANDELION
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,64 +2,291 @@ package io.dico.parcels2.blockvisitor
|
|||||||
|
|
||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.Region
|
||||||
import io.dico.parcels2.util.Vec3i
|
import io.dico.parcels2.util.Vec3i
|
||||||
|
import io.dico.parcels2.util.ext.clampMax
|
||||||
|
|
||||||
abstract class RegionTraverser {
|
private typealias Scope = SequenceScope<Vec3i>
|
||||||
fun traverseRegion(region: Region): Iterable<Vec3i> = Iterable { iterator<Vec3i> { build(region) } }
|
|
||||||
|
|
||||||
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)) } }
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region.origin.y + region.size.y > worldHeight) {
|
||||||
|
val size = region.size.withY(worldHeight - region.origin.y)
|
||||||
|
return Region(region.origin, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return region
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract suspend fun Scope.build(region: Region)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val upward = create { traverseUpward(it) }
|
val upward = Directional(TraverseDirection(1, 1, 1), TraverseOrder(Dimension.Y, Dimension.X))
|
||||||
val downward = create { traverseDownward(it) }
|
val downward = Directional(TraverseDirection(1, -1, 1), TraverseOrder(Dimension.Y, Dimension.X))
|
||||||
val forClearing get() = downward
|
val toClear get() = downward
|
||||||
val forFilling get() = upward
|
val toFill get() = upward
|
||||||
|
|
||||||
inline fun create(crossinline builder: suspend SequenceScope<Vec3i>.(Region) -> Unit) = object : RegionTraverser() {
|
fun convergingTo(y: Int) = Slicing(y, upward, downward, true)
|
||||||
override suspend fun SequenceScope<Vec3i>.build(region: Region) {
|
|
||||||
builder(region)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun SequenceScope<Vec3i>.traverseUpward(region: Region) {
|
class Slicing(
|
||||||
val origin = region.origin
|
val bottomSectionMaxY: Int,
|
||||||
val size = region.size
|
val bottomTraverser: RegionTraverser,
|
||||||
repeat(size.y) { y ->
|
val topTraverser: RegionTraverser,
|
||||||
repeat(size.z) { z ->
|
val bottomFirst: Boolean = true
|
||||||
repeat(size.x) { x ->
|
) : RegionTraverser() {
|
||||||
yield(origin.add(x, size.y - y - 1, z))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun slice(region: Region, atY: Int): Pair<Region, Region?> {
|
private fun slice(region: Region, atY: Int): Pair<Region, Region?> {
|
||||||
if (atY < region.size.y + 1) {
|
if (atY < region.size.y + 1) {
|
||||||
val first = Region(region.origin, region.size.withY(atY + 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 first to second
|
||||||
}
|
}
|
||||||
return region to null
|
return region to null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun upToAndDownUntil(y: Int) = create { region ->
|
override suspend fun Scope.build(region: Region) {
|
||||||
val (bottom, top) = slice(region, y)
|
val (bottom, top) = slice(region, bottomSectionMaxY)
|
||||||
traverseUpward(bottom)
|
|
||||||
top?.let { traverseDownward(it) }
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -3,9 +3,13 @@ package io.dico.parcels2.blockvisitor
|
|||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.Region
|
||||||
import io.dico.parcels2.util.Vec3i
|
import io.dico.parcels2.util.Vec3i
|
||||||
import io.dico.parcels2.util.get
|
import io.dico.parcels2.util.get
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.Material
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.block.data.BlockData
|
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
|
// TODO order paste such that attachables are placed after the block they depend on
|
||||||
class Schematic {
|
class Schematic {
|
||||||
val size: Vec3i get() = _size!!
|
val size: Vec3i get() = _size!!
|
||||||
@@ -15,15 +19,17 @@ class Schematic {
|
|||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _data: Array<BlockData?>? = null
|
private var blockDatas: Array<BlockData?>? = null
|
||||||
//private var extra: Map<Vec3i, (Block) -> Unit>? = null
|
//private var extra: Map<Vec3i, (Block) -> Unit>? = null
|
||||||
private var isLoaded = false; private set
|
private var isLoaded = false; private set
|
||||||
|
private val traverser: RegionTraverser = RegionTraverser.upward
|
||||||
|
|
||||||
fun getLoadTask(world: World, region: Region): TimeLimitedTask = {
|
fun getLoadTask(world: World, region: Region): TimeLimitedTask = {
|
||||||
val size = region.size.also { _size = it }
|
_size = region.size
|
||||||
val data = arrayOfNulls<BlockData>(region.blockCount).also { _data = it }
|
|
||||||
|
val data = arrayOfNulls<BlockData>(region.blockCount).also { blockDatas = it }
|
||||||
//val extra = mutableMapOf<Vec3i, (Block) -> Unit>().also { extra = 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()) {
|
for ((index, vec) in blocks.withIndex()) {
|
||||||
markSuspensionPoint()
|
markSuspensionPoint()
|
||||||
@@ -39,14 +45,26 @@ class Schematic {
|
|||||||
fun getPasteTask(world: World, position: Vec3i): TimeLimitedTask = {
|
fun getPasteTask(world: World, position: Vec3i): TimeLimitedTask = {
|
||||||
if (!isLoaded) throw IllegalStateException()
|
if (!isLoaded) throw IllegalStateException()
|
||||||
val region = Region(position, _size!!)
|
val region = Region(position, _size!!)
|
||||||
val blocks = RegionTraverser.downward.traverseRegion(region)
|
val blocks = traverser.traverseRegion(region, worldHeight = world.maxHeight)
|
||||||
val data = _data!!
|
val blockDatas = blockDatas!!
|
||||||
|
|
||||||
|
val postponed = mutableListOf<Pair<Vec3i, BlockData>>()
|
||||||
|
|
||||||
for ((index, vec) in blocks.withIndex()) {
|
for ((index, vec) in blocks.withIndex()) {
|
||||||
markSuspensionPoint()
|
markSuspensionPoint()
|
||||||
val block = world[vec]
|
val block = world[vec]
|
||||||
if (block.y > 255) continue
|
val type = blockDatas[index] ?: air
|
||||||
data[index]?.let { block.blockData = it }
|
if (type !== air && isAttachable(type.material)) {
|
||||||
|
|
||||||
|
|
||||||
|
postponed += vec to type
|
||||||
|
} else {
|
||||||
|
block.blockData = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((vec, data) in postponed) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import io.dico.parcels2.blockvisitor.RegionTraverser
|
|||||||
import io.dico.parcels2.doBlockOperation
|
import io.dico.parcels2.doBlockOperation
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.block.BlockFace
|
||||||
|
import org.bukkit.block.data.Directional
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import java.util.Random
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ class DefaultParcelGenerator(
|
|||||||
override val worktimeLimiter: WorktimeLimiter
|
override val worktimeLimiter: WorktimeLimiter
|
||||||
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
|
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
|
||||||
override val world: World = this@DefaultParcelGenerator.world
|
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(
|
/*override*/ fun getBottomBlock(parcel: ParcelId): Vec2i = Vec2i(
|
||||||
sectionSize * (parcel.x - 1) + pathOffset + o.offsetX,
|
sectionSize * (parcel.x - 1) + pathOffset + o.offsetX,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class ParcelEntityTracker(val parcelProvider: ParcelProvider) {
|
|||||||
remove()
|
remove()
|
||||||
|
|
||||||
val newParcel = parcelProvider.getParcelAt(entity.location)
|
val newParcel = parcelProvider.getParcelAt(entity.location)
|
||||||
if (newParcel !== parcel && !(newParcel != null && newParcel.hasBlockVisitors)) {
|
if (newParcel !== parcel && (newParcel == null || !newParcel.hasBlockVisitors)) {
|
||||||
entity.remove()
|
entity.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,14 +41,13 @@ class ParcelEntityTracker(val parcelProvider: ParcelProvider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val newParcel = parcelProvider.getParcelAt(entity.location)
|
val newParcel = parcelProvider.getParcelAt(entity.location)
|
||||||
if (newParcel !== parcel && !(newParcel != null && newParcel.hasBlockVisitors)) {
|
if (newParcel !== parcel && (newParcel == null || !newParcel.hasBlockVisitors)) {
|
||||||
remove()
|
remove()
|
||||||
entity.remove()
|
entity.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("RedundantLambdaArrow")
|
|
||||||
fun swapParcels(parcel1: Parcel, parcel2: Parcel) {
|
fun swapParcels(parcel1: Parcel, parcel2: Parcel) {
|
||||||
map.editLoop { ->
|
map.editLoop { ->
|
||||||
if (value === parcel1) {
|
if (value === parcel1) {
|
||||||
|
|||||||
@@ -196,11 +196,10 @@ class ParcelListeners(
|
|||||||
when (event.action) {
|
when (event.action) {
|
||||||
Action.RIGHT_CLICK_BLOCK -> run {
|
Action.RIGHT_CLICK_BLOCK -> run {
|
||||||
val type = clickedBlock.type
|
val type = clickedBlock.type
|
||||||
val interactable = Interactables.listedMaterials.containsKey(type)
|
|
||||||
&& (parcel.effectiveInteractableConfig.isInteractable(type) || (parcel != null && parcel.canBuild(user)))
|
val interactableClass = Interactables[type]
|
||||||
if (!interactable) {
|
if (interactableClass != null && (parcel.effectiveInteractableConfig.isInteractable(type) || (parcel != null && parcel.canBuild(user)))) {
|
||||||
val interactableClassName = Interactables[type]!!.name
|
user.sendParcelMessage(nopermit = true, message = "You cannot interact with ${interactableClass.name} in this parcel")
|
||||||
user.sendParcelMessage(nopermit = true, message = "You cannot interact with $interactableClassName in this parcel")
|
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
return@l
|
return@l
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package io.dico.parcels2.util
|
package io.dico.parcels2.util
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CancellableContinuation
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.Delay
|
||||||
import kotlinx.coroutines.Runnable
|
import kotlinx.coroutines.Runnable
|
||||||
|
import kotlinx.coroutines.timeunit.TimeUnit
|
||||||
import org.bukkit.plugin.Plugin
|
import org.bukkit.plugin.Plugin
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
abstract class MainThreadDispatcher : CoroutineDispatcher() {
|
abstract class MainThreadDispatcher : CoroutineDispatcher(), Delay {
|
||||||
abstract val mainThread: Thread
|
abstract val mainThread: Thread
|
||||||
abstract fun runOnMainThread(task: Runnable)
|
abstract fun runOnMainThread(task: Runnable)
|
||||||
}
|
}
|
||||||
@@ -27,5 +30,14 @@ fun MainThreadDispatcher(plugin: Plugin): MainThreadDispatcher {
|
|||||||
if (Thread.currentThread() === mainThread) task.run()
|
if (Thread.currentThread() === mainThread) task.run()
|
||||||
else plugin.server.scheduler.runTaskLater(plugin, task, 0)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package io.dico.parcels2.util
|
|||||||
|
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
|
import org.bukkit.block.BlockFace
|
||||||
|
|
||||||
data class Vec3d(
|
data class Vec3d(
|
||||||
val x: Double,
|
val x: Double,
|
||||||
@@ -32,6 +33,27 @@ data class Vec3i(
|
|||||||
infix fun withY(o: Int) = Vec3i(x, o, z)
|
infix fun withY(o: Int) = Vec3i(x, o, z)
|
||||||
infix fun withZ(o: Int) = Vec3i(x, y, o)
|
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 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")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
|||||||
Reference in New Issue
Block a user