org.bukkit.Location.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of chest-server Show documentation
Show all versions of chest-server Show documentation
A spigot fork to kotlin structure and news.
The newest version!
package org.bukkit
import io.github.uinnn.serializer.serial.LocationSerializer
import net.chestmc.common.interfaces.Localizable
import kotlinx.serialization.Serializable
import net.chestmc.Coordinate
import org.bukkit.block.Block
import org.bukkit.configuration.serialization.ConfigurationSerializable
import org.bukkit.util.NumberConversions
import org.bukkit.util.Vector
import java.util.*
import kotlin.math.*
/**
* Represents a 3-dimensional position in a world
*/
@Serializable(LocationSerializer::class)
open class Location(
var world: World,
var x: Double,
var y: Double,
var z: Double,
var pitch: Float = 0f,
var yaw: Float = 0f,
) : Cloneable, ConfigurationSerializable, Comparable, Localizable {
/**
* Backend access to the [Localizable] implementation.
*/
override var location: Location = this
set(value) = throw IllegalAccessException("Tryed to change the location backend access.")
/**
* Gets the chunk at the represented location.
*/
val chunk: Chunk get() = world.getChunkAt(this)
/**
* Gets the block at the represented location.
*/
val block: Block get() = world.getBlockAt(this)
/**
* Gets the floored value of the X component, indicating the block that
* this location is contained with.
*/
val blockX: Int get() = locToBlock(x)
/**
* Gets the floored value of the Y component, indicating the block that
* this location is contained with.
*/
val blockY: Int get() = locToBlock(y)
/**
* Gets the floored value of the Z component, indicating the block that
* this location is contained with.
*/
val blockZ: Int get() = locToBlock(z)
/**
* Constructs a new location with the specified world and coordinates.
*/
constructor(world: World, x: Number, y: Number, z: Number) :
this(world, x.toDouble(), y.toDouble(), z.toDouble(), 0f, 0f)
/**
* Constructs a new location with the specified world and coordinates.
*/
constructor(world: String, x: Number, y: Number, z: Number) :
this(Bukkit.getWorld(world), x, y, z)
/**
* Constructs a new location with the specified world, coordinates and direction.
*/
constructor(world: String, x: Number, y: Number, z: Number, pitch: Number, yaw: Number) :
this(Bukkit.getWorld(world), x.toDouble(), y.toDouble(), z.toDouble(), pitch.toFloat(), yaw.toFloat())
/**
* Constructs a new location with the specified world and coordinates.
*/
constructor(world: UUID, x: Number, y: Number, z: Number) :
this(Bukkit.getWorld(world), x, y, z)
/**
* Constructs a new location with the specified world, coordinates and direction.
*/
constructor(world: UUID, x: Number, y: Number, z: Number, pitch: Number, yaw: Number) :
this(Bukkit.getWorld(world), x.toDouble(), y.toDouble(), z.toDouble(), pitch.toFloat(), yaw.toFloat())
/**
* Gets a unit-vector pointing in the direction that this Location is facing.
*/
var direction: Vector
get() {
val vector = Vector()
val rotX: Double = yaw.toDouble()
val rotY: Double = pitch.toDouble()
val xz = cos(Math.toRadians(rotY))
vector.y = -sin(Math.toRadians(rotY))
vector.x = -xz * sin(Math.toRadians(rotX))
vector.z = xz * cos(Math.toRadians(rotX))
return vector
}
set(value) {
setDirection(value)
}
/**
* Sets the [yaw] and [pitch] to point in the direction of the vector.
*/
fun setDirection(vector: Vector): Location {
val pi = 2 * Math.PI
val x = vector.x
val z = vector.z
if (x == 0.0 && z == 0.0) {
pitch = if (vector.y > 0) -90f else 90.toFloat()
return this
}
val theta = atan2(-x, z)
yaw = Math.toDegrees((theta + pi) % pi).toFloat()
val x2 = NumberConversions.square(x)
val z2 = NumberConversions.square(z)
val xz = sqrt(x2 + z2)
pitch = Math.toDegrees(atan(-vector.y / xz)).toFloat()
return this
}
/**
* Adds the location by another.
*/
fun add(vec: Location): Location {
x += vec.x
y += vec.y
z += vec.z
return this
}
/**
* Adds the location by a vector.
*/
fun add(vec: Vector): Location {
x += vec.x
y += vec.y
z += vec.z
return this
}
/**
* Adds the location by another. Not world-aware.
*/
fun add(x: Double, y: Double, z: Double): Location {
this.x += x
this.y += y
this.z += z
return this
}
/**
* Subtracts the location by another.
*/
fun subtract(vec: Location): Location {
x -= vec.x
y -= vec.y
z -= vec.z
return this
}
/**
* Subtracts the location by a vector.
*/
fun subtract(vec: Vector): Location {
x -= vec.x
y -= vec.y
z -= vec.z
return this
}
/**
* Subtracts the location by another. Not world-aware and
* orientation independent.
*/
fun subtract(x: Double, y: Double, z: Double): Location {
this.x -= x
this.y -= y
this.z -= z
return this
}
/**
* Gets the magnitude of the location, defined as sqrt(x^2+y^2+z^2). The
* value of this method is not cached and uses a costly square-root
* function, so do not repeatedly call this method to get the location's
* magnitude. NaN will be returned if the inner result of the sqrt()
* function overflows, which will be caused if the length is too long. Not
* world-aware and orientation independent.
*/
fun length(): Double =
sqrt(NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z))
/**
* Gets the magnitude of the location squared. Not world-aware and
* orientation independent.
*/
fun lengthSquared(): Double =
NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z)
/**
* Get the distance between this location and another. The value of this
* method is not cached and uses a costly square-root function, so do not
* repeatedly call this method to get the location's magnitude. NaN will
* be returned if the inner result of the sqrt() function overflows, which
* will be caused if the distance is too long.
*/
fun distance(o: Location): Double = sqrt(distanceSquared(o))
/**
* Get the squared distance between this location and another.
*/
fun distanceSquared(o: Location): Double =
NumberConversions.square(x - o.x) + NumberConversions.square(y - o.y) + NumberConversions.square(z - o.z)
/**
* Performs scalar multiplication, multiplying all components with a
* scalar. Not world-aware.
*/
fun multiply(m: Double): Location {
x *= m
y *= m
z *= m
return this
}
/**
* Zero this location's components. Not world-aware.
*/
fun zero(): Location {
x = 0.0
y = 0.0
z = 0.0
return this
}
override fun equals(other: Any?): Boolean {
if (other == null) {
return false
}
if (javaClass != other.javaClass) {
return false
}
val other = other as Location
if (world != other.world) {
return false
}
if (java.lang.Double.doubleToLongBits(x) != java.lang.Double.doubleToLongBits(other.x)) {
return false
}
if (java.lang.Double.doubleToLongBits(y) != java.lang.Double.doubleToLongBits(other.y)) {
return false
}
if (java.lang.Double.doubleToLongBits(z) != java.lang.Double.doubleToLongBits(other.z)) {
return false
}
return if (java.lang.Float.floatToIntBits(pitch) != java.lang.Float.floatToIntBits(other.pitch)) {
false
} else java.lang.Float.floatToIntBits(yaw) == java.lang.Float.floatToIntBits(other.yaw)
}
override fun hashCode(): Int {
var hash = 3
hash = 19 * hash + world.hashCode()
hash = 19 * hash + (java.lang.Double.doubleToLongBits(x) xor (java.lang.Double.doubleToLongBits(x) ushr 32)).toInt()
hash = 19 * hash + (java.lang.Double.doubleToLongBits(y) xor (java.lang.Double.doubleToLongBits(y) ushr 32)).toInt()
hash = 19 * hash + (java.lang.Double.doubleToLongBits(z) xor (java.lang.Double.doubleToLongBits(z) ushr 32)).toInt()
hash = 19 * hash + java.lang.Float.floatToIntBits(pitch)
hash = 19 * hash + java.lang.Float.floatToIntBits(yaw)
return hash
}
override fun toString(): String = "Location{world=$world,x=$x,y=$y,z=$z,pitch=$pitch,yaw=$yaw}"
/**
* Converts this location to a coordinate.
*/
fun toCoordinate(): Coordinate = Coordinate.from(this)
/**
* Constructs a new [Vector] based on this Location
*
* @return New Vector containing the coordinates represented by this
* Location
*/
open fun toVector(): Vector = Vector(x, y, z)
public override fun clone(): Location {
return try {
super.clone() as Location
} catch (e: CloneNotSupportedException) {
throw Error(e)
}
}
override fun compareTo(other: Location): Int {
if ((x == other.x || y == other.y) && z == other.z) return 0
return if (x < other.x && y < other.y && z < other.z) -1 else 0
}
@Utility
override fun serialize(): Map {
val data: MutableMap = HashMap()
data["world"] = world.name
data["x"] = x
data["y"] = y
data["z"] = z
data["yaw"] = yaw
data["pitch"] = pitch
return data
}
companion object {
/**
* Safely converts a double (location coordinate) to an int (block coordinate)
*/
@JvmStatic
fun locToBlock(loc: Double): Int = NumberConversions.floor(loc)
/**
* Required method for deserialization.
*/
@JvmStatic
fun deserialize(args: Map): Location {
val world = Bukkit.getWorld(args["world"] as String?) ?: throw IllegalArgumentException("unknown world")
return Location(world,
NumberConversions.toDouble(args["x"]),
NumberConversions.toDouble(args["y"]),
NumberConversions.toDouble(args["z"]),
NumberConversions.toFloat(args["yaw"]),
NumberConversions.toFloat(args["pitch"]))
}
/**
* Converts the specified string to a location.
*/
fun from(string: String): Location {
val split = string.split('|')
return Location(split[0], split[1].toDouble(), split[2].toDouble(), split[3].toDouble())
}
/**
* Converts the specified string to a location.
*/
fun from(world: World, string: String): Location {
val split = string.split('|')
return Location(world, split[0].toDouble(), split[1].toDouble(), split[2].toDouble())
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy