BlastingCrisis/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Area.kt

118 lines
3.9 KiB
Kotlin

package cc.maxmc.blastingcrisis.misc
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.configuration.serialization.ConfigurationSerializable
import org.bukkit.configuration.serialization.SerializableAs
import org.bukkit.util.Vector
import taboolib.common.util.random
import kotlin.math.max
import kotlin.math.min
@SerializableAs("Area")
class Area(loc1: Location, loc2: Location) : ConfigurationSerializable {
val locTop: Location
val locMin: Location
@Suppress("unused") // Bukkit Specification
constructor(map: Map<String, Any>) : this(map["locTop"] as Location, map["locMin"] as Location)
init {
if (loc1.world != loc2.world) throw IllegalArgumentException("Locations must be of the same world.")
locTop = Location(loc1.world, max(loc1.x, loc2.x), max(loc1.y, loc2.y), max(loc1.z, loc2.z))
locMin = Location(loc1.world, min(loc1.x, loc2.x), min(loc1.y, loc2.y), min(loc1.z, loc2.z))
}
/**
* check if the given location is in this area
*
* @param location location to check
*
* @return true if the location is in this area
*/
fun contains(location: Location): Boolean {
if (location.world != locTop.world) return false
if (location.x !in (locMin.x - 1)..(locTop.x + 1)) return false
if (location.y !in locMin.y..locTop.y + 1) return false
return location.z in (locMin.z - 1)..(locTop.z + 1)
}
fun containsBlock(location: Location): Boolean {
if (location.world != locTop.world) return false
if (location.x !in locMin.x..locTop.x) return false
if (location.y !in locMin.y..locTop.y) return false
return location.z in locMin.z..locTop.z
}
/**
* get all locations of the blocks in this area
*
* @return all locations of the blocks in this area
*/
fun forBlocksInArea(): List<Location> {
val blocks = arrayListOf<Location>()
for (x in locMin.blockX..locTop.blockX) {
for (y in locMin.blockY..locTop.blockY) {
for (z in locMin.blockZ..locTop.blockZ) {
blocks.add(Location(locTop.world, x.toDouble(), y.toDouble(), z.toDouble()))
}
}
}
return blocks
}
/**
* get all locations of the non-air blocks in this area
*
* @return all locations of the non-air blocks in this area
*/
fun forBlocksWithoutAir(): List<Location> {
return forBlocksInArea().filter { it.block.type != Material.AIR }
}
fun getAirPercentage(): Double {
val blocks = forBlocksInArea()
return blocks.filter { it.block.type == Material.AIR }.size.toDouble() / blocks.size.toDouble()
}
/**
* generate a random Location that player can stand
*
* @return a random Location that player can stand
*/
tailrec fun randomLocation(): Location {
val x = random(locMin.blockX, locTop.blockX)
val z = random(locMin.blockZ, locTop.blockZ)
for (y in locMin.blockY..locTop.blockY) {
val loc = Vector(x, y, z).toLocation(locMin.world)
val add = loc.clone().add(0.0, 1.0, 0.0)
if (loc.block.type == Material.AIR && add.block.type == Material.AIR) return loc
}
return randomLocation()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as Area
if (locTop != other.locTop) return false
return locMin == other.locMin
}
override fun hashCode(): Int {
var result = locTop.hashCode()
result = 31 * result + locMin.hashCode()
return result
}
override fun serialize() = mutableMapOf<String, Any>("locTop" to locTop, "locMin" to locMin)
override fun toString(): String {
return "Area(locTop=$locTop, locMin=$locMin)"
}
}