mirror of https://github.com/ppy/osu
86a8ab6db6
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. |
||
---|---|---|
.. | ||
Backgrounds | ||
Edit | ||
Import | ||
Menu | ||
OnlinePlay | ||
Play | ||
Ranking | ||
Select | ||
Spectate | ||
Utility | ||
BackgroundScreen.cs | ||
BackgroundScreenStack.cs | ||
IHandlePresentBeatmap.cs | ||
IHasSubScreenStack.cs | ||
IOsuScreen.cs | ||
IPerformFromScreenRunner.cs | ||
Loader.cs | ||
OsuScreen.cs | ||
OsuScreenDependencies.cs | ||
OsuScreenStack.cs | ||
ScorePresentType.cs | ||
ScreenWhiteBox.cs | ||
StartupScreen.cs |