package cofh.lib.util.position;
import cofh.lib.util.helpers.BlockHelper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
public class BlockPosition implements Comparable<BlockPosition>, Serializable {
private static final long serialVersionUID = 8671402745765780610L;
public int x;
public int y;
public int z;
public ForgeDirection orientation;
public BlockPosition(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
orientation = ForgeDirection.UNKNOWN;
}
public BlockPosition(int x, int y, int z, ForgeDirection orientation) {
this.x = x;
this.y = y;
this.z = z;
this.orientation = orientation;
}
public BlockPosition(BlockPosition p) {
x = p.x;
y = p.y;
z = p.z;
orientation = p.orientation;
}
public BlockPosition(NBTTagCompound tag) {
x = tag.getInteger("bp_i");
y = tag.getInteger("bp_j");
z = tag.getInteger("bp_k");
if (!tag.hasKey("bp_dir")) {
orientation = ForgeDirection.UNKNOWN;
} else {
orientation = ForgeDirection.getOrientation(tag.getByte("bp_dir"));
}
}
public BlockPosition(TileEntity tile) {
x = tile.xCoord;
y = tile.yCoord;
z = tile.zCoord;
if (tile instanceof IRotateableTile) {
orientation = ((IRotateableTile) tile).getDirectionFacing();
} else {
orientation = ForgeDirection.UNKNOWN;
}
}
public static <T extends TileEntity & IRotateableTile> BlockPosition fromRotateableTile(T te) {
return new BlockPosition(te);
}
public BlockPosition copy() {
return new BlockPosition(x, y, z, orientation);
}
public BlockPosition copy(ForgeDirection orientation) {
return new BlockPosition(x, y, z, orientation);
}
public BlockPosition setOrientation(ForgeDirection o) {
orientation = o;
return this;
}
public BlockPosition step(int dir) {
int[] d = BlockHelper.SIDE_COORD_MOD[dir];
x += d[0];
y += d[1];
z += d[2];
return this;
}
public BlockPosition step(int dir, int dist) {
int[] d = BlockHelper.SIDE_COORD_MOD[dir];
x += d[0] * dist;
y += d[1] * dist;
z += d[2] * dist;
return this;
}
public BlockPosition step(ForgeDirection dir) {
x += dir.offsetX;
y += dir.offsetY;
z += dir.offsetZ;
return this;
}
public BlockPosition step(ForgeDirection dir, int dist) {
x += dir.offsetX * dist;
y += dir.offsetY * dist;
z += dir.offsetZ * dist;
return this;
}
public BlockPosition moveForwards(int step) {
switch (orientation) {
case UP:
y = y + step;
break;
case DOWN:
y = y - step;
break;
case SOUTH:
z = z + step;
break;
case NORTH:
z = z - step;
break;
case EAST:
x = x + step;
break;
case WEST:
x = x - step;
break;
default:
}
return this;
}
public BlockPosition moveBackwards(int step) {
return moveForwards(-step);
}
public BlockPosition moveRight(int step) {
switch (orientation) {
case UP:
case SOUTH:
x = x - step;
break;
case DOWN:
case NORTH:
x = x + step;
break;
case EAST:
z = z + step;
break;
case WEST:
z = z - step;
break;
default:
break;
}
return this;
}
public BlockPosition moveLeft(int step) {
return moveRight(-step);
}
public BlockPosition moveUp(int step) {
switch (orientation) {
case EAST:
case WEST:
case NORTH:
case SOUTH:
y = y + step;
break;
case UP:
z = z - step;
break;
case DOWN:
z = z + step;
default:
break;
}
return this;
}
public BlockPosition moveDown(int step) {
return moveUp(-step);
}
public void writeToNBT(NBTTagCompound tag) {
tag.setInteger("bp_i", x);
tag.setInteger("bp_j", y);
tag.setInteger("bp_k", z);
tag.setByte("bp_dir", (byte) orientation.ordinal());
}
@Override
public String toString() {
if (orientation == null) {
return "{" + x + ", " + y + ", " + z + "}";
}
return "{" + x + ", " + y + ", " + z + ";" + orientation.toString() + "}";
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof BlockPosition)) {
return false;
}
BlockPosition bp = (BlockPosition) obj;
return bp.x == x & bp.y == y & bp.z == z & bp.orientation == orientation;
}
// so compiler will optimize
public boolean equals(BlockPosition bp) {
return bp != null && bp.x == x & bp.y == y & bp.z == z & bp.orientation == orientation;
}
@Override
public int hashCode() {
return (x & 0xFFF) | (y & 0xFF << 8) | (z & 0xFFF << 12);
}
public BlockPosition min(BlockPosition p) {
return new BlockPosition(p.x > x ? x : p.x, p.y > y ? y : p.y, p.z > z ? z : p.z);
}
public BlockPosition max(BlockPosition p) {
return new BlockPosition(p.x < x ? x : p.x, p.y < y ? y : p.y, p.z < z ? z : p.z);
}
public List<BlockPosition> getAdjacent(boolean includeVertical) {
List<BlockPosition> a = new ArrayList<BlockPosition>(4 + (includeVertical ? 2 : 0));
a.add(copy(ForgeDirection.EAST).moveForwards(1));
a.add(copy(ForgeDirection.WEST).moveForwards(1));
a.add(copy(ForgeDirection.SOUTH).moveForwards(1));
a.add(copy(ForgeDirection.NORTH).moveForwards(1));
if (includeVertical) {
a.add(copy(ForgeDirection.UP).moveForwards(1));
a.add(copy(ForgeDirection.DOWN).moveForwards(1));
}
return a;
}
public boolean blockExists(World world) {
return world.blockExists(x, y, z);
}
public TileEntity getTileEntity(World world) {
return world.getTileEntity(x, y, z);
}
public Block getBlock(World world) {
return world.getBlock(x, y, z);
}
@SuppressWarnings("unchecked")
public <T> T getTileEntity(World world, Class<T> targetClass) {
TileEntity te = world.getTileEntity(x, y, z);
if (targetClass.isInstance(te)) {
return (T) te;
} else {
return null;
}
}
public static ForgeDirection getDirection(int xS, int yS, int zS, int x, int y, int z) {
int dir = 0;
if (y < yS)
dir |= 1;
else if (y != yS)
dir |= 2;
if (z < zS)
dir |= 4;
else if (z != zS)
dir |= 8;
if (x < xS)
dir |= 16;
else if (x != xS)
dir |= 32;
switch (dir) {
case 2: return ForgeDirection.UP;
case 1: return ForgeDirection.DOWN;
case 4: return ForgeDirection.WEST;
case 8: return ForgeDirection.EAST;
case 16: return ForgeDirection.NORTH;
case 32: return ForgeDirection.SOUTH;
default: return ForgeDirection.UNKNOWN;
}
}
public static TileEntity getTileEntityRaw(World world, int x, int y, int z) {
if (!world.blockExists(x, y, z))
return null;
return world.getChunkFromBlockCoords(x, z).getTileEntityUnsafe(x & 15, y, z & 15);
}
@SuppressWarnings("unchecked")
public static <T> T getTileEntityRaw(World world, int x, int y, int z, Class<T> targetClass) {
TileEntity te = getTileEntityRaw(world, x, y, z);
if (targetClass.isInstance(te)) {
return (T) te;
} else {
return null;
}
}
public static boolean blockExists(TileEntity start, ForgeDirection dir) {
final int x = start.xCoord + dir.offsetX, y = start.yCoord + dir.offsetY, z = start.zCoord + dir.offsetZ;
return start.getWorldObj().blockExists(x, y, z);
}
public static TileEntity getAdjacentTileEntity(TileEntity start, ForgeDirection dir) {
final int x = start.xCoord + dir.offsetX, y = start.yCoord + dir.offsetY, z = start.zCoord + dir.offsetZ;
return getTileEntityRaw(start.getWorldObj(), x, y, z);
}
@SuppressWarnings("unchecked")
public static <T> T getAdjacentTileEntity(TileEntity start, ForgeDirection direction, Class<T> targetClass) {
TileEntity te = getAdjacentTileEntity(start, direction);
if (targetClass.isInstance(te)) {
return (T) te;
} else {
return null;
}
}
/* Comparable */
@Override
public int compareTo(BlockPosition other) {
return this.x == other.x ? this.y == other.y ? this.z - other.z : this.y - other.y : this.x - other.x;
}
}