summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt')
-rw-r--r--src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt139
1 files changed, 121 insertions, 18 deletions
diff --git a/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
index dc8ac28..b749b36 100644
--- a/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
+++ b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
@@ -6,27 +6,89 @@ import io.dico.parcels2.util.math.Vec3i
import io.dico.parcels2.util.math.clampMax
private typealias Scope = SequenceScope<Vec3i>
+/*
+class ParcelTraverser(
+ val parcelProvider: ParcelProvider,
+ val delegate: RegionTraverser,
+ scope: CoroutineScope
+) : RegionTraverser(), CoroutineScope by scope {
-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)
+ class OccupiedException(parcelId: ParcelId) : Exception("Parcel $parcelId is occupied")
+
+ /**
+ * Traverse the blocks of parcel's land
+ * The iterator must be exhausted, else the permit to traverse it will not be reclaimed.
+ *
+ * @throws OccupiedException if a parcel is maintained with the given parcel id and an
+ * iterator exists for it that has not been exhausted
+ */
+ fun traverseParcel(parcelId: ParcelId): Iterator<Vec3i> {
+ val world = parcelProvider.getWorldById(parcelId.worldId)
+ ?: throw IllegalArgumentException()
+ val parcel = parcelProvider.getParcelById(parcelId)
+
+ val medium = if (parcel != null) {
+ if (parcel.hasBlockVisitors || parcel !is ParcelImpl) {
+ throw OccupiedException(parcelId)
+ }
+ parcel.hasBlockVisitors = true
+ TraverserMedium { parcel.hasBlockVisitors = false }
+ } else {
+ TraverserMedium.DoNothing
+ }
+
+ val region = world.blockManager.getRegion(parcelId)
+ return traverseRegion(region, world.world.maxHeight, medium)
+ }
+
+ override suspend fun Scope.build(region: Region, medium: TraverserMedium) {
+ with(delegate) {
+ return build(region, medium)
}
+ }
+
+}
- if (region.origin.y + region.size.y > worldHeight) {
- val size = region.size.withY(worldHeight - region.origin.y)
- return Region(region.origin, size)
+@Suppress("FunctionName")
+inline fun TraverserMedium(crossinline whenComplete: () -> Unit) =
+ object : TraverserMedium {
+ override fun iterationCompleted() {
+ whenComplete()
}
+ }
+
+/**
+ * An object that is able to communicate with an iterator returned by [RegionTraverser]
+ *
+ */
+interface TraverserMedium {
- return region
+ /**
+ * Called by the traverser during first [Iterator.hasNext] call that returns false
+ */
+ fun iterationCompleted()
+
+ /**
+ * The default [TraverserMedium], which does nothing.
+ */
+ object DoNothing : TraverserMedium {
+ override fun iterationCompleted() {}
}
+}*/
+
+sealed class RegionTraverser {
- protected abstract suspend fun Scope.build(region: Region)
+ /**
+ * Get an iterator traversing [region] using this traverser.
+ * Depending on the implementation, [region] might be traversed in a specific order and direction.
+ */
+ fun traverseRegion(
+ region: Region,
+ worldHeight: Int = 256/*,
+ medium: TraverserMedium = TraverserMedium.DoNothing*/
+ ): Iterator<Vec3i> = iterator { build(validify(region, worldHeight)/*, medium*/) }
+
+ abstract suspend fun Scope.build(region: Region/*, medium: TraverserMedium = TraverserMedium.DoNothing*/)
companion object {
val upward = Directional(TraverseDirection(1, 1, 1), TraverseOrderFactory.createWith(Dimension.Y, Dimension.X))
@@ -34,9 +96,35 @@ sealed class RegionTraverser {
val toClear get() = downward
val toFill get() = upward
+ /**
+ * The returned [RegionTraverser] will traverse the regions
+ * * below and including absolute level [y] first, in [upward] direction.
+ * * above absolute level [y] last, in [downward] direction.
+ */
fun convergingTo(y: Int) = Slicing(y, upward, downward, true)
+ /**
+ * The returned [RegionTraverser] will traverse the regions
+ * * above absolute level [y] first, in [upward] direction.
+ * * below and including absolute level [y] second, in [downward] direction.
+ */
fun separatingFrom(y: Int) = Slicing(y, downward, upward, false)
+
+ 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
+ }
+
}
class Directional(
@@ -50,7 +138,7 @@ sealed class RegionTraverser {
}
}
- override suspend fun Scope.build(region: Region) {
+ override suspend fun Scope.build(region: Region/*, medium: TraverserMedium*/) {
val order = order
val (primary, secondary, tertiary) = order.toArray()
val (origin, size) = region
@@ -71,6 +159,7 @@ sealed class RegionTraverser {
}
}
+ /*medium.iterationCompleted()*/
}
}
@@ -91,7 +180,7 @@ sealed class RegionTraverser {
return region to null
}
- override suspend fun Scope.build(region: Region) {
+ override suspend fun Scope.build(region: Region/*, medium: TraverserMedium*/) {
val (bottom, top) = slice(region, bottomSectionMaxY)
if (bottomFirst) {
@@ -101,15 +190,22 @@ sealed class RegionTraverser {
top?.let { with(topTraverser) { build(it) } }
with(bottomTraverser) { build(bottom) }
}
+
+ /*medium.iterationCompleted()*/
}
}
+ /**
+ * Returns [Directional] instance that would be responsible for
+ * emitting the given position if it is contained in a region.
+ * [Directional] instance has a set order and direction
+ */
fun childForPosition(position: Vec3i): Directional {
var cur = this
while (true) {
when (cur) {
- is Directional ->
- return cur
+ /*is ParcelTraverser -> cur = cur.delegate*/
+ is Directional -> return cur
is Slicing ->
cur =
if (position.y <= cur.bottomSectionMaxY) cur.bottomTraverser
@@ -118,10 +214,17 @@ sealed class RegionTraverser {
}
}
+ /**
+ * Returns true if and only if this traverser would visit the given
+ * [block] position before the given [current] position.
+ * If at least one of [block] and [current] is not contained in a
+ * region being traversed the result is undefined.
+ */
fun comesFirst(current: Vec3i, block: Vec3i): Boolean {
var cur = this
while (true) {
when (cur) {
+ /*is ParcelTraverser -> cur = cur.delegate*/
is Directional -> return cur.direction.comesFirst(current, block)
is Slicing -> {
val border = cur.bottomSectionMaxY