From 165d40d06f306b67ea97f63eba5256387755e700 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 19 Mar 2025 15:12:31 +0900 Subject: [PATCH 1/5] Add helpers to MultiplayerRoom --- osu.Game/Online/Multiplayer/MultiplayerRoom.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs index b8b90d907f..db1722af8c 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -81,6 +81,18 @@ namespace osu.Game.Online.Multiplayer Playlist = room.Playlist.Select(p => new MultiplayerPlaylistItem(p)).ToArray(); } + /// + /// Retrieves the active as determined by the room's current settings. + /// + [IgnoreMember] + public MultiplayerPlaylistItem CurrentPlaylistItem => Playlist.Single(item => item.ID == Settings.PlaylistItemId); + + /// + /// Determines whether a user is able to add playlist items to this room. + /// + /// The user to check. + public bool CanAddPlaylistItems(MultiplayerRoomUser user) => user.Equals(Host) || Settings.QueueMode != QueueMode.HostOnly; + public override string ToString() => $"RoomID:{RoomID} Host:{Host?.UserID} Users:{Users.Count} State:{State} Settings: [{Settings}]"; } } From b4a934a7979b8b6ef23db9d0c8919034b195111f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 19 Mar 2025 15:41:24 +0900 Subject: [PATCH 2/5] Refactor spectate button to remove selected item bindable --- .../TestSceneMultiplayerSpectateButton.cs | 7 ++--- .../Match/MultiplayerMatchFooter.cs | 1 - .../Match/MultiplayerSpectateButton.cs | 26 +++++++++---------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs index 9e6734ce99..ff5436a87d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs @@ -5,7 +5,6 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -71,15 +70,13 @@ namespace osu.Game.Tests.Visual.Multiplayer { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(200, 50), - SelectedItem = new Bindable(room.Playlist.First()) + Size = new Vector2(200, 50) }, startControl = new MatchStartControl { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(200, 50), - SelectedItem = new Bindable(room.Playlist.First()) + Size = new Vector2(200, 50) } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index 2b592bd8b9..074961cc4f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -36,7 +36,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match new MultiplayerSpectateButton { RelativeSizeAxes = Axes.Both, - SelectedItem = selectedItem }, null, new MatchStartControl diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs index 3186cf89a4..3c4f7eb9b1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs @@ -21,12 +21,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public partial class MultiplayerSpectateButton : CompositeDrawable { - public required Bindable SelectedItem - { - get => selectedItem; - set => selectedItem.Current = value; - } - [Resolved] private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!; @@ -36,10 +30,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match [Resolved] private MultiplayerClient client { get; set; } = null!; - private readonly BindableWithCurrent selectedItem = new BindableWithCurrent(); private readonly RoundedButton button; private IBindable operationInProgress = null!; + private long? lastPlaylistItemId; public MultiplayerSpectateButton() { @@ -75,7 +69,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { base.LoadComplete(); - SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(checkForAutomaticDownload), true); client.RoomUpdated += onRoomUpdated; updateState(); } @@ -121,11 +114,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void checkForAutomaticDownload() { - PlaylistItem? item = SelectedItem.Value; - - downloadCheckCancellation?.Cancel(); - - if (item == null) + if (client.Room == null) return; if (!automaticallyDownload.Value) @@ -140,10 +129,17 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match if (client.LocalUser?.State != MultiplayerUserState.Spectating) return; + MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; + + if (item.ID == lastPlaylistItemId) + return; + + downloadCheckCancellation?.Cancel(); + // In a perfect world we'd use BeatmapAvailability, but there's no event-driven flow for when a selection changes. // ie. if selection changes from "not downloaded" to another "not downloaded" we wouldn't get a value changed raised. beatmapLookupCache - .GetBeatmapAsync(item.Beatmap.OnlineID, (downloadCheckCancellation = new CancellationTokenSource()).Token) + .GetBeatmapAsync(item.BeatmapID, (downloadCheckCancellation = new CancellationTokenSource()).Token) .ContinueWith(resolved => Schedule(() => { var beatmapSet = resolved.GetResultSafely()?.BeatmapSet; @@ -156,6 +152,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match beatmapDownloader.Download(beatmapSet); })); + + lastPlaylistItemId = item.ID; } #endregion From ca2c48bbd611823228afdc220d0902777154b81e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 19 Mar 2025 15:43:57 +0900 Subject: [PATCH 3/5] Refactor ready button to remove selected item bindable --- .../Multiplayer/TestSceneMatchStartControl.cs | 7 ++----- .../Multiplayer/Match/MatchStartControl.cs | 15 +++------------ .../Multiplayer/Match/MultiplayerMatchFooter.cs | 1 - 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs index fb9c801fb4..1ac98db4ca 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs @@ -101,15 +101,13 @@ namespace osu.Game.Tests.Visual.Multiplayer [SetUpSteps] public void SetUpSteps() { - PlaylistItem item = null!; - AddStep("reset state", () => { multiplayerClient.Invocations.Clear(); beatmapAvailability.Value = BeatmapAvailability.LocallyAvailable(); - item = new PlaylistItem(Beatmap.Value.BeatmapInfo) + PlaylistItem item = new PlaylistItem(Beatmap.Value.BeatmapInfo) { RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID }; @@ -139,8 +137,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(250, 50), - SelectedItem = new Bindable(item) + Size = new Vector2(250, 50) }; }); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs index 0d90d44496..a91b844900 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Threading; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.Countdown; -using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osuTK; @@ -23,22 +22,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public partial class MatchStartControl : CompositeDrawable { - public required Bindable SelectedItem - { - get => selectedItem; - set => selectedItem.Current = value; - } - [Resolved] private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!; - [Resolved(canBeNull: true)] + [Resolved] private IDialogOverlay? dialogOverlay { get; set; } [Resolved] private MultiplayerClient client { get; set; } = null!; - private readonly BindableWithCurrent selectedItem = new BindableWithCurrent(); private readonly MultiplayerReadyButton readyButton; private readonly MultiplayerCountdownButton countdownButton; @@ -98,9 +90,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { base.LoadComplete(); - SelectedItem.BindValueChanged(_ => updateState()); client.RoomUpdated += onRoomUpdated; client.LoadRequested += onLoadRequested; + updateState(); } @@ -214,8 +206,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match readyButton.Enabled.Value = countdownButton.Enabled.Value = client.Room.State != MultiplayerRoomState.Closed - && SelectedItem.Value?.ID == client.Room.Settings.PlaylistItemId - && !client.Room.Playlist.Single(i => i.ID == client.Room.Settings.PlaylistItemId).Expired + && !client.Room.CurrentPlaylistItem.Expired && !operationInProgress.Value; // When the local user is the host and spectating the match, the ready button should be enabled only if any users are ready. diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index 074961cc4f..979285701f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -41,7 +41,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match new MatchStartControl { RelativeSizeAxes = Axes.Both, - SelectedItem = selectedItem }, null } From 606bf1eb9f89c9db4cf246833fba387dc4125ca2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 19 Mar 2025 15:45:29 +0900 Subject: [PATCH 4/5] Remove no-longer used bindable from footer --- .../Multiplayer/TestSceneMultiplayerMatchFooter.cs | 7 +------ .../Multiplayer/Match/MultiplayerMatchFooter.cs | 10 ---------- .../Multiplayer/MultiplayerMatchSubScreen.cs | 5 +---- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs index edeb1708e0..c2d3b17ccb 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs @@ -1,11 +1,9 @@ // 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.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; namespace osu.Game.Tests.Visual.Multiplayer @@ -29,10 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, Height = 50, - Child = new MultiplayerMatchFooter - { - SelectedItem = new Bindable() - } + Child = new MultiplayerMatchFooter() } }; }); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index 979285701f..b3923ddde3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -1,10 +1,8 @@ // 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.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { @@ -13,14 +11,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private const float ready_button_width = 600; private const float spectate_button_width = 200; - public required Bindable SelectedItem - { - get => selectedItem; - set => selectedItem.Current = value; - } - - private readonly BindableWithCurrent selectedItem = new BindableWithCurrent(); - public MultiplayerMatchFooter() { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 5a2da5a555..2b3243e01d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -254,10 +254,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer this.Push(new MultiplayerMatchFreestyleSelect(Room, item)); } - protected override Drawable CreateFooter() => new MultiplayerMatchFooter - { - SelectedItem = SelectedItem - }; + protected override Drawable CreateFooter() => new MultiplayerMatchFooter(); protected override RoomSettingsOverlay CreateRoomSettingsOverlay(Room room) => new MultiplayerMatchSettingsOverlay(room); From 6f1c00ff97c83e150491efe2b773e2a0616091e5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 20 Mar 2025 20:51:38 +0900 Subject: [PATCH 5/5] Revert changes to spectate button cancellation --- .../Multiplayer/Match/MultiplayerSpectateButton.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs index 3c4f7eb9b1..13abe7bb14 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs @@ -33,7 +33,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private readonly RoundedButton button; private IBindable operationInProgress = null!; - private long? lastPlaylistItemId; public MultiplayerSpectateButton() { @@ -114,6 +113,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void checkForAutomaticDownload() { + downloadCheckCancellation?.Cancel(); + if (client.Room == null) return; @@ -131,11 +132,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match MultiplayerPlaylistItem item = client.Room.CurrentPlaylistItem; - if (item.ID == lastPlaylistItemId) - return; - - downloadCheckCancellation?.Cancel(); - // In a perfect world we'd use BeatmapAvailability, but there's no event-driven flow for when a selection changes. // ie. if selection changes from "not downloaded" to another "not downloaded" we wouldn't get a value changed raised. beatmapLookupCache @@ -152,8 +148,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match beatmapDownloader.Download(beatmapSet); })); - - lastPlaylistItemId = item.ID; } #endregion