Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@smoogipoo
Copy link
Contributor

Same code as multiplayer:

private void onLeaving()
{
// Must hide this overlay because it is added to a global container.
userModsSelectOverlay.Hide();
endHandlingTrack();
}
/// <summary>
/// Handles changes in the track to keep it looping while active.
/// </summary>
private void beginHandlingTrack()
{
Beatmap.BindValueChanged(applyLoopingToTrack, true);
}
/// <summary>
/// Stops looping the current track and stops handling further changes to the track.
/// </summary>
private void endHandlingTrack()
{
Beatmap.ValueChanged -= applyLoopingToTrack;
Beatmap.Value.Track.Looping = false;
previewTrackManager.StopAnyPlaying(this);
}
/// <summary>
/// Invoked on changes to the beatmap to loop the track. See: <see cref="beginHandlingTrack"/>.
/// </summary>
/// <param name="beatmap">The beatmap change event.</param>
private void applyLoopingToTrack(ValueChangedEvent<WorkingBeatmap> beatmap)
{
if (!this.IsCurrentScreen())
return;
beatmap.NewValue.PrepareTrackForPreview(true);
music.EnsurePlayingSomething();
}

@peppy
Copy link
Member

peppy commented Oct 21, 2025

It would be nice if the song changed at the precise point of random selection, rather than in the next step.

Also, this changes the behaviour on entering a match in a slightly weird way – even though there's not a valid song to play, on entering a match (after matchmaking succeeds) it plays a new random track from the start. For a lot of songs this results in an awkward silence. Can we make it continue playing the menu track until a valid track is available to take over?

Copy link
Member

@peppy peppy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As commented.

@smoogipoo
Copy link
Contributor Author

smoogipoo commented Oct 21, 2025

this changes the behaviour on entering a match in a slightly weird way – even though there's not a valid song to play

I think the last commit should resolve this for you. Please check again.

It would be nice if the song changed at the precise point of random selection, rather than in the next step.

Client-side can be done via:

diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs
index 1d3153915f..00bcfaffdb 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/BeatmapSelect/BeatmapSelectGrid.cs
@@ -16,6 +16,7 @@
 using osu.Framework.Utils;
 using osu.Game.Graphics.Containers;
 using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Online.Multiplayer;
 using osu.Game.Online.Rooms;
 using osuTK;
 
@@ -33,6 +34,12 @@ public partial class BeatmapSelectGrid : CompositeDrawable
 
         public event Action<MultiplayerPlaylistItem>? ItemSelected;
 
+        [Resolved]
+        private ScreenMatchmaking? matchmakingScreen { get; set; }
+
+        [Resolved]
+        private MultiplayerClient client { get; set; } = null!;
+
         private readonly Dictionary<long, BeatmapSelectPanel> panelLookup = new Dictionary<long, BeatmapSelectPanel>();
 
         private readonly PanelGridContainer panelGridContainer;
@@ -151,7 +158,8 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId
                 this.Delay(ARRANGE_DELAY)
                     .Schedule(() => ArrangeItemsForRollAnimation())
                     .Delay(arrange_duration + present_beatmap_delay)
-                    .Schedule(() => PresentUnanimouslyChosenBeatmap(finalItemId));
+                    .Schedule(() => PresentUnanimouslyChosenBeatmap(finalItemId))
+                    .Schedule(() => setBeatmap(finalItemId));
             }
             else
             {
@@ -160,7 +168,8 @@ public void RollAndDisplayFinalBeatmap(long[] candidateItemIds, long finalItemId
                     .Delay(arrange_duration)
                     .Schedule(() => PlayRollAnimation(finalItemId, roll_duration))
                     .Delay(roll_duration + present_beatmap_delay)
-                    .Schedule(() => PresentRolledBeatmap(finalItemId));
+                    .Schedule(() => PresentRolledBeatmap(finalItemId))
+                    .Schedule(() => setBeatmap(finalItemId));
             }
         }
 
@@ -341,6 +350,16 @@ internal void PresentUnanimouslyChosenBeatmap(long finalItem)
             PresentRolledBeatmap(finalItem);
         }
 
+        private void setBeatmap(long playlistItemId)
+        {
+            MultiplayerPlaylistItem? item = client.Room?.Playlist.SingleOrDefault(item => item.ID == playlistItemId);
+
+            if (item == null)
+                return;
+
+            matchmakingScreen?.SetPlaylistItem(item);
+        }
+
         private partial class PanelGridContainer : FillFlowContainer<BeatmapSelectPanel>
         {
             public bool LayoutDisabled;
diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs
index c16cf5cb99..35f255d98e 100644
--- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs
+++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs
@@ -38,6 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match
     /// <summary>
     /// The main matchmaking screen which houses a custom <see cref="ScreenStack"/> through the life cycle of a single session.
     /// </summary>
+    [Cached]
     public partial class ScreenMatchmaking : OsuScreen, IPreviewTrackOwner
     {
         /// <summary>
@@ -225,19 +226,8 @@ private void updateGameplayState()
             if (item.Expired)
                 return;
 
-            RulesetInfo ruleset = rulesets.GetRuleset(item.RulesetID)!;
-            Ruleset rulesetInstance = ruleset.CreateInstance();
-
-            // Update global gameplay state to correspond to the new selection.
-            // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
-            var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", item.BeatmapID);
-
-            if (localBeatmap != null)
+            if (SetPlaylistItem(item))
             {
-                Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
-                Ruleset.Value = ruleset;
-                Mods.Value = item.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
-
                 // Notify the server that the beatmap has been set and that we are ready to start gameplay.
                 if (client.LocalUser!.State == MultiplayerUserState.Idle)
                     client.ChangeState(MultiplayerUserState.Ready).FireAndForget();
@@ -252,6 +242,29 @@ private void updateGameplayState()
             client.ChangeBeatmapAvailability(beatmapAvailabilityTracker.Availability.Value).FireAndForget();
         }
 
+        /// <summary>
+        /// Attempts to set the global beatmap from the given playlist item.
+        /// </summary>
+        /// <param name="item">The playlist item.</param>
+        /// <returns><c>true</c> if the beatmap exists locally and was set, <c>false</c> otherwise.</returns>
+        public bool SetPlaylistItem(MultiplayerPlaylistItem item)
+        {
+            RulesetInfo ruleset = rulesets.GetRuleset(item.RulesetID)!;
+            Ruleset rulesetInstance = ruleset.CreateInstance();
+
+            // Update global gameplay state to correspond to the new selection.
+            // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
+            var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", item.BeatmapID);
+            if (localBeatmap == null)
+                return false;
+
+            Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
+            Ruleset.Value = ruleset;
+            Mods.Value = item.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
+
+            return true;
+        }
+
         private void onLoadRequested() => Scheduler.Add(() =>
         {
             updateGameplayState();

But, it's a little bit awkward - this method doesn't start the download for example. Would leave this for a future effort.

@peppy
Copy link
Member

peppy commented Oct 23, 2025

But, it's a little bit awkward - this method doesn't start the download for example. Would leave this for a future effort.

Sure but I'd hope it's prioritised. I think it will add a really nice feel to the flow which is missing atm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants