package mekanism.api; import java.util.ArrayList; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.MathHelper; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraftforge.common.util.ForgeDirection; import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; import io.netty.buffer.ByteBuf; /** * Coord4D - an integer-based way to keep track of and perform operations on blocks in a Minecraft-based environment. This also takes * in account the dimension the coordinate is in. * @author aidancbrady * */ public class Coord4D { public int xCoord; public int yCoord; public int zCoord; public int dimensionId; /** * Creates a Coord4D WITHOUT a dimensionId. Don't use unless absolutely necessary. * @param x - x coordinate * @param y - y coordinate * @param z - z coordinate */ public Coord4D(int x, int y, int z) { xCoord = x; yCoord = y; zCoord = z; dimensionId = 0; } /** * Creates a Coord4D from an entity's position, rounded down. * @param entity - entity to create the Coord4D from */ public Coord4D(Entity entity) { xCoord = (int)entity.posX; yCoord = (int)entity.posY; zCoord = (int)entity.posZ; dimensionId = entity.worldObj.provider.dimensionId; } /** * Creates a Coord4D from the defined x, y, z, and dimension values. * @param x - x coordinate * @param y - y coordinate * @param z - z coordinate * @param dimension - dimension ID */ public Coord4D(int x, int y, int z, int dimension) { xCoord = x; yCoord = y; zCoord = z; dimensionId = dimension; } /** * Gets the metadata of the block representing this Coord4D. * @param world - world this Coord4D is in * @return the metadata of this Coord4D's block */ public int getMetadata(IBlockAccess world) { return world.getBlockMetadata(xCoord, yCoord, zCoord); } /** * Gets the TileEntity of the block representing this Coord4D. * @param world - world this Coord4D is in * @return the TileEntity of this Coord4D's block */ public TileEntity getTileEntity(IBlockAccess world) { if(world instanceof World && !exists((World)world)) { return null; } return world.getTileEntity(xCoord, yCoord, zCoord); } /** * Gets the Block value of the block representing this Coord4D. * @param world - world this Coord4D is in * @return the Block value of this Coord4D's block */ public Block getBlock(IBlockAccess world) { if(world instanceof World && !exists((World)world)) { return null; } return world.getBlock(xCoord, yCoord, zCoord); } /** * Writes this Coord4D's data to an NBTTagCompound. * @param nbtTags - tag compound to write to * @return the tag compound with this Coord4D's data */ public NBTTagCompound write(NBTTagCompound nbtTags) { nbtTags.setInteger("x", xCoord); nbtTags.setInteger("y", yCoord); nbtTags.setInteger("z", zCoord); nbtTags.setInteger("dimensionId", dimensionId); return nbtTags; } /** * Writes this Coord4D's data to an ArrayList for packet transfer. * @param data - the ArrayList to add the data to */ public void write(ArrayList data) { data.add(xCoord); data.add(yCoord); data.add(zCoord); data.add(dimensionId); } /** * Writes this Coord4D's data to a ByteBuf for packet transfer. * @param dataStream - the ByteBuf to add the data to */ public void write(ByteBuf dataStream) { dataStream.writeInt(xCoord); dataStream.writeInt(yCoord); dataStream.writeInt(zCoord); dataStream.writeInt(dimensionId); } /** * Translates this Coord4D by the defined x, y, and z values. * @param x - x value to translate * @param y - y value to translate * @param z - z value to translate * @return translated Coord4D */ public Coord4D translate(int x, int y, int z) { xCoord += x; yCoord += y; zCoord += z; return this; } /** * Creates and returns a new Coord4D translated to the defined offsets of the side. * @param side - side to translate this Coord4D to * @return translated Coord4D */ public Coord4D getFromSide(ForgeDirection side) { return getFromSide(side, 1); } /** * Creates and returns a new Coord4D translated to the defined offsets of the side by the defined amount. * @param side - side to translate this Coord4D to * @param amount - how far to translate this Coord4D * @return translated Coord4D */ public Coord4D getFromSide(ForgeDirection side, int amount) { return new Coord4D(xCoord+(side.offsetX*amount), yCoord+(side.offsetY*amount), zCoord+(side.offsetZ*amount), dimensionId); } public ItemStack getStack(IBlockAccess world) { Block block = getBlock(world); if(block == null || block == Blocks.air) { return null; } return new ItemStack(block, 1, getMetadata(world)); } /** * Returns a new Coord4D from a defined TileEntity's xCoord, yCoord and zCoord values. * @param tileEntity - TileEntity at the location that will represent this Coord4D * @return the Coord4D object from the TileEntity */ public static Coord4D get(TileEntity tileEntity) { return new Coord4D(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, tileEntity.getWorldObj().provider.dimensionId); } /** * Returns a new Coord4D from a tag compound. * @param data - tag compound to read from * @return the Coord4D from the tag compound */ public static Coord4D read(NBTTagCompound tag) { return new Coord4D(tag.getInteger("x"), tag.getInteger("y"), tag.getInteger("z"), tag.getInteger("id")); } /** * Returns a new Coord4D from a ByteBuf. * @param dataStream - data input to read from * @return the Coord4D from the data input */ public static Coord4D read(ByteBuf dataStream) { return new Coord4D(dataStream.readInt(), dataStream.readInt(), dataStream.readInt(), dataStream.readInt()); } /** * Creates and returns a new Coord4D with values representing the difference between the defined Coord4D * @param other - the Coord4D to subtract from this * @return a Coord4D representing the distance between the defined Coord4D */ public Coord4D difference(Coord4D other) { return new Coord4D(xCoord-other.xCoord, yCoord-other.yCoord, zCoord-other.zCoord, dimensionId); } /** * A method used to find the ForgeDirection represented by the distance of the defined Coord4D. Most likely won't have many * applicable uses. * @param other - Coord4D to find the side difference of * @return ForgeDirection representing the side the defined relative Coord4D is on to this */ public ForgeDirection sideDifference(Coord4D other) { Coord4D diff = difference(other); for(ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { if(side.offsetX == diff.xCoord && side.offsetY == diff.yCoord && side.offsetZ == diff.zCoord) { return side; } } return ForgeDirection.UNKNOWN; } /** * Gets the distance to a defined Coord4D. * @param obj - the Coord4D to find the distance to * @return the distance to the defined Coord4D */ public int distanceTo(Coord4D obj) { int subX = xCoord - obj.xCoord; int subY = yCoord - obj.yCoord; int subZ = zCoord - obj.zCoord; return (int)MathHelper.sqrt_double(subX * subX + subY * subY + subZ * subZ); } /** * Whether or not the defined side of this Coord4D is visible. * @param side - side to check * @param world - world this Coord4D is in * @return */ public boolean sideVisible(ForgeDirection side, IBlockAccess world) { return world.isAirBlock(xCoord+side.offsetX, yCoord+side.offsetY, zCoord+side.offsetZ); } /** * Gets a TargetPoint with the defined range from this Coord4D with the appropriate coordinates and dimension ID. * @param range - the range the packet can be sent in of this Coord4D * @return TargetPoint relative to this Coord4D */ public TargetPoint getTargetPoint(double range) { return new TargetPoint(dimensionId, xCoord, yCoord, zCoord, range); } /** * Steps this Coord4D in the defined side's offset without creating a new value. * @param side - side to step towards * @return this Coord4D */ public Coord4D step(ForgeDirection side) { return translate(side.offsetX, side.offsetY, side.offsetZ); } /** * Whether or not the chunk this Coord4D is in exists and is loaded. * @param world - world this Coord4D is in * @return the chunk of this Coord4D */ public boolean exists(World world) { return world.getChunkProvider().chunkExists(xCoord >> 4, zCoord >> 4); } /** * Gets the chunk this Coord4D is in. * @param world - world this Coord4D is in * @return the chunk of this Coord4D */ public Chunk getChunk(World world) { return world.getChunkFromBlockCoords(xCoord, zCoord); } /** * Gets the Chunk3D object with chunk coordinates correlating to this Coord4D's location * @return Chunk3D with correlating chunk coordinates. */ public Chunk3D getChunk3D() { return new Chunk3D(this); } /** * Whether or not the block this Coord4D represents is an air block. * @param world - world this Coord4D is in * @return if this Coord4D is an air block */ public boolean isAirBlock(IBlockAccess world) { return world.isAirBlock(xCoord, yCoord, zCoord); } /** * Whether or not this block this Coord4D represents is replaceable. * @param world - world this Coord4D is in * @return if this Coord4D is replaceable */ public boolean isReplaceable(IBlockAccess world) { return getBlock(world).isReplaceable(world, xCoord, yCoord, zCoord); } /** * Gets a bounding box that contains the area this Coord4D would take up in a world. * @return this Coord4D's bounding box */ public AxisAlignedBB getBoundingBox() { return AxisAlignedBB.getBoundingBox(xCoord, yCoord, zCoord, xCoord+1, yCoord+1, zCoord+1); } @Override public Coord4D clone() { return new Coord4D(xCoord, yCoord, zCoord, dimensionId); } @Override public String toString() { return "[Coord4D: " + xCoord + ", " + yCoord + ", " + zCoord + ", dim=" + dimensionId + "]"; } @Override public boolean equals(Object obj) { return obj instanceof Coord4D && ((Coord4D)obj).xCoord == xCoord && ((Coord4D)obj).yCoord == yCoord && ((Coord4D)obj).zCoord == zCoord && ((Coord4D)obj).dimensionId == dimensionId; } @Override public int hashCode() { int code = 1; code = 31 * code + xCoord; code = 31 * code + yCoord; code = 31 * code + zCoord; code = 31 * code + dimensionId; return code; } }