Package com.bergerkiller.bukkit.common.utils

Source Code of com.bergerkiller.bukkit.common.utils.BlockUtil

package com.bergerkiller.bukkit.common.utils;

import java.util.ArrayList;
import java.util.Collection;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.Sign;
import org.bukkit.event.block.BlockCanBuildEvent;
import org.bukkit.event.block.BlockRedstoneEvent;
import org.bukkit.material.Attachable;
import org.bukkit.material.Lever;
import org.bukkit.material.MaterialData;
import org.bukkit.material.PoweredRail;
import org.bukkit.material.Rails;
import org.bukkit.material.Directional;

import com.bergerkiller.bukkit.common.bases.IntVector3;
import com.bergerkiller.bukkit.common.conversion.Conversion;
import com.bergerkiller.bukkit.common.internal.CommonNMS;
import com.bergerkiller.bukkit.common.protocol.CommonPacket;
import com.bergerkiller.bukkit.common.reflection.SafeField;
import com.bergerkiller.bukkit.common.reflection.classes.BlockStateRef;
import com.bergerkiller.bukkit.common.reflection.classes.TileEntityRef;
import com.bergerkiller.bukkit.common.reflection.classes.WorldRef;

/**
* Multiple Block utilities you can use to manipulate blocks and get block information
*/
public class BlockUtil extends MaterialUtil {

  static {
    // Temporary hack because Bukkit is updating far too slowly
    try {
      if (Material.ACTIVATOR_RAIL.getData() == MaterialData.class) {
        SafeField.set(Material.ACTIVATOR_RAIL, "ctor", PoweredRail.class.getConstructor(int.class, byte.class));
      }
    } catch (Throwable t) {
      t.printStackTrace();
    }
  }

  /**
   * Performs an event asking other plugins whether a block can change to a different Material
   *
   * @param block to check
   * @param type that the block is about to be set to (built)
   * @return True if permitted, False if not
   */
  public static boolean canBuildBlock(org.bukkit.block.Block block, Material type) {
    return canBuildBlock(block, type, true);
  }

  /**
   * Performs an event asking other plugins whether a block can change to a different Material
   *
   * @param block to check
   * @param type that the block is about to be set to (built)
   * @param isBuildable - Initial allow state
   * @return True if permitted, False if not
   */
  @SuppressWarnings("deprecation")
  public static boolean canBuildBlock(org.bukkit.block.Block block, Material type, boolean isBuildable) {
    return CommonUtil.callEvent(new BlockCanBuildEvent(block, type.getId(), true)).isBuildable();
  }

  /**
   * Sets the Block type and data at once, then performs physics
   *
   * @param block to set the type and data of
   * @param type to set to
   * @param data to set to
   */
  public static void setTypeAndData(org.bukkit.block.Block block, Material type, MaterialData data) {
    setTypeAndData(block, type, data, true);
  }

  /**
   * Sets the Block type and data at once
   *
   * @param block to set the type and data of
   * @param type to set to
   * @param data to set to
   * @param update - whether to perform physics afterwards
   */
  @SuppressWarnings("deprecation")
  public static void setTypeAndData(org.bukkit.block.Block block, Material type, MaterialData data, boolean update) {
    block.setTypeIdAndData(type.getId(), data.getData(), update);
  }

  /**
   * Sets the Block type and data at once, then performs physics
   *
   * @param block to set the type and data of
   * @param type to set to
   * @param data to set to
   */
  public static void setTypeAndRawData(org.bukkit.block.Block block, Material type, int data) {
    setTypeAndRawData(block, type, data, true);
  }

  /**
   * Sets the Block type and data at once
   *
   * @param block to set the type and data of
   * @param type to set to
   * @param data to set to
   * @param update - whether to perform physics afterwards
   */
  @SuppressWarnings("deprecation")
  public static void setTypeAndRawData(org.bukkit.block.Block block, Material type, int data, boolean update) {
    block.setTypeIdAndData(type.getId(), (byte) data, update);
  }

  /**
   * Sets the Material Data for a Block
   *
   * @param block to set it for
   * @param materialData to set to
   */
  @SuppressWarnings("deprecation")
  public static void setData(org.bukkit.block.Block block, MaterialData materialData) {
    block.setData(materialData.getData());
  }

