From f25b5147ef319c42329fd645490bf7ecc1907eb1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Feb 2021 15:37:45 +0900 Subject: [PATCH 01/18] Select last playlist item in match subscreen --- .../Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index c5130baa94..76608fb5c1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -302,7 +302,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) { - SelectedItem.Value = Playlist.FirstOrDefault(); + SelectedItem.Value = Playlist.LastOrDefault(); if (SelectedItem.Value?.AllowedMods.Any() != true) { From 855d24dce769ae8ab65bd8f2daadfe638e6a76d8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Feb 2021 17:35:44 +0900 Subject: [PATCH 02/18] Cache selected item bindable from RoomSubScreen --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 1 + osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 2946d07588..6a2844fa74 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -21,6 +21,7 @@ namespace osu.Game.Screens.OnlinePlay.Match [Cached(typeof(IPreviewTrackOwner))] public abstract class RoomSubScreen : OnlinePlaySubScreen, IPreviewTrackOwner { + [Cached(typeof(IBindable))] protected readonly Bindable SelectedItem = new Bindable(); public override bool DisallowExternalBeatmapRulesetChanges => true; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index b2f3e4a1d9..c1aa93526f 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay @@ -50,5 +52,13 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(typeof(Room))] protected Bindable Duration { get; private set; } + + /// + /// The currently selected item in the . + /// May be null if this is not inside a . + /// + [CanBeNull] + [Resolved(typeof(Room), CanBeNull = true)] + protected IBindable SelectedItem { get; private set; } } } From 3ff9e14e35f851b32f40eb2339b6652beea37c2c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Feb 2021 18:56:13 +0900 Subject: [PATCH 03/18] Make StatefulMultiplayerClient control current playlist item --- .../Multiplayer/MultiplayerRoomSettings.cs | 12 +++++-- .../Multiplayer/StatefulMultiplayerClient.cs | 35 ++++++++++--------- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 4 --- .../Multiplayer/MultiplayerMatchSubScreen.cs | 13 ++++--- .../Playlists/PlaylistsRoomSubScreen.cs | 7 ++-- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index 4fb9d724b5..04752f4e6f 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -36,18 +36,26 @@ namespace osu.Game.Online.Multiplayer [Key(5)] public IEnumerable AllowedMods { get; set; } = Enumerable.Empty(); + /// + /// Only used for client-side mutation. + /// + [Key(6)] + public int PlaylistItemId { get; set; } + public bool Equals(MultiplayerRoomSettings other) => BeatmapID == other.BeatmapID && BeatmapChecksum == other.BeatmapChecksum && RequiredMods.SequenceEqual(other.RequiredMods) && AllowedMods.SequenceEqual(other.AllowedMods) && RulesetID == other.RulesetID - && Name.Equals(other.Name, StringComparison.Ordinal); + && Name.Equals(other.Name, StringComparison.Ordinal) + && PlaylistItemId == other.PlaylistItemId; public override string ToString() => $"Name:{Name}" + $" Beatmap:{BeatmapID} ({BeatmapChecksum})" + $" RequiredMods:{string.Join(',', RequiredMods)}" + $" AllowedMods:{string.Join(',', AllowedMods)}" - + $" Ruleset:{RulesetID}"; + + $" Ruleset:{RulesetID}" + + $" Item:{PlaylistItemId}"; } } diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index 18464a5f61..f5f4c3a8ba 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -66,6 +66,8 @@ namespace osu.Game.Online.Multiplayer /// public readonly BindableList CurrentMatchPlayingUserIds = new BindableList(); + public readonly Bindable CurrentMatchPlayingItem = new Bindable(); + /// /// The corresponding to the local player, if available. /// @@ -94,9 +96,6 @@ namespace osu.Game.Online.Multiplayer private Room? apiRoom; - // Todo: This is temporary, until the multiplayer server returns the item id on match start or otherwise. - private int playlistItemId; - [BackgroundDependencyLoader] private void load() { @@ -142,7 +141,6 @@ namespace osu.Game.Online.Multiplayer { Room = joinedRoom; apiRoom = room; - playlistItemId = room.Playlist.SingleOrDefault()?.ID ?? 0; }, cancellationSource.Token); // Update room settings. @@ -218,7 +216,8 @@ namespace osu.Game.Online.Multiplayer BeatmapChecksum = item.GetOr(existingPlaylistItem).Beatmap.Value.MD5Hash, RulesetID = item.GetOr(existingPlaylistItem).RulesetID, RequiredMods = item.HasValue ? item.Value.AsNonNull().RequiredMods.Select(m => new APIMod(m)).ToList() : Room.Settings.RequiredMods, - AllowedMods = item.HasValue ? item.Value.AsNonNull().AllowedMods.Select(m => new APIMod(m)).ToList() : Room.Settings.AllowedMods + AllowedMods = item.HasValue ? item.Value.AsNonNull().AllowedMods.Select(m => new APIMod(m)).ToList() : Room.Settings.AllowedMods, + PlaylistItemId = Room.Settings.PlaylistItemId, }); } @@ -506,14 +505,13 @@ namespace osu.Game.Online.Multiplayer Room.Settings = settings; apiRoom.Name.Value = Room.Settings.Name; - // The playlist update is delayed until an online beatmap lookup (below) succeeds. - // In-order for the client to not display an outdated beatmap, the playlist is forcefully cleared here. - apiRoom.Playlist.Clear(); + // The current item update is delayed until an online beatmap lookup (below) succeeds. + // In-order for the client to not display an outdated beatmap, the current item is forcefully cleared here. + CurrentMatchPlayingItem.Value = null; RoomUpdated?.Invoke(); var req = new GetBeatmapSetRequest(settings.BeatmapID, BeatmapSetLookupType.BeatmapId); - req.Success += res => { if (cancellationToken.IsCancellationRequested) @@ -540,18 +538,21 @@ namespace osu.Game.Online.Multiplayer var mods = settings.RequiredMods.Select(m => m.ToMod(ruleset)); var allowedMods = settings.AllowedMods.Select(m => m.ToMod(ruleset)); - PlaylistItem playlistItem = new PlaylistItem - { - ID = playlistItemId, - Beatmap = { Value = beatmap }, - Ruleset = { Value = ruleset.RulesetInfo }, - }; + // Update an existing playlist item from the API room, or create a new item. + var playlistItem = apiRoom.Playlist.FirstOrDefault(i => i.ID == settings.PlaylistItemId); + if (playlistItem == null) + apiRoom.Playlist.Add(playlistItem = new PlaylistItem()); + + playlistItem.ID = settings.PlaylistItemId; + playlistItem.Beatmap.Value = beatmap; + playlistItem.Ruleset.Value = ruleset.RulesetInfo; + playlistItem.RequiredMods.Clear(); playlistItem.RequiredMods.AddRange(mods); + playlistItem.AllowedMods.Clear(); playlistItem.AllowedMods.AddRange(allowedMods); - apiRoom.Playlist.Clear(); // Clearing should be unnecessary, but here for sanity. - apiRoom.Playlist.Add(playlistItem); + CurrentMatchPlayingItem.Value = playlistItem; } /// diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 6a2844fa74..7740af9f63 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -28,9 +28,6 @@ namespace osu.Game.Screens.OnlinePlay.Match private Sample sampleStart; - [Resolved(typeof(Room), nameof(Room.Playlist))] - protected BindableList Playlist { get; private set; } - /// /// Any mods applied by/to the local user. /// @@ -74,7 +71,6 @@ namespace osu.Game.Screens.OnlinePlay.Match base.LoadComplete(); SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged)); - SelectedItem.Value = Playlist.FirstOrDefault(); managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy(); managerUpdated.BindValueChanged(beatmapUpdated); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 76608fb5c1..f55b5b9713 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Diagnostics; using System.Linq; using JetBrains.Annotations; @@ -269,7 +268,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { base.LoadComplete(); - Playlist.BindCollectionChanged(onPlaylistChanged, true); + SelectedItem.BindValueChanged(onSelectedItemChanged); + SelectedItem.BindTo(client.CurrentMatchPlayingItem); + BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true); UserMods.BindValueChanged(onUserModsChanged); @@ -300,11 +301,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return base.OnBackButton(); } - private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) + private void onSelectedItemChanged(ValueChangedEvent item) { - SelectedItem.Value = Playlist.LastOrDefault(); - - if (SelectedItem.Value?.AllowedMods.Any() != true) + if (item.NewValue?.AllowedMods.Any() != true) { userModsSection.Hide(); userModsSelectOverlay.Hide(); @@ -313,7 +312,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer else { userModsSection.Show(); - userModsSelectOverlay.IsValidMod = m => SelectedItem.Value.AllowedMods.Any(a => a.GetType() == m.GetType()); + userModsSelectOverlay.IsValidMod = m => item.NewValue.AllowedMods.Any(a => a.GetType() == m.GetType()); } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 88731a10bc..b4870ab580 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -27,6 +27,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } + [Resolved(typeof(Room), nameof(Room.Playlist))] + private BindableList playlist { get; set; } + private MatchSettingsOverlay settingsOverlay; private MatchLeaderboard leaderboard; @@ -117,7 +120,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists new DrawableRoomPlaylistWithResults { RelativeSizeAxes = Axes.Both, - Items = { BindTarget = Playlist }, + Items = { BindTarget = playlist }, SelectedItem = { BindTarget = SelectedItem }, RequestShowResults = item => { @@ -222,7 +225,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists // Set the first playlist item. // This is scheduled since updating the room and playlist may happen in an arbitrary order (via Room.CopyFrom()). - Schedule(() => SelectedItem.Value = Playlist.FirstOrDefault()); + Schedule(() => SelectedItem.Value = playlist.FirstOrDefault()); } }, true); } From 2a1096a3c8ca7a3c5f656963dcbcb2c6e7770eed Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Feb 2021 19:02:16 +0900 Subject: [PATCH 04/18] Make BeatmapSelectionControl use the selected item --- .../Match/BeatmapSelectionControl.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index f17e04d4d4..769596956b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -1,14 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Specialized; -using System.Linq; +using System.Diagnostics; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Online.API; +using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match @@ -60,7 +61,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { base.LoadComplete(); - Playlist.BindCollectionChanged(onPlaylistChanged, true); + Debug.Assert(SelectedItem != null); + SelectedItem.BindValueChanged(onSelectedItemChanged, true); + Host.BindValueChanged(host => { if (RoomID.Value == null || host.NewValue?.Equals(api.LocalUser.Value) == true) @@ -70,12 +73,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }, true); } - private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) + private void onSelectedItemChanged(ValueChangedEvent selectedItem) { - if (Playlist.Any()) - beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(Playlist.Single(), false, false); - else + if (selectedItem.NewValue == null) beatmapPanelContainer.Clear(); + else + beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(selectedItem.NewValue, false, false); } } } From e24a5949c5a61c105e9f4670c07cdbccf0d7def6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Feb 2021 19:26:51 +0900 Subject: [PATCH 05/18] Fix resolve --- osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index c1aa93526f..4c4b1ff6d0 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -58,7 +58,7 @@ namespace osu.Game.Screens.OnlinePlay /// May be null if this is not inside a . /// [CanBeNull] - [Resolved(typeof(Room), CanBeNull = true)] + [Resolved(CanBeNull = true)] protected IBindable SelectedItem { get; private set; } } } From 100097d78f0b28c66a86d9d8a4b8bbe309964429 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Feb 2021 21:32:35 +0900 Subject: [PATCH 06/18] Fix playlist not being handled correctly for non-joined cases --- .../Multiplayer/StatefulMultiplayerClient.cs | 8 ++++---- .../Multiplayer/Match/BeatmapSelectionControl.cs | 14 +++++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index f5f4c3a8ba..e9eb80e6a1 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -539,10 +539,7 @@ namespace osu.Game.Online.Multiplayer var allowedMods = settings.AllowedMods.Select(m => m.ToMod(ruleset)); // Update an existing playlist item from the API room, or create a new item. - var playlistItem = apiRoom.Playlist.FirstOrDefault(i => i.ID == settings.PlaylistItemId); - - if (playlistItem == null) - apiRoom.Playlist.Add(playlistItem = new PlaylistItem()); + var playlistItem = apiRoom.Playlist.FirstOrDefault(i => i.ID == settings.PlaylistItemId) ?? new PlaylistItem(); playlistItem.ID = settings.PlaylistItemId; playlistItem.Beatmap.Value = beatmap; @@ -552,6 +549,9 @@ namespace osu.Game.Online.Multiplayer playlistItem.AllowedMods.Clear(); playlistItem.AllowedMods.AddRange(allowedMods); + if (!apiRoom.Playlist.Contains(playlistItem)) + apiRoom.Playlist.Add(playlistItem); + CurrentMatchPlayingItem.Value = playlistItem; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 769596956b..8d394f2c2b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -2,8 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Diagnostics; +using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; @@ -62,7 +62,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match base.LoadComplete(); Debug.Assert(SelectedItem != null); - SelectedItem.BindValueChanged(onSelectedItemChanged, true); + SelectedItem.BindValueChanged(_ => updateBeatmap()); + Playlist.BindCollectionChanged((_, __) => updateBeatmap(), true); Host.BindValueChanged(host => { @@ -73,12 +74,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }, true); } - private void onSelectedItemChanged(ValueChangedEvent selectedItem) + private void updateBeatmap() { - if (selectedItem.NewValue == null) + Debug.Assert(SelectedItem != null); + PlaylistItem item = SelectedItem.Value ?? Playlist.FirstOrDefault(); + + if (item == null) beatmapPanelContainer.Clear(); else - beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(selectedItem.NewValue, false, false); + beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(item, false, false); } } } From f61b8e6154c596a33f43dceed8f55b35ce479f58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 16 Feb 2021 21:32:38 +0900 Subject: [PATCH 07/18] Change to long --- osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index 04752f4e6f..473382cf5f 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -40,7 +40,7 @@ namespace osu.Game.Online.Multiplayer /// Only used for client-side mutation. /// [Key(6)] - public int PlaylistItemId { get; set; } + public long PlaylistItemId { get; set; } public bool Equals(MultiplayerRoomSettings other) => BeatmapID == other.BeatmapID From fb0e9d6760c2877ae97b40ad62d601b9e6774369 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Feb 2021 16:44:39 +0900 Subject: [PATCH 08/18] Add played property to playlist item --- osu.Game/Online/Rooms/PlaylistItem.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Online/Rooms/PlaylistItem.cs b/osu.Game/Online/Rooms/PlaylistItem.cs index 61982101c1..1d409d4b56 100644 --- a/osu.Game/Online/Rooms/PlaylistItem.cs +++ b/osu.Game/Online/Rooms/PlaylistItem.cs @@ -23,6 +23,12 @@ namespace osu.Game.Online.Rooms [JsonProperty("ruleset_id")] public int RulesetID { get; set; } + /// + /// Whether this is still a valid selection for the . + /// + [JsonProperty("expired")] + public bool Expired { get; set; } + [JsonIgnore] public readonly Bindable Beatmap = new Bindable(); From 0d1149911c44f16b1017c96ed79638fbcfe00a5c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Feb 2021 17:33:10 +0900 Subject: [PATCH 09/18] Don't display expired playlist items --- osu.Game/Online/Rooms/Room.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 997f45ce52..aaaa712860 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -148,6 +148,12 @@ namespace osu.Game.Online.Rooms if (EndDate.Value != null && DateTimeOffset.Now >= EndDate.Value) Status.Value = new RoomStatusEnded(); + // Todo: This is not the best way/place to do this, but the intention is to display all playlist items when the room has ended, + // and display only the non-expired playlist items while the room is still active. + // In order to achieve this, all expired items are removed from the source Room. + if (!(Status.Value is RoomStatusEnded)) + other.Playlist.RemoveAll(i => i.Expired); + if (!Playlist.SequenceEqual(other.Playlist)) { Playlist.Clear(); From 70a995919cde7ae34501afac229872cf7317e693 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Feb 2021 17:58:24 +0900 Subject: [PATCH 10/18] Update comments --- osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs | 3 --- osu.Game/Online/Rooms/Room.cs | 4 ++-- .../OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index 473382cf5f..7d6c76bc2f 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -36,9 +36,6 @@ namespace osu.Game.Online.Multiplayer [Key(5)] public IEnumerable AllowedMods { get; set; } = Enumerable.Empty(); - /// - /// Only used for client-side mutation. - /// [Key(6)] public long PlaylistItemId { get; set; } diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index aaaa712860..00a7979f2c 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -149,8 +149,8 @@ namespace osu.Game.Online.Rooms Status.Value = new RoomStatusEnded(); // Todo: This is not the best way/place to do this, but the intention is to display all playlist items when the room has ended, - // and display only the non-expired playlist items while the room is still active. - // In order to achieve this, all expired items are removed from the source Room. + // and display only the non-expired playlist items while the room is still active. In order to achieve this, all expired items are removed from the source Room. + // More refactoring is required before this can be done locally instead - DrawableRoomPlaylist is currently directly bound to the playlist to display items in the room. if (!(Status.Value is RoomStatusEnded)) other.Playlist.RemoveAll(i => i.Expired); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 8d394f2c2b..3cf0767cf8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -77,6 +77,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void updateBeatmap() { Debug.Assert(SelectedItem != null); + + // When the selected item is null, the match hasn't yet been created. Use the playlist directly, which is mutated by song selection. PlaylistItem item = SelectedItem.Value ?? Playlist.FirstOrDefault(); if (item == null) From 604add04e495cbed44991962f3fa4e1bcb8b1451 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Feb 2021 19:06:37 +0900 Subject: [PATCH 11/18] Fix song select mods being reset incorrectly --- osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index b201c62b7f..c60743a226 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using Humanizer; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -31,6 +32,10 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(typeof(Room), nameof(Room.Playlist))] protected BindableList Playlist { get; private set; } + [CanBeNull] + [Resolved(CanBeNull = true)] + private IBindable selectedItem { get; set; } + private readonly Bindable> freeMods = new Bindable>(Array.Empty()); private readonly FreeModSelectOverlay freeModSelectOverlay; @@ -66,8 +71,8 @@ namespace osu.Game.Screens.OnlinePlay // At this point, Mods contains both the required and allowed mods. For selection purposes, it should only contain the required mods. // Similarly, freeMods is currently empty but should only contain the allowed mods. - Mods.Value = Playlist.FirstOrDefault()?.RequiredMods.Select(m => m.CreateCopy()).ToArray() ?? Array.Empty(); - freeMods.Value = Playlist.FirstOrDefault()?.AllowedMods.Select(m => m.CreateCopy()).ToArray() ?? Array.Empty(); + Mods.Value = selectedItem?.Value?.RequiredMods.Select(m => m.CreateCopy()).ToArray() ?? Array.Empty(); + freeMods.Value = selectedItem?.Value?.AllowedMods.Select(m => m.CreateCopy()).ToArray() ?? Array.Empty(); Ruleset.BindValueChanged(onRulesetChanged); } From 2a1bb2f578ac8b74e6a7d5e7a949a7e995acc6c1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Feb 2021 21:38:01 +0900 Subject: [PATCH 12/18] Fix selected item potentially changing during gameplay --- .../Multiplayer/MultiplayerMatchSubScreen.cs | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index c1930c525c..b5eff04532 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -46,7 +46,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private MultiplayerMatchSettingsOverlay settingsOverlay; private Drawable userModsSection; - private IBindable isConnected; + private readonly IBindable isConnected = new Bindable(); + private readonly IBindable matchCurrentItem = new Bindable(); [CanBeNull] private IDisposable readyClickOperation; @@ -268,8 +269,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { base.LoadComplete(); - SelectedItem.BindValueChanged(onSelectedItemChanged); - SelectedItem.BindTo(client.CurrentMatchPlayingItem); + matchCurrentItem.BindTo(client.CurrentMatchPlayingItem); + matchCurrentItem.BindValueChanged(onCurrentItemChanged, true); BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true); UserMods.BindValueChanged(onUserModsChanged); @@ -277,7 +278,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer client.LoadRequested += onLoadRequested; client.RoomUpdated += onRoomUpdated; - isConnected = client.IsConnected.GetBoundCopy(); + isConnected.BindTo(client.IsConnected); isConnected.BindValueChanged(connected => { if (!connected.NewValue) @@ -285,6 +286,33 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }, true); } + private void onCurrentItemChanged(ValueChangedEvent item) + { + if (client?.LocalUser == null) + return; + + // If we're about to enter gameplay, schedule the item to be set at a later time. + if (client.LocalUser.State > MultiplayerUserState.Ready) + { + Schedule(() => onCurrentItemChanged(item)); + return; + } + + SelectedItem.Value = item.NewValue; + + if (item.NewValue?.AllowedMods.Any() != true) + { + userModsSection.Hide(); + userModsSelectOverlay.Hide(); + userModsSelectOverlay.IsValidMod = _ => false; + } + else + { + userModsSection.Show(); + userModsSelectOverlay.IsValidMod = m => item.NewValue.AllowedMods.Any(a => a.GetType() == m.GetType()); + } + } + protected override void UpdateMods() { if (SelectedItem.Value == null || client.LocalUser == null) @@ -313,21 +341,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return base.OnBackButton(); } - private void onSelectedItemChanged(ValueChangedEvent item) - { - if (item.NewValue?.AllowedMods.Any() != true) - { - userModsSection.Hide(); - userModsSelectOverlay.Hide(); - userModsSelectOverlay.IsValidMod = _ => false; - } - else - { - userModsSection.Show(); - userModsSelectOverlay.IsValidMod = m => item.NewValue.AllowedMods.Any(a => a.GetType() == m.GetType()); - } - } - private ModSettingChangeTracker modSettingChangeTracker; private ScheduledDelegate debouncedModSettingsUpdate; From 6ef235c4c5290f3254ed247b2f20054dde1aceaf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 17 Feb 2021 21:42:22 +0900 Subject: [PATCH 13/18] Fix beatmap panel flickering multiple times --- .../Match/BeatmapSelectionControl.cs | 17 ++------ .../Screens/OnlinePlay/OnlinePlayComposite.cs | 41 +++++++++++++++++-- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 3cf0767cf8..3af0d5b715 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -1,15 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Diagnostics; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Online.API; -using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match @@ -61,10 +58,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { base.LoadComplete(); - Debug.Assert(SelectedItem != null); - SelectedItem.BindValueChanged(_ => updateBeatmap()); - Playlist.BindCollectionChanged((_, __) => updateBeatmap(), true); - + SelectedItem.BindValueChanged(_ => updateBeatmap(), true); Host.BindValueChanged(host => { if (RoomID.Value == null || host.NewValue?.Equals(api.LocalUser.Value) == true) @@ -76,15 +70,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void updateBeatmap() { - Debug.Assert(SelectedItem != null); - - // When the selected item is null, the match hasn't yet been created. Use the playlist directly, which is mutated by song selection. - PlaylistItem item = SelectedItem.Value ?? Playlist.FirstOrDefault(); - - if (item == null) + if (SelectedItem.Value == null) beatmapPanelContainer.Clear(); else - beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(item, false, false); + beatmapPanelContainer.Child = new DrawableRoomPlaylistItem(SelectedItem.Value, false, false); } } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index a7058d0ede..f203ef927c 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Specialized; +using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -57,11 +59,44 @@ namespace osu.Game.Screens.OnlinePlay protected Bindable Duration { get; private set; } /// - /// The currently selected item in the . - /// May be null if this is not inside a . + /// The currently selected item in the , or the first item from + /// if this is not within a . /// + protected IBindable SelectedItem => selectedItem; + + private readonly Bindable selectedItem = new Bindable(); + [CanBeNull] [Resolved(CanBeNull = true)] - protected IBindable SelectedItem { get; private set; } + private IBindable subScreenSelectedItem { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (subScreenSelectedItem != null) + subScreenSelectedItem.BindValueChanged(onSelectedItemChanged, true); + else + Playlist.BindCollectionChanged(onPlaylistChanged, true); + } + + /// + /// Invoked when the selected item from within a changes. + /// Does not occur when this is outside a . + /// + private void onSelectedItemChanged(ValueChangedEvent item) + { + // If the room hasn't been created yet, fall-back to the first item from the playlist. + selectedItem.Value = RoomID.Value == null ? Playlist.FirstOrDefault() : item.NewValue; + } + + /// + /// Invoked when the playlist changes. + /// Does not occur when this is inside a . + /// + private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) + { + selectedItem.Value = Playlist.FirstOrDefault(); + } } } From 56e9e10ff584742f80c21971771874c7f21ab745 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 18 Feb 2021 15:30:31 +0900 Subject: [PATCH 14/18] Make server authoritative in playlist item id --- osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index e9eb80e6a1..416162779d 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -217,7 +217,6 @@ namespace osu.Game.Online.Multiplayer RulesetID = item.GetOr(existingPlaylistItem).RulesetID, RequiredMods = item.HasValue ? item.Value.AsNonNull().RequiredMods.Select(m => new APIMod(m)).ToList() : Room.Settings.RequiredMods, AllowedMods = item.HasValue ? item.Value.AsNonNull().AllowedMods.Select(m => new APIMod(m)).ToList() : Room.Settings.AllowedMods, - PlaylistItemId = Room.Settings.PlaylistItemId, }); } From e911760318edfb87b86bd6f5b74da4e285c441f5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 18 Feb 2021 15:47:33 +0900 Subject: [PATCH 15/18] Split OnlinePlayComposite to remove if-statement --- .../Match/BeatmapSelectionControl.cs | 2 +- .../Screens/OnlinePlay/OnlinePlayComposite.cs | 36 ++++-------------- .../OnlinePlay/RoomSubScreenComposite.cs | 38 +++++++++++++++++++ 3 files changed, 46 insertions(+), 30 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/RoomSubScreenComposite.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 3af0d5b715..ebe63e26d6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class BeatmapSelectionControl : OnlinePlayComposite + public class BeatmapSelectionControl : RoomSubScreenComposite { [Resolved] private MultiplayerMatchSubScreen matchSubScreen { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index f203ef927c..eb0b23f13f 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -2,9 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Specialized; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; @@ -14,6 +12,9 @@ using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay { + /// + /// A that exposes bindables for properties. + /// public class OnlinePlayComposite : CompositeDrawable { [Resolved(typeof(Room))] @@ -62,41 +63,18 @@ namespace osu.Game.Screens.OnlinePlay /// The currently selected item in the , or the first item from /// if this is not within a . /// - protected IBindable SelectedItem => selectedItem; - - private readonly Bindable selectedItem = new Bindable(); - - [CanBeNull] - [Resolved(CanBeNull = true)] - private IBindable subScreenSelectedItem { get; set; } + protected readonly Bindable SelectedItem = new Bindable(); protected override void LoadComplete() { base.LoadComplete(); - if (subScreenSelectedItem != null) - subScreenSelectedItem.BindValueChanged(onSelectedItemChanged, true); - else - Playlist.BindCollectionChanged(onPlaylistChanged, true); + Playlist.BindCollectionChanged((_, __) => UpdateSelectedItem(), true); } - /// - /// Invoked when the selected item from within a changes. - /// Does not occur when this is outside a . - /// - private void onSelectedItemChanged(ValueChangedEvent item) + protected virtual void UpdateSelectedItem() { - // If the room hasn't been created yet, fall-back to the first item from the playlist. - selectedItem.Value = RoomID.Value == null ? Playlist.FirstOrDefault() : item.NewValue; - } - - /// - /// Invoked when the playlist changes. - /// Does not occur when this is inside a . - /// - private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) - { - selectedItem.Value = Playlist.FirstOrDefault(); + SelectedItem.Value = Playlist.FirstOrDefault(); } } } diff --git a/osu.Game/Screens/OnlinePlay/RoomSubScreenComposite.cs b/osu.Game/Screens/OnlinePlay/RoomSubScreenComposite.cs new file mode 100644 index 0000000000..4cfd881aa3 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/RoomSubScreenComposite.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Match; + +namespace osu.Game.Screens.OnlinePlay +{ + /// + /// An with additional logic tracking the currently-selected inside a . + /// + public class RoomSubScreenComposite : OnlinePlayComposite + { + [Resolved] + private IBindable subScreenSelectedItem { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + subScreenSelectedItem.BindValueChanged(_ => UpdateSelectedItem(), true); + } + + protected override void UpdateSelectedItem() + { + if (RoomID.Value == null) + { + // If the room hasn't been created yet, fall-back to the base logic. + base.UpdateSelectedItem(); + return; + } + + SelectedItem.Value = subScreenSelectedItem.Value; + } + } +} From bc10fcafae2d57b6bb07d6bf666ee72577e5b8f9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 19 Feb 2021 13:23:01 +0900 Subject: [PATCH 16/18] Remove now unnecessary schedule --- .../Multiplayer/MultiplayerMatchSubScreen.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index b5eff04532..cb2b6dda95 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -47,7 +47,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private Drawable userModsSection; private readonly IBindable isConnected = new Bindable(); - private readonly IBindable matchCurrentItem = new Bindable(); [CanBeNull] private IDisposable readyClickOperation; @@ -269,8 +268,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { base.LoadComplete(); - matchCurrentItem.BindTo(client.CurrentMatchPlayingItem); - matchCurrentItem.BindValueChanged(onCurrentItemChanged, true); + SelectedItem.BindTo(client.CurrentMatchPlayingItem); + SelectedItem.BindValueChanged(onSelectedItemChanged, true); BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true); UserMods.BindValueChanged(onUserModsChanged); @@ -286,20 +285,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }, true); } - private void onCurrentItemChanged(ValueChangedEvent item) + private void onSelectedItemChanged(ValueChangedEvent item) { if (client?.LocalUser == null) return; - // If we're about to enter gameplay, schedule the item to be set at a later time. - if (client.LocalUser.State > MultiplayerUserState.Ready) - { - Schedule(() => onCurrentItemChanged(item)); - return; - } - - SelectedItem.Value = item.NewValue; - if (item.NewValue?.AllowedMods.Any() != true) { userModsSection.Hide(); From 183a481a345ea4fff4b55dd6df7fcdbc4e1dad4b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 19 Feb 2021 13:32:32 +0900 Subject: [PATCH 17/18] Refactor playlist update to remove .Contains() check --- .../Multiplayer/StatefulMultiplayerClient.cs | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index 416162779d..ed97307c95 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -537,21 +537,30 @@ namespace osu.Game.Online.Multiplayer var mods = settings.RequiredMods.Select(m => m.ToMod(ruleset)); var allowedMods = settings.AllowedMods.Select(m => m.ToMod(ruleset)); - // Update an existing playlist item from the API room, or create a new item. - var playlistItem = apiRoom.Playlist.FirstOrDefault(i => i.ID == settings.PlaylistItemId) ?? new PlaylistItem(); + // Try to retrieve the existing playlist item from the API room. + var playlistItem = apiRoom.Playlist.FirstOrDefault(i => i.ID == settings.PlaylistItemId); - playlistItem.ID = settings.PlaylistItemId; - playlistItem.Beatmap.Value = beatmap; - playlistItem.Ruleset.Value = ruleset.RulesetInfo; - playlistItem.RequiredMods.Clear(); - playlistItem.RequiredMods.AddRange(mods); - playlistItem.AllowedMods.Clear(); - playlistItem.AllowedMods.AddRange(allowedMods); - - if (!apiRoom.Playlist.Contains(playlistItem)) + if (playlistItem != null) + updateItem(playlistItem); + else + { + // An existing playlist item does not exist, so append a new one. + updateItem(playlistItem = new PlaylistItem()); apiRoom.Playlist.Add(playlistItem); + } CurrentMatchPlayingItem.Value = playlistItem; + + void updateItem(PlaylistItem item) + { + item.ID = settings.PlaylistItemId; + item.Beatmap.Value = beatmap; + item.Ruleset.Value = ruleset.RulesetInfo; + item.RequiredMods.Clear(); + item.RequiredMods.AddRange(mods); + item.AllowedMods.Clear(); + item.AllowedMods.AddRange(allowedMods); + } } /// From c0e0bd4f421764ae6418597ed30bb64d501a69e8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 19 Feb 2021 13:57:04 +0900 Subject: [PATCH 18/18] Add compatibility with old server build --- osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs index ed97307c95..bfd505fb19 100644 --- a/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/StatefulMultiplayerClient.cs @@ -94,6 +94,10 @@ namespace osu.Game.Online.Multiplayer [Resolved] private RulesetStore rulesets { get; set; } = null!; + // Only exists for compatibility with old osu-server-spectator build. + // Todo: Can be removed on 2021/02/26. + private long defaultPlaylistItemId; + private Room? apiRoom; [BackgroundDependencyLoader] @@ -141,6 +145,7 @@ namespace osu.Game.Online.Multiplayer { Room = joinedRoom; apiRoom = room; + defaultPlaylistItemId = apiRoom.Playlist.FirstOrDefault()?.ID ?? 0; }, cancellationSource.Token); // Update room settings. @@ -553,7 +558,7 @@ namespace osu.Game.Online.Multiplayer void updateItem(PlaylistItem item) { - item.ID = settings.PlaylistItemId; + item.ID = settings.PlaylistItemId == 0 ? defaultPlaylistItemId : settings.PlaylistItemId; item.Beatmap.Value = beatmap; item.Ruleset.Value = ruleset.RulesetInfo; item.RequiredMods.Clear();