1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-13 11:12:54 +08:00

Fix thread race conditions on pausing close to a fail.

This commit is contained in:
Dean Herbert 2017-04-13 11:41:08 +09:00
parent 7b240d84da
commit 94bf1d65b6
No known key found for this signature in database
GPG Key ID: 46D71BF4958ABB49

View File

@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play
private const double pause_cooldown = 1000;
private double lastPauseActionTime;
private bool canPause => Time.Current >= lastPauseActionTime + pause_cooldown;
private bool canPause => ValidForResume && !HasFailed && Time.Current >= lastPauseActionTime + pause_cooldown;
private IAdjustableClock sourceClock;
private IFrameBasedClock interpolatedSourceClock;
@ -206,11 +206,28 @@ namespace osu.Game.Screens.Play
{
if (!canPause && !force) return;
lastPauseActionTime = Time.Current;
hudOverlay.KeyCounter.IsCounting = false;
pauseOverlay.Retries = RestartCount;
pauseOverlay.Show();
sourceClock.Stop();
// the actual pausing is potentially happening on a different thread.
// we want to wait for the source clock to stop so we can be sure all components are in a stable state.
if (!IsPaused)
{
Schedule(() => Pause(force));
return;
}
// we need to do a final check after all of our children have processed up to the paused clock time.
// this is to cover cases where, for instance, the player fails in the last processed frame (which would change canPause).
// as the scheduler runs before children updates, let's schedule for the next frame.
Schedule(() =>
{
if (!canPause) return;
lastPauseActionTime = Time.Current;
hudOverlay.KeyCounter.IsCounting = false;
pauseOverlay.Retries = RestartCount;
pauseOverlay.Show();
});
}
public void Resume()
@ -227,11 +244,11 @@ namespace osu.Game.Screens.Play
var newPlayer = new Player();
ValidForResume = false;
LoadComponentAsync(newPlayer, delegate
{
newPlayer.RestartCount = RestartCount + 1;
ValidForResume = false;
if (!Push(newPlayer))
{
// Error(?)
@ -247,10 +264,11 @@ namespace osu.Game.Screens.Play
if (scoreProcessor.HasFailed || onCompletionEvent != null)
return;
ValidForResume = false;
Delay(1000);
onCompletionEvent = Schedule(delegate
{
ValidForResume = false;
Push(new Results
{
Score = scoreProcessor.CreateScore()
@ -262,8 +280,6 @@ namespace osu.Game.Screens.Play
{
sourceClock.Stop();
Delay(500);
HasFailed = true;
failOverlay.Retries = RestartCount;
failOverlay.Show();