diff --git a/src/main/java/com/garbagemule/MobArena/ArenaImpl.java b/src/main/java/com/garbagemule/MobArena/ArenaImpl.java index c411983..68bca3e 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaImpl.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaImpl.java @@ -97,6 +97,7 @@ public class ArenaImpl implements Arena private Map playerData = new HashMap<>(); private Set arenaPlayers, lobbyPlayers, readyPlayers, specPlayers, deadPlayers; + private Set movingPlayers; private Set leavingPlayers; private Set randoms; @@ -165,6 +166,7 @@ public class ArenaImpl implements Arena this.specPlayers = new HashSet<>(); this.deadPlayers = new HashSet<>(); this.randoms = new HashSet<>(); + this.movingPlayers = new HashSet<>(); this.leavingPlayers = new HashSet<>(); // Classes, items and permissions @@ -518,7 +520,9 @@ public class ArenaImpl implements Arena System.out.println("[MobArena] Invincibility glitch attempt stopped!"); } + movingPlayers.add(p); p.teleport(region.getArenaWarp()); + movingPlayers.remove(p); p.setAllowFlight(false); p.setFlying(false); //movePlayerToLocation(p, region.getArenaWarp()); @@ -663,6 +667,11 @@ public class ArenaImpl implements Arena return false; } + if (movingPlayers.contains(p)) { + return false; + } + movingPlayers.add(p); + // Announce globally (must happen before moving player) if (settings.getBoolean("global-join-announce", false)) { if (lobbyPlayers.isEmpty()) { @@ -710,6 +719,7 @@ public class ArenaImpl implements Arena } } + movingPlayers.remove(p); return true; } @@ -785,6 +795,11 @@ public class ArenaImpl implements Arena return true; } + @Override + public boolean isMoving(Player p) { + return movingPlayers.contains(p) || leavingPlayers.contains(p); + } + @Override public boolean isLeaving(Player p) { return leavingPlayers.contains(p); @@ -878,11 +893,17 @@ public class ArenaImpl implements Arena @Override public void playerSpec(Player p, Location loc) { + if (movingPlayers.contains(p)) { + return; + } + movingPlayers.add(p); + storePlayerData(p, loc); MAUtils.sitPets(p); movePlayerToSpec(p); messenger.tell(p, Msg.SPEC_PLAYER_SPECTATE); + movingPlayers.remove(p); } private void spawnPets() { diff --git a/src/main/java/com/garbagemule/MobArena/ArenaListener.java b/src/main/java/com/garbagemule/MobArena/ArenaListener.java index dc2e676..52b932a 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaListener.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaListener.java @@ -1173,44 +1173,54 @@ public class ArenaListener return TeleportResponse.IDGAF; } - Location to = event.getTo(); - Location from = event.getFrom(); Player p = event.getPlayer(); + /* + * Players that are being moved around by the arena are always allowed + * to teleport. They stay in this "moving" state only during the actual + * transition and are removed from that state as soon as the transition + * is complete. + */ + if (arena.isMoving(p) || p.hasPermission("mobarena.admin.teleport")) { + return TeleportResponse.ALLOW; + } + + Location to = event.getTo(); + Location from = event.getFrom(); + + /* + * At this point we're looking at warping of players that are either in + * the arena - but not in the "moving" state - or not in the arena. The + * tricky bit here is to figure out the edge cases. This is essentially + * a matter of players "teleporting on their own" (or with assistance + * from other plugins). + */ if (region.contains(from)) { - // Players with proper admin permission can warp out - if (p.hasPermission("mobarena.admin.teleport")) { + if (region.contains(to)) { + // Inside -> inside + if (!arena.inArena(p)) { + arena.getMessenger().tell(p, Msg.WARP_TO_ARENA); + return TeleportResponse.REJECT; + } return TeleportResponse.ALLOW; + } else { + // Inside -> outside + if (arena.getAllPlayers().contains(p)) { + arena.getMessenger().tell(p, Msg.WARP_FROM_ARENA); + return TeleportResponse.REJECT; + } + return TeleportResponse.IDGAF; } - - // Players not in the arena are free to warp out. - if (!arena.inArena(p) && !arena.inLobby(p) && !arena.inSpec(p)) { - return TeleportResponse.ALLOW; + } else { + if (region.contains(to)) { + // Outside -> inside + arena.getMessenger().tell(p, Msg.WARP_TO_ARENA); + return TeleportResponse.REJECT; + } else { + // Outside -> outside + return TeleportResponse.IDGAF; } - - // Covers the case in which both locations are in the arena. - if (region.contains(to) || region.isWarp(to) || to.equals(arena.getPlayerEntry(p))) { - return TeleportResponse.ALLOW; - } - - arena.getMessenger().tell(p, Msg.WARP_FROM_ARENA); - return TeleportResponse.REJECT; } - else if (region.contains(to)) { - // Players with proper admin permission can warp in - if (p.hasPermission("mobarena.admin.teleport")) { - return TeleportResponse.ALLOW; - } - - if (region.isWarp(from) || region.isWarp(to) || to.equals(arena.getPlayerEntry(p))) { - return TeleportResponse.ALLOW; - } - - arena.getMessenger().tell(p, Msg.WARP_TO_ARENA); - return TeleportResponse.REJECT; - } - - return TeleportResponse.IDGAF; } public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { diff --git a/src/main/java/com/garbagemule/MobArena/framework/Arena.java b/src/main/java/com/garbagemule/MobArena/framework/Arena.java index 70e2607..207d887 100644 --- a/src/main/java/com/garbagemule/MobArena/framework/Arena.java +++ b/src/main/java/com/garbagemule/MobArena/framework/Arena.java @@ -154,6 +154,8 @@ public interface Arena boolean playerLeave(Player p); + boolean isMoving(Player p); + boolean isLeaving(Player p); void playerDeath(Player p);