  /**
   * Sets the Material Data for a Block
   *
   * @param block to set it for
   * @param materialData to set to
   * @param doPhysics - True to perform physics, False for 'silent'
   */
  @SuppressWarnings("deprecation")
  public static void setData(org.bukkit.block.Block block, MaterialData materialData, boolean doPhysics) {
    block.setData(materialData.getData(), doPhysics);
  }

  /**
   * Directly obtains the Material Data from the block<br>
   * This alternative does not create a Block State and is preferred if you only need material data
   */
  public static MaterialData getData(org.bukkit.block.Block block) {
    return getData(MaterialUtil.getTypeId(block), MaterialUtil.getRawData(block));
  }

  /**
   * Gets the Material data for the block specified and attempts to cast it
   *
   * @param block to get the Material data for
   * @param type to cast to
   * @return The cast material data, or null if there was no data or if casting failed
   */
  public static <T> T getData(org.bukkit.block.Block block, Class<T> type) {
    return CommonUtil.tryCast(getData(block), type);
  }

  /**
   * Calculates the so-called 'Manhatten Distance' between two locations<br>
   * This is the distance between two points without going diagonally
   *
   * @param b1 location
   * @param b2 location
   * @param checkY state, True to include the y distance, False to exclude it
   * @return The manhattan distance
   */
  public static int getManhattanDistance(Location b1, Location b2, boolean checkY) {
    int d = Math.abs(b1.getBlockX() - b2.getBlockX());
    d += Math.abs(b1.getBlockZ() - b2.getBlockZ());
    if (checkY)
      d += Math.abs(b1.getBlockY() - b2.getBlockY());
    return d;
  }

  /**
   * Calculates the so-called 'Manhatten Distance' between two blocks<br>
   * This is the distance between two points without going diagonally
   *
   * @param b1 block
   * @param b2 block
   * @param checkY state, True to include the y distance, False to exclude it
   * @return The Manhattan distance
   */
  public static int getManhattanDistance(org.bukkit.block.Block b1, org.bukkit.block.Block b2, boolean checkY) {
    int d = Math.abs(b1.getX() - b2.getX());
    d += Math.abs(b1.getZ() - b2.getZ());
    if (checkY)
      d += Math.abs(b1.getY() - b2.getY());
    return d;
  }

  /**
   * Checks if two Blocks are equal
   *
   * @param block1 to evaluate
   * @param block2 to evaluate
   * @return True if the blocks are the same, False if not
   */
  public static boolean equals(org.bukkit.block.Block block1, org.bukkit.block.Block block2) {
    if (block1 == null || block2 == null)
      return false;
    if (block1 == block2)
      return true;
    return block1.getX() == block2.getX() && block1.getZ() == block2.getZ() && block1.getY() == block2.getY() && block1.getWorld() == block2.getWorld();
  }

  /**
   * Gets all the Blocks relative to a main block using multiple Block Faces
   *
   * @param main block
   * @param faces to get the blocks relative to the main of
   * @return An array of relative blocks to the main based on the input faces
   */
  public static org.bukkit.block.Block[] getRelative(org.bukkit.block.Block main, BlockFace... faces) {
    if (main == null) {
      return new org.bukkit.block.Block[0];
    }
    org.bukkit.block.Block[] rval = new org.bukkit.block.Block[faces.length];
    for (int i = 0; i < rval.length; i++) {
      rval[i] = main.getRelative(faces[i]);
    }
    return rval;
  }

  /**
   * Gets the Block at the coordinates specified
   *
   * @param world of the block
   * @param at coordinates
   * @return Block at the coordinates in the world
   */
  public static org.bukkit.block.Block getBlock(org.bukkit.World world, IntVector3 at) {
    return world.getBlockAt(at.x, at.y, at.z);
  }

  /**
   * Gets the face an attachable block is attached to<br>
   * Returns DOWN if the block is not attachable
   *
   * @param attachable block
   * @return Attached face
   */
  public static BlockFace getAttachedFace(org.bukkit.block.Block attachable) {
    Attachable data = getData(attachable, Attachable.class);
    return data == null ? BlockFace.DOWN : data.getAttachedFace();
  }

