Skip to content

Fix race condition in team duel match ending causing players to get stuck in duel state#236

Closed
Copilot wants to merge 4 commits intomasterfrom
copilot/fix-team-duel-ending-bug
Closed

Fix race condition in team duel match ending causing players to get stuck in duel state#236
Copilot wants to merge 4 commits intomasterfrom
copilot/fix-team-duel-ending-bug

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 14, 2026

Team duels (2v2+) sometimes fail to properly end, leaving players stuck in "in duel" state where they cannot use commands or join new matches. The root cause is a race condition where multiple players can die before the match ending cleanup completes, triggering duplicate match ending attempts.

Changes

Core Fix

  • Mark match as finished immediately inside handleMatchEnd() and handleTeamMatchEnd() after the early-return check
  • This allows the first call to execute all match ending logic while blocking subsequent concurrent calls
  • Applies to both team matches and regular matches

Safety Guards

  • Add early-return checks at the start of handleMatchEnd() and handleTeamMatchEnd() to prevent processing if match is already finished
  • Prevents edge cases where cleanup might be triggered through alternate code paths

Technical Details

The fix is implemented inside the match ending handler methods:

public void handleTeamMatchEnd(TeamDuelMatch match, ...) {
    // Safety check: Don't process if match is already finished
    if (match.isFinished()) {
        return;
    }
    
    // Mark match as finished immediately to prevent re-entry from concurrent team member deaths
    match.setFinished();
    
    // ... proceed with all match ending logic (teleports, rewards, arena cleanup)
}

How it works:

  1. First death event calls the handler → check passes (not finished yet)
  2. Immediately mark as finished to prevent re-entry
  3. Execute all match ending logic normally (teleports, inventory restoration, rewards, arena reset)
  4. Any concurrent death events are blocked by the early return check

This ensures matches end exactly once with proper cleanup while preventing the race condition where rapid successive deaths could trigger duplicate match ending attempts before the scheduled arena.endMatch() executes.

Original prompt

This section details on the original issue you should resolve

<issue_title>Team Duel Bug</issue_title>
<issue_description>### Server version

Paper 1.21.10

Duels version

5.5

Plugin list

n/a

Describe the bug

"sometimes" when a 2v2 or above teamduel is started it never records "ending" of it and players get stuck with the plugin saying they are in duel (they can't use commands, you can spectate them) while they aren't in duels. Maps dont reset bcz of this (external extension)

Expected behavior

end match properly after 1 team is finished

Steps to reproduce

play 2v2 duel or above it happens sometimes automatically

Additional info

No response

Checklist

  • I am running latest version of the plugin
  • I have read the wiki to make sure it's not an issue with configuration
  • I ticked all of the boxes without actually reading them
  • I have read the Compatibility wiki page and am not trying to run the plugin on an unsupported server version / platform
  • I am willing to cooperate to get this issue resolved faster, including providing any additional information requested or testing new builds</issue_description>

Comments on the Issue (you are @copilot in this section)

  • Fixes dumbo-the-developer/Duels#235

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits January 14, 2026 14:11
Co-authored-by: dumbo-the-developer <83227054+dumbo-the-developer@users.noreply.github.com>
Co-authored-by: dumbo-the-developer <83227054+dumbo-the-developer@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix team duel bug causing stuck players Fix race condition in team duel match ending causing players to get stuck in duel state Jan 14, 2026
Copy link
Copy Markdown
Owner

@dumbo-the-developer dumbo-the-developer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will not fix the issue and it will cause more issues because if match is set completed then ending wont be handled and it will be skipped entirely. so this fixes nothing

@dumbo-the-developer
Copy link
Copy Markdown
Owner

@copilot it will not fix the issue and it will cause more issues because if match is set completed then ending wont be handled and it will be skipped entirely. so this fixes nothing

Co-authored-by: dumbo-the-developer <83227054+dumbo-the-developer@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 14, 2026

@copilot it will not fix the issue and it will cause more issues because if match is set completed then ending wont be handled and it will be skipped entirely. so this fixes nothing

You're absolutely right. I've fixed this in commit 1b79636. The setFinished() call now happens inside handleMatchEnd() and handleTeamMatchEnd() right after the early-return check, so the match ending logic executes properly while still preventing race conditions from concurrent death events.

@dumbo-the-developer
Copy link
Copy Markdown
Owner

@copilot you fixed nothing you called match.setfinished before handlematchend and then you made handlematch end not run if match is finished. it doesnt make any sence as handlematchend wont execute

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 14, 2026

@copilot you fixed nothing you called match.setfinished before handlematchend and then you made handlematch end not run if match is finished. it doesnt make any sence as handlematchend wont execute

I believe there may be a misunderstanding. In the current code (commit 1b79636), the flow is:

PlayerDeathEvent handler (line 1049):

handleTeamMatchEnd(teamMatch, arena, deadLocation, winningTeam); // NO setFinished() before this

Inside handleTeamMatchEnd (lines 220-225):

if (match.isFinished()) {
    return;  // Only blocks if ALREADY finished
}
match.setFinished();  // Mark finished AFTER the check passes
// ... rest of method executes normally with all cleanup logic

The first call executes completely. Subsequent concurrent calls are blocked. Could you clarify what specific issue you're seeing with this approach?

@dumbo-the-developer dumbo-the-developer deleted the copilot/fix-team-duel-ending-bug branch January 14, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants