1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 16:12:57 +08:00

Fix quick retry immediately after completion marking score as failed

Closes https://github.com/ppy/osu/issues/25247.

The scenario involved here is as follows:

1. User completes beatmap by hitting all notes.
2. `checkScoreCompleted()` determines completion, and calls
   `progressToResults(withDelay: true)`.
3. `progressToResults()` schedules `resultsDisplayDelegate`, which
   includes a call to `prepareAndImportScoreAsync()`, a second in the
   future.
4. User presses quick retry hotkey.
   This calls `Player.Restart(quickRestart: true)`,
   which invokes `Player.RestartRequested`,
   which in turn calls `PlayerLoader.restartRequested(true)`,
   which in turn causes `PlayerLoader` to make itself current,
   which means that `Player.OnExiting()` will get called.
5. `Player.OnExiting()` sees that `prepareScoreForDisplayTask` is null
   (because `prepareAndImportScoreAsync()` - which sets it -
   is scheduled to happen in the future), and as such assumes that
   the score did not complete. Thus, it marks the score as failed.
6. `Player.Restart()` after invoking `RestartRequested` calls
   `PerformExit(false)`, which then will unconditionally call
   `prepareAndImportScoreAsync()`. But the score has already been marked
   as failed.

The flow above can be described as "convoluted", but I'm not sure I have
it in me right now to try and refactor it again. Therefore, to fix,
switch the `prepareScoreForDisplayTask` null check in
`Player.OnExiting()` to check `GameplayState.HasPassed` instead, as it
is not susceptible to the same out-of-order read issue.
This commit is contained in:
Bartłomiej Dach 2023-10-27 11:39:43 +02:00
parent 7140eee870
commit 86a8ab6db6
No known key found for this signature in database

View File

@ -1115,8 +1115,7 @@ namespace osu.Game.Screens.Play
if (!GameplayState.HasPassed && !GameplayState.HasFailed)
GameplayState.HasQuit = true;
// if arriving here and the results screen preparation task hasn't run, it's safe to say the user has not completed the beatmap.
if (prepareScoreForDisplayTask == null && DrawableRuleset.ReplayScore == null)
if (!GameplayState.HasPassed && DrawableRuleset.ReplayScore == null)
ScoreProcessor.FailScore(Score.ScoreInfo);
}