From 7e53df5226667d6b7c1ba13bc9898a066e722ddf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= <dach.bartlomiej@gmail.com>
Date: Fri, 6 Sep 2024 13:01:50 +0200
Subject: [PATCH 1/2] Add failing test coverage

---
 .../TestScenePlayerScoreSubmission.cs         | 29 +++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
index 5e22e47572..c382f0828b 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs
@@ -8,7 +8,9 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using NUnit.Framework;
+using osu.Framework.Graphics.Containers;
 using osu.Framework.Screens;
+using osu.Framework.Testing;
 using osu.Game.Beatmaps;
 using osu.Game.Online.API;
 using osu.Game.Online.Rooms;
@@ -26,6 +28,7 @@ using osu.Game.Scoring;
 using osu.Game.Screens.Play;
 using osu.Game.Screens.Ranking;
 using osu.Game.Tests.Beatmaps;
+using osuTK.Input;
 
 namespace osu.Game.Tests.Visual.Gameplay
 {
@@ -177,6 +180,30 @@ namespace osu.Game.Tests.Visual.Gameplay
             AddAssert("ensure no submission", () => Player.SubmittedScore == null);
         }
 
+        [Test]
+        public void TestEmptyFailStillImports()
+        {
+            prepareTestAPI(true);
+
+            createPlayerTest(true);
+
+            AddUntilStep("wait for token request", () => Player.TokenCreationRequested);
+
+            AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed);
+            AddUntilStep("wait for fail overlay", () => Player.FailOverlay.State.Value, () => Is.EqualTo(Visibility.Visible));
+
+            AddStep("attempt import", () =>
+            {
+                InputManager.MoveMouseTo(Player.ChildrenOfType<SaveFailedScoreButton>().Single());
+                InputManager.Click(MouseButton.Left);
+            });
+            AddUntilStep("wait for import to start", () => Player.ScoreImportStarted);
+            AddStep("allow import", () => Player.AllowImportCompletion.Release());
+
+            AddUntilStep("import completed", () => Player.ImportedScore, () => Is.Not.Null);
+            AddAssert("ensure no submission", () => Player.SubmittedScore, () => Is.Null);
+        }
+
         [Test]
         public void TestSubmissionOnFail()
         {
@@ -378,6 +405,8 @@ namespace osu.Game.Tests.Visual.Gameplay
             public SemaphoreSlim AllowImportCompletion { get; }
             public Score ImportedScore { get; private set; }
 
+            public new FailOverlay FailOverlay => base.FailOverlay;
+
             public FakeImportingPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false)
                 : base(allowPause, showResults, pauseOnFocusLost)
             {

From 4e9ad1388fb0de72c6197faa9ad6d56fb1a87087 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= <dach.bartlomiej@gmail.com>
Date: Fri, 6 Sep 2024 13:16:27 +0200
Subject: [PATCH 2/2] Fix stall when attempting to import replay after hitting
 nothing

---
 osu.Game/Screens/Play/SubmittingPlayer.cs | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs
index 6c5f7fab9e..aea3bf6d5c 100644
--- a/osu.Game/Screens/Play/SubmittingPlayer.cs
+++ b/osu.Game/Screens/Play/SubmittingPlayer.cs
@@ -274,6 +274,16 @@ namespace osu.Game.Screens.Play
                 return Task.CompletedTask;
             }
 
+            // if the user never hit anything, this score should not be counted in any way.
+            if (!score.ScoreInfo.Statistics.Any(s => s.Key.IsHit() && s.Value > 0))
+            {
+                Logger.Log("No hits registered, skipping score submission");
+                return Task.CompletedTask;
+            }
+
+            // mind the timing of this.
+            // once `scoreSubmissionSource` is created, it is presumed that submission is taking place in the background,
+            // so all exceptional circumstances that would disallow submission must be handled above.
             lock (scoreSubmissionLock)
             {
                 if (scoreSubmissionSource != null)
@@ -282,10 +292,6 @@ namespace osu.Game.Screens.Play
                 scoreSubmissionSource = new TaskCompletionSource<bool>();
             }
 
-            // if the user never hit anything, this score should not be counted in any way.
-            if (!score.ScoreInfo.Statistics.Any(s => s.Key.IsHit() && s.Value > 0))
-                return Task.CompletedTask;
-
             Logger.Log($"Beginning score submission (token:{token.Value})...");
             var request = CreateSubmissionRequest(score, token.Value);