From 8ee2fed53b35577a735153f28a4fcf47b49cb034 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:05:56 +0000 Subject: [PATCH 1/4] Initial plan From 5f48e4e2e0a928c04c9a8546e4509b65d6d63e94 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:11:38 +0000 Subject: [PATCH 2/4] Fix team duel race condition by marking matches as finished immediately Co-authored-by: dumbo-the-developer <83227054+dumbo-the-developer@users.noreply.github.com> --- .../duels/duel/DuelManager.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java b/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java index ca03ab19..35efa66e 100644 --- a/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java +++ b/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java @@ -87,6 +87,11 @@ public DuelManager(final DuelsPlugin plugin) { } public void handleMatchEnd(DuelMatch match, ArenaImpl arena, Player loser, Location deadLocation, Player winner) { + // Safety check: Don't process if match is already finished (prevents duplicate processing) + if (match.isFinished()) { + return; + } + DuelsPlugin.getMorePaperLib().scheduling().regionSpecificScheduler(arena.first().getLocation()).runDelayed(() -> { if (arena.size() == 0) { match.getAllPlayers().forEach(matchPlayer -> { @@ -208,6 +213,11 @@ public void handleMatchEnd(DuelMatch match, ArenaImpl arena, Player loser, Locat } public void handleTeamMatchEnd(TeamDuelMatch match, ArenaImpl arena, Location deadLocation, TeamDuelMatch.Team winningTeam) { + // Safety check: Don't process if match is already finished (prevents duplicate processing) + if (match.isFinished()) { + return; + } + DuelsPlugin.getMorePaperLib().scheduling().regionSpecificScheduler(deadLocation).runDelayed(() -> { if (config.isSpawnFirework()) { DuelsPlugin.getMorePaperLib().scheduling().regionSpecificScheduler(deadLocation).run(() -> { @@ -1029,6 +1039,11 @@ public void on(final PlayerDeathEvent event) { // Check if any team is completely eliminated TeamDuelMatch.Team winningTeam = teamMatch.getWinningTeam(); if (winningTeam != null && teamMatch.size() == 1) { + // CRITICAL FIX: Mark match as finished IMMEDIATELY to prevent race condition + // where multiple players die before match ending is processed, causing the + // match to never properly end and players to get stuck "in duel" + match.setFinished(); + final Location deadLocation = player.getEyeLocation().clone(); handleTeamMatchEnd(teamMatch, arena, deadLocation, winningTeam); return; @@ -1051,6 +1066,10 @@ public void on(final PlayerDeathEvent event) { return; } + // CRITICAL FIX: Mark match as finished IMMEDIATELY to prevent race condition + // where multiple players die before match ending is processed + match.setFinished(); + final Location deadLocation = player.getEyeLocation().clone(); handleMatchEnd(match, arena, player, deadLocation, match.getAlivePlayers().iterator().next()); } From 88bef271b51f1a7256f0656ac9768b4f81cacdb6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:12:48 +0000 Subject: [PATCH 3/4] Improve comments based on code review feedback Co-authored-by: dumbo-the-developer <83227054+dumbo-the-developer@users.noreply.github.com> --- .../java/com/meteordevelopments/duels/duel/DuelManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java b/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java index 35efa66e..74f30441 100644 --- a/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java +++ b/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java @@ -87,7 +87,7 @@ public DuelManager(final DuelsPlugin plugin) { } public void handleMatchEnd(DuelMatch match, ArenaImpl arena, Player loser, Location deadLocation, Player winner) { - // Safety check: Don't process if match is already finished (prevents duplicate processing) + // Safety check: Don't process if match is already finished (prevents race condition where multiple death events trigger concurrent match ending) if (match.isFinished()) { return; } @@ -213,7 +213,7 @@ public void handleMatchEnd(DuelMatch match, ArenaImpl arena, Player loser, Locat } public void handleTeamMatchEnd(TeamDuelMatch match, ArenaImpl arena, Location deadLocation, TeamDuelMatch.Team winningTeam) { - // Safety check: Don't process if match is already finished (prevents duplicate processing) + // Safety check: Don't process if team match is already finished (prevents race condition where multiple team member deaths trigger concurrent match ending) if (match.isFinished()) { return; } From 1b79636d8e31c8d905d33c4bfb33c7fe08d6c340 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 14:37:30 +0000 Subject: [PATCH 4/4] Fix: Move setFinished() inside handler methods to allow proper execution Co-authored-by: dumbo-the-developer <83227054+dumbo-the-developer@users.noreply.github.com> --- .../duels/duel/DuelManager.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java b/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java index 74f30441..8d416ce0 100644 --- a/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java +++ b/duels-plugin/src/main/java/com/meteordevelopments/duels/duel/DuelManager.java @@ -92,6 +92,9 @@ public void handleMatchEnd(DuelMatch match, ArenaImpl arena, Player loser, Locat return; } + // Mark match as finished immediately to prevent re-entry from concurrent death events + match.setFinished(); + DuelsPlugin.getMorePaperLib().scheduling().regionSpecificScheduler(arena.first().getLocation()).runDelayed(() -> { if (arena.size() == 0) { match.getAllPlayers().forEach(matchPlayer -> { @@ -218,6 +221,9 @@ public void handleTeamMatchEnd(TeamDuelMatch match, ArenaImpl arena, Location de return; } + // Mark match as finished immediately to prevent re-entry from concurrent team member deaths + match.setFinished(); + DuelsPlugin.getMorePaperLib().scheduling().regionSpecificScheduler(deadLocation).runDelayed(() -> { if (config.isSpawnFirework()) { DuelsPlugin.getMorePaperLib().scheduling().regionSpecificScheduler(deadLocation).run(() -> { @@ -1039,11 +1045,6 @@ public void on(final PlayerDeathEvent event) { // Check if any team is completely eliminated TeamDuelMatch.Team winningTeam = teamMatch.getWinningTeam(); if (winningTeam != null && teamMatch.size() == 1) { - // CRITICAL FIX: Mark match as finished IMMEDIATELY to prevent race condition - // where multiple players die before match ending is processed, causing the - // match to never properly end and players to get stuck "in duel" - match.setFinished(); - final Location deadLocation = player.getEyeLocation().clone(); handleTeamMatchEnd(teamMatch, arena, deadLocation, winningTeam); return; @@ -1066,10 +1067,6 @@ public void on(final PlayerDeathEvent event) { return; } - // CRITICAL FIX: Mark match as finished IMMEDIATELY to prevent race condition - // where multiple players die before match ending is processed - match.setFinished(); - final Location deadLocation = player.getEyeLocation().clone(); handleMatchEnd(match, arena, player, deadLocation, match.getAlivePlayers().iterator().next()); }