mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-11-01 00:10:40 +01:00
Rewrote SafeSpotTeleport
Moved coords to longs instead of ints for island locations Created a SafeTeleportBuilder class Created a utility Pair class
This commit is contained in:
parent
4bd02a59ef
commit
ed65aa421d
@ -8,7 +8,6 @@ import org.bukkit.Location;
|
||||
import us.tastybento.bskyblock.Constants;
|
||||
import us.tastybento.bskyblock.api.commands.CompositeCommand;
|
||||
import us.tastybento.bskyblock.api.commands.User;
|
||||
import us.tastybento.bskyblock.util.SafeSpotTeleport;
|
||||
import us.tastybento.bskyblock.util.SafeTeleportBuilder;
|
||||
|
||||
public class AdminTeleportCommand extends CompositeCommand {
|
||||
|
@ -30,7 +30,7 @@ public class IslandCache {
|
||||
*/
|
||||
private HashMap<UUID, Island> islandsByUUID;
|
||||
// 2D islandGrid of islands, x,z
|
||||
private TreeMap<Integer, TreeMap<Integer, Island>> islandGrid = new TreeMap<>();
|
||||
private TreeMap<Long, TreeMap<Long, Island>> islandGrid = new TreeMap<>();
|
||||
|
||||
public IslandCache() {
|
||||
islandsByLocation = HashBiMap.create();
|
||||
@ -72,7 +72,7 @@ public class IslandCache {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: min x is in the grid :" + newIsland.getMinX());
|
||||
}
|
||||
TreeMap<Integer, Island> zEntry = islandGrid.get(newIsland.getMinX());
|
||||
TreeMap<Long, Island> zEntry = islandGrid.get(newIsland.getMinX());
|
||||
if (zEntry.containsKey(newIsland.getMinZ())) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: min z is in the grid :" + newIsland.getMinZ());
|
||||
@ -111,7 +111,7 @@ public class IslandCache {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: added island to grid at " + newIsland.getMinX() + "," + newIsland.getMinZ());
|
||||
}
|
||||
TreeMap<Integer, Island> zEntry = new TreeMap<>();
|
||||
TreeMap<Long, Island> zEntry = new TreeMap<>();
|
||||
zEntry.put(newIsland.getMinZ(), newIsland);
|
||||
islandGrid.put(newIsland.getMinX(), zEntry);
|
||||
}
|
||||
@ -177,8 +177,8 @@ public class IslandCache {
|
||||
plugin.getLogger().info("DEBUG: deleting island at " + island.getCenter());
|
||||
}
|
||||
if (island != null) {
|
||||
int x = island.getMinX();
|
||||
int z = island.getMinZ();
|
||||
long x = island.getMinX();
|
||||
long z = island.getMinZ();
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: x = " + x + " z = " + z);
|
||||
}
|
||||
@ -186,7 +186,7 @@ public class IslandCache {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: x found");
|
||||
}
|
||||
TreeMap<Integer, Island> zEntry = islandGrid.get(x);
|
||||
TreeMap<Long, Island> zEntry = islandGrid.get(x);
|
||||
if (zEntry.containsKey(z)) {
|
||||
if (DEBUG) {
|
||||
plugin.getLogger().info("DEBUG: z found - deleting the island");
|
||||
@ -228,14 +228,14 @@ public class IslandCache {
|
||||
* @param z
|
||||
* @return Island or null
|
||||
*/
|
||||
public Island getIslandAt(int x, int z) {
|
||||
public Island getIslandAt(long x, long z) {
|
||||
if (DEBUG2) {
|
||||
plugin.getLogger().info("DEBUG: getting island at " + x + "," + z);
|
||||
plugin.getLogger().info("DEBUG: island grid is " + islandGrid.size());
|
||||
}
|
||||
Entry<Integer, TreeMap<Integer, Island>> en = islandGrid.floorEntry(x);
|
||||
Entry<Long, TreeMap<Long, Island>> en = islandGrid.floorEntry(x);
|
||||
if (en != null) {
|
||||
Entry<Integer, Island> ent = en.getValue().floorEntry(z);
|
||||
Entry<Long, Island> ent = en.getValue().floorEntry(z);
|
||||
if (ent != null) {
|
||||
// Check if in the island range
|
||||
Island island = ent.getValue();
|
||||
|
@ -626,8 +626,8 @@ public class IslandsManager {
|
||||
}
|
||||
// Try to fix this teleport location and teleport the player if possible
|
||||
new SafeTeleportBuilder(plugin).entity(player)
|
||||
.location(plugin.getPlayers().getHomeLocation(player.getUniqueId(), number))
|
||||
.setHome(true)
|
||||
.island(plugin.getIslands().getIsland(player.getUniqueId()))
|
||||
.portal(false)
|
||||
.homeNumber(number)
|
||||
.build();
|
||||
return;
|
||||
|
@ -25,6 +25,7 @@ import us.tastybento.bskyblock.api.flags.Flag;
|
||||
import us.tastybento.bskyblock.database.objects.adapters.Adapter;
|
||||
import us.tastybento.bskyblock.database.objects.adapters.FlagSerializer;
|
||||
import us.tastybento.bskyblock.managers.RanksManager;
|
||||
import us.tastybento.bskyblock.util.Pair;
|
||||
import us.tastybento.bskyblock.util.Util;
|
||||
|
||||
/**
|
||||
@ -47,14 +48,14 @@ public class Island implements DataObject {
|
||||
private int range;
|
||||
|
||||
// Coordinates of the island area
|
||||
private int minX;
|
||||
private long minX;
|
||||
|
||||
private int minZ;
|
||||
private long minZ;
|
||||
|
||||
// Coordinates of minimum protected area
|
||||
private int minProtectedX;
|
||||
private long minProtectedX;
|
||||
|
||||
private int minProtectedZ;
|
||||
private long minProtectedZ;
|
||||
|
||||
// Protection size
|
||||
private int protectionRange;
|
||||
@ -212,28 +213,28 @@ public class Island implements DataObject {
|
||||
/**
|
||||
* @return the minProtectedX
|
||||
*/
|
||||
public int getMinProtectedX() {
|
||||
public long getMinProtectedX() {
|
||||
return minProtectedX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minProtectedZ
|
||||
*/
|
||||
public int getMinProtectedZ() {
|
||||
public long getMinProtectedZ() {
|
||||
return minProtectedZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minX
|
||||
*/
|
||||
public int getMinX() {
|
||||
public long getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minZ
|
||||
*/
|
||||
public int getMinZ() {
|
||||
public long getMinZ() {
|
||||
return minZ;
|
||||
}
|
||||
|
||||
@ -315,8 +316,8 @@ public class Island implements DataObject {
|
||||
*/
|
||||
public int getTileEntityCount(Material material, World world) {
|
||||
int result = 0;
|
||||
for (int x = getMinProtectedX() /16; x <= (getMinProtectedX() + getProtectionRange() - 1)/16; x++) {
|
||||
for (int z = getMinProtectedZ() /16; z <= (getMinProtectedZ() + getProtectionRange() - 1)/16; z++) {
|
||||
for (int x = (int) (getMinProtectedX() /16); x <= (getMinProtectedX() + getProtectionRange() - 1)/16; x++) {
|
||||
for (int z = (int) (getMinProtectedZ() /16); z <= (getMinProtectedZ() + getProtectionRange() - 1)/16; z++) {
|
||||
for (BlockState holder : world.getChunkAt(x, z).getTileEntities()) {
|
||||
//plugin.getLogger().info("DEBUG: tile entity: " + holder.getType());
|
||||
if (onIsland(holder.getLocation())) {
|
||||
@ -396,22 +397,31 @@ public class Island implements DataObject {
|
||||
return center.getBlockZ();
|
||||
}
|
||||
|
||||
public boolean inIslandSpace(Location location) {
|
||||
if (Util.inWorld(location)) {
|
||||
return inIslandSpace(location.getBlockX(), location.getBlockZ());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if coords are in the island space
|
||||
* @param x
|
||||
* @param z
|
||||
* @return true if in the island space
|
||||
*/
|
||||
public boolean inIslandSpace(int x, int z) {
|
||||
public boolean inIslandSpace(long x, long z) {
|
||||
//Bukkit.getLogger().info("DEBUG: center - " + center);
|
||||
return x >= minX && x < minX + range*2 && z >= minZ && z < minZ + range*2;
|
||||
}
|
||||
|
||||
public boolean inIslandSpace(Location location) {
|
||||
if (Util.inWorld(location)) {
|
||||
return inIslandSpace(location.getBlockX(), location.getBlockZ());
|
||||
}
|
||||
return false;
|
||||
/**
|
||||
* Checks if the coords are in island space
|
||||
* @param blockCoord
|
||||
* @return true or false
|
||||
*/
|
||||
public boolean inIslandSpace(Pair<Long, Long> blockCoord) {
|
||||
return inIslandSpace(blockCoord.x, blockCoord.z);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -567,28 +577,29 @@ public class Island implements DataObject {
|
||||
/**
|
||||
* @param minProtectedX the minProtectedX to set
|
||||
*/
|
||||
public void setMinProtectedX(int minProtectedX) {
|
||||
public final void setMinProtectedX(long minProtectedX) {
|
||||
this.minProtectedX = minProtectedX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minProtectedZ the minProtectedZ to set
|
||||
*/
|
||||
public void setMinProtectedZ(int minProtectedZ) {
|
||||
public final void setMinProtectedZ(long minProtectedZ) {
|
||||
this.minProtectedZ = minProtectedZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minX the minX to set
|
||||
*/
|
||||
public void setMinX(int minX) {
|
||||
public final void setMinX(long minX) {
|
||||
this.minX = minX;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param minZ the minZ to set
|
||||
*/
|
||||
public void setMinZ(int minZ) {
|
||||
public final void setMinZ(long minZ) {
|
||||
this.minZ = minZ;
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,9 @@ public class IslandWorld {
|
||||
private static final String CREATING = "Creating ";
|
||||
|
||||
private BSkyBlock plugin;
|
||||
private static World islandWorld;
|
||||
private static World netherWorld;
|
||||
private static World endWorld;
|
||||
private World islandWorld;
|
||||
private World netherWorld;
|
||||
private World endWorld;
|
||||
|
||||
/**
|
||||
* Generates the Skyblock worlds.
|
||||
|
@ -34,10 +34,10 @@ public class DeleteIslandChunks {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
int minXChunk = island.getMinX() / 16;
|
||||
int maxXChunk = (island.getRange() * 2 + island.getMinX() - 1) /16;
|
||||
int minZChunk = island.getMinZ() / 16;
|
||||
int maxZChunk = (island.getRange() * 2 + island.getMinZ() - 1) /16;
|
||||
int minXChunk = (int) (island.getMinX() / 16);
|
||||
int maxXChunk = (int) ((island.getRange() * 2 + island.getMinX() - 1) /16);
|
||||
int minZChunk = (int) (island.getMinZ() / 16);
|
||||
int maxZChunk = (int) ((island.getRange() * 2 + island.getMinZ() - 1) /16);
|
||||
for (int x = minXChunk; x <= maxXChunk; x++) {
|
||||
for (int z = minZChunk; z<=maxZChunk; z++) {
|
||||
world.regenerateChunk(x, z);
|
||||
|
65
src/main/java/us/tastybento/bskyblock/util/Pair.java
Normal file
65
src/main/java/us/tastybento/bskyblock/util/Pair.java
Normal file
@ -0,0 +1,65 @@
|
||||
package us.tastybento.bskyblock.util;
|
||||
|
||||
|
||||
public class Pair<X, Z> {
|
||||
public X x;
|
||||
public Z z;
|
||||
|
||||
public Pair(X x, Z z) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pair [x=" + x + ", z=" + z + "]";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((x == null) ? 0 : x.hashCode());
|
||||
result = prime * result + ((z == null) ? 0 : z.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Pair)) {
|
||||
return false;
|
||||
}
|
||||
Pair<?, ?> other = (Pair<?, ?>) obj;
|
||||
if (x == null) {
|
||||
if (other.x != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!x.equals(other.x)) {
|
||||
return false;
|
||||
}
|
||||
if (z == null) {
|
||||
if (other.z != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!z.equals(other.z)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +1,22 @@
|
||||
package us.tastybento.bskyblock.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import us.tastybento.bskyblock.BSkyBlock;
|
||||
import us.tastybento.bskyblock.api.commands.User;
|
||||
import us.tastybento.bskyblock.database.objects.Island;
|
||||
|
||||
/**
|
||||
@ -26,197 +27,221 @@ import us.tastybento.bskyblock.database.objects.Island;
|
||||
public class SafeSpotTeleport {
|
||||
|
||||
private enum State {
|
||||
CENTER, SURROUNDING, LAST_CHECK, FAILURE, CENTER_WAIT, SURROUNDING_WAIT
|
||||
CHECKING, WAITING
|
||||
}
|
||||
private static final int MAX_CHUNKS = 10;
|
||||
private static final long SPEED = 10;
|
||||
private State step = State.CENTER;
|
||||
private State step = State.CHECKING;
|
||||
private BukkitTask task;
|
||||
|
||||
// Parameters
|
||||
private final Entity entity;
|
||||
private final Location location;
|
||||
private final boolean portal;
|
||||
private final int homeNumber;
|
||||
|
||||
// Locations
|
||||
private Location bestSpot;
|
||||
|
||||
|
||||
private BSkyBlock plugin;
|
||||
private final Entity entity;
|
||||
private final Location location;
|
||||
private final int homeNumber;
|
||||
private final boolean setHome;
|
||||
private int lastX;
|
||||
private int lastZ;
|
||||
private int chunksToCheck = 10;
|
||||
private int worldHeight = 255;
|
||||
private World world;
|
||||
private double safeDistance;
|
||||
private Vector safeSpotInChunk;
|
||||
private boolean safeSpotFound;
|
||||
private Vector portalPart;
|
||||
private ChunkSnapshot portalChunk;
|
||||
private ChunkSnapshot safeChunk;
|
||||
private List<Pair<Integer, Integer>> chunksToScan;
|
||||
|
||||
/**
|
||||
* Teleports and entity to a safe spot on island
|
||||
* @param plugin2
|
||||
* @param entity2
|
||||
* @param island
|
||||
* @param plugin
|
||||
* @param entity
|
||||
* @param location
|
||||
* @param failureMessage
|
||||
* @param setHome2
|
||||
* @param homeNumber2
|
||||
* @param portal
|
||||
* @param homeNumber
|
||||
*/
|
||||
public SafeSpotTeleport(BSkyBlock plugin2, Entity entity2, Location location, String failureMessage, boolean setHome2,
|
||||
int homeNumber2) {
|
||||
this.plugin = plugin2;
|
||||
this.entity = entity2;
|
||||
this.setHome = setHome2;
|
||||
this.homeNumber = homeNumber2;
|
||||
public SafeSpotTeleport(BSkyBlock plugin, Entity entity, Location location, String failureMessage, boolean portal,
|
||||
int homeNumber) {
|
||||
this.plugin = plugin;
|
||||
this.entity = entity;
|
||||
this.location = location;
|
||||
this.portal = portal;
|
||||
this.homeNumber = homeNumber;
|
||||
|
||||
// Put player into spectator mode
|
||||
if (entity instanceof Player && ((Player)entity).getGameMode().equals(GameMode.SURVIVAL)) {
|
||||
((Player)entity).setGameMode(GameMode.SPECTATOR);
|
||||
}
|
||||
// Get world info
|
||||
world = location.getWorld();
|
||||
worldHeight = world.getEnvironment().equals(Environment.NETHER) ? world.getMaxHeight() - 20 : world.getMaxHeight() - 2;
|
||||
|
||||
// Get island mins and max
|
||||
Island island = plugin.getIslands().getIslandAt(location).orElse(null);
|
||||
if (island == null) {
|
||||
if (entity instanceof Player) {
|
||||
User.getInstance((Player)entity).sendMessage(failureMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Set the minimums and maximums
|
||||
lastX = island.getMinProtectedX() / 16;
|
||||
lastZ = island.getMinProtectedZ() / 16;
|
||||
int biggestX = (island.getMinProtectedX() + island.getProtectionRange() - 1) / 16;
|
||||
int biggestZ = (island.getMinProtectedZ() + island.getProtectionRange() - 1) / 16;
|
||||
// Get chunks to scan
|
||||
chunksToScan = getChunksToScan();
|
||||
|
||||
// Start a recurring task until done or cancelled
|
||||
task = plugin.getServer().getScheduler().runTaskTimer(plugin, () -> {
|
||||
Bukkit.getLogger().info("State = " + step);
|
||||
Bukkit.getLogger().info("Chunks to scan size = " + chunksToScan.size());
|
||||
List<ChunkSnapshot> chunkSnapshot = new ArrayList<>();
|
||||
switch (step) {
|
||||
case CENTER:
|
||||
// Add the center chunk
|
||||
chunkSnapshot.add(location.toVector().toLocation(world).getChunk().getChunkSnapshot());
|
||||
// Add immediately adjacent chunks
|
||||
for (int x = location.getChunk().getX()-1; x <= location.getChunk().getX()+1; x++) {
|
||||
for (int z = location.getChunk().getZ()-1; z <= location.getChunk().getZ()+1; z++) {
|
||||
if (x != location.getChunk().getX() || z != location.getChunk().getZ()) {
|
||||
chunkSnapshot.add(world.getChunkAt(x, z).getChunkSnapshot());
|
||||
}
|
||||
}
|
||||
case CHECKING:
|
||||
Iterator<Pair<Integer, Integer>> it = chunksToScan.iterator();
|
||||
if (!it.hasNext()) {
|
||||
Bukkit.getLogger().info("Nothing left!");
|
||||
// Nothing left
|
||||
tidyUp(entity, failureMessage);
|
||||
return;
|
||||
}
|
||||
// Add chunk snapshots to the list
|
||||
while (it.hasNext() && chunkSnapshot.size() < MAX_CHUNKS) {
|
||||
Pair<Integer, Integer> pair = it.next();
|
||||
chunkSnapshot.add(location.getWorld().getChunkAt(pair.x, pair.z).getChunkSnapshot());
|
||||
it.remove();
|
||||
}
|
||||
// Move to next step
|
||||
step = State.CENTER_WAIT;
|
||||
step = State.WAITING;
|
||||
Bukkit.getLogger().info("Chunk snapshot size = " + chunkSnapshot.size());
|
||||
checkChunks(chunkSnapshot);
|
||||
break;
|
||||
case CENTER_WAIT:
|
||||
// Do nothing while the center scan is done
|
||||
case WAITING:
|
||||
// Do nothing while the scan is done
|
||||
break;
|
||||
case SURROUNDING:
|
||||
for (int x = lastX; x <= biggestX; x++) {
|
||||
for (int z = lastZ; z <= biggestZ; z++) {
|
||||
chunkSnapshot.add(world.getChunkAt(x, z).getChunkSnapshot());
|
||||
if (chunkSnapshot.size() == chunksToCheck) {
|
||||
lastX = x;
|
||||
lastZ = z;
|
||||
step = State.SURROUNDING_WAIT;
|
||||
checkChunks(chunkSnapshot);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Last few chunks, may be none
|
||||
step = State.LAST_CHECK;
|
||||
checkChunks(chunkSnapshot);
|
||||
break;
|
||||
case SURROUNDING_WAIT:
|
||||
// Do nothing while the surrounding scan is done
|
||||
break;
|
||||
case LAST_CHECK:
|
||||
// Do nothing while the last few chunks are scanned
|
||||
break;
|
||||
case FAILURE:
|
||||
// We are done searching - failure
|
||||
task.cancel();
|
||||
if (entity instanceof Player) {
|
||||
if (!failureMessage.isEmpty()) {
|
||||
entity.sendMessage(failureMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0L, SPEED);
|
||||
}
|
||||
|
||||
private boolean checkChunks(List<ChunkSnapshot> chunkSnapshot) {
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
// Find a safe spot, defined as a solid block, with 2 air spaces above it
|
||||
//long time = System.nanoTime();
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int z = 0;
|
||||
double distance = 0D;
|
||||
private void tidyUp(Entity entity, String failureMessage) {
|
||||
// Nothing left to check and still not canceled
|
||||
task.cancel();
|
||||
// Check portal
|
||||
if (portal && bestSpot != null) {
|
||||
Bukkit.getLogger().info("No portals found, going to best spot");
|
||||
// No portals found, teleport to the best spot we found
|
||||
teleportEntity(bestSpot);
|
||||
}
|
||||
// Failed - no safe spot
|
||||
if (entity instanceof Player && !failureMessage.isEmpty()) {
|
||||
entity.sendMessage(failureMessage);
|
||||
}
|
||||
}
|
||||
|
||||
for (ChunkSnapshot chunk: chunkSnapshot) {
|
||||
// Run through the chunk
|
||||
for (x = 0; x< 16; x++) {
|
||||
for (z = 0; z < 16; z++) {
|
||||
// Work down from the entry point up
|
||||
for (y = Math.min(chunk.getHighestBlockYAt(x, z), worldHeight); y >= 0; y--) {
|
||||
//System.out.println("Trying " + (16 * chunk.getX() + x) + " " + y + " " + (16 * chunk.getZ() + z));
|
||||
// Check for portal - only if this is not a safe home search
|
||||
if (!setHome && chunk.getBlockType(x, y, z).equals(Material.PORTAL)) {
|
||||
if (portalPart == null || (distance > location.toVector().distanceSquared(new Vector(x,y,z)))) {
|
||||
// First one found or a closer one, save the chunk the position and the distance
|
||||
portalChunk = chunk;
|
||||
portalPart = new Vector(x,y,z);
|
||||
distance = portalPart.distanceSquared(location.toVector());
|
||||
/**
|
||||
* Gets a set of chunk coords that will be scanned.
|
||||
* @param entity
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
private List<Pair<Integer, Integer>> getChunksToScan() {
|
||||
List<Pair<Integer, Integer>> result = new ArrayList<>();
|
||||
// Get island if available
|
||||
Optional<Island> island = plugin.getIslands().getIslandAt(location);
|
||||
int maxRadius = island.map(x -> x.getProtectionRange()).orElse(plugin.getSettings().getIslandProtectionRange());
|
||||
Bukkit.getLogger().info("default island radius = " + plugin.getSettings().getIslandProtectionRange());
|
||||
Bukkit.getLogger().info("Max radius = " + maxRadius);
|
||||
int x = location.getBlockX();
|
||||
int z = location.getBlockZ();
|
||||
// Create ever increasing squares around the target location
|
||||
int radius = 0;
|
||||
do {
|
||||
for (long i = x - radius; i <= x + radius; i++) {
|
||||
for (long j = z - radius; j <= z + radius; j++) {
|
||||
|
||||
Pair<Long, Long> blockCoord = new Pair<>(i,j);
|
||||
Pair<Integer, Integer> chunkCoord = new Pair<>((int)i/16, (int)j/16);
|
||||
if (!result.contains(chunkCoord)) {
|
||||
Bukkit.getLogger().info("Block coord = " + blockCoord);
|
||||
Bukkit.getLogger().info("New chunk coord " + chunkCoord);
|
||||
// Add the chunk coord
|
||||
if (!island.isPresent()) {
|
||||
// If there is no island, just add it
|
||||
Bukkit.getLogger().info("No island, adding chunk coord ");
|
||||
result.add(chunkCoord);
|
||||
} else {
|
||||
// If there is an island, only add it if the coord is in island space
|
||||
island.ifPresent(is -> {
|
||||
if (is.inIslandSpace(blockCoord)) {
|
||||
Bukkit.getLogger().info("Island, adding chunk coord");
|
||||
result.add(chunkCoord);
|
||||
} else {
|
||||
Bukkit.getLogger().info("Island, block coord not in island space");
|
||||
}
|
||||
}
|
||||
// Check for safe spot, but only if it is closer than one we have found already
|
||||
if (!safeSpotFound || (safeDistance > location.toVector().distanceSquared(new Vector(x,y,z)))) {
|
||||
// No safe spot yet, or closer distance
|
||||
if (checkBlock(chunk,x,y,z, worldHeight)) {
|
||||
safeChunk = chunk;
|
||||
safeSpotFound = true;
|
||||
safeSpotInChunk = new Vector(x,y,z);
|
||||
safeDistance = location.toVector().distanceSquared(safeSpotInChunk);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} //end z
|
||||
} // end x
|
||||
// If this is not a home search do a check for portal
|
||||
if (!this.setHome) {
|
||||
checkPortal();
|
||||
}
|
||||
|
||||
// If successful, teleport otherwise move to the next step in the state machine
|
||||
if (safeSpotFound) {
|
||||
task.cancel();
|
||||
teleportEntity();
|
||||
} else if (step.equals(State.SURROUNDING_WAIT) || step.equals(State.CENTER_WAIT)) {
|
||||
step = State.SURROUNDING;
|
||||
} else if (step.equals(State.LAST_CHECK)) {
|
||||
step = State.FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
radius++;
|
||||
} while (radius < maxRadius);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through the chunks and if a safe spot is found, fires off the teleportation
|
||||
* @param chunkSnapshot
|
||||
*/
|
||||
private void checkChunks(List<ChunkSnapshot> chunkSnapshot) {
|
||||
// Run async task to scan chunks
|
||||
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||
|
||||
for (ChunkSnapshot chunk: chunkSnapshot) {
|
||||
if (scanChunk(chunk)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Nothing happened, change state
|
||||
step = State.CHECKING;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param chunk
|
||||
* @return true if a safe spot was found
|
||||
*/
|
||||
private boolean scanChunk(ChunkSnapshot chunk) {
|
||||
Bukkit.getLogger().info("Scanning chunk at " + chunk.getX() + " " + chunk.getZ());
|
||||
Bukkit.getLogger().info("Portal = " + portal);
|
||||
World world = location.getWorld();
|
||||
// Max height
|
||||
int maxHeight = location.getWorld().getMaxHeight() - 20;
|
||||
// Run through the chunk
|
||||
for (int x = 0; x< 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
// Work down from the entry point up
|
||||
for (int y = Math.min(chunk.getHighestBlockYAt(x, z), maxHeight); y >= 0; y--) {
|
||||
if (checkBlock(chunk, x,y,z, maxHeight)) {
|
||||
Bukkit.getLogger().info("safe: " + x + " " + y + " "+ z);
|
||||
Vector newSpot = new Vector(chunk.getX() * 16 + x + 0.5D, y + 1, chunk.getZ() * 16 + z + 0.5D);
|
||||
// Check for portal
|
||||
if (portal) {
|
||||
if (chunk.getBlockType(x, y, z).equals(Material.PORTAL)) {
|
||||
// Teleport as soon as we find a portal
|
||||
teleportEntity(newSpot.toLocation(world));
|
||||
return true;
|
||||
} else if (bestSpot == null ) {
|
||||
// Stash the best spot
|
||||
bestSpot = newSpot.toLocation(world);
|
||||
}
|
||||
} else {
|
||||
// Regular search - teleport as soon as we find something
|
||||
teleportEntity(newSpot.toLocation(world));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} //end z
|
||||
} // end x
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports entity to the safe spot
|
||||
*/
|
||||
private void teleportEntity() {
|
||||
final Vector spot = new Vector((16 *safeChunk.getX()) + 0.5D, 1, (16 * safeChunk.getZ()) + 0.5D).add(safeSpotInChunk);
|
||||
private void teleportEntity(Location loc) {
|
||||
task.cancel();
|
||||
// Return to main thread and teleport the player
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> {
|
||||
Location destination = spot.toLocation(world);
|
||||
if (setHome && entity instanceof Player) {
|
||||
plugin.getPlayers().setHomeLocation(entity.getUniqueId(), destination, homeNumber);
|
||||
if (!portal && entity instanceof Player) {
|
||||
// Set home
|
||||
plugin.getPlayers().setHomeLocation(entity.getUniqueId(), loc, homeNumber);
|
||||
}
|
||||
Vector velocity = entity.getVelocity();
|
||||
entity.teleport(destination);
|
||||
entity.teleport(loc);
|
||||
// Exit spectator mode if in it
|
||||
if (entity instanceof Player) {
|
||||
Player player = (Player)entity;
|
||||
@ -230,10 +255,12 @@ public class SafeSpotTeleport {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a portal is safe
|
||||
* Subscan to find the bottom of the portal
|
||||
*/
|
||||
private void checkPortal() {
|
||||
/*
|
||||
private Location checkPortal() {
|
||||
if (portalPart == null) {
|
||||
return;
|
||||
}
|
||||
@ -254,7 +281,7 @@ public class SafeSpotTeleport {
|
||||
safeSpotInChunk = new Vector(x,y,z);
|
||||
safeChunk = portalChunk;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Returns true if the location is a safe one.
|
||||
@ -265,21 +292,21 @@ public class SafeSpotTeleport {
|
||||
* @param worldHeight
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean checkBlock(ChunkSnapshot chunk, int x, int y, int z, int worldHeight) {
|
||||
int type = chunk.getBlockTypeId(x, y, z);
|
||||
if (type != 0) { // AIR
|
||||
int space1 = chunk.getBlockTypeId(x, Math.min(y + 1, worldHeight), z);
|
||||
int space2 = chunk.getBlockTypeId(x, Math.min(y + 2, worldHeight), z);
|
||||
if ((space1 == 0 && space2 == 0) || (space1 == Material.PORTAL.getId() || space2 == Material.PORTAL.getId())) {
|
||||
Bukkit.getLogger().info("checking " + x + " " + y + " "+ z);
|
||||
Material type = chunk.getBlockType(x, y, z);
|
||||
if (!type.equals(Material.AIR)) { // AIR
|
||||
Material space1 = chunk.getBlockType(x, Math.min(y + 1, 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))) {
|
||||
// Now there is a chance that this is a safe spot
|
||||
// Check for safe ground
|
||||
Material mat = Material.getMaterial(type);
|
||||
if (!mat.toString().contains("FENCE")
|
||||
&& !mat.toString().contains("DOOR")
|
||||
&& !mat.toString().contains("GATE")
|
||||
&& !mat.toString().contains("PLATE")) {
|
||||
switch (mat) {
|
||||
if (!type.toString().contains("FENCE")
|
||||
&& !type.toString().contains("DOOR")
|
||||
&& !type.toString().contains("GATE")
|
||||
&& !type.toString().contains("PLATE")) {
|
||||
switch (type) {
|
||||
// Unsafe
|
||||
case ANVIL:
|
||||
case BARRIER:
|
||||
@ -307,11 +334,10 @@ public class SafeSpotTeleport {
|
||||
case WATER:
|
||||
case WEB:
|
||||
case WOOD_BUTTON:
|
||||
//System.out.println("Block is dangerous " + mat.toString());
|
||||
//Block is dangerous
|
||||
break;
|
||||
default:
|
||||
// Safe
|
||||
// System.out.println("Block is safe " + mat.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -320,4 +346,5 @@ public class SafeSpotTeleport {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -11,7 +11,7 @@ public class SafeTeleportBuilder {
|
||||
private BSkyBlock plugin;
|
||||
private Entity entity;
|
||||
private int homeNumber = 0;
|
||||
private boolean setHome = false;
|
||||
private boolean portal = false;
|
||||
private String failureMessage = "";
|
||||
private Location location;
|
||||
|
||||
@ -51,12 +51,12 @@ public class SafeTeleportBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the home of the player to the safe location
|
||||
* This is a portal teleportation
|
||||
* @param setHome
|
||||
* @return
|
||||
*/
|
||||
public SafeTeleportBuilder setHome(boolean setHome) {
|
||||
this.setHome = setHome;
|
||||
public SafeTeleportBuilder portal(boolean portal) {
|
||||
this.portal = portal;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ public class SafeTeleportBuilder {
|
||||
* @return
|
||||
*/
|
||||
public SafeSpotTeleport build() {
|
||||
return new SafeSpotTeleport(plugin, entity, location, failureMessage, setHome, homeNumber);
|
||||
return new SafeSpotTeleport(plugin, entity, location, failureMessage, portal, homeNumber);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user