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

org.bukkit.Location Maven / Gradle / Ivy

package org.bukkit;

import net.minecraft.server.BlockPosition;
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 walkmc.StructureBox;
import walkmc.block.IBlock;
import walkmc.interfaces.Localizable;

import java.util.HashMap;
import java.util.Map;

/**
 * Represents a 3-dimensional position in a world
 */
public class Location implements Cloneable, ConfigurationSerializable, Comparable, Localizable {
	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(final World world, final double x, final double y, final double z) {
		this(world, x, y, z, 0, 0);
	}
	
	public Location(final World world, final int x, final int y, final int 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(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;
	}
	
	public static Location fromLong(World world, long i) {
		int j = (int) (i << 64 - BlockPosition.g - BlockPosition.c >> 64 - BlockPosition.c);
		int k = (int) (i << 64 - BlockPosition.f - BlockPosition.e >> 64 - BlockPosition.e);
		int l = (int) (i << 64 - BlockPosition.d >> 64 - BlockPosition.d);
		
		return new Location(world, j, k, l);
	}
	
	/**
	 * 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);
	}
	
	/**
	 * Required method for deserialization
	 *
	 * @param args map to deserialize
	 * @return deserialized location
	 * @throws IllegalArgumentException if the world don't exists
	 * @see ConfigurationSerializable
	 */
	public static Location deserialize(Map 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")));
	}
	
	@Override
	public int compareTo(@NotNull Location o) {
		if ((x == o.x || y == o.y) && z == o.z)
			return 0;
		return x < o.x && y < o.y && z < o.z ? -1 : 1;
	}
	
	public StructureBox rangeTo(Location max) {
		return new StructureBox(this, max);
	}
	
	public StructureBox rangeTo(Block max) {
		return new StructureBox(this, max.getLocation());
	}
	
	public long asLong() {
		return ((long) this.getX() & BlockPosition.h) << BlockPosition.g | ((long) this.getY() & BlockPosition.i) << BlockPosition.f | ((long) this.getZ() & BlockPosition.j);
	}
	
	/**
	 * Gets the world that this location resides in
	 *
	 * @return World that contains this location
	 */
	public World getWorld() {
		return world;
	}
	
	/**
	 * Sets the world that this location resides in
	 *
	 * @param world New world that this location resides in
	 */
	public void setWorld(World world) {
		this.world = world;
	}
	
	/**
	 * Gets the chunk at the represented location
	 *
	 * @return Chunk at the represented location
	 */
	public Chunk getChunk() {
		return world.getChunkAt(this);
	}
	
	/**
	 * Gets the block at the represented location
	 *
	 * @return Block at the represented location
	 */
	public Block getBlock() {
		return world.getBlockAt(this);
	}
	
	/**
	 * Gets the custom block instance represented by the block of this location.
	 */
	public IBlock getCustomBlock() {
		return world.getCustomBlock(this);
	}
	
	/**
	 * Sets the custom block of the block represented in this location.
	 */
	public void setCustomBlock(IBlock block) {
		world.setCustomBlock(this, block);
	}
	
	/**
	 * Returns if this location has a custom block.
	 */
	public boolean isCustomBlock() {
		return world.isCustomBlock(this);
	}
	
	/**
  * Removes a possible existent custom block from the specified location
  */
	public void removeCustomBlock() {
		world.removeCustomBlock(this);
	}
	
	/**
	 * Gets the x-coordinate of this location
	 *
	 * @return x-coordinate
	 */
	public double getX() {
		return x;
	}
	
	/**
	 * Sets the x-coordinate of this location
	 *
	 * @param x X-coordinate
	 */
	public void setX(double x) {
		this.x = 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);
	}
	
	/**
	 * Gets the y-coordinate of this location
	 *
	 * @return y-coordinate
	 */
	public double getY() {
		return y;
	}
	
	/**
	 * Sets the y-coordinate of this location
	 *
	 * @param y y-coordinate
	 */
	public void setY(double y) {
		this.y = 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);
	}
	
	/**
	 * Gets the z-coordinate of this location
	 *
	 * @return z-coordinate
	 */
	public double getZ() {
		return z;
	}
	
	/**
	 * Sets the z-coordinate of this location
	 *
	 * @param z z-coordinate
	 */
	public void setZ(double z) {
		this.z = 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);
	}
	
	/**
	 * Gets the yaw of this location, measured in degrees.
	 * 
    *
  • A yaw of 0 or 360 represents the positive z direction. *
  • A yaw of 180 represents the negative z direction. *
  • A yaw of 90 represents the negative x direction. *
  • A yaw of 270 represents the positive x direction. *
* 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 yaw of this location, measured in degrees. *
    *
  • A yaw of 0 or 360 represents the positive z direction. *
  • A yaw of 180 represents the negative z direction. *
  • A yaw of 90 represents the negative x direction. *
  • A yaw of 270 represents the positive x direction. *
* 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 pitch of this location, measured in degrees. *
    *
  • A pitch of 0 represents level forward facing. *
  • A pitch of 90 represents downward facing, or negative y * direction. *
  • A pitch of -90 represents upward facing, or positive y direction. *
* Increasing pitch values the equivalent of looking down. * * @return the incline's pitch */ public float getPitch() { return pitch; } /** * Sets the pitch of this location, measured in degrees. *
    *
  • A pitch of 0 represents level forward facing. *
  • A pitch of 90 represents downward facing, or negative y * direction. *
  • A pitch of -90 represents upward facing, or positive y direction. *
* Increasing pitch values the equivalent of looking down. * * @param pitch new incline's pitch */ public void setPitch(float pitch) { this.pitch = 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} */ 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 */ public Location setDirection(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. * * @param vec The other location * @return the same location * @throws IllegalArgumentException for differing worlds * @see Vector */ public Location add(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. * * @param vec Vector to use * @return the same location * @see Vector */ public Location add(Vector vec) { this.x += vec.getX(); this.y += vec.getY(); this.z += vec.getZ(); return this; } /** * Adds the location by another. Not world-aware. * * @param x X coordinate * @param y Y coordinate * @param z Z coordinate * @return the same location * @see Vector */ 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. * * @param vec The other location * @return the same location * @throws IllegalArgumentException for differing worlds * @see Vector */ public Location subtract(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. * * @param vec The vector to use * @return the same location * @see Vector */ public Location subtract(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. * * @param x X coordinate * @param y Y coordinate * @param z Z coordinate * @return the same location * @see Vector */ 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. * * @return the magnitude * @see Vector */ 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. * * @return the magnitude * @see Vector */ 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. * * @param o The other location * @return the distance * @throws IllegalArgumentException for differing worlds * @see Vector */ public double distance(Location o) { return Math.sqrt(distanceSquared(o)); } /** * Get the squared distance between this location and another. * * @param o The other location * @return the distance * @throws IllegalArgumentException for differing worlds * @see Vector */ public double distanceSquared(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 * @return the same location * @see Vector */ public Location multiply(double m) { x *= m; y *= m; z *= m; return this; } /** * Zero this location's components. Not world-aware. * * @return the same location * @see Vector */ 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; } return Float.floatToIntBits(this.yaw) == Float.floatToIntBits(other.yaw); } @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 */ public Vector toVector() { return new Vector(x, y, z); } @Override public Location clone() { try { return (Location) super.clone(); } catch (CloneNotSupportedException e) { throw new Error(e); } } @Utility public Map serialize() { Map data = new HashMap(); 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; } @NotNull @Override public Location getLocation() { return this; } @Override public void setLocation(@NotNull Location location) { throw new IllegalArgumentException("cannot change the backend access location from localizable object"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy