ChestShop-3/src/main/java/com/Acrobot/Breeze/Utils/BlockUtil.java

176 lines
6.7 KiB
Java

package com.Acrobot.Breeze.Utils;
import com.google.common.collect.ImmutableMap;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Chest;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.material.Attachable;
import org.bukkit.material.Directional;
import org.bukkit.material.MaterialData;
import org.bukkit.util.Vector;
import java.util.Map;
/**
* @author Acrobot
*/
public class BlockUtil {
/**
* Checks if the block is a sign
*
* @param block Block to check
* @return Is this block a sign?
*/
public static boolean isSign(Block block) {
return block.getType() == Material.SIGN_POST
|| block.getType() == Material.WALL_SIGN;
}
/**
* Checks if the block is a chest
*
* @param block Block to check
* @return Is this block a chest?
*/
public static boolean isChest(Block block) {
return block.getState() instanceof Chest;
}
/**
* Checks if the InventoryHolder is a chest
*
* @param holder Inventory holder to check
* @return Is this holder a chest?
*/
public static boolean isChest(InventoryHolder holder) {
return holder instanceof Chest || holder instanceof DoubleChest;
}
/**
* Gets the block to which the sign is attached
*
* @param sign Sign which is attached
* @return Block to which the sign is attached
*/
public static Block getAttachedBlock(Sign sign) {
return sign.getBlock().getRelative(((Attachable) sign.getData()).getAttachedFace());
}
/**
* Opens the holder's inventory GUI
*
* @param holder Inventory holder
* @param player Player on whose screen the GUI is going to be shown
* @return Was the opening successful?
*/
public static boolean openBlockGUI(InventoryHolder holder, Player player) {
Inventory inventory = holder.getInventory();
player.openInventory(inventory);
return true;
}
private static final BoundingBox BLOCK = new BoundingBox(new Vector(), new Vector(1, 1, 1));
private static final Map<Material, BoundingBox> BOXES = ImmutableMap.of(
Material.WALL_SIGN, new BoundingBox(new Vector(0, 0.28125, 0), new Vector(1, 0.78125, 0.125)), // Default direction is South
Material.SIGN_POST, new BoundingBox(new Vector(0.25, 0, 0.25), new Vector(0.75, 1, 0.75))
);
public static BoundingBox getBoundingBox(Block block) {
BoundingBox box = BOXES.getOrDefault(block.getType(), BLOCK);
MaterialData data = block.getState().getData();
if (data instanceof Directional) {
Directional directional = (Directional) data;
box = box.getFacing(directional.getFacing());
}
return box;
}
public static class BoundingBox {
private final Vector minimumPoint;
private final Vector maximumPoint;
BoundingBox(Vector minimumPoint, Vector maximumPoint) {
while (minimumPoint.getX() < 0 || maximumPoint.getX() < 0) {
minimumPoint.setX(1 + minimumPoint.getX());
maximumPoint.setX(1 + maximumPoint.getX());
}
while (minimumPoint.getY() < 0 || maximumPoint.getY() < 0) {
minimumPoint.setY(1 + minimumPoint.getY());
maximumPoint.setY(1 + maximumPoint.getY());
}
while (minimumPoint.getZ() < 0 || maximumPoint.getZ() < 0) {
minimumPoint.setZ(1 + minimumPoint.getZ());
maximumPoint.setZ(1 + maximumPoint.getZ());
}
this.minimumPoint = min(minimumPoint, maximumPoint);
this.maximumPoint = max(minimumPoint, maximumPoint);
}
private Vector min(Vector v1, Vector v2) {
return new Vector(Math.min(v1.getX(), v2.getX()), Math.min(v1.getY(), v2.getY()), Math.min(v1.getZ(), v2.getZ()));
}
private Vector max(Vector v1, Vector v2) {
return new Vector(Math.max(v1.getX(), v2.getX()), Math.max(v1.getY(), v2.getY()), Math.max(v1.getZ(), v2.getZ()));
}
/**
* Checks if a certain vector hits the hitbox of a block.
* Only really checks for Signs as we don't need the rest
*
* @param source The start location including the direction
* @param block The block to check
* @param distance The maximum distance from the source location to check for
* @param precision The precision of the steps of the trace
* @return Does the vector intercept the box?
*/
public boolean intercepts(Location source, Block block, double distance, double precision) {
if (source.distanceSquared(block.getLocation()) > distance * distance) {
return false;
}
Vector posMin = block.getLocation().toVector().add(minimumPoint);
Vector posMax = block.getLocation().toVector().add(maximumPoint);
Vector direction = source.getDirection();
for (double d = 0; d < distance; d += precision) {
Location check = source.clone().add(direction.clone().multiply(d));
if (check.getX() >= posMin.getX() && check.getX() < posMax.getX()
&& check.getY() >= posMin.getY() && check.getY() < posMax.getY()
&& check.getZ() >= posMin.getZ() && check.getZ() < posMax.getZ()) {
return true;
}
}
return false;
}
BoundingBox getFacing(BlockFace face) {
Vector minPoint = minimumPoint.clone();
Vector maxPoint = maximumPoint.clone();
if (face == BlockFace.NORTH || face == BlockFace.EAST || face == BlockFace.SOUTH || face == BlockFace.WEST) {
if (face.getModX() == 0) {
minPoint.setX(face.getModZ() * minimumPoint.getX());
maxPoint.setX(face.getModZ() * maximumPoint.getX());
minPoint.setZ(face.getModZ() * minimumPoint.getZ());
maxPoint.setZ(face.getModZ() * maximumPoint.getZ());
} else if (face.getModZ() == 0) {
minPoint.setX(face.getModX() * minimumPoint.getZ());
maxPoint.setX(face.getModX() * maximumPoint.getZ());
minPoint.setZ(face.getModX() * minimumPoint.getX());
maxPoint.setZ(face.getModX() * maximumPoint.getX());
}
}
return new BoundingBox(minPoint, maxPoint);
}
}
}