Merge branch 'master' into fix-pofl-on-cooldown

This commit is contained in:
Salman Ahmed
2021-02-22 10:03:27 +03:00
57 changed files with 892 additions and 412 deletions

View File

@ -339,7 +339,7 @@ namespace osu.Game.Screens.Play
{
HoldToQuit =
{
Action = performUserRequestedExit,
Action = () => PerformExit(true),
IsPaused = { BindTarget = GameplayClockContainer.IsPaused }
},
PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = GameplayClockContainer.UserPlaybackRate } } },
@ -363,14 +363,14 @@ namespace osu.Game.Screens.Play
FailOverlay = new FailOverlay
{
OnRetry = Restart,
OnQuit = performUserRequestedExit,
OnQuit = () => PerformExit(true),
},
PauseOverlay = new PauseOverlay
{
OnResume = Resume,
Retries = RestartCount,
OnRetry = Restart,
OnQuit = performUserRequestedExit,
OnQuit = () => PerformExit(true),
},
new HotkeyExitOverlay
{
@ -379,7 +379,7 @@ namespace osu.Game.Screens.Play
if (!this.IsCurrentScreen()) return;
fadeOut(true);
PerformExit(true);
PerformExit(false);
},
},
failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, },
@ -432,9 +432,9 @@ namespace osu.Game.Screens.Play
if (gameActive.Value == false)
{
if (canPause)
Pause();
else
bool paused = Pause();
if (!paused)
Scheduler.AddOnce(updatePauseOnFocusLostState);
}
}
@ -483,23 +483,47 @@ namespace osu.Game.Screens.Play
/// <summary>
/// Exits the <see cref="Player"/>.
/// </summary>
/// <param name="userRequested">
/// Whether the exit is requested by the user, or a higher-level game component.
/// Pausing is allowed only in the former case.
/// <param name="showDialogFirst">
/// Whether the pause or fail dialog should be shown before performing an exit.
/// If true and a dialog is not yet displayed, the exit will be blocked the the relevant dialog will display instead.
/// </param>
protected void PerformExit(bool userRequested)
protected void PerformExit(bool showDialogFirst)
{
// if a restart has been requested, cancel any pending completion (user has shown intent to restart).
completionProgressDelegate?.Cancel();
ValidForResume = false;
// there is a chance that the exit was performed after the transition to results has started.
// we want to give the user what they want, so forcefully return to this screen (to proceed with the upwards exit process).
if (!this.IsCurrentScreen())
{
ValidForResume = false;
this.MakeCurrent();
return;
}
if (!this.IsCurrentScreen()) return;
bool pauseOrFailDialogVisible =
PauseOverlay.State.Value == Visibility.Visible || FailOverlay.State.Value == Visibility.Visible;
if (userRequested)
performUserRequestedExit();
else
this.Exit();
if (showDialogFirst && !pauseOrFailDialogVisible)
{
// if the fail animation is currently in progress, accelerate it (it will show the pause dialog on completion).
if (ValidForResume && HasFailed)
{
failAnimation.FinishTransforms(true);
return;
}
// there's a chance the pausing is not supported in the current state, at which point immediate exit should be preferred.
if (pausingSupportedByCurrentState)
{
// in the case a dialog needs to be shown, attempt to pause and show it.
// this may fail (see internal checks in Pause()) but the fail cases are temporary, so don't fall through to Exit().
Pause();
return;
}
}
this.Exit();
}
private void performUserRequestedSkip()
@ -513,20 +537,6 @@ namespace osu.Game.Screens.Play
updateSampleDisabledState();
}
private void performUserRequestedExit()
{
if (ValidForResume && HasFailed && !FailOverlay.IsPresent)
{
failAnimation.FinishTransforms(true);
return;
}
if (canPause)
Pause();
else
this.Exit();
}
/// <summary>
/// Restart gameplay via a parent <see cref="PlayerLoader"/>.
/// <remarks>This can be called from a child screen in order to trigger the restart process.</remarks>
@ -543,10 +553,7 @@ namespace osu.Game.Screens.Play
sampleRestart?.Play();
RestartRequested?.Invoke();
if (this.IsCurrentScreen())
PerformExit(true);
else
this.MakeCurrent();
PerformExit(false);
}
private ScheduledDelegate completionProgressDelegate;
@ -675,15 +682,18 @@ namespace osu.Game.Screens.Play
protected bool PauseCooldownActive =>
lastPauseActionTime.HasValue && GameplayClockContainer.GameplayClock.CurrentTime < lastPauseActionTime + pause_cooldown;
private bool canPause =>
/// <summary>
/// A set of conditionals which defines whether the current game state and configuration allows for
/// pausing to be attempted via <see cref="Pause"/>. If false, the game should generally exit if a user pause
/// is attempted.
/// </summary>
private bool pausingSupportedByCurrentState =>
// must pass basic screen conditions (beatmap loaded, instance allows pause)
LoadedBeatmapSuccessfully && Configuration.AllowPause && ValidForResume
// replays cannot be paused and exit immediately
&& !DrawableRuleset.HasReplayLoaded.Value
// cannot pause if we are already in a fail state
&& !HasFailed
// cannot pause if already paused (or in a cooldown state) unless we are in a resuming state.
&& (IsResuming || (GameplayClockContainer.IsPaused.Value == false && !PauseCooldownActive));
&& !HasFailed;
private bool canResume =>
// cannot resume from a non-paused state
@ -693,9 +703,12 @@ namespace osu.Game.Screens.Play
// already resuming
&& !IsResuming;
public void Pause()
public bool Pause()
{
if (!canPause) return;
if (!pausingSupportedByCurrentState) return false;
if (!IsResuming && PauseCooldownActive)
return false;
if (IsResuming)
{
@ -706,6 +719,7 @@ namespace osu.Game.Screens.Play
GameplayClockContainer.Stop();
PauseOverlay.Show();
lastPauseActionTime = GameplayClockContainer.GameplayClock.CurrentTime;
return true;
}
public void Resume()
@ -814,14 +828,6 @@ namespace osu.Game.Screens.Play
return true;
}
// ValidForResume is false when restarting
if (ValidForResume)
{
if (PauseCooldownActive && !GameplayClockContainer.IsPaused.Value)
// still want to block if we are within the cooldown period and not already paused.
return true;
}
// GameplayClockContainer performs seeks / start / stop operations on the beatmap's track.
// as we are no longer the current screen, we cannot guarantee the track is still usable.
GameplayClockContainer?.StopUsingBeatmapClock();