mirror of
https://github.com/ppy/osu.git
synced 2024-11-13 17:27:48 +08:00
Merge pull request #25097 from peppy/results-screen-progress-fast
Show results immediately if user hits "back" key after finishing gameplay
This commit is contained in:
commit
5f51b8a7c9
@ -72,12 +72,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStoryboardExitDuringOutroStillExits()
|
||||
public void TestStoryboardExitDuringOutroProgressesToResults()
|
||||
{
|
||||
CreateTest();
|
||||
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||
AddStep("exit via pause", () => Player.ExitViaPause());
|
||||
AddAssert("player exited", () => !Player.IsCurrentScreen() && Player.GetChildScreen() == null);
|
||||
AddUntilStep("reached results screen", () => Stack.CurrentScreen is ResultsScreen);
|
||||
}
|
||||
|
||||
[TestCase(false)]
|
||||
@ -171,7 +171,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("disable storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, false));
|
||||
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||
AddStep("exit via pause", () => Player.ExitViaPause());
|
||||
AddAssert("player exited", () => Stack.CurrentScreen == null);
|
||||
AddUntilStep("reached results screen", () => Stack.CurrentScreen is ResultsScreen);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -215,6 +215,24 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
AddAssert("retry count is 1", () => player.RestartCount == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRetryImmediatelyAfterCompletion()
|
||||
{
|
||||
var getOriginalPlayer = playToCompletion();
|
||||
|
||||
AddStep("attempt to retry", () => getOriginalPlayer().ChildrenOfType<HotkeyRetryOverlay>().First().Action());
|
||||
AddUntilStep("wait for player", () => Game.ScreenStack.CurrentScreen != getOriginalPlayer() && Game.ScreenStack.CurrentScreen is Player);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitImmediatelyAfterCompletion()
|
||||
{
|
||||
var player = playToCompletion();
|
||||
|
||||
AddStep("attempt to exit", () => player().ChildrenOfType<HotkeyExitOverlay>().First().Action());
|
||||
AddUntilStep("wait for results", () => Game.ScreenStack.CurrentScreen is ResultsScreen);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRetryFromResults()
|
||||
{
|
||||
@ -778,6 +796,13 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
}
|
||||
|
||||
private Func<Player> playToResults()
|
||||
{
|
||||
var player = playToCompletion();
|
||||
AddUntilStep("wait for results", () => (Game.ScreenStack.CurrentScreen as ResultsScreen)?.IsLoaded == true);
|
||||
return player;
|
||||
}
|
||||
|
||||
private Func<Player> playToCompletion()
|
||||
{
|
||||
Player player = null;
|
||||
|
||||
@ -803,7 +828,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
AddUntilStep("wait for track playing", () => beatmap().Track.IsRunning);
|
||||
AddStep("seek to near end", () => player.ChildrenOfType<GameplayClockContainer>().First().Seek(beatmap().Beatmap.HitObjects[^1].StartTime - 1000));
|
||||
AddUntilStep("wait for pass", () => (Game.ScreenStack.CurrentScreen as ResultsScreen)?.IsLoaded == true);
|
||||
AddUntilStep("wait for complete", () => player.GameplayState.HasPassed);
|
||||
|
||||
return () => player;
|
||||
}
|
||||
|
||||
|
@ -279,8 +279,10 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
if (!this.IsCurrentScreen()) return;
|
||||
|
||||
fadeOut(true);
|
||||
PerformExit(false);
|
||||
if (PerformExit(false))
|
||||
// The hotkey overlay dims the screen.
|
||||
// If the operation succeeds, we want to make sure we stay dimmed to keep continuity.
|
||||
fadeOut(true);
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -298,8 +300,10 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
if (!this.IsCurrentScreen()) return;
|
||||
|
||||
fadeOut(true);
|
||||
Restart(true);
|
||||
if (Restart(true))
|
||||
// The hotkey overlay dims the screen.
|
||||
// If the operation succeeds, we want to make sure we stay dimmed to keep continuity.
|
||||
fadeOut(true);
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -565,20 +569,9 @@ namespace osu.Game.Screens.Play
|
||||
/// Whether the pause or fail dialog should be shown before performing an exit.
|
||||
/// If <see langword="true"/> and a dialog is not yet displayed, the exit will be blocked and the relevant dialog will display instead.
|
||||
/// </param>
|
||||
protected void PerformExit(bool showDialogFirst)
|
||||
/// <returns>Whether this call resulted in a final exit.</returns>
|
||||
protected bool PerformExit(bool showDialogFirst)
|
||||
{
|
||||
// there is a chance that an exit request occurs after the transition to results has already started.
|
||||
// even in such a case, the user has shown intent, so forcefully return to this screen (to proceed with the upwards exit process).
|
||||
if (!this.IsCurrentScreen())
|
||||
{
|
||||
ValidForResume = false;
|
||||
|
||||
// in the potential case that this instance has already been exited, this is required to avoid a crash.
|
||||
if (this.GetChildScreen() != null)
|
||||
this.MakeCurrent();
|
||||
return;
|
||||
}
|
||||
|
||||
bool pauseOrFailDialogVisible =
|
||||
PauseOverlay.State.Value == Visibility.Visible || FailOverlay.State.Value == Visibility.Visible;
|
||||
|
||||
@ -588,7 +581,7 @@ namespace osu.Game.Screens.Play
|
||||
if (ValidForResume && GameplayState.HasFailed)
|
||||
{
|
||||
failAnimationContainer.FinishTransforms(true);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// even if this call has requested a dialog, there is a chance the current player mode doesn't support pausing.
|
||||
@ -597,21 +590,32 @@ namespace osu.Game.Screens.Play
|
||||
// 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;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// if an exit has been requested, cancel any pending completion (the user has shown intention to exit).
|
||||
resultsDisplayDelegate?.Cancel();
|
||||
// Matching osu!stable behaviour, if the results screen is pending and the user requests an exit,
|
||||
// show the results instead.
|
||||
if (GameplayState.HasPassed && !isRestarting)
|
||||
{
|
||||
progressToResults(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// import current score if possible.
|
||||
prepareAndImportScoreAsync();
|
||||
|
||||
// The actual exit is performed if
|
||||
// - the pause / fail dialog was not requested
|
||||
// - the pause / fail dialog was requested but is already displayed (user showing intention to exit).
|
||||
// - the pause / fail dialog was requested but couldn't be displayed due to the type or state of this Player instance.
|
||||
this.Exit();
|
||||
// Screen may not be current if a restart has been performed.
|
||||
if (this.IsCurrentScreen())
|
||||
{
|
||||
// The actual exit is performed if
|
||||
// - the pause / fail dialog was not requested
|
||||
// - the pause / fail dialog was requested but is already displayed (user showing intention to exit).
|
||||
// - the pause / fail dialog was requested but couldn't be displayed due to the type or state of this Player instance.
|
||||
this.Exit();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void performUserRequestedSkip()
|
||||
@ -660,10 +664,11 @@ namespace osu.Game.Screens.Play
|
||||
/// <remarks>This can be called from a child screen in order to trigger the restart process.</remarks>
|
||||
/// </summary>
|
||||
/// <param name="quickRestart">Whether a quick restart was requested (skipping intro etc.).</param>
|
||||
public void Restart(bool quickRestart = false)
|
||||
/// <returns>Whether this call resulted in a restart.</returns>
|
||||
public bool Restart(bool quickRestart = false)
|
||||
{
|
||||
if (!Configuration.AllowRestart)
|
||||
return;
|
||||
return false;
|
||||
|
||||
isRestarting = true;
|
||||
|
||||
@ -673,7 +678,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
RestartRequested?.Invoke(quickRestart);
|
||||
|
||||
PerformExit(false);
|
||||
return PerformExit(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -729,9 +734,6 @@ namespace osu.Game.Screens.Play
|
||||
// is no chance that a user could return to the (already completed) Player instance from a child screen.
|
||||
ValidForResume = false;
|
||||
|
||||
if (!Configuration.ShowResults)
|
||||
return;
|
||||
|
||||
bool storyboardStillRunning = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value;
|
||||
|
||||
// If the current beatmap has a storyboard, this method will be called again on storyboard completion.
|
||||
@ -754,10 +756,16 @@ namespace osu.Game.Screens.Play
|
||||
/// <param name="withDelay">Whether a minimum delay (<see cref="RESULTS_DISPLAY_DELAY"/>) should be added before the screen is displayed.</param>
|
||||
private void progressToResults(bool withDelay)
|
||||
{
|
||||
resultsDisplayDelegate?.Cancel();
|
||||
if (!Configuration.ShowResults)
|
||||
return;
|
||||
|
||||
// Setting this early in the process means that even if something were to go wrong in the order of events following, there
|
||||
// is no chance that a user could return to the (already completed) Player instance from a child screen.
|
||||
ValidForResume = false;
|
||||
|
||||
double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0;
|
||||
|
||||
resultsDisplayDelegate?.Cancel();
|
||||
resultsDisplayDelegate = new ScheduledDelegate(() =>
|
||||
{
|
||||
if (prepareScoreForDisplayTask == null)
|
||||
@ -1200,8 +1208,11 @@ namespace osu.Game.Screens.Play
|
||||
float fadeOutDuration = instant ? 0 : 250;
|
||||
this.FadeOut(fadeOutDuration);
|
||||
|
||||
ApplyToBackground(b => b.IgnoreUserSettings.Value = true);
|
||||
storyboardReplacesBackground.Value = false;
|
||||
if (this.IsCurrentScreen())
|
||||
{
|
||||
ApplyToBackground(b => b.IgnoreUserSettings.Value = true);
|
||||
storyboardReplacesBackground.Value = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -414,6 +414,8 @@ namespace osu.Game.Screens.Play
|
||||
quickRestart = quickRestartRequested;
|
||||
hideOverlays = true;
|
||||
ValidForResume = true;
|
||||
|
||||
this.MakeCurrent();
|
||||
}
|
||||
|
||||
private void contentIn()
|
||||
|
Loading…
Reference in New Issue
Block a user