package com.bergerkiller.bukkit.common; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import com.bergerkiller.bukkit.common.config.ConfigurationNode; import com.bergerkiller.bukkit.common.utils.WorldUtil; /** * Contains a world name and block coordinates */ public class BlockLocation { public final int x, y, z; public final String world; /** * Initializes a new Block Location using the data in the configuration node * * @param node to use */ public BlockLocation(ConfigurationNode node) { this.world = node.get("world", "world"); this.x = node.get("x", 0); this.y = node.get("y", 0); this.z = node.get("z", 0); } /** * Initializes a new Block Location using a Block * * @param block to use */ public BlockLocation(Block block) { this(block.getWorld(), block.getX(), block.getY(), block.getZ()); } /** * Initializes a new Block Location using a Location * * @param location to use */ public BlockLocation(Location location) { this(location.getWorld(), location.getBlockX(), location.getBlockY(), location.getBlockZ()); } /** * Initializes a new Block Location using a world and x/y/z coordinate * * @param world to use the name of * @param x - coordinate * @param y - coordinate * @param z - coordinate */ public BlockLocation(World world, final int x, final int y, final int z) { this(world == null ? null : world.getName(), x, y, z); } /** * Initializes a new Block Location using a world and x/y/z coordinate * * @param world name to use * @param x - coordinate * @param y - coordinate * @param z - coordinate */ public BlockLocation(final String world, final int x, final int y, final int z) { this.world = world; this.x = x; this.y = y; this.z = z; } /** * Tries to parse a Block Location from a String value * * @param value to parse * @return Block Location, or null if it could not be parsed */ public static BlockLocation parseLocation(String value) { if (value.length() < 10) { return null; } try { StringBuilder world = new StringBuilder(value.length() - 9); String[] bits = value.split("_"); int z = Integer.parseInt(bits[bits.length - 1]); int y = Integer.parseInt(bits[bits.length - 2]); int x = Integer.parseInt(bits[bits.length - 3]); // get world int worldbitcount = bits.length - 3; for (int i = 0; i < worldbitcount; i++) { world.append(bits[i]); if (i != worldbitcount - 1) world.append('_'); } return new BlockLocation(world.toString(), x, y, z); } catch (Throwable t) { return null; } } /** * Gets the chunk this Block Location is in<br> * <b>Will load the chunk if it isn't loaded</b> * * @return the Chunk, or null if the world this location is in is not loaded */ public Chunk getChunk() { World world = this.getWorld(); if (world == null) { return null; } return world.getChunkAt(this.x >> 4, this.z >> 4); } /** * Gets the Location from this Block Location * * @return the Location of the middle of the Block, or null if the world is not loaded */ public Location getLocation() { World world = this.getWorld(); return world == null ? null : new Location(world, this.x + 0.5, this.y + 0.5, this.z + 0.5); } /** * Gets the Block this Location is in * * @return the Block, or null if the world this location is in is not loaded */ public Block getBlock() { World world = this.getWorld(); return world == null ? null : world.getBlockAt(this.x, this.y, this.z); } /** * Gets the World this Location is in * * @return the World, or null if it is not loaded */ public World getWorld() { return Bukkit.getServer().getWorld(this.world); } /** * Checks if this location is loaded * * @return True if it is loaded, False if not */ public boolean isLoaded() { return WorldUtil.isLoaded(this.getWorld(), this.x, this.y, this.z); } /** * Checks if this Location is in the World specified * * @param world to check * @return True if it is in the world, False if not */ public boolean isIn(World world) { if (this.world == null && world == null) { return true; } else if (this.world == null || world == null) { return false; } else { return this.world.equals(world.getName()); } } /** * Checks if this Block Location is within the boundaries of a chunk * * @param chunk to check * @return True if within, False if not */ public boolean isIn(Chunk chunk) { if (chunk != null && this.isIn(chunk.getWorld())) { return (this.x >> 4) == chunk.getX() && (this.z >> 4) == chunk.getZ(); } return false; } /** * Checks if this Block Location is within the boundaries of a cuboid * * @param point1 of the Cuboid * @param point2 of the Cuboid * @return True if within, False if not */ public boolean isIn(BlockLocation point1, BlockLocation point2) { if (point1 != null && point2 != null && point1.world.equals(point2.world) && point1.world.equals(this.world)) { int value; value = Math.min(point1.x, point2.x); if (this.x < value || this.x > (value + Math.abs(point1.x - point2.x))) { return false; } value = Math.min(point1.y, point2.y); if (this.y < value || this.y > (value + Math.abs(point1.y - point2.y))) { return false; } value = Math.min(point1.z, point2.z); if (this.z < value || this.z > (value + Math.abs(point1.z - point2.z))) { return false; } return true; } return false; } @Override public String toString() { return this.world + "_" + this.x + "_" + this.y + "_" + this.z; } @Override public boolean equals(Object object) { if (object == this) { return true; } else if (object instanceof BlockLocation) { BlockLocation bloc = (BlockLocation) object; return bloc.x == this.x && bloc.y == this.y && bloc.z == this.z && bloc.world.equals(this.world); } else { return false; } } @Override public int hashCode() { int hash = 3; hash = 53 * hash + this.world.hashCode(); hash = 53 * hash + (this.x ^ (this.x >> 16)); hash = 53 * hash + (this.y ^ (this.y >> 16)); hash = 53 * hash + (this.z ^ (this.z >> 16)); return hash; } public void save(ConfigurationNode node) { node.set("world", this.world); node.set("x", this.x); node.set("y", this.y); node.set("z", this.z); } }