13
0
geforkt von Mirrors/Paper
Bukkit/Spigot c240b58f66 Begin implementation of CheckStyle style checking
By: md_5 <git@md-5.net>
2019-04-23 14:00:20 +10:00

672 Zeilen
19 KiB
Java

package org.bukkit;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.block.Block;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a 3-dimensional position in a world.
* <br>
* No constraints are placed on any angular values other than that they be
* specified in degrees. This means that negative angles or angles of greater
* magnitude than 360 are valid, but may be normalized to any other equivalent
* representation by the implementation.
*/
public class Location implements Cloneable, ConfigurationSerializable {
private World world;
private double x;
private double y;
private double z;
private float pitch;
private float yaw;
/**
* Constructs a new Location with the given coordinates
*
* @param world The world in which this location resides
* @param x The x-coordinate of this new location
* @param y The y-coordinate of this new location
* @param z The z-coordinate of this new location
*/
public Location(@Nullable final World world, final double x, final double y, final double z) {
this(world, x, y, z, 0, 0);
}
/**
* Constructs a new Location with the given coordinates and direction
*
* @param world The world in which this location resides
* @param x The x-coordinate of this new location
* @param y The y-coordinate of this new location
* @param z The z-coordinate of this new location
* @param yaw The absolute rotation on the x-plane, in degrees
* @param pitch The absolute rotation on the y-plane, in degrees
*/
public Location(@Nullable final World world, final double x, final double y, final double z, final float yaw, final float pitch) {
this.world = world;
this.x = x;
this.y = y;
this.z = z;
this.pitch = pitch;
this.yaw = yaw;
}
/**
* Sets the world that this location resides in
*
* @param world New world that this location resides in
*/
public void setWorld(@Nullable World world) {
this.world = world;
}
/**
* Gets the world that this location resides in
*
* @return World that contains this location
*/
@Nullable
public World getWorld() {
return world;
}
/**
* Gets the chunk at the represented location
*
* @return Chunk at the represented location
*/
@NotNull
public Chunk getChunk() {
return world.getChunkAt(this);
}
/**
* Gets the block at the represented location
*
* @return Block at the represented location
*/
@NotNull
public Block getBlock() {
return world.getBlockAt(this);
}
/**
* Sets the x-coordinate of this location
*
* @param x X-coordinate
*/
public void setX(double x) {
this.x = x;
}
/**
* Gets the x-coordinate of this location
*
* @return x-coordinate
*/
public double getX() {
return x;
}
/**
* Gets the floored value of the X component, indicating the block that
* this location is contained with.
*
* @return block X
*/
public int getBlockX() {
return locToBlock(x);
}
/**
* Sets the y-coordinate of this location
*
* @param y y-coordinate
*/
public void setY(double y) {
this.y = y;
}
/**
* Gets the y-coordinate of this location
*
* @return y-coordinate
*/
public double getY() {
return y;
}
/**
* Gets the floored value of the Y component, indicating the block that
* this location is contained with.
*
* @return block y
*/
public int getBlockY() {
return locToBlock(y);
}
/**
* Sets the z-coordinate of this location
*
* @param z z-coordinate
*/
public void setZ(double z) {
this.z = z;
}
/**
* Gets the z-coordinate of this location
*
* @return z-coordinate
*/
public double getZ() {
return z;
}
/**
* Gets the floored value of the Z component, indicating the block that
* this location is contained with.
*
* @return block z
*/
public int getBlockZ() {
return locToBlock(z);
}
/**
* Sets the yaw of this location, measured in degrees.
* <ul>
* <li>A yaw of 0 or 360 represents the positive z direction.
* <li>A yaw of 180 represents the negative z direction.
* <li>A yaw of 90 represents the negative x direction.
* <li>A yaw of 270 represents the positive x direction.
* </ul>
* Increasing yaw values are the equivalent of turning to your
* right-facing, increasing the scale of the next respective axis, and
* decreasing the scale of the previous axis.
*
* @param yaw new rotation's yaw
*/
public void setYaw(float yaw) {
this.yaw = yaw;
}
/**
* Gets the yaw of this location, measured in degrees.
* <ul>
* <li>A yaw of 0 or 360 represents the positive z direction.
* <li>A yaw of 180 represents the negative z direction.
* <li>A yaw of 90 represents the negative x direction.
* <li>A yaw of 270 represents the positive x direction.
* </ul>
* Increasing yaw values are the equivalent of turning to your
* right-facing, increasing the scale of the next respective axis, and
* decreasing the scale of the previous axis.
*
* @return the rotation's yaw
*/
public float getYaw() {
return yaw;
}
/**
* Sets the pitch of this location, measured in degrees.
* <ul>
* <li>A pitch of 0 represents level forward facing.
* <li>A pitch of 90 represents downward facing, or negative y
* direction.
* <li>A pitch of -90 represents upward facing, or positive y direction.
* </ul>
* Increasing pitch values the equivalent of looking down.
*
* @param pitch new incline's pitch
*/
public void setPitch(float pitch) {
this.pitch = pitch;
}
/**
* Gets the pitch of this location, measured in degrees.
* <ul>
* <li>A pitch of 0 represents level forward facing.
* <li>A pitch of 90 represents downward facing, or negative y
* direction.
* <li>A pitch of -90 represents upward facing, or positive y direction.
* </ul>
* Increasing pitch values the equivalent of looking down.
*
* @return the incline's pitch
*/
public float getPitch() {
return pitch;
}
/**
* Gets a unit-vector pointing in the direction that this Location is
* facing.
*
* @return a vector pointing the direction of this location's {@link
* #getPitch() pitch} and {@link #getYaw() yaw}
*/
@NotNull
public Vector getDirection() {
Vector vector = new Vector();
double rotX = this.getYaw();
double rotY = this.getPitch();
vector.setY(-Math.sin(Math.toRadians(rotY)));
double xz = Math.cos(Math.toRadians(rotY));
vector.setX(-xz * Math.sin(Math.toRadians(rotX)));
vector.setZ(xz * Math.cos(Math.toRadians(rotX)));
return vector;
}
/**
* Sets the {@link #getYaw() yaw} and {@link #getPitch() pitch} to point
* in the direction of the vector.
*
* @param vector the direction vector
* @return the same location
*/
@NotNull
public Location setDirection(@NotNull Vector vector) {
/*
* Sin = Opp / Hyp
* Cos = Adj / Hyp
* Tan = Opp / Adj
*
* x = -Opp
* z = Adj
*/
final double _2PI = 2 * Math.PI;
final double x = vector.getX();
final double z = vector.getZ();
if (x == 0 && z == 0) {
pitch = vector.getY() > 0 ? -90 : 90;
return this;
}
double theta = Math.atan2(-x, z);
yaw = (float) Math.toDegrees((theta + _2PI) % _2PI);
double x2 = NumberConversions.square(x);
double z2 = NumberConversions.square(z);
double xz = Math.sqrt(x2 + z2);
pitch = (float) Math.toDegrees(Math.atan(-vector.getY() / xz));
return this;
}
/**
* Adds the location by another.
*
* @see Vector
* @param vec The other location
* @return the same location
* @throws IllegalArgumentException for differing worlds
*/
@NotNull
public Location add(@NotNull Location vec) {
if (vec == null || vec.getWorld() != getWorld()) {
throw new IllegalArgumentException("Cannot add Locations of differing worlds");
}
x += vec.x;
y += vec.y;
z += vec.z;
return this;
}
/**
* Adds the location by a vector.
*
* @see Vector
* @param vec Vector to use
* @return the same location
*/
@NotNull
public Location add(@NotNull Vector vec) {
this.x += vec.getX();
this.y += vec.getY();
this.z += vec.getZ();
return this;
}
/**
* Adds the location by another. Not world-aware.
*
* @see Vector
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @return the same location
*/
@NotNull
public Location add(double x, double y, double z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
/**
* Subtracts the location by another.
*
* @see Vector
* @param vec The other location
* @return the same location
* @throws IllegalArgumentException for differing worlds
*/
@NotNull
public Location subtract(@NotNull Location vec) {
if (vec == null || vec.getWorld() != getWorld()) {
throw new IllegalArgumentException("Cannot add Locations of differing worlds");
}
x -= vec.x;
y -= vec.y;
z -= vec.z;
return this;
}
/**
* Subtracts the location by a vector.
*
* @see Vector
* @param vec The vector to use
* @return the same location
*/
@NotNull
public Location subtract(@NotNull Vector vec) {
this.x -= vec.getX();
this.y -= vec.getY();
this.z -= vec.getZ();
return this;
}
/**
* Subtracts the location by another. Not world-aware and
* orientation independent.
*
* @see Vector
* @param x X coordinate
* @param y Y coordinate
* @param z Z coordinate
* @return the same location
*/
@NotNull
public Location subtract(double x, double y, double z) {
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.
*
* @see Vector
* @return the magnitude
*/
public double length() {
return Math.sqrt(NumberConversions.square(x) + NumberConversions.square(y) + NumberConversions.square(z));
}
/**
* Gets the magnitude of the location squared. Not world-aware and
* orientation independent.
*
* @see Vector
* @return the magnitude
*/
public double lengthSquared() {
return 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.
*
* @see Vector
* @param o The other location
* @return the distance
* @throws IllegalArgumentException for differing worlds
*/
public double distance(@NotNull Location o) {
return Math.sqrt(distanceSquared(o));
}
/**
* Get the squared distance between this location and another.
*
* @see Vector
* @param o The other location
* @return the distance
* @throws IllegalArgumentException for differing worlds
*/
public double distanceSquared(@NotNull Location o) {
if (o == null) {
throw new IllegalArgumentException("Cannot measure distance to a null location");
} else if (o.getWorld() == null || getWorld() == null) {
throw new IllegalArgumentException("Cannot measure distance to a null world");
} else if (o.getWorld() != getWorld()) {
throw new IllegalArgumentException("Cannot measure distance between " + getWorld().getName() + " and " + o.getWorld().getName());
}
return 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.
*
* @param m The factor
* @see Vector
* @return the same location
*/
@NotNull
public Location multiply(double m) {
x *= m;
y *= m;
z *= m;
return this;
}
/**
* Zero this location's components. Not world-aware.
*
* @see Vector
* @return the same location
*/
@NotNull
public Location zero() {
x = 0;
y = 0;
z = 0;
return this;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Location other = (Location) obj;
if (this.world != other.world && (this.world == null || !this.world.equals(other.world))) {
return false;
}
if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) {
return false;
}
if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) {
return false;
}
if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z)) {
return false;
}
if (Float.floatToIntBits(this.pitch) != Float.floatToIntBits(other.pitch)) {
return false;
}
if (Float.floatToIntBits(this.yaw) != Float.floatToIntBits(other.yaw)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 19 * hash + (this.world != null ? this.world.hashCode() : 0);
hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
hash = 19 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
hash = 19 * hash + Float.floatToIntBits(this.pitch);
hash = 19 * hash + Float.floatToIntBits(this.yaw);
return hash;
}
@Override
public String toString() {
return "Location{" + "world=" + world + ",x=" + x + ",y=" + y + ",z=" + z + ",pitch=" + pitch + ",yaw=" + yaw + '}';
}
/**
* Constructs a new {@link Vector} based on this Location
*
* @return New Vector containing the coordinates represented by this
* Location
*/
@NotNull
public Vector toVector() {
return new Vector(x, y, z);
}
@Override
@NotNull
public Location clone() {
try {
return (Location) super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
/**
* Check if each component of this Location is finite.
*
* @throws IllegalArgumentException if any component is not finite
*/
public void checkFinite() throws IllegalArgumentException {
NumberConversions.checkFinite(x, "x not finite");
NumberConversions.checkFinite(y, "y not finite");
NumberConversions.checkFinite(z, "z not finite");
NumberConversions.checkFinite(pitch, "pitch not finite");
NumberConversions.checkFinite(yaw, "yaw not finite");
}
/**
* Safely converts a double (location coordinate) to an int (block
* coordinate)
*
* @param loc Precise coordinate
* @return Block coordinate
*/
public static int locToBlock(double loc) {
return NumberConversions.floor(loc);
}
@Utility
@NotNull
public Map<String, Object> serialize() {
Map<String, Object> data = new HashMap<String, Object>();
data.put("world", this.world.getName());
data.put("x", this.x);
data.put("y", this.y);
data.put("z", this.z);
data.put("yaw", this.yaw);
data.put("pitch", this.pitch);
return data;
}
/**
* Required method for deserialization
*
* @param args map to deserialize
* @return deserialized location
* @throws IllegalArgumentException if the world don't exists
* @see ConfigurationSerializable
*/
@NotNull
public static Location deserialize(@NotNull Map<String, Object> args) {
World world = Bukkit.getWorld((String) args.get("world"));
if (world == null) {
throw new IllegalArgumentException("unknown world");
}
return new Location(world, NumberConversions.toDouble(args.get("x")), NumberConversions.toDouble(args.get("y")), NumberConversions.toDouble(args.get("z")), NumberConversions.toFloat(args.get("yaw")), NumberConversions.toFloat(args.get("pitch")));
}
/**
* Normalizes the given yaw angle to a value between <code>+/-180</code>
* degrees.
*
* @param yaw the yaw in degrees
* @return the normalized yaw in degrees
* @see Location#getYaw()
*/
public static float normalizeYaw(float yaw) {
yaw %= 360.0f;
if (yaw >= 180.0f) {
yaw -= 360.0f;
} else if (yaw < -180.0f) {
yaw += 360.0f;
}
return yaw;
}
/**
* Normalizes the given pitch angle to a value between <code>+/-90</code>
* degrees.
*
* @param pitch the pitch in degrees
* @return the normalized pitch in degrees
* @see Location#getPitch()
*/
public static float normalizePitch(float pitch) {
if (pitch > 90.0f) {
pitch = 90.0f;
} else if (pitch < -90.0f) {
pitch = -90.0f;
}
return pitch;
}
}