2013-06-08 23:31:19 +02:00
|
|
|
package com.earth2me.essentials.utils;
|
|
|
|
|
2018-01-19 02:52:44 +01:00
|
|
|
import com.earth2me.essentials.IEssentials;
|
2019-01-11 12:10:46 +01:00
|
|
|
import io.papermc.lib.PaperLib;
|
2013-08-11 23:42:29 +02:00
|
|
|
import net.ess3.api.IUser;
|
|
|
|
import org.bukkit.GameMode;
|
2013-06-08 23:31:19 +02:00
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.Material;
|
|
|
|
import org.bukkit.World;
|
|
|
|
import org.bukkit.block.Block;
|
|
|
|
import org.bukkit.entity.LivingEntity;
|
|
|
|
import org.bukkit.inventory.ItemStack;
|
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
import static com.earth2me.essentials.I18n.tl;
|
|
|
|
|
|
|
|
|
|
|
|
public class LocationUtil {
|
|
|
|
// The player can stand inside these materials
|
2019-01-11 12:10:46 +01:00
|
|
|
private static final Set<Material> HOLLOW_MATERIALS = new HashSet<>();
|
2015-09-28 04:25:46 +02:00
|
|
|
private static final Set<Material> TRANSPARENT_MATERIALS = new HashSet<>();
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
static {
|
2015-09-28 04:25:46 +02:00
|
|
|
// Materials from Material.isTransparent()
|
2018-01-19 02:52:44 +01:00
|
|
|
for (Material mat : Material.values()) {
|
|
|
|
if (mat.isTransparent()) {
|
|
|
|
HOLLOW_MATERIALS.add(mat);
|
|
|
|
}
|
|
|
|
}
|
2015-09-28 04:25:46 +02:00
|
|
|
|
|
|
|
TRANSPARENT_MATERIALS.addAll(HOLLOW_MATERIALS);
|
|
|
|
TRANSPARENT_MATERIALS.add(Material.WATER);
|
2018-07-29 18:39:32 +02:00
|
|
|
try {
|
|
|
|
TRANSPARENT_MATERIALS.add(Material.valueOf("FLOWING_WATER"));
|
2019-01-11 12:10:46 +01:00
|
|
|
} catch (Exception ignored) {} // 1.13 WATER uses Levelled
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static final int RADIUS = 3;
|
|
|
|
public static final Vector3D[] VOLUME;
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static ItemStack convertBlockToItem(final Block block) {
|
2018-01-19 02:52:44 +01:00
|
|
|
return new ItemStack(block.getType(), 1);
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2013-08-11 23:42:29 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static class Vector3D {
|
|
|
|
public int x;
|
|
|
|
public int y;
|
|
|
|
public int z;
|
2013-11-15 01:22:10 +01:00
|
|
|
|
2019-01-11 12:10:46 +01:00
|
|
|
Vector3D(int x, int y, int z) {
|
2015-04-15 06:06:16 +02:00
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
|
|
|
this.z = z;
|
|
|
|
}
|
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
static {
|
2019-01-11 12:10:46 +01:00
|
|
|
List<Vector3D> pos = new ArrayList<>();
|
2015-04-15 06:06:16 +02:00
|
|
|
for (int x = -RADIUS; x <= RADIUS; x++) {
|
|
|
|
for (int y = -RADIUS; y <= RADIUS; y++) {
|
|
|
|
for (int z = -RADIUS; z <= RADIUS; z++) {
|
|
|
|
pos.add(new Vector3D(x, y, z));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-11 12:10:46 +01:00
|
|
|
pos.sort(Comparator.comparingInt(a -> (a.x * a.x + a.y * a.y + a.z * a.z)));
|
2015-04-15 06:06:16 +02:00
|
|
|
VOLUME = pos.toArray(new Vector3D[0]);
|
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static Location getTarget(final LivingEntity entity) throws Exception {
|
2018-01-19 02:52:44 +01:00
|
|
|
Block block = null;
|
2015-11-15 15:59:19 +01:00
|
|
|
try {
|
|
|
|
block = entity.getTargetBlock(TRANSPARENT_MATERIALS, 300);
|
|
|
|
} catch (NoSuchMethodError e) {
|
2018-01-19 02:52:44 +01:00
|
|
|
// failing now :(
|
2015-11-15 15:59:19 +01:00
|
|
|
}
|
2015-04-15 06:06:16 +02:00
|
|
|
if (block == null) {
|
|
|
|
throw new Exception("Not targeting a block");
|
|
|
|
}
|
|
|
|
return block.getLocation();
|
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2019-01-11 12:10:46 +01:00
|
|
|
private static boolean isBlockAboveAir(final World world, final int x, final int y, final int z) {
|
|
|
|
PaperLib.getChunkAtAsync(world, x, z); // Get the chunk first so it can be loaded async
|
2018-01-19 02:52:44 +01:00
|
|
|
return y > world.getMaxHeight() || HOLLOW_MATERIALS.contains(world.getBlockAt(x, y - 1, z).getType());
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static boolean isBlockUnsafeForUser(final IUser user, final World world, final int x, final int y, final int z) {
|
2018-06-18 23:38:54 +02:00
|
|
|
if (user.getBase().isOnline() && world.equals(user.getBase().getWorld()) && (user.getBase().getGameMode() == GameMode.CREATIVE || user.getBase().getGameMode() == GameMode.SPECTATOR || user.isGodModeEnabled()) && user.getBase().getAllowFlight()) {
|
2015-04-15 06:06:16 +02:00
|
|
|
return false;
|
|
|
|
}
|
2014-07-12 17:33:50 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
if (isBlockDamaging(world, x, y, z)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return isBlockAboveAir(world, x, y, z);
|
|
|
|
}
|
2014-07-12 17:33:50 +02:00
|
|
|
|
2019-01-11 12:10:46 +01:00
|
|
|
private static boolean isBlockUnsafe(final World world, final int x, final int y, final int z) {
|
2018-01-19 02:52:44 +01:00
|
|
|
return isBlockDamaging(world, x, y, z) || isBlockAboveAir(world, x, y, z);
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static boolean isBlockDamaging(final World world, final int x, final int y, final int z) {
|
2019-01-11 12:10:46 +01:00
|
|
|
PaperLib.getChunkAtAsync(world, x, z); // Get the chunk first so it can be loaded async
|
2015-04-15 06:06:16 +02:00
|
|
|
final Block below = world.getBlockAt(x, y - 1, z);
|
2018-01-19 02:52:44 +01:00
|
|
|
|
|
|
|
switch (below.getType()) {
|
|
|
|
case LAVA:
|
|
|
|
case FIRE:
|
|
|
|
return true;
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
2018-09-01 11:35:08 +02:00
|
|
|
|
|
|
|
if (MaterialUtil.isBed(below.getType())) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-29 18:39:32 +02:00
|
|
|
try {
|
|
|
|
if (below.getType() == Material.valueOf("FLOWING_LAVA")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} catch (Exception ignored) { // 1.13 LAVA uses Levelled
|
|
|
|
}
|
2018-09-01 11:35:08 +02:00
|
|
|
|
|
|
|
Material PORTAL = EnumUtil.getMaterial("NETHER_PORTAL", "PORTAL");
|
|
|
|
|
2018-07-29 18:39:32 +02:00
|
|
|
if (world.getBlockAt(x, y, z).getType() == PORTAL) {
|
2017-01-20 16:17:00 +01:00
|
|
|
return true;
|
|
|
|
}
|
2018-01-19 02:52:44 +01:00
|
|
|
|
2015-09-28 04:25:46 +02:00
|
|
|
return (!HOLLOW_MATERIALS.contains(world.getBlockAt(x, y, z).getType())) || (!HOLLOW_MATERIALS.contains(world.getBlockAt(x, y + 1, z).getType()));
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
2014-02-23 18:41:25 +01:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
// Not needed if using getSafeDestination(loc)
|
|
|
|
public static Location getRoundedDestination(final Location loc) {
|
|
|
|
final World world = loc.getWorld();
|
|
|
|
int x = loc.getBlockX();
|
|
|
|
int y = (int) Math.round(loc.getY());
|
|
|
|
int z = loc.getBlockZ();
|
|
|
|
return new Location(world, x + 0.5, y, z + 0.5, loc.getYaw(), loc.getPitch());
|
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
|
2016-06-26 16:21:35 +02:00
|
|
|
/**
|
|
|
|
* @deprecated Use {@link #getSafeDestination(IEssentials, IUser, Location)}
|
|
|
|
*/
|
|
|
|
@Deprecated
|
2015-04-15 06:06:16 +02:00
|
|
|
public static Location getSafeDestination(final IUser user, final Location loc) throws Exception {
|
2016-06-26 16:21:35 +02:00
|
|
|
return getSafeDestination(null, user, loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Location getSafeDestination(final IEssentials ess, final IUser user, final Location loc) throws Exception {
|
2015-04-15 06:06:16 +02:00
|
|
|
if (user.getBase().isOnline() && loc.getWorld().equals(user.getBase().getWorld()) && (user.getBase().getGameMode() == GameMode.CREATIVE || user.isGodModeEnabled()) && user.getBase().getAllowFlight()) {
|
|
|
|
if (shouldFly(loc)) {
|
|
|
|
user.getBase().setFlying(true);
|
|
|
|
}
|
2016-06-26 16:21:35 +02:00
|
|
|
// ess can be null if old deprecated method is calling it.
|
|
|
|
if (ess == null || ess.getSettings().isTeleportToCenterLocation()) {
|
|
|
|
return getRoundedDestination(loc);
|
|
|
|
} else {
|
|
|
|
return loc;
|
|
|
|
}
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
|
|
|
return getSafeDestination(loc);
|
|
|
|
}
|
2014-02-23 18:41:25 +01:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static Location getSafeDestination(final Location loc) throws Exception {
|
|
|
|
if (loc == null || loc.getWorld() == null) {
|
|
|
|
throw new Exception(tl("destinationNotSet"));
|
|
|
|
}
|
|
|
|
final World world = loc.getWorld();
|
|
|
|
int x = loc.getBlockX();
|
|
|
|
int y = (int) Math.round(loc.getY());
|
|
|
|
int z = loc.getBlockZ();
|
|
|
|
final int origX = x;
|
|
|
|
final int origY = y;
|
|
|
|
final int origZ = z;
|
|
|
|
while (isBlockAboveAir(world, x, y, z)) {
|
|
|
|
y -= 1;
|
|
|
|
if (y < 0) {
|
|
|
|
y = origY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isBlockUnsafe(world, x, y, z)) {
|
|
|
|
x = Math.round(loc.getX()) == origX ? x - 1 : x + 1;
|
|
|
|
z = Math.round(loc.getZ()) == origZ ? z - 1 : z + 1;
|
|
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
while (isBlockUnsafe(world, x, y, z)) {
|
|
|
|
i++;
|
|
|
|
if (i >= VOLUME.length) {
|
|
|
|
x = origX;
|
|
|
|
y = origY + RADIUS;
|
|
|
|
z = origZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
x = origX + VOLUME[i].x;
|
|
|
|
y = origY + VOLUME[i].y;
|
|
|
|
z = origZ + VOLUME[i].z;
|
|
|
|
}
|
|
|
|
while (isBlockUnsafe(world, x, y, z)) {
|
|
|
|
y += 1;
|
|
|
|
if (y >= world.getMaxHeight()) {
|
|
|
|
x += 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (isBlockUnsafe(world, x, y, z)) {
|
|
|
|
y -= 1;
|
|
|
|
if (y <= 1) {
|
|
|
|
x += 1;
|
|
|
|
y = world.getHighestBlockYAt(x, z);
|
|
|
|
if (x - 48 > loc.getBlockX()) {
|
|
|
|
throw new Exception(tl("holeInFloor"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new Location(world, x + 0.5, y, z + 0.5, loc.getYaw(), loc.getPitch());
|
|
|
|
}
|
2013-08-11 23:42:29 +02:00
|
|
|
|
2015-04-15 06:06:16 +02:00
|
|
|
public static boolean shouldFly(Location loc) {
|
|
|
|
final World world = loc.getWorld();
|
|
|
|
final int x = loc.getBlockX();
|
|
|
|
int y = (int) Math.round(loc.getY());
|
|
|
|
final int z = loc.getBlockZ();
|
|
|
|
int count = 0;
|
|
|
|
while (LocationUtil.isBlockUnsafe(world, x, y, z) && y > -1) {
|
|
|
|
y--;
|
|
|
|
count++;
|
|
|
|
if (count > 2) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2013-08-11 23:42:29 +02:00
|
|
|
|
2015-06-01 17:32:37 +02:00
|
|
|
return y < 0;
|
2015-04-15 06:06:16 +02:00
|
|
|
}
|
2013-06-08 23:31:19 +02:00
|
|
|
}
|