Completed nether portals

Also fixed some issues around admin commands and the teleport admin
commands in particular.
This commit is contained in:
Tastybento 2018-02-11 11:12:56 -08:00
parent b9c262fd5c
commit c07b649488
13 changed files with 123 additions and 139 deletions

View File

@ -19,6 +19,7 @@ general:
use-in-game: "&cThis command is only available in game." use-in-game: "&cThis command is only available in game."
no-team: "&cYou do not have a team!" no-team: "&cYou do not have a team!"
no-island: "&cYou do not have an island!" no-island: "&cYou do not have an island!"
player-has-no-island: "&cThat player has no island!"
already-have-island: "&cYou already have an island!" already-have-island: "&cYou already have an island!"
no-safe-location: "&cNo safe location found on island!" no-safe-location: "&cNo safe location found on island!"
not-leader: "&cYou are not the leader of your island!" not-leader: "&cYou are not the leader of your island!"
@ -31,17 +32,26 @@ general:
commands: commands:
help: help:
header: "&7=========== &c%bsb_plugin_name% &7===========" header: "&7=========== &c%bsb_plugin_name% &7==========="
syntax: "&b[usage] &a[parameters] &7: &e[description]" syntax: "&b[usage] &a[parameters]&7: &e[description]"
end: "&7=================================" end: "&7================================="
parameters: "[command]" parameters: "[command]"
description: "help command" description: "help command"
admin: admin:
help: help:
description: "Admin command" description: "admin command"
parameters: ""
version: version:
description: "display %bsb_plugin_name% and addons versions" description: "display %bsb_plugin_name% and addons versions"
setrange: setrange:
parameters: "[player] [range]"
description: "set the range of player's island"
range-updated: "Island range updated to [number]" range-updated: "Island range updated to [number]"
reload:
description: "reload the plugin"
tp:
parameters: "[player]"
description: "teleport to a player's island"
manual: "&cNo safe warp found! Manually tp near to &b[location] &cand check it out"
island: island:
about: about:
description: "display info about %bsb_plugin_name%" description: "display info about %bsb_plugin_name%"

View File

@ -162,7 +162,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
return true; return true;
} }
// Check perms, but only if this isn't the console // Check perms, but only if this isn't the console
if ((sender instanceof Player) && !cmd.getPermission().isEmpty() && !sender.hasPermission(cmd.getPermission())) { if ((sender instanceof Player) && !sender.isOp() && !cmd.getPermission().isEmpty() && !sender.hasPermission(cmd.getPermission())) {
user.sendMessage("general.errors.no-permission"); user.sendMessage("general.errors.no-permission");
return true; return true;
} }
@ -469,12 +469,11 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
* Show help * Show help
* @param command * @param command
* @param user * @param user
* @param args
*/ */
protected void showHelp(CompositeCommand command, User user, List<String> args) { protected void showHelp(CompositeCommand command, User user) {
Optional<CompositeCommand> helpCommand = command.getSubCommand("help"); Optional<CompositeCommand> helpCommand = command.getSubCommand("help");
if (helpCommand.isPresent()) { if (helpCommand.isPresent()) {
helpCommand.get().execute(user, args); helpCommand.get().execute(user, new ArrayList<>());
} }
} }
} }

View File

