242 lines
8.0 KiB
Java
242 lines
8.0 KiB
Java
/**
|
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
|
* Copyright (C) 2015 dmulloy2
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with this program;
|
|
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
* 02111-1307 USA
|
|
*/
|
|
package com.comphenix.protocol.wrappers;
|
|
|
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
|
import com.comphenix.protocol.reflect.StructureModifier;
|
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
|
import com.google.common.base.Objects;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.World;
|
|
import org.bukkit.util.Vector;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
|
|
/**
|
|
* Copies a immutable net.minecraft.server.BlockPosition, which represents a integer 3D vector.
|
|
*
|
|
* @author dmulloy2
|
|
*/
|
|
public class BlockPosition {
|
|
|
|
/**
|
|
* Represents the null (0, 0, 0) origin.
|
|
*/
|
|
public static BlockPosition ORIGIN = new BlockPosition(0, 0, 0);
|
|
|
|
private static Constructor<?> blockPositionConstructor;
|
|
|
|
// Use protected members, like Bukkit
|
|
protected final int x;
|
|
protected final int y;
|
|
protected final int z;
|
|
|
|
// Used to access a BlockPosition, in case it's names are changed
|
|
private static StructureModifier<Integer> intModifier;
|
|
|
|
/**
|
|
* Construct an immutable 3D vector.
|
|
* @param x - x coordinate
|
|
* @param y - y coordinate
|
|
* @param z - z coordinate
|
|
*/
|
|
public BlockPosition(int x, int y, int z) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
}
|
|
|
|
/**
|
|
* Construct an immutable integer 3D vector from a mutable Bukkit vector.
|
|
* @param vector - the mutable real Bukkit vector to copy.
|
|
*/
|
|
public BlockPosition(Vector vector) {
|
|
if (vector == null)
|
|
throw new IllegalArgumentException("Vector cannot be NULL.");
|
|
this.x = vector.getBlockX();
|
|
this.y = vector.getBlockY();
|
|
this.z = vector.getBlockZ();
|
|
}
|
|
|
|
/**
|
|
* Convert this instance to an equivalent real 3D vector.
|
|
* @return Real 3D vector.
|
|
*/
|
|
public Vector toVector() {
|
|
return new Vector(x, y, z);
|
|
}
|
|
|
|
/**
|
|
* Convert this instance to an equivalent Location.
|
|
* @param world World for the location
|
|
* @return Location
|
|
*/
|
|
public Location toLocation(World world) {
|
|
return new Location(world, x, y, z);
|
|
}
|
|
|
|
/**
|
|
* Retrieve the x-coordinate.
|
|
* @return X coordinate.
|
|
*/
|
|
public int getX() {
|
|
return x;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the y-coordinate.
|
|
* @return Y coordinate.
|
|
*/
|
|
public int getY() {
|
|
return y;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the z-coordinate.
|
|
* @return Z coordinate.
|
|
*/
|
|
public int getZ() {
|
|
return z;
|
|
}
|
|
|
|
/**
|
|
* Adds the current position and a given position together, producing a result position.
|
|
* @param other - the other position.
|
|
* @return The new result position.
|
|
*/
|
|
public BlockPosition add(BlockPosition other) {
|
|
if (other == null)
|
|
throw new IllegalArgumentException("other cannot be NULL");
|
|
return new BlockPosition(x + other.x, y + other.y, z + other.z);
|
|
}
|
|
|
|
/**
|
|
* Adds the current position and a given position together, producing a result position.
|
|
* @param other - the other position.
|
|
* @return The new result position.
|
|
*/
|
|
public BlockPosition subtract(BlockPosition other) {
|
|
if (other == null)
|
|
throw new IllegalArgumentException("other cannot be NULL");
|
|
return new BlockPosition(x - other.x, y - other.y, z - other.z);
|
|
}
|
|
|
|
/**
|
|
* Multiply each dimension in the current position by the given factor.
|
|
* @param factor - multiplier.
|
|
* @return The new result.
|
|
*/
|
|
public BlockPosition multiply(int factor) {
|
|
return new BlockPosition(x * factor, y * factor, z * factor);
|
|
}
|
|
|
|
/**
|
|
* Divide each dimension in the current position by the given divisor.
|
|
* @param divisor - the divisor.
|
|
* @return The new result.
|
|
*/
|
|
public BlockPosition divide(int divisor) {
|
|
if (divisor == 0)
|
|
throw new IllegalArgumentException("Cannot divide by null.");
|
|
return new BlockPosition(x / divisor, y / divisor, z / divisor);
|
|
}
|
|
|
|
/**
|
|
* Used to convert between NMS ChunkPosition and the wrapper instance.
|
|
* @return A new converter.
|
|
*/
|
|
public static EquivalentConverter<BlockPosition> getConverter() {
|
|
return new EquivalentConverter<BlockPosition>() {
|
|
@Override
|
|
public Object getGeneric(BlockPosition specific) {
|
|
if (blockPositionConstructor == null) {
|
|
try {
|
|
blockPositionConstructor = MinecraftReflection.getBlockPositionClass().
|
|
getConstructor(int.class, int.class, int.class);
|
|
} catch (Exception e) {
|
|
throw new RuntimeException("Cannot find block position constructor.", e);
|
|
}
|
|
}
|
|
|
|
// Construct the underlying BlockPosition
|
|
try {
|
|
return blockPositionConstructor.newInstance(specific.x, specific.y, specific.z);
|
|
} catch (Exception e) {
|
|
throw new RuntimeException("Cannot construct BlockPosition.", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public BlockPosition getSpecific(Object generic) {
|
|
if (MinecraftReflection.isBlockPosition(generic)) {
|
|
// Use a structure modifier
|
|
intModifier = new StructureModifier<>(generic.getClass(), null, false).withType(int.class);
|
|
|
|
// Damn it all
|
|
if (intModifier.size() < 3) {
|
|
throw new IllegalStateException("Cannot read class " + generic.getClass() + " for its integer fields.");
|
|
}
|
|
|
|
if (intModifier.size() >= 3) {
|
|
try {
|
|
StructureModifier<Integer> instance = intModifier.withTarget(generic);
|
|
return new BlockPosition(instance.read(0), instance.read(1), instance.read(2));
|
|
} catch (FieldAccessException e) {
|
|
// This is an exeptional work-around, so we don't want to burden the caller with the messy details
|
|
throw new RuntimeException("Field access error.", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otherwise, return NULL
|
|
return null;
|
|
}
|
|
|
|
// Thanks Java Generics!
|
|
@Override
|
|
public Class<BlockPosition> getSpecificType() {
|
|
return BlockPosition.class;
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
// Fast checks
|
|
if (this == obj) return true;
|
|
if (obj == null) return false;
|
|
|
|
// Only compare objects of similar type
|
|
if (obj instanceof BlockPosition) {
|
|
BlockPosition other = (BlockPosition) obj;
|
|
return x == other.x && y == other.y && z == other.z;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return Objects.hashCode(x, y, z);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "BlockPosition [x=" + x + ", y=" + y + ", z=" + z + "]";
|
|
}
|
|
}
|