All Downloads are FREE. Search and download functionalities are using the official Maven repository.

walkmc.StructureBox.kt Maven / Gradle / Ivy

package walkmc

import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import org.bukkit.*
import org.bukkit.block.*
import org.bukkit.entity.*
import walkmc.extensions.strings.*
import kotlin.math.*

/**
 * A structure box is very similar to [BoundingBox], but this is to use with areas.
 */
@Serializable(StructureBoxSerializer::class)
data class StructureBox(
	var world: World,
	var minX: Int,
	var minY: Int,
	var minZ: Int,
	var maxX: Int,
	var maxY: Int,
	var maxZ: Int,
) : Iterable {
	
	constructor(min: Block, max: Block) : this(min.location, max.location)
	constructor(min: Entity, max: Entity) : this(min.location, max.location)
	constructor(min: Location, max: Location) : this(
		min.world,
		min(min.blockX, max.blockX),
		min(min.blockY, max.blockY),
		min(min.blockZ, max.blockZ),
		max(min.blockX, max.blockX),
		max(min.blockY, max.blockY),
		max(min.blockZ, max.blockZ),
	)
	
	/**
	 * Returns the minimum location representation of this structure box.
	 */
	val minPosition: Location
		get() = Location(world, minX, minY, minZ)
	
	/**
	 * Returns the maximum location representation of this structure box.
	 */
	val maxPosition: Location
		get() = Location(world, maxX, maxY, maxZ)
	
	/**
	 * Gets the volume of this structure box.
	 */
	val volume: Int
		get() = (minX * maxX) + (minY * maxY) + (minZ * maxZ)
	
	/**
	 * Gets the corners of this structure box.
	 */
	val corners: List
		get() = buildList {
			add(minPosition)
			add(Location(world, minX, minY, maxZ))
			add(Location(world, minX, maxY, minZ))
			add(Location(world, minX, maxY, maxZ))
			add(Location(world, maxX, minY, minZ))
			add(Location(world, maxX, minY, maxZ))
			add(Location(world, maxX, maxY, minZ))
			add(maxPosition)
		}
	
	/**
	 * Gets a relative location of this box with the specified [x], [y] and [z].
	 */
	fun relative(x: Int, y: Int, z: Int): Location = Location(world, minX + x, minY + y, minZ + z)
	
	/**
	 * Grows this structure box to the amount of radius.
	 */
	fun grow(radius: Int): StructureBox = apply {
		minX -= radius
		minY -= radius
		minZ -= radius
		maxX += radius
		maxY += radius
		maxZ += radius
	}
	
	/**
	 * Shrinks this structure box to the amount of radius.
	 */
	fun shrink(radius: Int): StructureBox = apply {
		minX += radius
		minY += radius
		minZ += radius
		maxX -= radius
		maxY -= radius
		maxZ -= radius
	}
	
	/**
	 * Verifies if a another box is collind with this box.
	 */
	fun isColliding(other: StructureBox): Boolean =
		isCollidingX(other) || isCollidingY(other) || isCollidingZ(other)
	
	/**
	 * Verifies if the X of a another box is collind with X of this box.
	 */
	fun isCollidingX(other: StructureBox): Boolean = other.maxX > minX && other.minX < maxX
	
	/**
	 * Verifies if the Y of a another box is collind with Y of this box.
	 */
	fun isCollidingY(other: StructureBox): Boolean = other.maxY > minY && other.minY < maxY
	
	/**
	 * Verifies if the Z of a another box is collind with Z of this box.
	 */
	fun isCollidingZ(other: StructureBox): Boolean = other.maxZ > minZ && other.minZ < maxZ
	
	/**
	 * Verifies if a location is inside of this box.
	 */
	fun isInside(loc: Location): Boolean =
		loc.blockX in minX until maxX && loc.blockY in minY until maxY && loc.blockZ in minZ until maxZ
	
	/**
	 * Verifies if a block is inside of this box.
	 */
	fun isInside(block: Block): Boolean = isInside(block.location)
	
	/**
	 * Verifies if a entity is inside of this box.
	 */
	fun isInside(entity: Entity): Boolean = isInside(entity.location)
	
	/**
	 * Converts this box to a [BoundingBox].
	 */
	fun toBoundingBox() = BoundingBox(
		minX.toDouble(),
		minY.toDouble(),
		minZ.toDouble(),
		maxX.toDouble(),
		maxY.toDouble(),
		maxZ.toDouble()
	)
	
	override fun toString(): String = "${world.name}:$minX:$minY:$minZ:$maxX:$maxY:$maxZ"
	override fun iterator(): Iterator = StructureBoxIterator(this)
	
	companion object {
		
		/**
		 * Converts a string to a structure box.
		 */
		fun from(string: String): StructureBox {
			val split = string.split(':', limit = 7)
			return StructureBox(
				split[0].toWorld(),
				split[1].toInt(),
				split[2].toInt(),
				split[3].toInt(),
				split[4].toInt(),
				split[5].toInt(),
				split[6].toInt()
			)
		}
	}
}

/**
 * A serializer for serializing [StructureBox].
 */
object StructureBoxSerializer : KSerializer {
	override val descriptor = PrimitiveSerialDescriptor("StructureBox", PrimitiveKind.STRING)
	
	override fun deserialize(decoder: Decoder): StructureBox {
		return StructureBox.from(decoder.decodeString())
	}
	
	override fun serialize(encoder: Encoder, value: StructureBox) {
		encoder.encodeString(value.toString())
	}
}

/**
 * Represents a iterator for [StructureBox].
 */
class StructureBoxIterator(val box: StructureBox) : Iterator {
	var offsetX = 0
	var offsetY = 0
	var offsetZ = 0
	val sizeX = abs(box.maxX - box.minX) + 1
	val sizeY = abs(box.maxY - box.minY) + 1
	val sizeZ = abs(box.maxZ - box.minZ) + 1
	
	override fun hasNext(): Boolean = offsetX < sizeX && offsetY < sizeY && offsetZ < sizeZ
	
	fun advance() {
		if (++offsetX >= sizeX) {
			offsetX = 0
			if (++offsetY >= sizeY) {
				offsetY = 0
				offsetZ++
			}
		}
	}
	
	override fun next(): Block {
		val block = box.relative(offsetX, offsetY, offsetZ).block
		advance()
		return block
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy