From ff820f730e821c67b02f18b00b079ecbd564aaca Mon Sep 17 00:00:00 2001 From: Jul Date: Mon, 5 Jan 2026 06:54:25 +0100 Subject: [PATCH] Fix play button starting wrong beatmap before selection loads (#36104) * Fix play button starting wrong beatmap before selection loads When clicking the osu! cookie (play button) before a newly selected beatmap finishes loading, the previous beatmap would be played instead of the currently selected one. This was caused by the cookie reading from the global beatmap state which is debounced by 150ms, while the Enter key correctly used the carousel's current selection. The fix makes the cookie use the same beatmap source as Enter - the carousel's current selection - which is always up-to-date regardless of debounce timing. Closes #36074 * Use ensureGlobalBeatmapValid() for logo and Enter key actions * Add test for beatmap selection timing bug Tests the fix for issue #36074 where clicking the play button immediately after selecting a different difficulty would start the wrong beatmap due to the 150ms selection debounce. --- .../SongSelectV2/TestSceneSongSelect.cs | 45 +++++++++++++++++++ osu.Game/Screens/SelectV2/SongSelect.cs | 2 + 2 files changed, 47 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs index a480e51adf..f47eafc937 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneSongSelect.cs @@ -659,6 +659,51 @@ namespace osu.Game.Tests.Visual.SongSelectV2 AddAssert("options disabled", () => !this.ChildrenOfType().Single().Enabled.Value); } + /// + /// tests that clicking the osu! logo immediately after selecting a different difficulty + /// (before the selection debounce completes) starts the correct beatmap. + /// this tests the fix for https://github.com/ppy/osu/issues/36074 + /// + [Test] + public void TestPlayCorrectBeatmapWhenSelectionNotFullyLoaded() + { + // import a beatmap set with multiple difficulties + ImportBeatmapForRuleset(0); + + LoadSongSelect(); + + // wait for initial beatmap to be selected + AddUntilStep("wait for first beatmap selected", () => !Beatmap.IsDefault); + + BeatmapInfo? firstBeatmap = null; + AddStep("store first difficulty", () => firstBeatmap = Beatmap.Value.BeatmapInfo); + + // start loading the first difficulty + AddStep("click logo to start loading", () => this.ChildrenOfType().Single().TriggerClick()); + AddUntilStep("wait for player loader", () => Stack.CurrentScreen is PlayerLoader); + + // return to song select + AddStep("press escape to return", () => InputManager.Key(Key.Escape)); + AddUntilStep("wait for return to song select", () => SongSelect.IsCurrentScreen()); + + // press down and schedule logo click to happen shortly after (but before 150ms debounce) + // this reproduces the race condition where Beatmap.Value hasn't updated yet + AddStep("select next difficulty and click logo immediately", () => + { + InputManager.Key(Key.Down); + Schedule(() => this.ChildrenOfType().Single().TriggerClick()); + }); + + AddUntilStep("wait for player loader", () => Stack.CurrentScreen is PlayerLoader); + + // verify we're loading the second difficulty, not the first + // without the fix, this would fail because Beatmap.Value still has the old value + AddAssert("player is loading second difficulty", () => + Beatmap.Value.BeatmapInfo.ID != firstBeatmap!.ID); + + AddUntilStep("wait for return to song select", () => SongSelect.IsCurrentScreen()); + } + #endregion } } diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 944c93bd5f..4bee63b57c 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -756,6 +756,7 @@ namespace osu.Game.Screens.SelectV2 logo.Action = () => { + ensureGlobalBeatmapValid(); SelectAndRun(Beatmap.Value.BeatmapInfo, OnStart); return false; }; @@ -999,6 +1000,7 @@ namespace osu.Game.Screens.SelectV2 // one of which is filtering out all visible beatmaps and attempting to start gameplay. // in that case, users still expect a `Select` press to advance to gameplay anyway, using the ambient selected beatmap if there is one, // which matches the behaviour resulting from clicking the osu! cookie in that scenario. + ensureGlobalBeatmapValid(); SelectAndRun(Beatmap.Value.BeatmapInfo, OnStart); return true;