Fixing nether teleportation bug within WB via timed exemption.

This commit is contained in:
Daniel Boston 2016-03-22 02:01:01 -04:00
parent 369a966a84
commit 3351b25175
3 changed files with 39 additions and 4 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.wimbli</groupId> <groupId>com.wimbli</groupId>
<artifactId>WorldBorder</artifactId> <artifactId>WorldBorder</artifactId>
<version>1.9.0</version> <version>1.9.1</version>
<name>WorldBorder</name> <name>WorldBorder</name>
<url>https://github.com/DevotedMC/WorldBorder</url> <url>https://github.com/DevotedMC/WorldBorder</url>
<issueManagement> <issueManagement>

View File

@ -17,7 +17,7 @@ import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.scheduler.BukkitRunnable;
public class BorderCheckTask implements Runnable public class BorderCheckTask implements Runnable
{ {
@ -39,6 +39,30 @@ public class BorderCheckTask implements Runnable
// track players who are being handled (moved back inside the border) already; needed since Bukkit is sometimes sending teleport events with the old (now incorrect) location still indicated, which can lead to a loop when we then teleport them thinking they're outside the border, triggering event again, etc. // track players who are being handled (moved back inside the border) already; needed since Bukkit is sometimes sending teleport events with the old (now incorrect) location still indicated, which can lead to a loop when we then teleport them thinking they're outside the border, triggering event again, etc.
private static Set<String> handlingPlayers = Collections.synchronizedSet(new LinkedHashSet<String>()); private static Set<String> handlingPlayers = Collections.synchronizedSet(new LinkedHashSet<String>());
/**
* In 1.9, there is a significant delay between teleportation event and when the player's location is actually updated.
* However, the player world is updated immediately. This disconnection causes the regular checkPlayer to
* incorrectly test the player's prior-world location against the new-world location during that inbetween period.
*
* This function allows a temporary delay against the check to let Minecraft "catch up" the player's _real_ location.
*/
public static void timedPlayerExemption(final Player player, long delay) {
handlingPlayers.add(player.getName().toLowerCase());
new BukkitRunnable() {
private final String playerName = player.getName().toLowerCase();
@Override
public void run() {
handlingPlayers.remove(playerName);
if (Config.Debug())
Config.log("Exemption for " + playerName + " expired");
}
}.runTaskLater(WorldBorder.plugin, delay);
if (Config.Debug())
Config.log("Exempting " + player.getName().toLowerCase() + " for " + delay + " ticks.");
}
// set targetLoc only if not current player location; set returnLocationOnly to true to have new Location returned if they need to be moved to one, instead of directly handling it // set targetLoc only if not current player location; set returnLocationOnly to true to have new Location returned if they need to be moved to one, instead of directly handling it
public static Location checkPlayer(Player player, Location targetLoc, boolean returnLocationOnly, boolean notify) public static Location checkPlayer(Player player, Location targetLoc, boolean returnLocationOnly, boolean notify)
{ {

View File

@ -20,7 +20,12 @@ public class WBListener implements Listener
return; return;
if (Config.Debug()) if (Config.Debug())
Config.log("Teleport cause: " + event.getCause().toString()); Config.log("General Teleport cause: " + event.getCause().toString());
if (PlayerTeleportEvent.TeleportCause.NETHER_PORTAL == event.getCause()) {
Config.log("Skipping teleport management event - covered by onPlayerPortal");
return;
}
Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, true); Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, true);
if (newLoc != null) if (newLoc != null)
@ -38,13 +43,19 @@ public class WBListener implements Listener
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerPortal(PlayerPortalEvent event) public void onPlayerPortal(PlayerPortalEvent event)
{ {
if (Config.Debug())
Config.log("Player Portal Teleport cause: " + event.getCause().toString());
// if knockback is set to 0, or portal redirection is disabled, simply return // if knockback is set to 0, or portal redirection is disabled, simply return
if (Config.KnockBack() == 0.0 || !Config.portalRedirection()) if (Config.KnockBack() == 0.0 || !Config.portalRedirection())
return; return;
Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, false); Location newLoc = BorderCheckTask.checkPlayer(event.getPlayer(), event.getTo(), true, false);
if (newLoc != null) if (newLoc != null) {
event.setTo(newLoc); event.setTo(newLoc);
}
BorderCheckTask.timedPlayerExemption(event.getPlayer(), 100l);
} }
@EventHandler(priority = EventPriority.MONITOR) @EventHandler(priority = EventPriority.MONITOR)