diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 590d84f310..c16cf5cb99 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -16,6 +16,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.Cursor; @@ -37,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match /// /// The main matchmaking screen which houses a custom through the life cycle of a single session. /// - public partial class ScreenMatchmaking : OsuScreen + public partial class ScreenMatchmaking : OsuScreen, IPreviewTrackOwner { /// /// Padding between rows of the content. @@ -74,6 +75,12 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match [Resolved] private AudioManager audio { get; set; } = null!; + [Resolved] + private PreviewTrackManager previewTrackManager { get; set; } = null!; + + [Resolved] + private MusicController music { get; set; } = null!; + private readonly MultiplayerRoom room; private Sample? sampleStart; @@ -224,19 +231,22 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match // 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); - Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); - Ruleset.Value = ruleset; - Mods.Value = item.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); - if (Beatmap.Value is DummyWorkingBeatmap) + if (localBeatmap != null) { - if (client.LocalUser!.State == MultiplayerUserState.Ready) - client.ChangeState(MultiplayerUserState.Idle).FireAndForget(); + 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(); } else { - if (client.LocalUser!.State == MultiplayerUserState.Idle) - client.ChangeState(MultiplayerUserState.Ready).FireAndForget(); + // Notify the server that we don't have the beatmap. + if (client.LocalUser!.State == MultiplayerUserState.Ready) + client.ChangeState(MultiplayerUserState.Idle).FireAndForget(); } client.ChangeBeatmapAvailability(beatmapAvailabilityTracker.Availability.Value).FireAndForget(); @@ -308,6 +318,18 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match return false; } + public override void OnEntering(ScreenTransitionEvent e) + { + base.OnEntering(e); + beginHandlingTrack(); + } + + public override void OnSuspending(ScreenTransitionEvent e) + { + onLeaving(); + base.OnSuspending(e); + } + private bool exitConfirmed; public override bool OnExiting(ScreenExitEvent e) @@ -320,6 +342,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match return true; } + onLeaving(); client.LeaveRoom().FireAndForget(); return false; } @@ -342,6 +365,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match public override void OnResuming(ScreenTransitionEvent e) { base.OnResuming(e); + beginHandlingTrack(); if (e.Last is not MultiplayerPlayerLoader playerLoader) return; @@ -355,6 +379,43 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match client.ChangeState(MultiplayerUserState.Idle); } + private void onLeaving() + { + endHandlingTrack(); + } + + /// + /// Handles changes in the track to keep it looping while active. + /// + private void beginHandlingTrack() + { + Beatmap.BindValueChanged(applyLoopingToTrack, true); + } + + /// + /// Stops looping the current track and stops handling further changes to the track. + /// + private void endHandlingTrack() + { + Beatmap.ValueChanged -= applyLoopingToTrack; + Beatmap.Value.Track.Looping = false; + + previewTrackManager.StopAnyPlaying(this); + } + + /// + /// Invoked on changes to the beatmap to loop the track. See: . + /// + /// The beatmap change event. + private void applyLoopingToTrack(ValueChangedEvent beatmap) + { + if (!this.IsCurrentScreen()) + return; + + beatmap.NewValue.PrepareTrackForPreview(true); + music.EnsurePlayingSomething(); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing);