Skip to content

fix(matchdata): don't award a 1v1 win to a player who reported a loss - #38

Open
doopey655 wants to merge 1 commit into
GeneralsOnlineDevelopmentTeam:mainfrom
nathan-soul:fix/1v1-winner-by-disconnect
Open

fix(matchdata): don't award a 1v1 win to a player who reported a loss#38
doopey655 wants to merge 1 commit into
GeneralsOnlineDevelopmentTeam:mainfrom
nathan-soul:fix/1v1-winner-by-disconnect

Conversation

@doopey655

@doopey655 doopey655 commented Aug 12, 2026

Copy link
Copy Markdown

When no slot reports won=true, winner determination falls back to "last to leave wins". If the winner disconnects at the results screen their outcome POST never lands, while the loser reports won=false and leaves cleanly a moment later — so the loser is awarded the win, despite having conceded.

Adds a 1v1 tie-break ahead of that fallback: exactly two active participants and exactly one in-game disconnect record means the disconnected player won — they are the only one who could not report, and the other has already conceded. Teams, FFA, both disconnected, and neither disconnected all fall through unchanged. Decisions and declines both log under the existing [WinnerDet] prefix.

Verified with unit tests against the extracted TryResolveOneVsOneByDisconnect; not included here since the repo has no test project yet. Happy to add one separately if wanted.

When no slot reports won=true, DetermineLobbyWinnerIfNotPresent falls back to
"last to leave wins". That inverts the result in a common case: a player whose
outcome POST never lands (disconnect at the results screen) is stamped early by
RecordPlayerIngameAbandon, while their opponent leaves cleanly from the score
screen moments later and is awarded the win - despite having explicitly reported
won=false.

The server already had the answer in the database and discarded it in favour of
guessing on exit order.

Add a 1v1 tie-break ahead of the timestamp fallback: when there are exactly two
active participants and exactly one of them has an in-game disconnect record,
that player wins. They are the only one who could not report, and their opponent
has already conceded, so nothing is left to guess.

Deliberately narrow - falls through to the existing fallback unchanged when:
  - the match is not 1v1 (a single disconnect says nothing in teams or FFA)
  - both players disconnected (genuinely undecidable)
  - neither disconnected (nothing to infer)
  - any slot claimed won=true (the conclusive path already handles it)

Observers and AI/placeholder slots are excluded using the same filter the
timestamp fallback applies. Both the decision and the declines are logged under
the existing [WinnerDet] prefix so a future wrong-winner report can be diagnosed
from logs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@JoKeRZH429 JoKeRZH429 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think you can make this way simpler/cleaner by adding a OutcomeReported flag per player when the /Outcome payload is processed, And then check that in the DetermineLobbyWinnerIfNotPresent function. There would be two ways of doing that, either using the MatchdataMemberModel, persisting it in the db and then querying it when needed, or storing it in memory (but probably can't be tied to the Lobby reference). Not sure which one would be better. But storing it in db would be much simpler code.

I do not like going off by abandoned timestamp. I haven't looked in that code in too much detail but I am not even sure if it gets cleared after a successful reconnect and it makes the code unnecessarily more complicated than need be. We already know explicitly whether a player submitted /Outcome, so better to make use of that imo

And you should also check that the match_roster_type is '1v1' alongside the condition that there are two non-observer players.

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