Multiverse-Core/src/main/java/com/onarandombox/MultiverseCore/utils/SimpleBlockSafety.java

269 lines
8.6 KiB
Java

/******************************************************************************
* Multiverse 2 Copyright (c) the Multiverse Team 2011. *
* Multiverse 2 is licensed under the BSD License. *
* For more information please check the README.md file included *
* with this project. *
******************************************************************************/
package com.onarandombox.MultiverseCore.utils;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.Core;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Bed;
import org.bukkit.entity.Minecart;
import org.bukkit.entity.Vehicle;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Set;
/**
* The default-implementation of {@link BlockSafety}.
*/
public class SimpleBlockSafety implements BlockSafety {
private final Core plugin;
private static final Set<BlockFace> AROUND_BLOCK = EnumSet.noneOf(BlockFace.class);
static {
AROUND_BLOCK.add(BlockFace.NORTH);
AROUND_BLOCK.add(BlockFace.NORTH_EAST);
AROUND_BLOCK.add(BlockFace.EAST);
AROUND_BLOCK.add(BlockFace.SOUTH_EAST);
AROUND_BLOCK.add(BlockFace.SOUTH);
AROUND_BLOCK.add(BlockFace.SOUTH_WEST);
AROUND_BLOCK.add(BlockFace.WEST);
AROUND_BLOCK.add(BlockFace.NORTH_WEST);
}
public SimpleBlockSafety(Core plugin) {
this.plugin = plugin;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isBlockAboveAir(Location l) {
Location downOne = l.clone();
downOne.setY(downOne.getY() - 1);
return (downOne.getBlock().getType() == MVMaterials.AIR);
}
/**
* {@inheritDoc}
*/
@Override
public boolean playerCanSpawnHereSafely(World world, double x, double y, double z) {
Location l = new Location(world, x, y, z);
return playerCanSpawnHereSafely(l);
}
/**
* {@inheritDoc}
*/
@Override
public boolean playerCanSpawnHereSafely(Location l) {
if (l == null) {
// Can't safely spawn at a null location!
return false;
}
World world = l.getWorld();
Location actual = l.clone();
Location upOne = l.clone();
Location downOne = l.clone();
upOne.setY(upOne.getY() + 1);
downOne.setY(downOne.getY() - 1);
if (isSolidBlock(world.getBlockAt(actual).getType())
|| isSolidBlock(upOne.getBlock().getType())) {
Logging.finer("Error Here (Actual)? (%s)[%s]", actual.getBlock().getType(),
isSolidBlock(actual.getBlock().getType()));
Logging.finer("Error Here (upOne)? (%s)[%s]", upOne.getBlock().getType(),
isSolidBlock(upOne.getBlock().getType()));
return false;
}
if (downOne.getBlock().getType() == MVMaterials.LAVA) {
Logging.finer("Error Here (downOne)? (%s)[%s]", downOne.getBlock().getType(), isSolidBlock(downOne.getBlock().getType()));
return false;
}
if (downOne.getBlock().getType() == MVMaterials.FIRE) {
Logging.finer("There's fire below! (%s)[%s]", actual.getBlock().getType(), isSolidBlock(actual.getBlock().getType()));
return false;
}
if (isBlockAboveAir(actual)) {
Logging.finer("Is block above air [%s]", isBlockAboveAir(actual));
Logging.finer("Has 2 blocks of water below [%s]", this.hasTwoBlocksofWaterBelow(actual));
return this.hasTwoBlocksofWaterBelow(actual);
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public Location getSafeBedSpawn(Location l) {
// The passed location, may be null (if the bed is invalid)
if (l == null) {
return null;
}
final Location trySpawn = this.getSafeSpawnAroundABlock(l);
if (trySpawn != null) {
return trySpawn;
}
Location otherBlock = this.findOtherBedPiece(l);
if (otherBlock == null) {
return null;
}
// Now we have 2 locations, check around each, if the type is bed, skip it.
return this.getSafeSpawnAroundABlock(otherBlock);
}
/**
* Find a safe spawn around a location. (N,S,E,W,NE,NW,SE,SW)
* @param l Location to check around
* @return A safe location, or none if it wasn't found.
*/
private Location getSafeSpawnAroundABlock(Location l) {
Iterator<BlockFace> checkblock = AROUND_BLOCK.iterator();
while (checkblock.hasNext()) {
final BlockFace face = checkblock.next();
if (this.playerCanSpawnHereSafely(l.getBlock().getRelative(face).getLocation())) {
// Don't forget to center the player.
return l.getBlock().getRelative(face).getLocation().add(.5, 0, .5);
}
}
return null;
}
/**
* Find the other bed block.
* @param checkLoc The location to check for the other piece at
* @return The location of the other bed piece, or null if it was a jacked up bed.
*/
private Location findOtherBedPiece(Location checkLoc) {
BlockData data = checkLoc.getBlock().getBlockData();
if (!(data instanceof Bed)) {
return null;
}
Bed b = (Bed) data;
if (b.getPart() == Bed.Part.HEAD) {
return checkLoc.getBlock().getRelative(b.getFacing().getOppositeFace()).getLocation();
}
// We shouldn't ever be looking at the foot, but here's the code for it.
return checkLoc.getBlock().getRelative(b.getFacing()).getLocation();
}
/**
* {@inheritDoc}
*/
@Override
public Location getTopBlock(Location l) {
Location check = l.clone();
check.setY(127); // SUPPRESS CHECKSTYLE: MagicNumberCheck
while (check.getY() > 0) {
if (this.playerCanSpawnHereSafely(check)) {
return check;
}
check.setY(check.getY() - 1);
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public Location getBottomBlock(Location l) {
Location check = l.clone();
check.setY(0);
while (check.getY() < 127) { // SUPPRESS CHECKSTYLE: MagicNumberCheck
if (this.playerCanSpawnHereSafely(check)) {
return check;
}
check.setY(check.getY() + 1);
}
return null;
}
/*
* If someone has a better way of this... Please either tell us, or submit a pull request!
*/
public static boolean isSolidBlock(Material type) {
return type.isSolid();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEntitiyOnTrack(Location l) {
Material currentBlock = l.getBlock().getType();
return (currentBlock == MVMaterials.POWERED_RAIL
|| currentBlock == MVMaterials.DETECTOR_RAIL
|| currentBlock == MVMaterials.RAIL
|| currentBlock == MVMaterials.ACTIVATOR_RAIL);
}
/**
* Checks recursively below a {@link Location} for 2 blocks of water.
*
* @param l The {@link Location}
* @return Whether there are 2 blocks of water
*/
private boolean hasTwoBlocksofWaterBelow(Location l) {
if (l.getBlockY() < 0) {
return false;
}
Location oneBelow = l.clone();
oneBelow.subtract(0, 1, 0);
if (oneBelow.getBlock().getType() == MVMaterials.WATER) {
Location twoBelow = oneBelow.clone();
twoBelow.subtract(0, 1, 0);
return (oneBelow.getBlock().getType() == MVMaterials.WATER);
}
if (oneBelow.getBlock().getType() != MVMaterials.AIR) {
return false;
}
return hasTwoBlocksofWaterBelow(oneBelow);
}
/**
* {@inheritDoc}
*/
@Override
public boolean canSpawnCartSafely(Minecart cart) {
if (this.isBlockAboveAir(cart.getLocation())) {
return true;
}
if (this.isEntitiyOnTrack(plugin.getLocationManipulation().getNextBlock(cart))) {
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean canSpawnVehicleSafely(Vehicle vehicle) {
if (this.isBlockAboveAir(vehicle.getLocation())) {
return true;
}
return false;
}
}