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) : 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 { val blocks = arrayListOf() 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 { 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("locTop" to locTop, "locMin" to locMin) override fun toString(): String { return "Area(locTop=$locTop, locMin=$locMin)" } }