Added LocationUtil in PandalibPaper
This commit is contained in:
parent
f0b9905b9d
commit
783b6651b0
@ -0,0 +1,183 @@
|
|||||||
|
package fr.pandacube.lib.paper.util;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.World.Environment;
|
||||||
|
import org.bukkit.WorldBorder;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import fr.pandacube.lib.core.util.RandomUtil;
|
||||||
|
import fr.pandacube.lib.paper.PandaLibPaper;
|
||||||
|
|
||||||
|
public class LocationUtil {
|
||||||
|
|
||||||
|
public static String conciseToString(Location loc) {
|
||||||
|
String world = loc.getWorld() == null ? "null" : loc.getWorld().getName();
|
||||||
|
return "(" + world + "," + loc.getBlockX() + "," + loc.getBlockY() + "," + loc.getBlockZ() + ")";
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return a random secure location in the provided world, inside the current
|
||||||
|
* WorldBorder. Will be on the surface, for non-nether world, or below the roof of the nether world
|
||||||
|
* @param w
|
||||||
|
* @param checkCubo true if the returned location can't be in a /cubo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static CompletableFuture<Location> getRandomSecureLocation(World w, Predicate<Location> extraSecureCheck) {
|
||||||
|
|
||||||
|
WorldBorder wb = w.getWorldBorder();
|
||||||
|
|
||||||
|
Location minWorld = wb.getCenter().clone().add(-wb.getSize()/2, 0, -wb.getSize()/2);
|
||||||
|
Location maxWorld = wb.getCenter().clone().add(wb.getSize()/2, 0, wb.getSize()/2);
|
||||||
|
|
||||||
|
return getRandomSecureLocation(w, minWorld, maxWorld, extraSecureCheck);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static final int maxTryBeforeCancelRandomLocation = 75;
|
||||||
|
public static CompletableFuture<Location> getRandomSecureLocation(World w, Location min, Location max, Predicate<Location> extraSecureCheck) {
|
||||||
|
|
||||||
|
CompletableFuture<Location> future = new CompletableFuture<Location>();
|
||||||
|
|
||||||
|
AtomicReference<BukkitTask> t = new AtomicReference<>();
|
||||||
|
AtomicInteger count = new AtomicInteger(0);
|
||||||
|
|
||||||
|
t.set(Bukkit.getScheduler().runTaskTimer(PandaLibPaper.getPlugin(), () -> {
|
||||||
|
|
||||||
|
count.incrementAndGet();
|
||||||
|
if (count.get() > maxTryBeforeCancelRandomLocation) {
|
||||||
|
future.complete(null);
|
||||||
|
t.get().cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a random (x,z) coordinate
|
||||||
|
Location ret = new Location(w,
|
||||||
|
RandomUtil.nextIntBetween(min.getBlockX(), max.getBlockX()) + 0.5,
|
||||||
|
w.getMaxHeight() - 1,
|
||||||
|
RandomUtil.nextIntBetween(min.getBlockZ(), max.getBlockZ()) + 0.5);
|
||||||
|
|
||||||
|
// find a secure y value
|
||||||
|
ret = getSecureLocationOrNull(ret);
|
||||||
|
|
||||||
|
if (ret == null)
|
||||||
|
// there is no secure y position for the provided (x,z) values
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (extraSecureCheck != null && !extraSecureCheck.test(ret))
|
||||||
|
return; // extra checks didn’t validate the location
|
||||||
|
|
||||||
|
//if (checkCubo && PandacubePaper.getPlugin().cuboManager != null)
|
||||||
|
// if (PandacubePaper.getPlugin().cuboManager.getCuboFromLocation(ret) != null)
|
||||||
|
// return; // il y a un cubo à l'endroit aléatoire sélectionnée
|
||||||
|
|
||||||
|
// tout est bon
|
||||||
|
future.complete(ret);
|
||||||
|
t.get().cancel();
|
||||||
|
|
||||||
|
}, 1, 1));
|
||||||
|
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param l
|
||||||
|
* @return a secure location with the same X and Z coordinate as the
|
||||||
|
* provided location, but Y modified to ensure security for player
|
||||||
|
* who will be teleported to this location.
|
||||||
|
* May return null if it is impossible to securize find a secure location.
|
||||||
|
*/
|
||||||
|
public static Location getSecureLocationOrNull(Location l) {
|
||||||
|
l = l.clone();
|
||||||
|
l.setY(l.getWorld().getEnvironment() == Environment.NETHER ? 126 : 256);
|
||||||
|
Block b = l.getBlock();
|
||||||
|
|
||||||
|
while (b.getY() >= 0 && !currPosSafe(b))
|
||||||
|
b = b.getRelative(BlockFace.DOWN);
|
||||||
|
|
||||||
|
return currPosSafe(b) ? b.getLocation().add(0.5, 0, 0.5) : null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean currPosSafe(Block b) {
|
||||||
|
return b.getY() >= b.getWorld().getMinHeight() + 1 && b.getY() <= b.getWorld().getMaxHeight()
|
||||||
|
&& isSecureFloor(b.getRelative(BlockFace.DOWN))
|
||||||
|
&& isAir(b)
|
||||||
|
&& isAir(b.getRelative(BlockFace.UP));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAir(Block b) { return b.getType() == Material.AIR; }
|
||||||
|
public static boolean isSecureFloor(Block b) { return !isAir(b) && !dangerousBlocks.contains(b.getType()); }
|
||||||
|
|
||||||
|
public static Set<Material> dangerousBlocks = EnumSet.of(
|
||||||
|
Material.LAVA,
|
||||||
|
Material.WATER,
|
||||||
|
Material.COBWEB,
|
||||||
|
Material.MAGMA_BLOCK,
|
||||||
|
Material.CAMPFIRE,
|
||||||
|
Material.SOUL_CAMPFIRE,
|
||||||
|
Material.FIRE,
|
||||||
|
Material.SOUL_FIRE,
|
||||||
|
Material.WITHER_ROSE,
|
||||||
|
Material.END_PORTAL,
|
||||||
|
Material.NETHER_PORTAL,
|
||||||
|
Material.END_GATEWAY
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the {@link Location} l is inside the cuboïd formed by the 2 others
|
||||||
|
* Locations min and max.
|
||||||
|
* @param l
|
||||||
|
* @param min
|
||||||
|
* @param max
|
||||||
|
* @return true if l is inside the cuboid min-max
|
||||||
|
*/
|
||||||
|
public static boolean isIn(Location l, Location min, Location max) {
|
||||||
|
return (l.getWorld().equals(min.getWorld()) && l.getWorld().equals(max.getWorld()) && l.getX() >= min.getX()
|
||||||
|
&& l.getX() <= max.getX() && l.getY() >= min.getY() && l.getY() <= max.getY() && l.getZ() >= min.getZ()
|
||||||
|
&& l.getZ() <= max.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new location based on the linear interpolation between p0 and p1, according to the value c.
|
||||||
|
* @param p0
|
||||||
|
* @param p1
|
||||||
|
* @param c between 0 and 1. If 0, it returns p0 and if 1, returns p1. Other finite numbers are allowed, but the returned location wont be part of the {@code [p0;p1]} segment.
|
||||||
|
* @return The location, linearly interpolated between p0 and p1 with the value c. The yaw and pitch in the returned location are those of p0.
|
||||||
|
* @throws IllegalArgumentException if the provided locations are not in the same world.
|
||||||
|
*/
|
||||||
|
public static Location lerp(Location p0, Location p1, float c) {
|
||||||
|
return p0.clone().add(p1.clone().subtract(p0).multiply(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user