  /**
   * Gets the Block an attachable block is attached to
   *
   * @param attachable block
   * @return Block the attachable is attached to
   */
  public static org.bukkit.block.Block getAttachedBlock(org.bukkit.block.Block attachable) {
    return attachable.getRelative(getAttachedFace(attachable));
  }

  /**
   * Gets the facing direction of a Directional block
   *
   * @param directional block
   * @return facing direction
   */
  public static BlockFace getFacing(org.bukkit.block.Block directional) {
    Directional data = getData(directional, Directional.class);
    return data == null ? BlockFace.NORTH : data.getFacing();
  }

  /**
   * Sets the facing direction of a Directional block
   *
   * @param block to set
   * @param facing direction to set to
   */
  public static void setFacing(org.bukkit.block.Block block, BlockFace facing) {
    MaterialData data = getData(block);
    if (data != null && data instanceof Directional) {
      ((Directional) data).setFacingDirection(facing);
      setData(block, data, true);
    }
  }

  /**
   * Sets the toggled state for all levers attached to a certain block
   *
   * @param block center
   * @param down state to set to
   */
  public static void setLeversAroundBlock(org.bukkit.block.Block block, boolean down) {
    org.bukkit.block.Block b;
    for (BlockFace dir : FaceUtil.ATTACHEDFACES) {
      // Attached lever at this direction?
      if (isType(b = block.getRelative(dir), Material.LEVER) && getAttachedFace(b) == dir.getOppositeFace()) {
        setLever(b, down);
      }
    }
  }

  /**
   * Checks if a given lever block is in the down state<br>
   * The block type is not checked.
   *
   * @param lever block
   * @return True if the lever is down, False if not
   */
  public static boolean isLeverDown(org.bukkit.block.Block lever) {
    int dat = getRawData(lever);
    return dat == (dat | 0x8);
  }

  /**
   * Sets the toggled state of a single lever<br>
   * <b>No Lever type check is performed</b>
   *
   * @param lever block
   * @param down state to set to
   */
  public static void setLever(org.bukkit.block.Block lever, boolean down) {
    int data = getRawData(lever);
    Lever newMaterialData = (Lever) getData(Material.LEVER, data);
    newMaterialData.setPowered(down);
    if (getRawData(newMaterialData) != data) {
      // CraftBukkit start - Redstone event for lever
      int old = !down ? 1 : 0;
      int current = down ? 1 : 0;
      BlockRedstoneEvent eventRedstone = new BlockRedstoneEvent(lever, old, current);
      CommonUtil.callEvent(eventRedstone);
      if ((eventRedstone.getNewCurrent() > 0) != down) {
        return;
      }
      // CraftBukkit end
      setData(lever, newMaterialData, true);
      applyPhysics(getAttachedBlock(lever), Material.LEVER);
    }
  }

  /**
   * Performs Physics at the block specified
   *
   * @param block to apply physics to
   * @param callertypeid of the Material, the source of these physics (use 0 if there is no caller)
   */
  @Deprecated
  public static void applyPhysics(org.bukkit.block.Block block, int callertypeid) {
    applyPhysics(block, getType(callertypeid));
  }

  /**
   * Performs Physics at the block specified
   *
   * @param block to apply physics to
   * @param callerType Material, the source of these physics (use Air if there is no caller)
   */
  public static void applyPhysics(org.bukkit.block.Block block, Material callerType) {
    CommonNMS.getNative(block.getWorld()).applyPhysics(block.getX(), block.getY(), block.getZ(), CommonNMS.getBlock(callerType));
  }

  /**
   * Obtains a new packet that can be used to update tile entity information to nearby players<br>
   * Returns null if none are needed or supported by the tile entity
   *
   * @param tileEntity to get the update packet for
   * @return update packet
   */
  public static CommonPacket getUpdatePacket(Object tileEntity) {
    return TileEntityRef.getUpdatePacket(tileEntity);
  }