@ -19,16 +19,19 @@ public class AdminCommand extends CompositeCommand {
public void setup() { public void setup() {
setPermission(Constants.PERMPREFIX + "admin.*"); setPermission(Constants.PERMPREFIX + "admin.*");
setOnlyPlayer(false); setOnlyPlayer(false);
setParameters("commands.admin.help.parameters");
setDescription("commands.admin.help.description"); setDescription("commands.admin.help.description");
new AdminVersionCommand(this); new AdminVersionCommand(this);
new AdminReloadCommand(this); new AdminReloadCommand(this);
new AdminTeleportCommand(this); new AdminTeleportCommand(this, "tp");
new AdminTeleportCommand(this, "tpnether");
new AdminTeleportCommand(this, "tpend");
} }
@Override @Override
public boolean execute(User user, List<String> args) { public boolean execute(User user, List<String> args) {
// By default run the attached help command, if it exists (it should) // By default run the attached help command, if it exists (it should)
showHelp(this, user, args); showHelp(this, user);
return false; return false;
} }

View File

@ -1,4 +0,0 @@
package us.tastybento.bskyblock.commands.admin;
public class AdminDeleteCommand {
}

View File

@ -11,33 +11,34 @@ import org.bukkit.Location;
import us.tastybento.bskyblock.Constants; import us.tastybento.bskyblock.Constants;
import us.tastybento.bskyblock.api.commands.CompositeCommand; import us.tastybento.bskyblock.api.commands.CompositeCommand;
import us.tastybento.bskyblock.api.commands.User; import us.tastybento.bskyblock.api.commands.User;
import us.tastybento.bskyblock.util.SafeTeleportBuilder;
import us.tastybento.bskyblock.util.Util; import us.tastybento.bskyblock.util.Util;
import us.tastybento.bskyblock.util.teleport.SafeTeleportBuilder;
public class AdminTeleportCommand extends CompositeCommand { public class AdminTeleportCommand extends CompositeCommand {
public AdminTeleportCommand(CompositeCommand parent) { public AdminTeleportCommand(CompositeCommand parent, String tpCommand) {
super(parent, "tp", "tpnether", "tpend"); super(parent, tpCommand);
} }
@Override @Override
public void setup() { public void setup() {
setPermission(Constants.PERMPREFIX + "admin.tp"); setPermission(Constants.PERMPREFIX + "admin.tp");
setOnlyPlayer(true); setOnlyPlayer(true);
setParameters("commands.admin.tp.parameters");
setDescription("commands.admin.tp.description"); setDescription("commands.admin.tp.description");
} }
@Override @Override
public boolean execute(User user, List<String> args) { public boolean execute(User user, List<String> args) {
if (args.isEmpty()) { if (args.isEmpty()) {
user.sendMessage("commands.admin.tp.help"); this.showHelp(this, user);
return true; return true;
} }
// Convert name to a UUID // Convert name to a UUID
final UUID targetUUID = getPlayers().getUUID(args.get(0)); final UUID targetUUID = getPlayers().getUUID(args.get(0));
if (targetUUID == null) { if (targetUUID == null) {
user.sendMessage("errors.unknown-player"); user.sendMessage("general.errors.unknown-player");
return false; return false;
} else { } else {
if (getPlayers().hasIsland(targetUUID) || getPlayers().inTeam(targetUUID)) { if (getPlayers().hasIsland(targetUUID) || getPlayers().inTeam(targetUUID)) {
@ -56,7 +57,7 @@ public class AdminTeleportCommand extends CompositeCommand {
.build(); .build();
return true; return true;
} }
user.sendMessage("command.admin.tp.no-island"); user.sendMessage("general.errors.player-has-no-island");
return false; return false;
} }
} }

View File

@ -51,7 +51,7 @@ public class IslandSetnameCommand extends CompositeCommand {
} }
// Explain command // Explain command
if (args.isEmpty()) { if (args.isEmpty()) {
showHelp(this, user, args); showHelp(this, user);
return false; return false;
} }

View File

@ -53,7 +53,7 @@ public class IslandTeamInviteCommand extends AbstractIslandTeamCommand {
return true; return true;
} }
// Show help // Show help
showHelp(this, user, args); showHelp(this, user);
return false; return false;
} else { } else {
// Only online players can be invited // Only online players can be invited

View File

@ -39,7 +39,7 @@ public class IslandTeamKickCommand extends AbstractIslandTeamCommand {
} }
// If args are not right, show help // If args are not right, show help
if (args.size() != 1) { if (args.size() != 1) {
showHelp(this, user, args); showHelp(this, user);
return false; return false;
} }
// Get target // Get target

View File

@ -42,7 +42,7 @@ public class IslandTeamSetownerCommand extends AbstractIslandTeamCommand {
} }
// If args are not right, show help // If args are not right, show help
if (args.size() != 1) { if (args.size() != 1) {
showHelp(this, user, args); showHelp(this, user);
return false; return false;
} }
//getPlugin().getLogger().info("DEBUG: arg[0] = " + args.get(0)); //getPlugin().getLogger().info("DEBUG: arg[0] = " + args.get(0));

