diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index a5e442b7de..7bf0482673 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -39,6 +39,9 @@ namespace osu.Game.Rulesets.UI
{
set
{
+ if (value == recorder)
+ return;
+
if (value != null && recorder != null)
throw new InvalidOperationException("Cannot attach more than one recorder");
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 6dc4854e80..bc453d2151 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -276,7 +276,7 @@ namespace osu.Game.Screens.Play
},
FailOverlay = new FailOverlay
{
- SaveReplay = prepareAndImportScore,
+ SaveReplay = async () => await prepareAndImportScoreAsync(true).ConfigureAwait(false),
OnRetry = () => Restart(),
OnQuit = () => PerformExit(true),
},
@@ -613,6 +613,9 @@ namespace osu.Game.Screens.Play
// if an exit has been requested, cancel any pending completion (the user has shown intention to exit).
resultsDisplayDelegate?.Cancel();
+ // 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).
@@ -735,14 +738,9 @@ 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;
- // Ensure we are not writing to the replay any more, as we are about to consume and store the score.
- DrawableRuleset.SetRecordTarget(null);
-
if (!Configuration.ShowResults)
return;
- prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
-
bool storyboardHasOutro = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value;
if (storyboardHasOutro)
@@ -756,35 +754,6 @@ namespace osu.Game.Screens.Play
progressToResults(true);
}
- ///
- /// Asynchronously run score preparation operations (database import, online submission etc.).
- ///
- /// The final score.
- private async Task prepareAndImportScore()
- {
- var scoreCopy = Score.DeepClone();
-
- try
- {
- await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.Error(ex, @"Score preparation failed!");
- }
-
- try
- {
- await ImportScore(scoreCopy).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.Error(ex, @"Score import failed!");
- }
-
- return scoreCopy.ScoreInfo;
- }
-
///
/// Queue the results screen for display.
///
@@ -800,12 +769,25 @@ namespace osu.Game.Screens.Play
resultsDisplayDelegate = new ScheduledDelegate(() =>
{
- if (prepareScoreForDisplayTask?.IsCompleted != true)
+ if (prepareScoreForDisplayTask == null)
+ {
+ // Try importing score since the task hasn't been invoked yet.
+ prepareAndImportScoreAsync();
+ return;
+ }
+
+ if (!prepareScoreForDisplayTask.IsCompleted)
// If the asynchronous preparation has not completed, keep repeating this delegate.
return;
resultsDisplayDelegate?.Cancel();
+ if (prepareScoreForDisplayTask.GetResultSafely() == null)
+ {
+ // If score import did not occur, we do not want to show the results screen.
+ return;
+ }
+
if (!this.IsCurrentScreen())
// This player instance may already be in the process of exiting.
return;
@@ -816,6 +798,51 @@ namespace osu.Game.Screens.Play
Scheduler.Add(resultsDisplayDelegate);
}
+ ///
+ /// Asynchronously run score preparation operations (database import, online submission etc.).
+ ///
+ /// Whether the score should be imported even if non-passing (or the current configuration doesn't allow for it).
+ /// The final score.
+ [ItemCanBeNull]
+ private Task prepareAndImportScoreAsync(bool forceImport = false)
+ {
+ // Ensure we are not writing to the replay any more, as we are about to consume and store the score.
+ DrawableRuleset.SetRecordTarget(null);
+
+ if (prepareScoreForDisplayTask != null)
+ return prepareScoreForDisplayTask;
+
+ // We do not want to import the score in cases where we don't show results
+ bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
+ if (!canShowResults && !forceImport)
+ return Task.FromResult(null);
+
+ return prepareScoreForDisplayTask = Task.Run(async () =>
+ {
+ var scoreCopy = Score.DeepClone();
+
+ try
+ {
+ await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(ex, @"Score preparation failed!");
+ }
+
+ try
+ {
+ await ImportScore(scoreCopy).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(ex, @"Score import failed!");
+ }
+
+ return scoreCopy.ScoreInfo;
+ });
+ }
+
protected override bool OnScroll(ScrollEvent e)
{
// During pause, allow global volume adjust regardless of settings.