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 02f75d0e7f 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.
This commit is contained in:
Andreas Troelsen 2018-04-23 21:55:30 +02:00
parent 37de1e66e9
commit 31aa4c15a1
3 changed files with 64 additions and 31 deletions

View File

@ -97,6 +97,7 @@ public class ArenaImpl implements Arena
private Map<Player,PlayerData> playerData = new HashMap<>();
private Set<Player> arenaPlayers, lobbyPlayers, readyPlayers, specPlayers, deadPlayers;
private Set<Player> movingPlayers;
private Set<Player> leavingPlayers;
private Set<Player> 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() {

View File

@ -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) {

View File

@ -154,6 +154,8 @@ public interface Arena
boolean playerLeave(Player p);
boolean isMoving(Player p);
boolean isLeaving(Player p);
void playerDeath(Player p);