diff --git a/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java b/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java index 272b1b5d7..af3dbbc9a 100644 --- a/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java +++ b/src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java @@ -316,7 +316,7 @@ public interface WorldSettings extends ConfigObject { */ @NonNull List getOnLeaveCommands(); - + /** * Returns a list of commands that should be executed when the player respawns after death if {@link Flags#ISLAND_RESPAWN} is true.
* @return a list of commands. @@ -537,4 +537,22 @@ public interface WorldSettings extends ConfigObject { { return "create"; } + + /** + * Make a nether portal when teleporting to the nether through an overworld portal + * @return true if a portal should be made + * @since 1.16.0 + */ + default boolean isMakeNetherPortals() { + return false; + } + + /** + * Make an end portal when teleporting to the end through an end portal + * @return true if a portal should be made + * @since 1.16.0 + */ + default boolean isMakeEndPortals() { + return false; + } } diff --git a/src/main/java/world/bentobox/bentobox/listeners/PlayerEntityPortalEvent.java b/src/main/java/world/bentobox/bentobox/listeners/PlayerEntityPortalEvent.java new file mode 100644 index 000000000..ed0cff519 --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/listeners/PlayerEntityPortalEvent.java @@ -0,0 +1,160 @@ +package world.bentobox.bentobox.listeners; + +import java.util.Optional; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.bukkit.event.entity.EntityPortalEvent; +import org.bukkit.event.player.PlayerPortalEvent; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; + +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.database.objects.Island; + +/** + * Abstracts PlayerPortalEvent and EntityPortalEvent + * @author tastybento + * + */ +public class PlayerEntityPortalEvent { + + private final EntityPortalEvent epe; + private final PlayerPortalEvent ppe; + + /** + * Create a hybrid PlayerEntityPortalEvent + * @param epe - EntityPortalEvent + */ + public PlayerEntityPortalEvent(EntityPortalEvent epe) { + this.ppe = null; + this.epe = epe; + } + + /** + * Create a hybrid PlayerEntityPortalEvent + * @param ppe - PlayerPortalEvent + */ + public PlayerEntityPortalEvent(PlayerPortalEvent ppe) { + this.ppe = ppe; + this.epe = null; + } + + /** + * Returns whether the server will attempt to create a destination portal or not. + * Only applicable to {@link PlayerPortalEvent} + * @return whether there should create be a destination portal created + */ + public boolean getCanCreatePortal() { + return epe == null ? ppe.getCanCreatePortal() : false; + } + + /** + * Returns the entity involved in this event + * @return Entity who is involved in this event + */ + @NonNull + public Entity getEntity() { + return epe == null ? ppe.getPlayer() : epe.getEntity(); + } + + /** + * Gets the location this player moved from + * @return Location the player or entity moved from + */ + @NonNull + public Location getFrom() { + return epe == null ? ppe.getFrom() : epe.getFrom(); + } + + /** + * Gets the location this player moved to + * @return Location the player moved to + */ + @Nullable + public Location getTo() { + return epe == null ? ppe.getTo() : epe.getTo(); + } + + /** + * @return true if constructed with an {@link EntityPortalEvent} + */ + public boolean isEntityPortalEvent() { + return epe != null; + } + + /** + * @return true if constructed with an {@link PlayerPortalEvent} + */ + public boolean isPlayerPortalEvent() { + return ppe != null; + } + + /** + * Sets the cancellation state of this event. A cancelled event will not be executed in the server, but will still pass to other plugins + * If a move or teleport event is cancelled, the player will be moved or teleported back to the Location as defined by getFrom(). This will not fire an event + * Specified by: setCancelled(...) in Cancellable + * @param cancel true if you wish to cancel this event + */ + public void setCancelled(boolean cancel) { + if (epe == null) { + ppe.setCancelled(cancel); + } else { + epe.setCancelled(cancel); + } + } + + /** + * Sets whether the server should attempt to create a destination portal or not. + * Only applicable to {@link PlayerPortalEvent} + * @param canCreatePortal Sets whether there should be a destination portal created + */ + public void setCanCreatePortal(boolean canCreatePortal) { + if (ppe != null) { + ppe.setCanCreatePortal(canCreatePortal); + } + + } + + /** + * Set the Block radius to search in for available portals. + * @param searchRadius the radius in which to search for a portal from the location + */ + public void setSearchRadius(int searchRadius) { + if (epe == null) { + ppe.setSearchRadius(searchRadius); + } else { + epe.setSearchRadius(searchRadius); + } + } + + /** + * Sets the location that this player will move to + * @param to New Location this player or entity will move to + */ + public void setTo(Location to) { + if (epe == null) { + ppe.setTo(to); + } else { + epe.setTo(to); + } + } + + /** + * Get island at the from location + * @return optional island at from location + */ + public Optional getIsland() { + return BentoBox.getInstance().getIslands().getProtectedIslandAt(getFrom()); + } + + /** + * Get the from world + * @return from world + */ + @Nullable + public World getWorld() { + return getFrom().getWorld(); + } +} diff --git a/src/main/java/world/bentobox/bentobox/listeners/PortalTeleportationListener.java b/src/main/java/world/bentobox/bentobox/listeners/PortalTeleportationListener.java index adce11c2d..d3af64304 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/PortalTeleportationListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/PortalTeleportationListener.java @@ -1,5 +1,6 @@ package world.bentobox.bentobox.listeners; +import java.util.Arrays; import java.util.HashSet; import java.util.Optional; import java.util.Set; @@ -10,12 +11,14 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.World.Environment; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPortalEnterEvent; import org.bukkit.event.entity.EntityPortalEvent; -import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; @@ -23,6 +26,7 @@ import org.bukkit.util.Vector; import org.eclipse.jdt.annotation.NonNull; import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.blueprints.Blueprint; import world.bentobox.bentobox.blueprints.BlueprintPaster; import world.bentobox.bentobox.blueprints.dataobjects.BlueprintBundle; @@ -57,19 +61,23 @@ public class PortalTeleportationListener implements Listener { * @param e */ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerPortal(PlayerMoveEvent e) { - UUID uuid = e.getPlayer().getUniqueId(); - if (inPortal.contains(uuid) || !plugin.getIWM().inWorld(Util.getWorld(e.getFrom().getWorld()))) { + public void onPlayerPortal(EntityPortalEnterEvent e) { + if (!(e.getEntity() instanceof Player)) { return; } - if (!Bukkit.getAllowNether() && e.getPlayer().getLocation().getBlock().getType().equals(Material.NETHER_PORTAL)) { + Material type = e.getLocation().getBlock().getType(); + UUID uuid = e.getEntity().getUniqueId(); + if (inPortal.contains(uuid) || !plugin.getIWM().inWorld(Util.getWorld(e.getLocation().getWorld()))) { + return; + } + if (!Bukkit.getAllowNether() && type.equals(Material.NETHER_PORTAL)) { inPortal.add(uuid); // Schedule a time Bukkit.getScheduler().runTaskLater(plugin, () -> { // Check again if still in portal - if (e.getPlayer().getLocation().getBlock().getType().equals(Material.NETHER_PORTAL)) { - PlayerPortalEvent en = new PlayerPortalEvent(e.getPlayer(), e.getPlayer().getLocation(), null, TeleportCause.NETHER_PORTAL, 0, false, 0); - if (!this.onNetherPortal(en)) { + if (type.equals(Material.NETHER_PORTAL)) { + PlayerPortalEvent en = new PlayerPortalEvent((Player)e.getEntity(), e.getLocation(), null, TeleportCause.NETHER_PORTAL, 0, false, 0); + if (!this.onIslandPortal(en)) { // Failed inPortal.remove(uuid); } @@ -79,9 +87,16 @@ public class PortalTeleportationListener implements Listener { }, 40); return; } - if (!Bukkit.getAllowEnd() && e.getPlayer().getLocation().getBlock().getType().equals(Material.END_PORTAL)) { - PlayerPortalEvent en = new PlayerPortalEvent(e.getPlayer(), e.getPlayer().getLocation(), null, TeleportCause.END_PORTAL, 0, false, 0); - this.onEndIslandPortal(en); + // End portals are instant transfer + if (!Bukkit.getAllowEnd() && (type.equals(Material.END_PORTAL) || type.equals(Material.END_GATEWAY))) { + PlayerPortalEvent en = new PlayerPortalEvent((Player)e.getEntity(), + e.getLocation(), + null, + type.equals(Material.END_PORTAL) ? TeleportCause.END_PORTAL : TeleportCause.END_GATEWAY, + 0, + false, + 0); + this.onIslandPortal(en); } } @@ -92,124 +107,52 @@ public class PortalTeleportationListener implements Listener { * @param e - event */ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onEntityPortal(EntityPortalEvent e) { + public boolean onEntityPortal(EntityPortalEvent e) { if (plugin.getIWM().inWorld(e.getFrom())) { - // Disable entity portal transfer due to dupe glitching - e.setCancelled(true); + Optional mat = Arrays.stream(BlockFace.values()) + .map(bf -> e.getFrom().getBlock().getRelative(bf).getType()) + .filter(m -> m.equals(Material.NETHER_PORTAL) + || m.equals(Material.END_PORTAL) + || m.equals(Material.END_GATEWAY)) + .findFirst(); + if (!mat.isPresent()) { + e.setCancelled(true); + return false; + } else if (mat.get().equals(Material.NETHER_PORTAL)){ + return processPortal(new PlayerEntityPortalEvent(e), Environment.NETHER); + } else { + return processPortal(new PlayerEntityPortalEvent(e), Environment.THE_END); + } } + return false; } /** - * Handles end portals + * Handles nether or end portals * @param e - event */ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - public boolean onEndIslandPortal(PlayerPortalEvent e) { - if (e.getCause() != TeleportCause.END_PORTAL) { - return false; - } - World fromWorld = e.getFrom().getWorld(); - World overWorld = Util.getWorld(fromWorld); - - if (fromWorld == null || !plugin.getIWM().inWorld(overWorld)) { - // Do nothing special + public boolean onIslandPortal(PlayerPortalEvent e) { + switch (e.getCause()) { + case END_GATEWAY: + case END_PORTAL: + return processPortal(new PlayerEntityPortalEvent(e), Environment.THE_END); + case NETHER_PORTAL: + return processPortal(new PlayerEntityPortalEvent(e), Environment.NETHER); + default: return false; } - // 1.14.4 requires explicit cancellation to prevent teleporting to the normal nether - if (!plugin.getIWM().isEndGenerate(overWorld)) { - e.setCancelled(true); - return false; - } - - // STANDARD END - if (!plugin.getIWM().isEndIslands(overWorld)) { - if (fromWorld.getEnvironment() != Environment.THE_END) { - if (Bukkit.getAllowEnd()) { - // To Standard end - e.setTo(plugin.getIWM().getEndWorld(overWorld).getSpawnLocation()); - } else { - new SafeSpotTeleport.Builder(plugin) - .entity(e.getPlayer()) - .location(plugin.getIWM().getEndWorld(overWorld).getSpawnLocation()) - .thenRun(() -> inPortal.remove(e.getPlayer().getUniqueId())) - .build(); - } - } - // From standard end - check if player has an island to go to - else if (plugin.getIslands().hasIsland(overWorld, e.getPlayer().getUniqueId()) - || plugin.getIslands().inTeam(overWorld, e.getPlayer().getUniqueId())) { - e.setCancelled(true); - plugin.getIslands().homeTeleportAsync(overWorld, e.getPlayer()); - } - // No island, so just do nothing - return false; - } - - // FROM END - // If entering an ender portal in the End. - if (fromWorld.getEnvironment() == Environment.THE_END) { - // If this is from the island nether, then go to the same vector, otherwise try island home location - Location to = plugin.getIslands().getIslandAt(e.getFrom()).map(i -> i.getSpawnPoint(Environment.NORMAL)).orElseGet(() -> e.getFrom().toVector().toLocation(overWorld)); - e.setCancelled(true); - // Else other worlds teleport to the overworld - new SafeSpotTeleport.Builder(plugin) - .entity(e.getPlayer()) - .location(to) - .portal() - .build(); - return true; - } - // TO END - - World endWorld = plugin.getIWM().getEndWorld(overWorld); - // If this is to island End, then go to the same vector, otherwise try spawn - Optional optionalIsland = plugin.getIslands().getIslandAt(e.getFrom()); - Location to = optionalIsland.map(i -> i.getSpawnPoint(Environment.THE_END)).orElseGet(() -> e.getFrom().toVector().toLocation(endWorld)); - e.setCancelled(true); - // Check if there is a missing end island - if (plugin.getIWM().isPasteMissingIslands(overWorld) - && !plugin.getIWM().isUseOwnGenerator(overWorld) - && plugin.getIWM().isEndGenerate(overWorld) - && plugin.getIWM().isEndIslands(overWorld) - && plugin.getIWM().getEndWorld(overWorld) != null - && optionalIsland.filter(i -> !i.hasEndIsland()) - .map(i -> { - // No end island present so paste the default one - pasteNewIsland(e.getPlayer(), to, i, Environment.THE_END); - return true; - }).orElse(false)) { - // We are done here - return true; - } - // Set player's velocity and fall distance to 0 - e.getPlayer().setVelocity(new Vector(0,0,0)); - e.getPlayer().setFallDistance(0); - - // Else other worlds teleport to the end - // Set player's velocity to zero one tick after cancellation - // Teleport - new SafeSpotTeleport.Builder(plugin) - .entity(e.getPlayer()) - .location(to) - .thenRun(() -> { - e.getPlayer().setVelocity(new Vector(0,0,0)); - e.getPlayer().setFallDistance(0); - }) - .build(); - return true; } /** - * Handles nether portals. + * Process the portal action * @param e - event - * @return false if teleport does not happen, true if it does + * @param env - environment that this relates to - NETHER or THE_END + * @return true if portal happens, false if not */ - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) // Use HIGH to allow Multiverse first shot - public boolean onNetherPortal(PlayerPortalEvent e) { - if (e.getCause() != TeleportCause.NETHER_PORTAL) { - return false; - } + private boolean processPortal(final PlayerEntityPortalEvent e, final Environment env) { + World fromWorld = e.getFrom().getWorld(); World overWorld = Util.getWorld(fromWorld); if (fromWorld == null || !plugin.getIWM().inWorld(overWorld)) { @@ -217,77 +160,262 @@ public class PortalTeleportationListener implements Listener { return false; } // 1.14.4 requires explicit cancellation to prevent teleporting to the normal nether - if (!plugin.getIWM().isNetherGenerate(overWorld)) { + if (!isGenerate(overWorld, env)) { e.setCancelled(true); return false; } - // STANDARD NETHER - if (!plugin.getIWM().isNetherIslands(overWorld)) { - if (fromWorld.getEnvironment() != Environment.NETHER) { - if (Bukkit.getAllowNether()) { - // To Standard Nether - e.setTo(plugin.getIWM().getNetherWorld(overWorld).getSpawnLocation()); - } else { - // Teleport to standard nether - new SafeSpotTeleport.Builder(plugin) - .entity(e.getPlayer()) - .location(plugin.getIWM().getNetherWorld(fromWorld).getSpawnLocation()) - .portal() - .build(); - } - } - // From standard nether - else { - e.setCancelled(true); - plugin.getIslands().homeTeleportAsync(overWorld, e.getPlayer()).thenAccept(b -> inPortal.remove(e.getPlayer().getUniqueId())); - } + // STANDARD NETHER OR END + if (!isIslands(overWorld, env)) { + handleStandardNetherOrEnd(e, fromWorld, overWorld, env); return true; } - // FROM NETHER - // If entering a nether portal in the nether, teleport to portal in overworld if there is one - if (fromWorld.getEnvironment() == Environment.NETHER) { - // If this is from the island nether, then go to the same vector, otherwise try island home location - Location to = plugin.getIslands().getIslandAt(e.getFrom()).map(i -> i.getSpawnPoint(Environment.NORMAL)).orElseGet(() -> e.getFrom().toVector().toLocation(overWorld)); - e.setCancelled(true); - // Else other worlds teleport to the nether - new SafeSpotTeleport.Builder(plugin) - .entity(e.getPlayer()) - .location(to) - .portal() - .thenRun(() -> inPortal.remove(e.getPlayer().getUniqueId())) - .build(); + // FROM NETHER OR END + // If entering a portal in the other world, teleport to a portal in overworld if there is one + if (fromWorld.getEnvironment().equals(env)) { + handleFromNetherOrEnd(e, overWorld, env); return true; } - // TO NETHER - World nether = plugin.getIWM().getNetherWorld(overWorld); - // If this is to island nether, then go to the same vector, otherwise try spawn - Optional optionalIsland = plugin.getIslands().getIslandAt(e.getFrom()); - Location to = optionalIsland.map(i -> i.getSpawnPoint(Environment.NETHER)).orElseGet(() -> e.getFrom().toVector().toLocation(nether)); - e.setCancelled(true); + // TO NETHER OR END + World toWorld = getNetherEndWorld(overWorld, env); + // Set whether portals should be created or not + e.setCanCreatePortal(plugin.getIWM().getAddon(overWorld).map(gm -> isMakePortals(gm, env)).orElse(false)); + // Set the destination location + // If portals cannot be created, then destination is the spawn point, otherwise it's the vector + e.setTo(getTo(e, env, toWorld)); + + // Find the distance from edge of island's protection and set the search radius + e.getIsland().ifPresent(i -> setSeachRadius(e, i)); + // Check if there is an island there or not - if (plugin.getIWM().isPasteMissingIslands(overWorld) && - !plugin.getIWM().isUseOwnGenerator(overWorld) - && plugin.getIWM().isNetherGenerate(overWorld) - && plugin.getIWM().isNetherIslands(overWorld) - && plugin.getIWM().getNetherWorld(overWorld) != null - && optionalIsland.filter(i -> !i.hasNetherIsland()).map(i -> { + if (e.getEntity().getType().equals(EntityType.PLAYER) + && plugin.getIWM().isPasteMissingIslands(overWorld) + && !plugin.getIWM().isUseOwnGenerator(overWorld) + && isGenerate(overWorld, env) + && isIslands(overWorld, env) + && getNetherEndWorld(overWorld, env) != null + && e.getIsland().filter(i -> !hasPartnerIsland(i, env)).map(i -> { // No nether island present so paste the default one - pasteNewIsland(e.getPlayer(), to, i, Environment.NETHER); + e.setCancelled(true); + inPortal.remove(e.getEntity().getUniqueId()); + pasteNewIsland((Player)e.getEntity(), e.getTo(), i, env); return true; }).orElse(false)) { // All done here return true; } - // Else other worlds teleport to the nether - new SafeSpotTeleport.Builder(plugin) - .entity(e.getPlayer()) - .location(to) - .portal() - .thenRun(() -> inPortal.remove(e.getPlayer().getUniqueId())) - .build(); + if (e.getCanCreatePortal()) { + // Let the server teleport + inPortal.remove(e.getEntity().getUniqueId()); + return true; + } + if (env.equals(Environment.THE_END)) { + // Prevent death from hitting the ground + e.getEntity().setVelocity(new Vector(0,0,0)); + e.getEntity().setFallDistance(0); + } + // If there is a portal to go to already, then the player will go there + Bukkit.getScheduler().runTask(plugin, () -> { + if (!e.getEntity().getWorld().equals(toWorld)) { + // Else manually teleport entity + new SafeSpotTeleport.Builder(plugin) + .entity(e.getEntity()) + .location(e.getTo()) + .portal() + .thenRun(() -> { + inPortal.remove(e.getEntity().getUniqueId()); + e.getEntity().setVelocity(new Vector(0,0,0)); + e.getEntity().setFallDistance(0); + }) + .build(); + } + }); return true; } + + /** + * Set the destination of this portal action + * @param e - event + * @param env - environment + * @param toWorld - to world + */ + Location getTo(PlayerEntityPortalEvent e, Environment env, World toWorld) { + // Null check - not that useful + if (e.getFrom().getWorld() == null || toWorld == null) { + return null; + } + if (!e.getCanCreatePortal()) { + // Legacy portaling + return e.getIsland().map(i -> i.getSpawnPoint(env)).orElse(e.getFrom().toVector().toLocation(toWorld)); + } + // Make portals + // For anywhere other than the end - it is the player's location that is used + if (!env.equals(Environment.THE_END)) { + return e.getFrom().toVector().toLocation(toWorld); + } + // If the-end then we want the platform to always be generated in the same place no matter where + // they enter the portal + final int x = e.getFrom().getBlockX(); + final int z = e.getFrom().getBlockZ(); + final int y = e.getFrom().getBlockY(); + int i = x; + int j = z; + int k = y; + // If the from is not a portal, then we have to find it + if (!e.getFrom().getBlock().getType().equals(Material.END_PORTAL)) { + // Find the portal - due to speed, it is possible that the player will be below or above the portal + for (k = 0; (k < e.getWorld().getMaxHeight()) && !e.getWorld().getBlockAt(x, k, z).getType().equals(Material.END_PORTAL); k++); + } + // Find the maximum x and z corner + for (; (i < x + 5) && e.getWorld().getBlockAt(i, k, z).getType().equals(Material.END_PORTAL); i++); + for (; (j < z + 5) && e.getWorld().getBlockAt(x, k, j).getType().equals(Material.END_PORTAL); j++); + return new Location(toWorld, i, k, j); + } + + + /** + * Check if vanilla portals should be used + * @param gm - game mode + * @param env - environment + * @return true or false + */ + private boolean isMakePortals(GameModeAddon gm, Environment env) { + return env.equals(Environment.NETHER) ? gm.getWorldSettings().isMakeNetherPortals() : gm.getWorldSettings().isMakeEndPortals(); + } + + /** + * Check if nether or end are generated + * @param gm - game mode + * @param env - environment + * @return true or false + */ + private boolean isGenerate(World overWorld, Environment env) { + return env.equals(Environment.NETHER) ? plugin.getIWM().isNetherGenerate(overWorld) : plugin.getIWM().isEndGenerate(overWorld); + } + + /** + * Check if nether or end islands are generated + * @param gm - game mode + * @param env - environment + * @return true or false + */ + private boolean isIslands(World overWorld, Environment env) { + return env.equals(Environment.NETHER) ? plugin.getIWM().isNetherIslands(overWorld) : plugin.getIWM().isEndIslands(overWorld); + } + + /** + * Get the nether or end world + * @param gm - game mode + * @param env - environment + * @return nether or end world + */ + private World getNetherEndWorld(World overWorld, Environment env) { + return env.equals(Environment.NETHER) ? plugin.getIWM().getNetherWorld(overWorld) : plugin.getIWM().getEndWorld(overWorld); + } + + /** + * Check if the island has a nether or end island already + * @param gm - game mode + * @param env - environment + * @return true or false + */ + private boolean hasPartnerIsland(Island i, Environment env) { + return env.equals(Environment.NETHER) ? i.hasNetherIsland() : i.hasEndIsland(); + } + + /** + * Check if the default nether or end are allowed by the server settings + * @param gm - game mode + * @param env - environment + * @return true or false + */ + private boolean isAllowedOnServer(Environment env) { + return env.equals(Environment.NETHER) ? Bukkit.getAllowNether() : Bukkit.getAllowEnd(); + } + + /** + * Handle teleport from nether or end to overworld + * @param e - event + * @param overWorld - over world + * @param env - environment + */ + private void handleFromNetherOrEnd(PlayerEntityPortalEvent e, World overWorld, Environment env) { + // Standard portals + if (plugin.getIWM().getAddon(overWorld).map(gm -> isMakePortals(gm, env)).orElse(false)) { + e.setTo(e.getFrom().toVector().toLocation(overWorld)); + // Find distance from edge of island's protection + plugin.getIslands().getIslandAt(e.getFrom()).ifPresent(i -> setSeachRadius(e, i)); + inPortal.remove(e.getEntity().getUniqueId()); + return; + } + // Custom portals + e.setCancelled(true); + // If this is from the island nether or end, then go to the same vector, otherwise try island home location + Location to = plugin.getIslands().getIslandAt(e.getFrom()).map(i -> i.getSpawnPoint(Environment.NORMAL)).orElse(e.getFrom().toVector().toLocation(overWorld)); + e.setTo(to); + // Else other worlds teleport to the nether + new SafeSpotTeleport.Builder(plugin) + .entity(e.getEntity()) + .location(to) + .portal() + .thenRun(() -> inPortal.remove(e.getEntity().getUniqueId())) + .build(); + + } + + + /** + * Handle teleport from or to standard nether or end + * @param e + * @param fromWorld + * @param overWorld + * @param env + */ + private void handleStandardNetherOrEnd(PlayerEntityPortalEvent e, World fromWorld, World overWorld, Environment env) { + if (fromWorld.getEnvironment() != env) { + World toWorld = getNetherEndWorld(overWorld, env); + Location spawnPoint = toWorld.getSpawnLocation(); + // If spawn is set as 0,63,0 in the End then move it to 100, 50 ,0. + if (env.equals(Environment.THE_END) && spawnPoint.toVector().equals(new Vector(0,63,0))) { + // Set to the default end spawn + spawnPoint = new Location(toWorld, 100, 50, 0); + toWorld.setSpawnLocation(100, 50, 0); + } + if (isAllowedOnServer(env)) { + // To Standard Nether or end + plugin.logDebug("Spawn = " + spawnPoint); + e.setTo(spawnPoint); + } else { + plugin.logDebug("Spawn = " + spawnPoint); + // Teleport to standard nether or end + new SafeSpotTeleport.Builder(plugin) + .entity(e.getEntity()) + .location(spawnPoint) + .portal() + .build(); + } + } + // From standard nether or end + else if (e.getEntity() instanceof Player){ + e.setCancelled(true); + plugin.getIslands().homeTeleportAsync(overWorld, (Player)e.getEntity()).thenAccept(b -> inPortal.remove(e.getEntity().getUniqueId())); + } + + } + + + void setSeachRadius(PlayerEntityPortalEvent e, Island i) { + if (!i.onIsland(e.getFrom())) return; + // Find max x or max z + int x = Math.abs(i.getCenter().getBlockX() - e.getFrom().getBlockX()); + int z = Math.abs(i.getCenter().getBlockZ() - e.getFrom().getBlockZ()); + int diff = i.getProtectionRange() - Math.max(x, z); + if (diff > 0 && diff < 128) { + e.setSearchRadius(diff); + } + } + + /** * Pastes the default nether or end island and teleports the player to the island's spawn point * @param player - player to teleport after pasting diff --git a/src/test/java/world/bentobox/bentobox/listeners/PortalTeleportationListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/PortalTeleportationListenerTest.java index b6fc0afa8..9da3be7e3 100644 --- a/src/test/java/world/bentobox/bentobox/listeners/PortalTeleportationListenerTest.java +++ b/src/test/java/world/bentobox/bentobox/listeners/PortalTeleportationListenerTest.java @@ -1,11 +1,13 @@ package world.bentobox.bentobox.listeners; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -16,9 +18,12 @@ import java.util.concurrent.CompletableFuture; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.World.Environment; +import org.bukkit.block.Block; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityPortalEvent; import org.bukkit.event.player.PlayerPortalEvent; @@ -40,6 +45,7 @@ import org.powermock.reflect.Whitebox; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.configuration.WorldSettings; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.blueprints.Blueprint; import world.bentobox.bentobox.blueprints.BlueprintPaster; @@ -79,6 +85,10 @@ public class PortalTeleportationListenerTest { private BlueprintsManager bpm; @Mock private GameModeAddon gameModeAddon; + @Mock + private WorldSettings ws; + @Mock + private Player player; @Before public void setUp() throws Exception { @@ -102,7 +112,7 @@ public class PortalTeleportationListenerTest { when(iwm.getNetherSpawnRadius(any())).thenReturn(100); when(plugin.getIWM()).thenReturn(iwm); - PowerMockito.mockStatic(Util.class); + PowerMockito.mockStatic(Util.class, Mockito.RETURNS_MOCKS); when(Util.getWorld(any())).thenReturn(world); // Settings @@ -167,7 +177,11 @@ public class PortalTeleportationListenerTest { defaultBB.setBlueprint(World.Environment.THE_END, bp); when(bpm.getDefaultBlueprintBundle(any())).thenReturn(defaultBB); when(bpm.getBlueprints(any())).thenReturn(Collections.singletonMap("blueprintname", bp)); - // Paster + // World Settings + when(gameModeAddon.getWorldSettings()).thenReturn(ws); + + // Player + when(player.getType()).thenReturn(EntityType.PLAYER); } @@ -183,26 +197,26 @@ public class PortalTeleportationListenerTest { } /** - * Test method for {@link PortalTeleportationListener#onEndIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnEndIslandPortalNotEnd() { + public void testonIslandPortalNotEnd() { Location from = mock(Location.class); // Teleport from world to nether when(from.getWorld()).thenReturn(world); when(from.toVector()).thenReturn(new Vector(1,2,3)); PortalTeleportationListener np = new PortalTeleportationListener(plugin); // Wrong cause - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.CHORUS_FRUIT); - np.onEndIslandPortal(e); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.CHORUS_FRUIT); + np.onIslandPortal(e); assertFalse(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onEndIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnEndIslandPortalNoEndWorldGenerated() { + public void testonIslandPortalNoEndWorldGenerated() { Location from = mock(Location.class); // Teleport from world to end when(from.getWorld()).thenReturn(world); @@ -210,46 +224,46 @@ public class PortalTeleportationListenerTest { // No end world when(iwm.isEndGenerate(any())).thenReturn(false); PortalTeleportationListener np = new PortalTeleportationListener(plugin); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.END_PORTAL); - np.onEndIslandPortal(e); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.END_PORTAL); + np.onIslandPortal(e); assertTrue(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onEndIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnEndIslandPortalWrongWorld() { + public void testonIslandPortalWrongWorld() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location loc = mock(Location.class); // Right cause, end exists, wrong world when(loc.getWorld()).thenReturn(mock(World.class)); wrongWorld(); - PlayerPortalEvent e = new PlayerPortalEvent(null, loc, null, TeleportCause.END_PORTAL); + PlayerPortalEvent e = new PlayerPortalEvent(player, loc, null, TeleportCause.END_PORTAL); when(iwm.isEndGenerate(world)).thenReturn(true); - np.onEndIslandPortal(e); + np.onIslandPortal(e); assertFalse(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onEndIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnEndIslandPortalNullWorld() { + public void testonIslandPortalNullWorld() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location loc = mock(Location.class); when(loc.getWorld()).thenReturn(null); - PlayerPortalEvent e = new PlayerPortalEvent(null, loc, null, TeleportCause.END_PORTAL); - assertFalse(np.onEndIslandPortal(e)); + PlayerPortalEvent e = new PlayerPortalEvent(player, loc, null, TeleportCause.END_PORTAL); + assertFalse(np.onIslandPortal(e)); assertFalse(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onEndIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnEndIslandPortalHome() { + public void testonIslandPortalHome() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from end @@ -262,27 +276,29 @@ public class PortalTeleportationListenerTest { // Right cause, end exists, right world PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.END_PORTAL); when(iwm.isEndGenerate(world)).thenReturn(true); - np.onEndIslandPortal(e); - assertFalse(e.isCancelled()); + // No island for player + when(im.hasIsland(any(), any(UUID.class))).thenReturn(false); + np.onIslandPortal(e); + assertTrue(e.isCancelled()); // Give player an island when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); - np.onEndIslandPortal(e); + np.onIslandPortal(e); assertTrue(e.isCancelled()); - verify(im).homeTeleportAsync(any(), eq(player)); + verify(im, times(2)).homeTeleportAsync(any(), eq(player)); } /** - * Test method for {@link PortalTeleportationListener#onEndIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnEndIslandPortalNonBentoBoxWorld() { + public void testonIslandPortalNonBentoBoxWorld() { when(iwm.inWorld(any(World.class))).thenReturn(false); PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from nether to world when(from.getWorld()).thenReturn(mock(World.class)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); - assertFalse(np.onEndIslandPortal(e)); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); + assertFalse(np.onIslandPortal(e)); // Verify assertFalse(e.isCancelled()); verify(iwm, never()).isEndGenerate(any()); @@ -295,8 +311,14 @@ public class PortalTeleportationListenerTest { public void testOnEntityPortal() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Entity ent = mock(Entity.class); + when(ent.getType()).thenReturn(EntityType.VILLAGER); + when(ent.getWorld()).thenReturn(world); Location from = mock(Location.class); - when(from.getWorld()).thenReturn(mock(World.class)); + when(from.getWorld()).thenReturn(world); + Block block = mock(Block.class); + when(from.getBlock()).thenReturn(block); + when(block.getRelative(any())).thenReturn(block); + when(block.getType()).thenReturn(Material.NETHER_PORTAL); // Not in world wrongWorld(); EntityPortalEvent e = new EntityPortalEvent(ent, from, null); @@ -307,49 +329,49 @@ public class PortalTeleportationListenerTest { when(iwm.inWorld(any(Location.class))).thenReturn(true); e = new EntityPortalEvent(ent, from, null); np.onEntityPortal(e); - assertTrue(e.isCancelled()); + assertFalse(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalNotPortal() { + public void testonIslandPortalNotPortal() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); - PlayerPortalEvent e = new PlayerPortalEvent(null, null, null, TeleportCause.COMMAND); - assertFalse(np.onNetherPortal(e)); + PlayerPortalEvent e = new PlayerPortalEvent(player, null, null, TeleportCause.COMMAND); + assertFalse(np.onIslandPortal(e)); } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalWrongWorld() { + public void testonIslandPortalWrongWorldNether() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); when(from.getWorld()).thenReturn(mock(World.class)); wrongWorld(); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); - assertFalse(np.onNetherPortal(e)); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); + assertFalse(np.onIslandPortal(e)); } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalFromWorldToNetherIsland() { + public void testonIslandPortalFromWorldToNetherIsland() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from world to nether when(from.getWorld()).thenReturn(world); when(from.toVector()).thenReturn(new Vector(1,2,3)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); // Nether islands active when(iwm.isNetherIslands(any())).thenReturn(true); when(iwm.isNetherGenerate(any())).thenReturn(true); - assertTrue(np.onNetherPortal(e)); - // Verify - assertTrue(e.isCancelled()); + assertTrue(np.onIslandPortal(e)); + // Event is not canceled + assertFalse(e.isCancelled()); // If nether islands, then to = from but in nether verify(from).toVector(); // Do not go to spawn @@ -357,105 +379,52 @@ public class PortalTeleportationListenerTest { } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalFromWorldToNetherIslandPasteBlueprintError() { + public void testonIslandPortalFromWorldToNetherIslandWithSpawnDefined() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); + Location to = mock(Location.class); + when(to.getWorld()).thenReturn(world); // Teleport from world to nether when(from.getWorld()).thenReturn(world); when(from.toVector()).thenReturn(new Vector(1,2,3)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); - // Nether islands active - when(iwm.isNetherIslands(any())).thenReturn(true); - when(iwm.isNetherGenerate(any())).thenReturn(true); - // Paste - when(iwm.isPasteMissingIslands(any())).thenReturn(true); - Island isle = mock(Island.class); - when(isle.getWorld()).thenReturn(world); - when(isle.hasEndIsland()).thenReturn(false); - Optional island = Optional.of(isle ); - when(im.getIslandAt(any())).thenReturn(island); - // No bp - when(bpm.getBlueprints(any())).thenReturn(Collections.emptyMap()); - // Test - assertTrue(np.onNetherPortal(e)); - // Error - verify(plugin).logError(eq("Could not paste default island in nether or end. Is there a nether-island or end-island blueprint?")); - } - - /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. - */ - @Test - public void testOnNetherPortalFromWorldToNetherIslandPasteBlueprint() { - PortalTeleportationListener np = new PortalTeleportationListener(plugin); - Location from = mock(Location.class); - // Teleport from world to nether - when(from.getWorld()).thenReturn(world); - when(from.toVector()).thenReturn(new Vector(1,2,3)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); - // Nether islands active - when(iwm.isNetherIslands(any())).thenReturn(true); - when(iwm.isNetherGenerate(any())).thenReturn(true); - // Paste - when(iwm.isPasteMissingIslands(any())).thenReturn(true); - Island isle = mock(Island.class); - when(isle.getWorld()).thenReturn(world); - when(isle.getCenter()).thenReturn(from); - when(isle.hasEndIsland()).thenReturn(false); - Optional island = Optional.of(isle ); - when(im.getIslandAt(any())).thenReturn(island); - // Test - assertTrue(np.onNetherPortal(e)); - // Error - verify(plugin, never()).logError(eq("Could not paste default island in nether or end. Is there a nether-island or end-island blueprint?")); - } - - /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. - */ - @Test - public void testOnNetherPortalFromWorldToNetherIslandWithSpawnDefined() { - PortalTeleportationListener np = new PortalTeleportationListener(plugin); - Location from = mock(Location.class); - // Teleport from world to nether - when(from.getWorld()).thenReturn(world); - when(from.toVector()).thenReturn(new Vector(1,2,3)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, to, TeleportCause.NETHER_PORTAL); // Nether islands active when(iwm.isNetherIslands(any())).thenReturn(true); when(iwm.isNetherGenerate(any())).thenReturn(true); + when(iwm.getNetherWorld(any())).thenReturn(nether); Island island = mock(Island.class); Location spawnLoc = mock(Location.class); + when(spawnLoc.getWorld()).thenReturn(world); when(island.getSpawnPoint(any())).thenReturn(spawnLoc); Optional optionalIsland = Optional.of(island); // Island exists at location when(im.getIslandAt(any())).thenReturn(optionalIsland); - assertTrue(np.onNetherPortal(e)); + assertTrue(np.onIslandPortal(e)); // Verify - assertTrue(e.isCancelled()); - // If nether islands, then to spawn location - verify(island).getSpawnPoint(eq(Environment.NETHER)); - // Do not go to from - verify(from, never()).toVector(); + assertFalse(e.isCancelled()); + // If nether islands, then to = from but in nether + verify(from).toVector(); + // Do not go to spawn + verify(nether, never()).getSpawnLocation(); } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalFromWorldToNetherIslandWithNoSpawnDefined() { + public void testonIslandPortalFromWorldToNetherIslandWithNoSpawnDefined() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from world to nether when(from.getWorld()).thenReturn(world); when(from.toVector()).thenReturn(new Vector(1,2,3)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); // Nether islands active when(iwm.isNetherIslands(any())).thenReturn(true); when(iwm.isNetherGenerate(any())).thenReturn(true); @@ -467,9 +436,9 @@ public class PortalTeleportationListenerTest { when(im.getIslandAt(any())).thenReturn(optionalIsland); - assertTrue(np.onNetherPortal(e)); + assertTrue(np.onIslandPortal(e)); // Verify - assertTrue(e.isCancelled()); + assertFalse(e.isCancelled()); // If nether islands, then to = from but in nether verify(from).toVector(); // Do not go to spawn @@ -477,30 +446,30 @@ public class PortalTeleportationListenerTest { } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalFromWorldToNetherStandard() { + public void testonIslandPortalFromWorldToNetherStandard() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from world to nether when(from.getWorld()).thenReturn(world); when(from.toVector()).thenReturn(new Vector(1,2,3)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); // Nether islands inactive when(iwm.isNetherIslands(any())).thenReturn(false); when(iwm.isNetherGenerate(any())).thenReturn(true); - assertTrue(np.onNetherPortal(e)); + assertTrue(np.onIslandPortal(e)); // Verify assertFalse(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. * @throws Exception */ @Test - public void testOnNetherPortalFromNetherStandard() throws Exception { + public void testonIslandPortalFromNetherStandard() throws Exception { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from nether to world @@ -515,26 +484,26 @@ public class PortalTeleportationListenerTest { when(iwm.isNetherGenerate(any())).thenReturn(true); // Player should be teleported to their island - assertTrue(np.onNetherPortal(e)); + assertTrue(np.onIslandPortal(e)); // Verify assertTrue(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalFromNetherIsland() { + public void testonIslandPortalFromNetherIsland() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from nether to world when(from.getWorld()).thenReturn(nether); when(from.toVector()).thenReturn(new Vector(1,2,3)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); // Nether islands active when(iwm.isNetherIslands(any())).thenReturn(true); when(iwm.isNetherGenerate(any())).thenReturn(true); - assertTrue(np.onNetherPortal(e)); + assertTrue(np.onIslandPortal(e)); // Verify assertTrue(e.isCancelled()); // If regular nether, then to = island location @@ -543,48 +512,81 @@ public class PortalTeleportationListenerTest { } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherIslandPortalNullLocation() { - PortalTeleportationListener np = new PortalTeleportationListener(plugin); - Location loc = null; - PlayerPortalEvent e = new PlayerPortalEvent(null, loc, null, TeleportCause.END_PORTAL); - assertFalse(np.onNetherPortal(e)); - assertFalse(e.isCancelled()); - } - - /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. - */ - @Test - public void testOnNetherPortalNullWorld() { + public void testonIslandPortalNullWorldNether() { PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from nether to world when(from.getWorld()).thenReturn(null); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); - assertFalse(np.onNetherPortal(e)); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); + assertFalse(np.onIslandPortal(e)); // Verify assertFalse(e.isCancelled()); } /** - * Test method for {@link PortalTeleportationListener#onNetherPortal(org.bukkit.event.player.PlayerPortalEvent)}. + * Test method for {@link PortalTeleportationListener#onIslandPortal(org.bukkit.event.player.PlayerPortalEvent)}. */ @Test - public void testOnNetherPortalNonBentoBoxWorld() { + public void testonIslandPortalNonBentoBoxWorldNether() { when(iwm.inWorld(any(World.class))).thenReturn(false); PortalTeleportationListener np = new PortalTeleportationListener(plugin); Location from = mock(Location.class); // Teleport from nether to world when(from.getWorld()).thenReturn(mock(World.class)); - PlayerPortalEvent e = new PlayerPortalEvent(null, from, null, TeleportCause.NETHER_PORTAL); - assertFalse(np.onNetherPortal(e)); + PlayerPortalEvent e = new PlayerPortalEvent(player, from, null, TeleportCause.NETHER_PORTAL); + assertFalse(np.onIslandPortal(e)); // Verify assertFalse(e.isCancelled()); verify(iwm, never()).isNetherGenerate(any()); } + /** + * Test method for {@link PortalTeleportationListener#setSeachRadius(PlayerPortalEvent, Island) + */ + @Test + public void testSetSeachRadius() { + Location from = mock(Location.class); + Location to = mock(Location.class); + PlayerPortalEvent e = new PlayerPortalEvent(p, from, to); + Island island = mock(Island.class); + when(island.onIsland(any())).thenReturn(true); + Location center = mock(Location.class); + when(center.getBlockX()).thenReturn(200); + when(center.getBlockZ()).thenReturn(200); + when(island.getCenter()).thenReturn(center); + when(island.getProtectionRange()).thenReturn(200); + PortalTeleportationListener np = new PortalTeleportationListener(plugin); + when(from.getBlockZ()).thenReturn(205); + assertEquals(128, e.getSearchRadius()); + + for (int x = 200; x < 410; x++) { + when(from.getBlockX()).thenReturn(x); + np.setSeachRadius(new PlayerEntityPortalEvent(e), island); + if (x >= 400) { + assertEquals(1, e.getSearchRadius()); + } else if (x < 273) { + assertEquals(128, e.getSearchRadius()); + } else if (x < 400) { + assertEquals(400 - x, e.getSearchRadius()); + } + } + } + + /** + * Test method for {@link PortalTeleportationListener#setSeachRadius(PlayerPortalEvent, Island) + */ + @Test + public void testSetSeachRadiusNotOnIsland() { + Location from = mock(Location.class); + PlayerPortalEvent e = new PlayerPortalEvent(p, from, null); + Island island = mock(Island.class); + when(island.onIsland(any())).thenReturn(false); + PortalTeleportationListener np = new PortalTeleportationListener(plugin); + np.setSeachRadius(new PlayerEntityPortalEvent(e), island); + assertEquals(128, e.getSearchRadius()); + } }