diff --git a/src/main/java/com/garbagemule/MobArena/ArenaImpl.java b/src/main/java/com/garbagemule/MobArena/ArenaImpl.java index f8b6c44..c411983 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 leavingPlayers; private Set randoms; // Classes stuff @@ -164,6 +165,7 @@ public class ArenaImpl implements Arena this.specPlayers = new HashSet<>(); this.deadPlayers = new HashSet<>(); this.randoms = new HashSet<>(); + this.leavingPlayers = new HashSet<>(); // Classes, items and permissions this.classes = plugin.getArenaMaster().getClasses(); @@ -742,6 +744,12 @@ public class ArenaImpl implements Arena return false; } + // Protect against infinite leave loops + if (leavingPlayers.contains(p)) { + return false; + } + leavingPlayers.add(p); + // Clear inventory if player is an arena player, and unmount if (arenaPlayers.contains(p)) { unmount(p); @@ -772,9 +780,16 @@ public class ArenaImpl implements Arena discardPlayer(p); endArena(); + + leavingPlayers.remove(p); return true; } + @Override + public boolean isLeaving(Player p) { + return leavingPlayers.contains(p); + } + @Override public void playerDeath(Player p) { diff --git a/src/main/java/com/garbagemule/MobArena/ArenaListener.java b/src/main/java/com/garbagemule/MobArena/ArenaListener.java index e950ac7..dc2e676 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaListener.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaListener.java @@ -942,6 +942,21 @@ public class ArenaListener public void onPlayerDropItem(PlayerDropItemEvent event) { Player p = event.getPlayer(); + /* + * If the player "drops an item" while in the process of leaving the + * arena, it has to be due to something that happens in the leaving + * process because most of the event system is single-threaded. This + * doesn't make much sense, but it can happen if the player earns a + * command reward of /give, which drops the item with a drop delay of + * 0 from the player, causing the player to immediately pick it up. + * Cancelling this event causes the player to somehow pick up the item + * twice, so we don't want to do that. This early return should guard + * against this specific case, and hopefully not break anything else. + */ + if (arena.isLeaving(p)) { + return; + } + // If the player is active in the arena, only cancel if sharing is not allowed if (arena.inArena(p)) { if (!canShare) { diff --git a/src/main/java/com/garbagemule/MobArena/framework/Arena.java b/src/main/java/com/garbagemule/MobArena/framework/Arena.java index 38557db..70e2607 100644 --- a/src/main/java/com/garbagemule/MobArena/framework/Arena.java +++ b/src/main/java/com/garbagemule/MobArena/framework/Arena.java @@ -153,6 +153,8 @@ public interface Arena void playerReady(Player p); boolean playerLeave(Player p); + + boolean isLeaving(Player p); void playerDeath(Player p);