  /**
   * Sets the alignment of Rails
   * Note that this only supports the rails that can curve.
   *
   * @param rails to set the alignment for
   * @param from direction
   * @param to direction
   */
  public static void setRails(org.bukkit.block.Block rails, BlockFace from, BlockFace to) {
    setRails(rails, FaceUtil.combine(from, to).getOppositeFace());
  }

  /**
   * Sets the alignment of Rails.
   * Note that this only supports the rails that can curve.
   *
   * @param rails to set the alignment for
   * @param direction alignment
   */
  public static void setRails(org.bukkit.block.Block rails, BlockFace direction) {
    Material type = rails.getType();
    if (type == Material.RAILS) {
      int olddata = getRawData(rails);
      Rails r = (Rails) MaterialUtil.getData(type, olddata);
      r.setDirection(FaceUtil.toRailsDirection(direction), r.isOnSlope());
      // If changed, update the data
      if (MaterialUtil.getRawData(r) != olddata) {
        setData(rails, r);
      }
    }
  }

  /**
   * Gets the state of a block, with additional safety measures taken
   *
   * @param block to get the state for
   * @return the Block State
   */
  public static BlockState getState(org.bukkit.block.Block block) {
    return BlockStateRef.toBlockState(block);
  }

  /**
   * Gets the State of a block, cast to a certain type
   *
   * @param block to get the state for
   * @param type to cast to
   * @return The block state cast to the type, or null if casting is not possible
   */
  public static <T extends BlockState> T getState(org.bukkit.block.Block block, Class<T> type) {
    return CommonUtil.tryCast(getState(block), type);
  }

  public static Rails getRails(org.bukkit.block.Block railsblock) {
    return getData(railsblock, Rails.class);
  }

  public static Sign getSign(org.bukkit.block.Block signblock) {
    return getState(signblock, Sign.class);
  }

  public static Chest getChest(org.bukkit.block.Block chestblock) {
    return getState(chestblock, Chest.class);
  }

  public static Collection<BlockState> getBlockStates(org.bukkit.block.Block middle) {
    return getBlockStates(middle, 0, 0, 0);
  }

  public static Collection<BlockState> getBlockStates(org.bukkit.block.Block middle, int radius) {
    return getBlockStates(middle, radius, radius, radius);
  }

  public static Collection<BlockState> getBlockStates(org.bukkit.block.Block middle, int radiusX, int radiusY, int radiusZ) {
    return getBlockStates(middle.getWorld(), middle.getX(), middle.getY(), middle.getZ(), radiusX, radiusY, radiusZ);
  }

  private static final ArrayList<BlockState> blockStateBuff = new ArrayList<BlockState>();

  public static Collection<BlockState> getBlockStates(org.bukkit.World world, int x, int y, int z, int radiusX, int radiusY, int radiusZ) {
    try {
      if (radiusX == 0 && radiusY == 0 && radiusZ == 0) {
        // simplified coding instead
        offerTile(world, x, y, z);
      } else {
        // loop through tile entity list
        int xMin = x - radiusX;
        int yMin = y - radiusY;
        int zMin = z - radiusZ;
        int xMax = x + radiusX;
        int yMax = y + radiusY;
        int zMax = z + radiusZ;
        int tx, ty, tz;
        for (Object tile : WorldRef.tileEntityList.get(Conversion.toWorldHandle.convert(world))) {
          tx = TileEntityRef.x.get(tile);
          ty = TileEntityRef.y.get(tile);
          tz = TileEntityRef.z.get(tile);
          if (tx < xMin || ty < yMin || tz < zMin || tx > xMax || ty > yMax || tz > zMax) {
            continue;
          }
          // Get again - security against ghost tiles
          offerTile(world, tx, ty, tz);
        }
      }
      return new ArrayList<BlockState>(blockStateBuff);
    } finally {
      blockStateBuff.clear();
    }
  }

  private static void offerTile(World world, int x, int y, int z) {
    BlockState state = Conversion.toBlockState.convert(TileEntityRef.getFromWorld(world, x, y, z));
    if (state != null) {
      blockStateBuff.add(state);
    }
  }
}
TOP

Related Classes of com.bergerkiller.bukkit.common.utils.BlockUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.