From 31aa4c15a1daa886d2f82e40736d5e45325d9be5 Mon Sep 17 00:00:00 2001 From: Andreas Troelsen Date: Mon, 23 Apr 2018 21:55:30 +0200 Subject: [PATCH] Guard against teleporting back to the arena on death. The /back command in Essentials - and similar commands from other plugins that allow you to warp back to your location of death - makes it possible to re-enter the arena after dying. This commit builds upon the "leaving players" of commit 02f75d0e7f82219348fc6b528e7561a26d352f53 and introduces a more general notion of players being "moved". The arena is "moving" a player if the player is being teleported somewhere by MobArena (to any arena warp), and in this case, all teleports of a player are permitted. This takes care of the cases where MobArena "might be doing it". The rest of the cases are due to commands, plugins, ender pearls, etc., and they are a little easier to deal with separately. The new logic is more straightforward and should prevent most exploits and permit most legit warp cases. This (hopefully) fixes #313. --- .../com/garbagemule/MobArena/ArenaImpl.java | 21 ++++++ .../garbagemule/MobArena/ArenaListener.java | 72 +++++++++++-------- .../garbagemule/MobArena/framework/Arena.java | 2 + 3 files changed, 64 insertions(+), 31 deletions(-) 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);