View File

@ -27,8 +27,8 @@ import us.tastybento.bskyblock.database.BSBDatabase;
import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler; import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler;
import us.tastybento.bskyblock.database.objects.Island; import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.util.DeleteIslandChunks; import us.tastybento.bskyblock.util.DeleteIslandChunks;
import us.tastybento.bskyblock.util.SafeTeleportBuilder;
import us.tastybento.bskyblock.util.Util; import us.tastybento.bskyblock.util.Util;
import us.tastybento.bskyblock.util.teleport.SafeTeleportBuilder;
/** /**
* The job of this class is manage all island related data. * The job of this class is manage all island related data.

View File

@ -24,7 +24,7 @@ import org.bukkit.util.Vector;
import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.commands.User; import us.tastybento.bskyblock.api.commands.User;
import us.tastybento.bskyblock.util.SafeTeleportBuilder; import us.tastybento.bskyblock.util.teleport.SafeTeleportBuilder;
public class NetherPortals implements Listener { public class NetherPortals implements Listener {
private final BSkyBlock plugin; private final BSkyBlock plugin;
@ -194,14 +194,19 @@ public class NetherPortals implements Listener {
if (!inWorlds(event.getFrom())) { if (!inWorlds(event.getFrom())) {
return; return;
} }
// If entering a portal in the nether or end, teleport home if you have one, else do nothing // If entering a portal in the nether, teleport to portal in overworld if there is one
if (!event.getFrom().getWorld().equals(world)) { if (event.getFrom().getWorld().equals(nether)) {
plugin.getLogger().info("Entered portal in nether or end"); plugin.getLogger().info("Entered portal in nether");
if (plugin.getIslands().hasIsland(event.getPlayer().getUniqueId())) { // If this is island nether, then go to the same vector, otherwise try spawn
plugin.getLogger().info("player has island - teleporting home"); Location to = plugin.getSettings().isNetherIslands() ? event.getFrom().toVector().toLocation(world) : plugin.getIslands().getIslandLocation(event.getPlayer().getUniqueId());
event.setCancelled(true); plugin.getLogger().info("Going to " + to);
plugin.getIslands().homeTeleport(event.getPlayer()); event.setCancelled(true);
} // Else other worlds teleport to the nether
new SafeTeleportBuilder(plugin)
.entity(event.getPlayer())
.location(to)
.portal()
.build();
return; return;
} }
plugin.getLogger().info("Entering nether portal in overworld"); plugin.getLogger().info("Entering nether portal in overworld");

View File

@ -1,4 +1,4 @@
package us.tastybento.bskyblock.util; package us.tastybento.bskyblock.util.teleport;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@ -18,6 +18,7 @@ import org.bukkit.util.Vector;
import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.database.objects.Island; import us.tastybento.bskyblock.database.objects.Island;
import us.tastybento.bskyblock.util.Pair;
/** /**
* A class that calculates finds a safe spot asynchronously and then teleports the player there. * A class that calculates finds a safe spot asynchronously and then teleports the player there.
@ -26,8 +27,8 @@ import us.tastybento.bskyblock.database.objects.Island;
*/ */
public class SafeSpotTeleport { public class SafeSpotTeleport {
private static final int MAX_CHUNKS = 10; private static final int MAX_CHUNKS = 50;
private static final long SPEED = 10; private static final long SPEED = 5;
private boolean checking = true; private boolean checking = true;
private BukkitTask task; private BukkitTask task;
@ -49,11 +50,11 @@ public class SafeSpotTeleport {
* @param plugin * @param plugin
* @param entity * @param entity
* @param location * @param location
* @param failureMessage * @param failureMessage - already translated failure message
* @param portal * @param portal
* @param homeNumber * @param homeNumber
*/ */
public SafeSpotTeleport(BSkyBlock plugin, Entity entity, Location location, String failureMessage, boolean portal, protected SafeSpotTeleport(BSkyBlock plugin, Entity entity, Location location, String failureMessage, boolean portal,
int homeNumber) { int homeNumber) {
this.plugin = plugin; this.plugin = plugin;
this.entity = entity; this.entity = entity;
@ -61,10 +62,8 @@ public class SafeSpotTeleport {
this.portal = portal; this.portal = portal;
this.homeNumber = homeNumber; this.homeNumber = homeNumber;
plugin.getLogger().info("Safe teleport called");
// Put player into spectator mode // Put player into spectator mode
if (entity instanceof Player && ((Player)entity).getGameMode().equals(GameMode.SURVIVAL)) { if (entity instanceof Player && ((Player)entity).getGameMode().equals(GameMode.SURVIVAL)) {
Bukkit.getLogger().info("Put player into spectator mode");
((Player)entity).setGameMode(GameMode.SPECTATOR); ((Player)entity).setGameMode(GameMode.SPECTATOR);
} }
@ -78,11 +77,8 @@ public class SafeSpotTeleport {
task = plugin.getServer().getScheduler().runTaskTimer(plugin, () -> { task = plugin.getServer().getScheduler().runTaskTimer(plugin, () -> {
List<ChunkSnapshot> chunkSnapshot = new ArrayList<>(); List<ChunkSnapshot> chunkSnapshot = new ArrayList<>();
if (checking) { if (checking) {
Bukkit.getLogger().info("Checking");
Iterator<Pair<Integer, Integer>> it = chunksToScan.iterator(); Iterator<Pair<Integer, Integer>> it = chunksToScan.iterator();
if (!it.hasNext()) { if (!it.hasNext()) {
// TODO REMOVE
Bukkit.getLogger().info("Nothing left!");
// Nothing left // Nothing left
tidyUp(entity, failureMessage); tidyUp(entity, failureMessage);
return; return;
@ -96,8 +92,6 @@ public class SafeSpotTeleport {
// Move to next step // Move to next step
checking = false; checking = false;
checkChunks(chunkSnapshot); checkChunks(chunkSnapshot);
} else {
Bukkit.getLogger().info("Not checking");
} }
}, 0L, SPEED); }, 0L, SPEED);
} }
@ -164,18 +158,15 @@ public class SafeSpotTeleport {
* @param chunkSnapshot * @param chunkSnapshot
*/ */
private void checkChunks(List<ChunkSnapshot> chunkSnapshot) { private void checkChunks(List<ChunkSnapshot> chunkSnapshot) {
Bukkit.getLogger().info("Chunksnapshot = " + chunkSnapshot.size());
// Run async task to scan chunks // Run async task to scan chunks
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
for (ChunkSnapshot chunk: chunkSnapshot) { for (ChunkSnapshot chunk: chunkSnapshot) {
if (scanChunk(chunk)) { if (scanChunk(chunk)) {
Bukkit.getLogger().info("Safe sport found!");
task.cancel(); task.cancel();
return; return;
} }
} }
Bukkit.getLogger().info("not found in initial list");
// Nothing happened, change state // Nothing happened, change state
checking = true; checking = true;
}); });
@ -187,7 +178,6 @@ public class SafeSpotTeleport {
* @return true if a safe spot was found * @return true if a safe spot was found
*/ */
private boolean scanChunk(ChunkSnapshot chunk) { private boolean scanChunk(ChunkSnapshot chunk) {
Bukkit.getLogger().info("Scanning chunk " + chunk.getX() + " " + chunk.getZ());
// Max height // Max height
int maxHeight = location.getWorld().getMaxHeight() - 20; int maxHeight = location.getWorld().getMaxHeight() - 20;
// Run through the chunk // Run through the chunk
@ -196,7 +186,6 @@ public class SafeSpotTeleport {
// Work down from the entry point up // Work down from the entry point up
for (int y = Math.min(chunk.getHighestBlockYAt(x, z), maxHeight); y >= 0; y--) { for (int y = Math.min(chunk.getHighestBlockYAt(x, z), maxHeight); y >= 0; y--) {
if (checkBlock(chunk, x,y,z, maxHeight)) { if (checkBlock(chunk, x,y,z, maxHeight)) {
Bukkit.getLogger().info("Check block returned true");
return true; return true;
} }
} // end y } // end y
@ -209,17 +198,14 @@ public class SafeSpotTeleport {
* Teleports entity to the safe spot * Teleports entity to the safe spot
*/ */
private void teleportEntity(Location loc) { private void teleportEntity(Location loc) {
Bukkit.getLogger().info("Teleporting!");
task.cancel(); task.cancel();
// Return to main thread and teleport the player // Return to main thread and teleport the player
plugin.getServer().getScheduler().runTask(plugin, () -> { plugin.getServer().getScheduler().runTask(plugin, () -> {
if (!portal && entity instanceof Player) { if (!portal && entity instanceof Player) {
Bukkit.getLogger().info("Setting home");
// Set home // Set home
plugin.getPlayers().setHomeLocation(entity.getUniqueId(), loc, homeNumber); plugin.getPlayers().setHomeLocation(entity.getUniqueId(), loc, homeNumber);
} }
Vector velocity = entity.getVelocity(); Vector velocity = entity.getVelocity();
Bukkit.getLogger().info("Teleported!");
entity.teleport(loc); entity.teleport(loc);
// Exit spectator mode if in it // Exit spectator mode if in it
if (entity instanceof Player) { if (entity instanceof Player) {
@ -234,34 +220,6 @@ public class SafeSpotTeleport {
} }
/**
* Subscan to find the bottom of the portal
*/
/*
private Location checkPortal() {
if (portalPart == null) {
return;
}
// There is a portal available, but is it safe?
// Get the lowest portal spot
int x = portalPart.getBlockX();
int y = portalPart.getBlockY();
int z = portalPart.getBlockZ();
while (portalChunk.getBlockType(x,y,z).equals(Material.PORTAL)) {
y--;
}
//System.out.print("DEBUG: Portal teleport loc = " + (16 * portalChunk.getX() + x) + "," + (y) + "," + (16 * portalChunk.getZ() + z));
// Now check if this is a safe location
if (checkBlock(portalChunk,x,y,z, worldHeight)) {
// Yes, so use this instead of the highest location
//System.out.print("DEBUG: Portal is safe");
safeSpotFound = true;
safeSpotInChunk = new Vector(x,y,z);
safeChunk = portalChunk;
}
}*/
/** /**
* Returns true if the location is a safe one. * Returns true if the location is a safe one.
* @param chunk * @param chunk
@ -277,64 +235,62 @@ public class SafeSpotTeleport {
if (!type.equals(Material.AIR)) { // AIR if (!type.equals(Material.AIR)) { // AIR
Material space1 = chunk.getBlockType(x, Math.min(y + 1, worldHeight), z); Material space1 = chunk.getBlockType(x, Math.min(y + 1, worldHeight), z);
Material space2 = chunk.getBlockType(x, Math.min(y + 2, worldHeight), z); Material space2 = chunk.getBlockType(x, Math.min(y + 2, worldHeight), z);
if ((space1.equals(Material.AIR) && space2.equals(Material.AIR)) || (space1.equals(Material.PORTAL) && space2.equals(Material.PORTAL))) { if ((space1.equals(Material.AIR) && space2.equals(Material.AIR)) || (space1.equals(Material.PORTAL) && space2.equals(Material.PORTAL))
if (!type.toString().contains("FENCE") && !type.toString().contains("DOOR") && !type.toString().contains("GATE") && !type.toString().contains("PLATE")) { && (!type.toString().contains("FENCE") && !type.toString().contains("DOOR") && !type.toString().contains("GATE") && !type.toString().contains("PLATE"))) {
Bukkit.getLogger().info("Checking " + type); switch (type) {
switch (type) { // Unsafe
// Unsafe case ANVIL:
case ANVIL: case BARRIER:
case BARRIER: case BOAT:
case BOAT: case CACTUS:
case CACTUS: case DOUBLE_PLANT:
case DOUBLE_PLANT: case ENDER_PORTAL:
case ENDER_PORTAL: case FIRE:
case FIRE: case FLOWER_POT:
case FLOWER_POT: case LADDER:
case LADDER: case LAVA:
case LAVA: case LEVER:
case LEVER: case LONG_GRASS:
case LONG_GRASS: case PISTON_EXTENSION:
case PISTON_EXTENSION: case PISTON_MOVING_PIECE:
case PISTON_MOVING_PIECE: case SIGN_POST:
case SIGN_POST: case SKULL:
case SKULL: case STANDING_BANNER:
case STANDING_BANNER: case STATIONARY_LAVA:
case STATIONARY_LAVA: case STATIONARY_WATER:
case STATIONARY_WATER: case STONE_BUTTON:
case STONE_BUTTON: case TORCH:
case TORCH: case TRIPWIRE:
case TRIPWIRE: case WATER:
case WATER: case WEB:
case WEB: case WOOD_BUTTON:
case WOOD_BUTTON: //Block is dangerous
//Block is dangerous break;
break; case PORTAL:
case PORTAL: if (portal) {
if (portal) { Bukkit.getLogger().info("Portal found");
Bukkit.getLogger().info("Portal found");
Vector newSpot = new Vector(chunk.getX() * 16 + x + 0.5D, y + 1, chunk.getZ() * 16 + z + 0.5D);
// Teleport as soon as we find a portal
teleportEntity(newSpot.toLocation(world));
return true;
}
break;
default:
// Safe
Vector newSpot = new Vector(chunk.getX() * 16 + x + 0.5D, y + 1, chunk.getZ() * 16 + z + 0.5D); Vector newSpot = new Vector(chunk.getX() * 16 + x + 0.5D, y + 1, chunk.getZ() * 16 + z + 0.5D);
// Check for portal // Teleport as soon as we find a portal
if (portal) { teleportEntity(newSpot.toLocation(world));
if (bestSpot == null) { return true;
Bukkit.getLogger().info("Best spot found = " + bestSpot); }
// Stash the best spot break;
bestSpot = newSpot.toLocation(world); default:
return false; // Safe
} Vector newSpot = new Vector(chunk.getX() * 16 + x + 0.5D, y + 1, chunk.getZ() * 16 + z + 0.5D);
} else { // Check for portal
// Regular search - teleport as soon as we find something if (portal) {
Bukkit.getLogger().info("Safe spot found, teleporting to new spot"); if (bestSpot == null) {
teleportEntity(newSpot.toLocation(world)); Bukkit.getLogger().info("Best spot found = " + bestSpot);
return true; // Stash the best spot
bestSpot = newSpot.toLocation(world);
return false;
} }
} else {
// Regular search - teleport as soon as we find something
Bukkit.getLogger().info("Safe spot found, teleporting to new spot");
teleportEntity(newSpot.toLocation(world));
return true;
} }
} }
} }

View File

@ -1,9 +1,11 @@
package us.tastybento.bskyblock.util; package us.tastybento.bskyblock.util.teleport;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.BSkyBlock;
import us.tastybento.bskyblock.api.commands.User;
import us.tastybento.bskyblock.database.objects.Island; import us.tastybento.bskyblock.database.objects.Island;
public class SafeTeleportBuilder { public class SafeTeleportBuilder {
@ -12,7 +14,7 @@ public class SafeTeleportBuilder {
private Entity entity; private Entity entity;
private int homeNumber = 0; private int homeNumber = 0;
private boolean portal = false; private boolean portal = false;
private String failureMessage = "general.errors.warp-not-safe"; private String failureMessage = "";
private Location location; private Location location;
@ -84,7 +86,19 @@ public class SafeTeleportBuilder {
* Try to teleport the player * Try to teleport the player
* @return * @return
*/ */
public SafeSpotTeleport build() { public SafeSpotTeleport build() {
// Error checking
if (entity == null) {
plugin.getLogger().severe("Attempt to safe teleport a null entity!");
return null;
}
if (location == null) {
plugin.getLogger().severe("Attempt to safe teleport to a null location!");
return null;
}
if (failureMessage.isEmpty() && entity instanceof Player) {
failureMessage = User.getInstance(entity).getTranslation("general.errors.warp-not-safe");
}
return new SafeSpotTeleport(plugin, entity, location, failureMessage, portal, homeNumber); return new SafeSpotTeleport(plugin, entity, location, failureMessage, portal, homeNumber);
} }