/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.utils.coords; import com.jcwhatever.nucleus.storage.IDataNode; import com.jcwhatever.nucleus.storage.serialize.DeserializeException; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.file.IByteReader; import com.jcwhatever.nucleus.utils.file.IByteWriter; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.util.Vector; import java.io.IOException; import javax.annotation.Nullable; /** * 3D immutable integer coordinates with no {@link org.bukkit.World} context. */ public class Coords3Di extends Coords2Di implements ICoords3Di { /** * Get {@link Coords3Di} from a {@link org.bukkit.Location}. * * @param location The location to convert. */ public static Coords3Di fromLocation(Location location) { return new Coords3Di(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } /** * Get {@link Coords3Di} from a {@link org.bukkit.util.Vector}. * * @param vector The vector to convert. */ public static Coords3Di fromVector(Vector vector) { return new Coords3Di(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); } /** * Get the distance from a source coordinate to a target coordinate. * * @param source The source coordinates. * @param target The target coordinates. */ public static double distance(ICoords3Di source, ICoords3Di target) { return Math.sqrt(distanceSquared(source, target)); } /** * Get the distance from a source coordinate to a target coordinate. * * @param source The source coordinates. * @param target The target coordinates. */ public static double distance(ICoords3Di source, ICoords3D target) { return Math.sqrt(distanceSquared(source, target)); } /** * Get distance squared between two coordinates. * * @param source The source coordinates. * @param destination The destination coordinates. */ public static double distanceSquared(ICoords3Di source, ICoords3Di destination) { PreCon.notNull(source); PreCon.notNull(destination); double deltaX = destination.getX() - source.getX(); double deltaY = destination.getY() - source.getY(); double deltaZ = destination.getZ() - source.getZ(); return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; } /** * Get distance squared between two coordinates. * * @param source The source coordinates. * @param destination The destination coordinates. */ public static double distanceSquared(ICoords3Di source, ICoords3D destination) { PreCon.notNull(source); PreCon.notNull(destination); double deltaX = destination.getX() - source.getX(); double deltaY = destination.getY() - source.getY(); double deltaZ = destination.getZ() - source.getZ(); return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; } /** * Get a {@link org.bukkit.block.Block} from the specified {@link org.bukkit.World} * using the specified coordinates. * * @param world The {@link org.bukkit.World} the block is in. * @param coords The coordinates of the block. */ public static Block getBlock(World world, ICoords3Di coords) { PreCon.notNull(world); return world.getBlockAt(coords.getX(), coords.getY(), coords.getZ()); } /** * Create a new {@link org.bukkit.Location} from the coordinates. * * @param coords The coordinates to convert. * @param world The {@link org.bukkit.World} value of the new location. */ public static Location toLocation(ICoords3Di coords, @Nullable World world) { return toLocation(coords, new Location(world, 0, 0, 0)); } /** * Copy coordinate values into an output {@link org.bukkit.Location}. * * @param output The output {@link org.bukkit.Location}. * * @return The output location. */ public static Location toLocation(ICoords3Di coords, Location output) { return copyTo(coords, output); } /** * Create a new {@link org.bukkit.util.Vector} from the coordinates. * * @param coords The coordinates to convert. */ public static Vector toVector(ICoords3Di coords) { return toVector(coords, new Vector(0, 0, 0)); } /** * Copy coordinate values into an output {@link org.bukkit.util.Vector}. * * @param coords The coordinates to convert. * @param output The output {@link org.bukkit.util.Vector}. * * @return The output location. */ public static Vector toVector(ICoords3Di coords, Vector output) { PreCon.notNull(coords); PreCon.notNull(output); output.setX(coords.getX()); output.setY(coords.getY()); output.setZ(coords.getZ()); return output; } /** * Copy the coordinate to an output {@link org.bukkit.Location}. * * @param coords The coordinates to copy from. * @param output The output {@link org.bukkit.Location}. * * @return The output {@link org.bukkit.Location}. */ public static Location copyTo(ICoords3Di coords, Location output) { PreCon.notNull(coords); PreCon.notNull(output); output.setX(coords.getX()); output.setY(coords.getY()); output.setZ(coords.getZ()); return output; } /** * Copy the coordinate values to an output {@link org.bukkit.Location}. * * @param coords The coords to copy from. * @param world The {@link org.bukkit.World} to put into the output {@link org.bukkit.Location}. * @param output The output {@link org.bukkit.Location}. * * @return The output {@link org.bukkit.Location}. */ public static Location copyTo(ICoords3Di coords, @Nullable World world, Location output) { PreCon.notNull(coords); PreCon.notNull(output); output.setWorld(world); output.setX(coords.getX()); output.setY(coords.getY()); output.setZ(coords.getZ()); return output; } private int _y; private boolean _canSeal; /** * Constructor. * * @param x The x coordinates. * @param y The y coordinates. * @param z The z coordinates. */ public Coords3Di(int x, int y, int z) { super(x, z); _y = y; _canSeal = true; seal(); } /** * Constructor. * * <p>Clones values from source coordinates.</p> * * @param source The source coordinates. */ public Coords3Di(ICoords3Di source) { this(source.getX(), source.getY(), source.getZ()); } /** * Constructor. * * <p>Clones values from source coordinates and adds delta values.</p> * * @param source The source coordinates. * @param deltaX The X coordinate values to add to the source coordinates. * @param deltaY The Y coordinate values to add to the source coordinates. * @param deltaZ The Z coordinate values to add to the source coordinates. */ public Coords3Di(ICoords3Di source, int deltaX, int deltaY, int deltaZ) { this(source.getX() + deltaX, source.getY() + deltaY, source.getZ() + deltaZ); } /** * Protected constructor for serialization. */ protected Coords3Di() {} @Override public int getY() { return _y; } /** * Get the distance from this coordinates to a target coordinate. * * @param target The target coordinates. */ public double distance(ICoords3D target) { return distance(this, target); } /** * Get the distance from this coordinates to a target coordinate. * * @param target The target coordinates. */ public double distance(ICoords3Di target) { return distance(this, target); } /** * Get the distance from this coordinates to a target coordinate squared. * * @param target The target coordinates. */ public double distanceSquared(ICoords3D target) { return distanceSquared(this, target); } /** * Get the distance from this coordinates to a target coordinate squared. * * @param target The target coordinates. */ public double distanceSquared(ICoords3Di target) { return distanceSquared(this, target); } /** * Create delta coordinates by subtracting other coordinates from * this coordinates. * * @param coords The other coordinates. */ public Coords3Di getDelta(ICoords3Di coords) { PreCon.notNull(coords); int deltaX = getX() - coords.getX(); int deltaY = getY() - coords.getY(); int deltaZ = getZ() - coords.getZ(); return new Coords3Di(deltaX, deltaY, deltaZ); } /** * Create delta coordinates by subtracting other coordinates from * this coordinates. * * @param coords The other coordinates. * @param output The {@link MutableCoords3Di} to put the results into. * * @return The output {@link MutableCoords3Di}. */ public MutableCoords3Di getDelta(ICoords3Di coords, MutableCoords3Di output) { PreCon.notNull(coords); PreCon.notNull(output); int deltaX = getX() - coords.getX(); int deltaY = getY() - coords.getY(); int deltaZ = getZ() - coords.getZ(); output.setX(deltaX); output.setY(deltaY); output.setZ(deltaZ); return output; } /** * Get a {@link org.bukkit.block.Block} from the specified {@link org.bukkit.World} * using this coordinates. * * @param world The {@link org.bukkit.World} the block is in. */ public Block getBlock(World world) { return getBlock(world, this); } /** * Create a new {@link org.bukkit.Location} from the coordinates. * * @param world The {@link org.bukkit.World} value of the new location. */ public Location toLocation(@Nullable World world) { return toLocation(this, new Location(world, 0, 0, 0)); } /** * Copy coordinate values into an output {@link org.bukkit.Location}. * * @param output The output {@link org.bukkit.Location}. * * @return The output location. */ public Location toLocation(Location output) { return toLocation(this, output); } /** * Create a new {@link org.bukkit.util.Vector} from the coordinates. */ public Vector toVector() { return toVector(this); } /** * Copy coordinate values into an output {@link org.bukkit.util.Vector}. * * @param output The output {@link org.bukkit.util.Vector}. * * @return The output location. */ public Vector toVector(Vector output) { return toVector(this, output); } /** * Create a new {@link Coords3D} using the coordinate values. */ public Coords3D to3D() { return new Coords3D(getX(), getY(), getZ()); } /** * Create a new {@link Coords2Di} using the coordinate values. * * <p>Drops the Y coordinate.</p> */ public Coords2Di to2Di() { return new Coords2Di(getX(), getZ()); } /** * Copy the coordinate values to an output {@link org.bukkit.Location}. * * @param output The output {@link org.bukkit.Location}. * * @return The output {@link org.bukkit.Location}. */ @Override public Location copyTo(Location output) { return copyTo(this, output); } /** * Copy the coordinate values to an output {@link org.bukkit.Location}. * * @param world The {@link org.bukkit.World} to put into the output {@link org.bukkit.Location}. * @param output The output {@link org.bukkit.Location}. * * @return The output {@link org.bukkit.Location}. */ @Override public Location copyTo(@Nullable World world, Location output) { return copyTo(this, world, output); } @Override public void serialize(IDataNode dataNode) { super.serialize(dataNode); dataNode.set("y", _y); } @Override public void deserialize(IDataNode dataNode) throws DeserializeException { super.deserialize(dataNode); _y = dataNode.getInteger("y"); _canSeal = true; seal(); } @Override public void serialize(IByteWriter writer) throws IOException { super.serialize(writer); writer.write(_y); } @Override public void deserialize(IByteReader reader) throws IOException, ClassNotFoundException, InstantiationException { super.deserialize(reader); _y = reader.getInteger(); _canSeal = true; seal(); } @Override public int hashCode() { return super.hashCode() ^ _y; } @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj instanceof ICoords3Di) { ICoords3Di other = (ICoords3Di)obj; return other.getX() == getX() && other.getY() == _y && other.getZ() == getZ(); } return false; } @Override public String toString() { return getClass().getSimpleName() + " { x:" + getX() + ", y:" + _y + ", z:" + getZ() + '}'; } /** * Set the Y coordinate. * * @param y The Y coordinate. * * @throws java.lang.IllegalStateException if the object is immutable. */ protected void setY(int y) { if (isImmutable()) throw new IllegalStateException("Coordinate is immutable."); _y = y; } /** * Invoked to make the object immutable. */ @Override protected void seal() { if (_canSeal) super.seal(); } }