2018-07-31 18:03:32 +02:00
|
|
|
package world.bentobox.bentobox.util.teleport;
|
2017-06-11 01:08:21 +02:00
|
|
|
|
2021-12-20 18:44:34 +01:00
|
|
|
import org.bukkit.*;
|
2019-10-03 22:01:14 +02:00
|
|
|
import org.bukkit.World.Environment;
|
|
|
|
import org.bukkit.block.BlockFace;
|
2017-06-11 01:08:21 +02:00
|
|
|
import org.bukkit.entity.Entity;
|
|
|
|
import org.bukkit.entity.Player;
|
2018-02-09 08:47:11 +01:00
|
|
|
import org.bukkit.scheduler.BukkitTask;
|
2017-06-11 01:08:21 +02:00
|
|
|
import org.bukkit.util.Vector;
|
2019-04-11 10:37:14 +02:00
|
|
|
import org.eclipse.jdt.annotation.Nullable;
|
2018-07-31 18:03:32 +02:00
|
|
|
import world.bentobox.bentobox.BentoBox;
|
|
|
|
import world.bentobox.bentobox.api.user.User;
|
|
|
|
import world.bentobox.bentobox.database.objects.Island;
|
|
|
|
import world.bentobox.bentobox.util.Pair;
|
2020-03-28 17:42:55 +01:00
|
|
|
import world.bentobox.bentobox.util.Util;
|
2017-06-11 01:08:21 +02:00
|
|
|
|
2021-12-20 18:44:34 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
2017-06-11 01:08:21 +02:00
|
|
|
/**
|
2018-02-09 05:08:46 +01:00
|
|
|
* A class that calculates finds a safe spot asynchronously and then teleports the player there.
|
2017-08-18 16:05:35 +02:00
|
|
|
*
|
2021-12-20 18:44:34 +01:00
|
|
|
* @author tastybento
|
2017-06-11 01:08:21 +02:00
|
|
|
*/
|
|
|
|
public class SafeSpotTeleport {
|
|
|
|
|
2019-09-21 00:16:09 +02:00
|
|
|
private static final int MAX_CHUNKS = 6;
|
2018-02-17 23:54:58 +01:00
|
|
|
private static final long SPEED = 1;
|
2019-09-21 00:16:09 +02:00
|
|
|
private static final int MAX_RADIUS = 50;
|
2018-02-10 22:09:32 +01:00
|
|
|
// Parameters
|
2018-02-09 08:47:11 +01:00
|
|
|
private final Entity entity;
|
|
|
|
private final Location location;
|
|
|
|
private final int homeNumber;
|
2020-03-28 17:42:55 +01:00
|
|
|
private final BentoBox plugin;
|
|
|
|
private final Runnable runnable;
|
2021-10-17 05:44:18 +02:00
|
|
|
private final Runnable failRunnable;
|
2020-06-02 10:22:35 +02:00
|
|
|
private final CompletableFuture<Boolean> result;
|
2021-03-01 19:42:08 +01:00
|
|
|
private final String homeName;
|
2021-03-28 00:57:15 +01:00
|
|
|
private final int maxHeight;
|
2021-12-20 18:44:34 +01:00
|
|
|
private final World world;
|
|
|
|
private final AtomicBoolean checking = new AtomicBoolean();
|
|
|
|
private BukkitTask task;
|
|
|
|
private boolean portal;
|
|
|
|
// Locations
|
|
|
|
private Location bestSpot;
|
|
|
|
private Iterator<Pair<Integer, Integer>> chunksToScanIterator;
|
|
|
|
private int checkedChunks = 0;
|
2017-06-11 01:08:21 +02:00
|
|
|
|
|
|
|
/**
|
2018-02-09 08:47:11 +01:00
|
|
|
* Teleports and entity to a safe spot on island
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2020-04-04 17:20:32 +02:00
|
|
|
* @param builder - safe spot teleport builder
|
2017-06-11 01:08:21 +02:00
|
|
|
*/
|
2020-04-04 17:20:32 +02:00
|
|
|
SafeSpotTeleport(Builder builder) {
|
2020-03-28 17:42:55 +01:00
|
|
|
this.plugin = builder.getPlugin();
|
|
|
|
this.entity = builder.getEntity();
|
|
|
|
this.location = builder.getLocation();
|
|
|
|
this.portal = builder.isPortal();
|
|
|
|
this.homeNumber = builder.getHomeNumber();
|
2021-03-01 19:42:08 +01:00
|
|
|
this.homeName = builder.getHomeName();
|
2020-03-28 17:42:55 +01:00
|
|
|
this.runnable = builder.getRunnable();
|
2021-10-17 05:44:18 +02:00
|
|
|
this.failRunnable = builder.getFailRunnable();
|
2020-06-02 10:22:35 +02:00
|
|
|
this.result = builder.getResult();
|
2021-12-20 18:44:34 +01:00
|
|
|
this.world = location.getWorld();
|
|
|
|
assert world != null;
|
|
|
|
this.maxHeight = world.getMaxHeight() - 20;
|
2021-03-28 00:57:15 +01:00
|
|
|
// Try to go
|
2021-12-20 18:44:34 +01:00
|
|
|
Util.getChunkAtAsync(location).thenRun(() -> tryToGo(builder.getFailureMessage()));
|
2020-11-27 02:25:17 +01:00
|
|
|
}
|
|
|
|
|
2021-03-28 00:57:15 +01:00
|
|
|
private void tryToGo(String failureMessage) {
|
2018-07-11 06:28:11 +02:00
|
|
|
if (plugin.getIslands().isSafeLocation(location)) {
|
|
|
|
if (portal) {
|
|
|
|
// If the desired location is safe, then that's where you'll go if there's no portal
|
|
|
|
bestSpot = location;
|
|
|
|
} else {
|
|
|
|
// If this is not a portal teleport, then go to the safe location immediately
|
2020-03-28 17:42:55 +01:00
|
|
|
Util.teleportAsync(entity, location).thenRun(() -> {
|
|
|
|
if (runnable != null) Bukkit.getScheduler().runTask(plugin, runnable);
|
2020-06-02 10:22:35 +02:00
|
|
|
result.complete(true);
|
2020-03-28 17:42:55 +01:00
|
|
|
});
|
2018-07-11 06:28:11 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2018-02-10 22:09:32 +01:00
|
|
|
// Get chunks to scan
|
2021-12-20 18:44:34 +01:00
|
|
|
chunksToScanIterator = getChunksToScan().iterator();
|
2018-02-10 23:32:13 +01:00
|
|
|
|
2018-02-09 08:47:11 +01:00
|
|
|
// Start a recurring task until done or cancelled
|
2020-11-27 02:25:17 +01:00
|
|
|
task = Bukkit.getScheduler().runTaskTimer(plugin, () -> gatherChunks(failureMessage), 0L, SPEED);
|
2019-11-09 02:12:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void gatherChunks(String failureMessage) {
|
2021-12-20 18:44:34 +01:00
|
|
|
if (checking.get()) {
|
2019-11-09 02:12:26 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-12-20 18:44:34 +01:00
|
|
|
checking.set(true);
|
|
|
|
if (checkedChunks > MAX_CHUNKS || !chunksToScanIterator.hasNext()) {
|
2019-11-09 02:12:26 +01:00
|
|
|
// Nothing left
|
|
|
|
tidyUp(entity, failureMessage);
|
|
|
|
return;
|
|
|
|
}
|
2021-12-20 18:44:34 +01:00
|
|
|
|
|
|
|
// Get the chunk
|
|
|
|
Pair<Integer, Integer> chunkPair = chunksToScanIterator.next();
|
|
|
|
chunksToScanIterator.remove();
|
|
|
|
checkedChunks++;
|
|
|
|
if (checkedChunks >= MAX_CHUNKS) {
|
|
|
|
checking.set(false);
|
|
|
|
return;
|
2019-11-09 02:12:26 +01:00
|
|
|
}
|
2021-12-20 18:44:34 +01:00
|
|
|
|
|
|
|
// Get the chunk snapshot and scan it
|
|
|
|
Util.getChunkAtAsync(world, chunkPair.x, chunkPair.z)
|
|
|
|
.thenApply(Chunk::getChunkSnapshot)
|
|
|
|
.whenCompleteAsync((snapshot, e) -> {
|
|
|
|
if (snapshot != null && scanChunk(snapshot)) {
|
|
|
|
task.cancel();
|
|
|
|
} else {
|
|
|
|
checking.set(false);
|
|
|
|
}
|
|
|
|
});
|
2018-02-10 22:09:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void tidyUp(Entity entity, String failureMessage) {
|
2020-05-02 23:11:37 +02:00
|
|
|
// Still Async!
|
2018-02-10 22:09:32 +01:00
|
|
|
// Nothing left to check and still not canceled
|
|
|
|
task.cancel();
|
|
|
|
// Check portal
|
|
|
|
if (portal && bestSpot != null) {
|
2019-02-21 19:41:59 +01:00
|
|
|
// Portals found, teleport to the best spot we found
|
2018-02-10 22:09:32 +01:00
|
|
|
teleportEntity(bestSpot);
|
2021-12-20 18:44:34 +01:00
|
|
|
} else if (entity instanceof Player player) {
|
2020-05-02 23:11:37 +02:00
|
|
|
// Return to main thread and teleport the player
|
|
|
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
|
|
|
// Failed, no safe spot
|
|
|
|
if (!failureMessage.isEmpty()) {
|
|
|
|
User.getInstance(entity).notify(failureMessage);
|
2018-06-25 03:23:57 +02:00
|
|
|
}
|
2020-05-02 23:11:37 +02:00
|
|
|
if (!plugin.getIWM().inWorld(entity.getLocation())) {
|
|
|
|
// Last resort
|
2021-12-20 18:44:34 +01:00
|
|
|
player.performCommand("spawn");
|
2019-10-03 22:01:14 +02:00
|
|
|
} else {
|
2020-05-02 23:11:37 +02:00
|
|
|
// Create a spot for the player to be
|
2021-12-20 18:44:34 +01:00
|
|
|
if (world.getEnvironment().equals(Environment.NETHER)) {
|
|
|
|
makeAndTeleport(Material.NETHERRACK);
|
|
|
|
} else if (world.getEnvironment().equals(Environment.THE_END)) {
|
|
|
|
makeAndTeleport(Material.END_STONE);
|
2020-05-02 23:11:37 +02:00
|
|
|
} else {
|
2021-12-20 18:44:34 +01:00
|
|
|
makeAndTeleport(Material.COBBLESTONE);
|
2020-05-02 23:11:37 +02:00
|
|
|
}
|
2019-10-03 22:01:14 +02:00
|
|
|
}
|
2021-10-17 05:44:18 +02:00
|
|
|
if (failRunnable != null) {
|
|
|
|
Bukkit.getScheduler().runTask(plugin, failRunnable);
|
|
|
|
}
|
2020-06-02 10:22:35 +02:00
|
|
|
result.complete(false);
|
2020-05-02 23:11:37 +02:00
|
|
|
});
|
2020-06-02 10:22:35 +02:00
|
|
|
} else {
|
2021-10-17 05:44:18 +02:00
|
|
|
if (failRunnable != null) {
|
|
|
|
Bukkit.getScheduler().runTask(plugin, failRunnable);
|
|
|
|
}
|
2020-06-02 10:22:35 +02:00
|
|
|
result.complete(false);
|
2018-02-10 22:09:32 +01:00
|
|
|
}
|
2019-10-03 22:01:14 +02:00
|
|
|
}
|
2018-06-25 03:23:57 +02:00
|
|
|
|
2021-12-20 18:44:34 +01:00
|
|
|
private void makeAndTeleport(Material m) {
|
2019-10-03 22:01:14 +02:00
|
|
|
location.getBlock().getRelative(BlockFace.DOWN).setType(m, false);
|
|
|
|
location.getBlock().setType(Material.AIR, false);
|
|
|
|
location.getBlock().getRelative(BlockFace.UP).setType(Material.AIR, false);
|
|
|
|
location.getBlock().getRelative(BlockFace.UP).getRelative(BlockFace.UP).setType(m, false);
|
2020-03-28 17:42:55 +01:00
|
|
|
Util.teleportAsync(entity, location.clone().add(new Vector(0.5D, 0D, 0.5D))).thenRun(() -> {
|
|
|
|
if (runnable != null) Bukkit.getScheduler().runTask(plugin, runnable);
|
2020-06-02 10:22:35 +02:00
|
|
|
result.complete(true);
|
2020-03-28 17:42:55 +01:00
|
|
|
});
|
2018-02-10 22:09:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a set of chunk coords that will be scanned.
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-06-10 01:40:38 +02:00
|
|
|
* @return - list of chunk coords to be scanned
|
2018-02-10 22:09:32 +01:00
|
|
|
*/
|
|
|
|
private List<Pair<Integer, Integer>> getChunksToScan() {
|
2020-06-02 14:22:46 +02:00
|
|
|
List<Pair<Integer, Integer>> chunksToScan = new ArrayList<>();
|
2021-12-20 18:44:34 +01:00
|
|
|
int maxRadius = plugin.getIslands().getIslandAt(location).map(Island::getProtectionRange).orElseGet(() -> plugin.getIWM().getIslandProtectionRange(world));
|
2019-08-27 04:19:45 +02:00
|
|
|
maxRadius = Math.min(MAX_RADIUS, maxRadius);
|
2018-02-10 22:09:32 +01:00
|
|
|
int x = location.getBlockX();
|
|
|
|
int z = location.getBlockZ();
|
|
|
|
// Create ever increasing squares around the target location
|
|
|
|
int radius = 0;
|
|
|
|
do {
|
2021-12-20 18:44:34 +01:00
|
|
|
for (int i = x - radius; i <= x + radius; i += 16) {
|
|
|
|
for (int j = z - radius; j <= z + radius; j += 16) {
|
|
|
|
addChunk(chunksToScan, new Pair<>(i, j), new Pair<>(i >> 4, j >> 4));
|
2017-06-11 01:08:21 +02:00
|
|
|
}
|
2018-02-09 08:47:11 +01:00
|
|
|
}
|
2018-02-10 22:09:32 +01:00
|
|
|
radius++;
|
|
|
|
} while (radius < maxRadius);
|
2020-06-02 14:22:46 +02:00
|
|
|
return chunksToScan;
|
2018-02-09 08:47:11 +01:00
|
|
|
}
|
|
|
|
|
2020-06-02 14:22:46 +02:00
|
|
|
private void addChunk(List<Pair<Integer, Integer>> chunksToScan, Pair<Integer, Integer> blockCoord, Pair<Integer, Integer> chunkCoord) {
|
|
|
|
if (!chunksToScan.contains(chunkCoord) && plugin.getIslands().getIslandAt(location).map(is -> is.inIslandSpace(blockCoord)).orElse(true)) {
|
|
|
|
chunksToScan.add(chunkCoord);
|
2018-02-12 00:22:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-10 22:09:32 +01:00
|
|
|
/**
|
2018-06-10 01:40:38 +02:00
|
|
|
* @param chunk - chunk snapshot
|
2018-02-10 22:09:32 +01:00
|
|
|
* @return true if a safe spot was found
|
|
|
|
*/
|
2018-06-25 01:22:44 +02:00
|
|
|
private boolean scanChunk(ChunkSnapshot chunk) {
|
2021-12-20 18:44:34 +01:00
|
|
|
int startY = location.getBlockY();
|
|
|
|
int minY = world.getMinHeight();
|
|
|
|
int maxY = 60; // Just a dummy value
|
|
|
|
|
|
|
|
// Check the safe spot at the current height
|
|
|
|
for (int x = 0; x < 16; x++) {
|
2018-02-10 22:09:32 +01:00
|
|
|
for (int z = 0; z < 16; z++) {
|
2021-12-20 18:44:34 +01:00
|
|
|
if (minY >= startY && checkBlock(chunk, x, startY, z)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
maxY = Math.max(chunk.getHighestBlockYAt(x, z), maxY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
maxY = Math.min(maxY, maxHeight);
|
|
|
|
|
|
|
|
// Expand the height up and down until a safe spot is found
|
|
|
|
int upperY = startY + 1;
|
|
|
|
int lowerY = startY - 1;
|
|
|
|
boolean checkUpper = upperY <= maxY;
|
|
|
|
boolean checkLower = lowerY >= minY;
|
|
|
|
int limitRange = plugin.getSettings().getSafeSpotSearchVerticalRange(); // Limit the y-coordinate range
|
|
|
|
while (limitRange > 0 && (checkUpper || checkLower)) {
|
|
|
|
for (int x = 0; x < 16; x++) {
|
|
|
|
for (int z = 0; z < 16; z++) {
|
|
|
|
if (checkUpper && checkBlock(chunk, x, upperY, z)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (checkLower && checkBlock(chunk, x, lowerY, z)) {
|
2018-02-10 23:32:13 +01:00
|
|
|
return true;
|
2018-02-10 22:09:32 +01:00
|
|
|
}
|
2021-12-20 18:44:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (checkUpper) {
|
|
|
|
upperY++;
|
|
|
|
if (upperY > maxY) {
|
|
|
|
checkUpper = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (checkLower) {
|
|
|
|
lowerY--;
|
|
|
|
if (lowerY < minY) {
|
|
|
|
checkLower = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
limitRange--;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can't find a safe spot
|
2018-02-10 22:09:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-02-09 08:47:11 +01:00
|
|
|
/**
|
|
|
|
* Teleports entity to the safe spot
|
|
|
|
*/
|
2018-02-17 23:54:58 +01:00
|
|
|
private void teleportEntity(final Location loc) {
|
2018-02-10 22:09:32 +01:00
|
|
|
task.cancel();
|
2018-02-09 08:47:11 +01:00
|
|
|
// Return to main thread and teleport the player
|
2020-05-02 23:11:37 +02:00
|
|
|
Bukkit.getScheduler().runTask(plugin, () -> {
|
2021-03-01 19:42:08 +01:00
|
|
|
if (!portal && entity instanceof Player && (homeNumber > 0 || !homeName.isEmpty())) {
|
2020-05-02 23:11:37 +02:00
|
|
|
// Set home if so marked
|
2021-03-01 19:42:08 +01:00
|
|
|
plugin.getIslands().setHomeLocation(User.getInstance(entity), loc, homeName);
|
2020-05-02 23:11:37 +02:00
|
|
|
}
|
|
|
|
Util.teleportAsync(entity, loc).thenRun(() -> {
|
|
|
|
if (runnable != null) Bukkit.getScheduler().runTask(plugin, runnable);
|
2020-06-02 10:22:35 +02:00
|
|
|
result.complete(true);
|
2020-05-02 23:11:37 +02:00
|
|
|
});
|
|
|
|
});
|
2018-02-09 08:47:11 +01:00
|
|
|
}
|
|
|
|
|
2018-02-02 05:30:57 +01:00
|
|
|
/**
|
|
|
|
* Returns true if the location is a safe one.
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-06-10 01:40:38 +02:00
|
|
|
* @param chunk - chunk snapshot
|
2021-12-20 18:44:34 +01:00
|
|
|
* @param x - x coordinate
|
|
|
|
* @param y - y coordinate
|
|
|
|
* @param z - z coordinate
|
2018-02-10 23:32:13 +01:00
|
|
|
* @return true if this is a safe spot, false if this is a portal scan
|
2018-02-02 05:30:57 +01:00
|
|
|
*/
|
2020-04-23 03:25:10 +02:00
|
|
|
boolean checkBlock(ChunkSnapshot chunk, int x, int y, int z) {
|
2018-02-10 22:09:32 +01:00
|
|
|
Material type = chunk.getBlockType(x, y, z);
|
2021-03-28 00:57:15 +01:00
|
|
|
Material space1 = chunk.getBlockType(x, Math.min(y + 1, maxHeight), z);
|
|
|
|
Material space2 = chunk.getBlockType(x, Math.min(y + 2, maxHeight), z);
|
2020-04-23 03:25:10 +02:00
|
|
|
if (space1.equals(Material.NETHER_PORTAL) || space2.equals(Material.NETHER_PORTAL)) {
|
|
|
|
// A portal has been found, switch to non-portal mode now
|
|
|
|
portal = false;
|
|
|
|
}
|
|
|
|
if (plugin.getIslands().checkIfSafe(world, type, space1, space2)) {
|
|
|
|
return safe(chunk, x, y, z, world);
|
2017-06-11 01:08:21 +02:00
|
|
|
}
|
2018-02-02 05:30:57 +01:00
|
|
|
return false;
|
2017-06-11 01:08:21 +02:00
|
|
|
}
|
2018-02-09 08:47:11 +01:00
|
|
|
|
2018-02-17 23:54:58 +01:00
|
|
|
private boolean safe(ChunkSnapshot chunk, int x, int y, int z, World world) {
|
2019-02-02 10:47:59 +01:00
|
|
|
Vector newSpot = new Vector((chunk.getX() << 4) + x + 0.5D, y + 1.0D, (chunk.getZ() << 4) + z + 0.5D);
|
2018-02-12 00:22:03 +01:00
|
|
|
if (portal) {
|
|
|
|
if (bestSpot == null) {
|
|
|
|
// Stash the best spot
|
|
|
|
bestSpot = newSpot.toLocation(world);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
teleportEntity(newSpot.toLocation(world));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2018-09-15 12:38:51 +02:00
|
|
|
|
|
|
|
public static class Builder {
|
2020-03-28 17:42:55 +01:00
|
|
|
private final BentoBox plugin;
|
2021-12-20 18:44:34 +01:00
|
|
|
private final CompletableFuture<Boolean> result = new CompletableFuture<>();
|
2018-09-15 12:38:51 +02:00
|
|
|
private Entity entity;
|
|
|
|
private int homeNumber = 0;
|
2021-03-06 17:14:31 +01:00
|
|
|
private String homeName = "";
|
2018-09-15 12:38:51 +02:00
|
|
|
private boolean portal = false;
|
|
|
|
private String failureMessage = "";
|
|
|
|
private Location location;
|
2020-03-28 17:42:55 +01:00
|
|
|
private Runnable runnable;
|
2021-10-17 05:44:18 +02:00
|
|
|
private Runnable failRunnable;
|
2018-09-15 12:38:51 +02:00
|
|
|
|
|
|
|
public Builder(BentoBox plugin) {
|
|
|
|
this.plugin = plugin;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set who or what is going to teleport
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-09-15 12:38:51 +02:00
|
|
|
* @param entity entity to teleport
|
|
|
|
* @return Builder
|
|
|
|
*/
|
|
|
|
public Builder entity(Entity entity) {
|
|
|
|
this.entity = entity;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the island to teleport to
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-09-15 12:38:51 +02:00
|
|
|
* @param island island destination
|
|
|
|
* @return Builder
|
|
|
|
*/
|
|
|
|
public Builder island(Island island) {
|
2021-02-13 19:19:53 +01:00
|
|
|
this.location = island.getProtectionCenter();
|
2018-09-15 12:38:51 +02:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the home number to this number
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-09-15 12:38:51 +02:00
|
|
|
* @param homeNumber home number
|
|
|
|
* @return Builder
|
2021-03-01 19:42:08 +01:00
|
|
|
* @deprecated use {@link #homeName}
|
2018-09-15 12:38:51 +02:00
|
|
|
*/
|
2021-03-01 19:42:08 +01:00
|
|
|
@Deprecated
|
2018-09-15 12:38:51 +02:00
|
|
|
public Builder homeNumber(int homeNumber) {
|
|
|
|
this.homeNumber = homeNumber;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2021-03-01 19:42:08 +01:00
|
|
|
/**
|
|
|
|
* Set the home name
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2021-03-01 19:42:08 +01:00
|
|
|
* @param homeName - home name
|
|
|
|
* @return Builder
|
2021-06-01 01:01:21 +02:00
|
|
|
* @since 1.16.0
|
2021-03-01 19:42:08 +01:00
|
|
|
*/
|
|
|
|
public Builder homeName(String homeName) {
|
|
|
|
this.homeName = homeName;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2018-09-15 12:38:51 +02:00
|
|
|
/**
|
|
|
|
* This is a portal teleportation
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-09-15 12:38:51 +02:00
|
|
|
* @return Builder
|
|
|
|
*/
|
|
|
|
public Builder portal() {
|
|
|
|
this.portal = true;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the failure message if this teleport cannot happen
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-09-15 12:38:51 +02:00
|
|
|
* @param failureMessage failure message to report to user
|
|
|
|
* @return Builder
|
|
|
|
*/
|
|
|
|
public Builder failureMessage(String failureMessage) {
|
|
|
|
this.failureMessage = failureMessage;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the desired location
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-09-15 12:38:51 +02:00
|
|
|
* @param location the location
|
|
|
|
* @return Builder
|
|
|
|
*/
|
|
|
|
public Builder location(Location location) {
|
|
|
|
this.location = location;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-06-02 10:22:35 +02:00
|
|
|
/**
|
|
|
|
* Try to teleport the player
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2021-08-30 03:17:38 +02:00
|
|
|
* @return CompletableFuture that will become true if successful and false if not
|
2020-06-02 10:22:35 +02:00
|
|
|
* @since 1.14.0
|
|
|
|
*/
|
|
|
|
@Nullable
|
|
|
|
public CompletableFuture<Boolean> buildFuture() {
|
|
|
|
build();
|
|
|
|
return result;
|
|
|
|
}
|
2020-11-27 02:25:17 +01:00
|
|
|
|
2018-09-15 12:38:51 +02:00
|
|
|
/**
|
|
|
|
* Try to teleport the player
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2018-09-15 12:38:51 +02:00
|
|
|
* @return SafeSpotTeleport
|
|
|
|
*/
|
2019-04-11 10:37:14 +02:00
|
|
|
@Nullable
|
2018-09-15 12:38:51 +02:00
|
|
|
public SafeSpotTeleport build() {
|
|
|
|
// Error checking
|
|
|
|
if (entity == null) {
|
|
|
|
plugin.logError("Attempt to safe teleport a null entity!");
|
2020-06-02 10:22:35 +02:00
|
|
|
result.complete(null);
|
2018-09-15 12:38:51 +02:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (location == null) {
|
|
|
|
plugin.logError("Attempt to safe teleport to a null location!");
|
2020-06-02 10:22:35 +02:00
|
|
|
result.complete(null);
|
2018-09-15 12:38:51 +02:00
|
|
|
return null;
|
|
|
|
}
|
2021-12-20 18:44:34 +01:00
|
|
|
if (location.getWorld() == null) {
|
|
|
|
plugin.logError("Attempt to safe teleport to a null world!");
|
|
|
|
result.complete(null);
|
|
|
|
return null;
|
|
|
|
}
|
2018-09-15 12:38:51 +02:00
|
|
|
if (failureMessage.isEmpty() && entity instanceof Player) {
|
2019-04-11 10:37:14 +02:00
|
|
|
failureMessage = "general.errors.no-safe-location-found";
|
2018-09-15 12:38:51 +02:00
|
|
|
}
|
2020-03-28 17:42:55 +01:00
|
|
|
return new SafeSpotTeleport(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The task to run after the player is safely teleported.
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2020-03-28 17:42:55 +01:00
|
|
|
* @param runnable - task
|
|
|
|
* @return Builder
|
|
|
|
* @since 1.13.0
|
|
|
|
*/
|
|
|
|
public Builder thenRun(Runnable runnable) {
|
|
|
|
this.runnable = runnable;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2021-10-17 05:44:18 +02:00
|
|
|
/**
|
|
|
|
* The task to run if the player is not safely teleported
|
2021-12-20 18:44:34 +01:00
|
|
|
*
|
2021-10-17 05:44:18 +02:00
|
|
|
* @param runnable - task
|
|
|
|
* @return Builder
|
|
|
|
* @since 1.18.0
|
|
|
|
*/
|
2021-12-20 18:44:34 +01:00
|
|
|
public Builder ifFail(Runnable runnable) {
|
2021-10-17 05:44:18 +02:00
|
|
|
this.failRunnable = runnable;
|
|
|
|
return this;
|
|
|
|
}
|
2021-12-20 18:44:34 +01:00
|
|
|
|
2020-03-28 17:42:55 +01:00
|
|
|
/**
|
|
|
|
* @return the plugin
|
|
|
|
*/
|
|
|
|
public BentoBox getPlugin() {
|
|
|
|
return plugin;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the entity
|
|
|
|
*/
|
|
|
|
public Entity getEntity() {
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the homeNumber
|
|
|
|
*/
|
|
|
|
public int getHomeNumber() {
|
|
|
|
return homeNumber;
|
|
|
|
}
|
|
|
|
|
2021-03-01 19:42:08 +01:00
|
|
|
/**
|
|
|
|
* @return the homeName
|
|
|
|
*/
|
|
|
|
public String getHomeName() {
|
|
|
|
return homeName;
|
|
|
|
}
|
|
|
|
|
2020-03-28 17:42:55 +01:00
|
|
|
/**
|
|
|
|
* @return the portal
|
|
|
|
*/
|
|
|
|
public boolean isPortal() {
|
|
|
|
return portal;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the failureMessage
|
|
|
|
*/
|
|
|
|
public String getFailureMessage() {
|
|
|
|
return failureMessage;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the location
|
|
|
|
*/
|
|
|
|
public Location getLocation() {
|
|
|
|
return location;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the runnable
|
|
|
|
*/
|
|
|
|
public Runnable getRunnable() {
|
|
|
|
return runnable;
|
2018-09-15 12:38:51 +02:00
|
|
|
}
|
2020-06-02 10:22:35 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the result
|
|
|
|
* @since 1.14.0
|
|
|
|
*/
|
|
|
|
public CompletableFuture<Boolean> getResult() {
|
|
|
|
return result;
|
|
|
|
}
|
2021-03-01 19:42:08 +01:00
|
|
|
|
2021-10-17 05:44:18 +02:00
|
|
|
/**
|
|
|
|
* @return the failRunnable
|
|
|
|
*/
|
|
|
|
public Runnable getFailRunnable() {
|
|
|
|
return failRunnable;
|
|
|
|
}
|
|
|
|
|
2021-03-01 19:42:08 +01:00
|
|
|
|
2018-09-15 12:38:51 +02:00
|
|
|
}
|
2020-06-02 10:22:35 +02:00
|
|
|
}
|