From 88abee705b37d0a6c9db00aa7b8a3f5323703590 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Jan 2021 10:48:53 +0300 Subject: [PATCH 01/19] Add missing event mapping for user beatmap availability change --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 50dc8f661c..6f789b1ef5 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -81,6 +81,7 @@ namespace osu.Game.Online.Multiplayer connection.On(nameof(IMultiplayerClient.HostChanged), ((IMultiplayerClient)this).HostChanged); connection.On(nameof(IMultiplayerClient.SettingsChanged), ((IMultiplayerClient)this).SettingsChanged); connection.On(nameof(IMultiplayerClient.UserStateChanged), ((IMultiplayerClient)this).UserStateChanged); + connection.On(nameof(IMultiplayerClient.UserBeatmapAvailabilityChanged), ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged); connection.On(nameof(IMultiplayerClient.LoadRequested), ((IMultiplayerClient)this).LoadRequested); connection.On(nameof(IMultiplayerClient.MatchStarted), ((IMultiplayerClient)this).MatchStarted); connection.On(nameof(IMultiplayerClient.ResultsReady), ((IMultiplayerClient)this).ResultsReady); From 4e6c1a3906ed40be5752b13994499f73b4c10142 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Jan 2021 10:49:38 +0300 Subject: [PATCH 02/19] Update client beatmap availability in-line with tracker --- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 ++ .../Multiplayer/MultiplayerMatchSubScreen.cs | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index c049d4be20..7569da00f2 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -43,6 +43,8 @@ namespace osu.Game.Screens.OnlinePlay.Match [Cached] protected readonly MultiplayerBeatmapTracker BeatmapTracker; + protected IBindable BeatmapAvailability => BeatmapTracker.Availability; + protected RoomSubScreen() { InternalChild = BeatmapTracker = new MultiplayerBeatmapTracker diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index a641935b9a..94288673fb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -184,7 +184,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.LoadComplete(); Playlist.BindCollectionChanged(onPlaylistChanged, true); + BeatmapAvailability.BindValueChanged(updateClientAvailability, true); + client.RoomUpdated += onRoomUpdated; client.LoadRequested += onLoadRequested; isConnected = client.IsConnected.GetBoundCopy(); @@ -208,6 +210,21 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => SelectedItem.Value = Playlist.FirstOrDefault(); + private void updateClientAvailability(ValueChangedEvent _ = null) + { + if (client.Room != null) + client.ChangeBeatmapAvailability(BeatmapAvailability.Value).CatchUnobservedExceptions(true); + } + + private void onRoomUpdated() + { + if (client.Room == null) + return; + + if (client.LocalUser?.BeatmapAvailability.Equals(BeatmapAvailability.Value) == false) + updateClientAvailability(); + } + private void onReadyClick() { Debug.Assert(readyClickOperation == null); @@ -262,7 +279,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.Dispose(isDisposing); if (client != null) + { client.LoadRequested -= onLoadRequested; + client.RoomUpdated -= onRoomUpdated; + } } } } From bd44bf8c0b9348f9443df2dfc95470d86bd80ecf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Jan 2021 10:46:48 +0300 Subject: [PATCH 03/19] Extract disabling progress bar user-interactivity --- osu.Game/Graphics/UserInterface/ProgressBar.cs | 8 +++++++- .../Overlays/BeatmapListing/Panels/DownloadProgressBar.cs | 8 +------- osu.Game/Overlays/NowPlayingOverlay.cs | 5 +++++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs index d271cd121c..4ee1c73bf5 100644 --- a/osu.Game/Graphics/UserInterface/ProgressBar.cs +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -40,8 +40,14 @@ namespace osu.Game.Graphics.UserInterface set => CurrentNumber.Value = value; } - public ProgressBar() + private readonly bool userInteractive; + public override bool HandlePositionalInput => userInteractive; + public override bool HandleNonPositionalInput => userInteractive; + + public ProgressBar(bool userInteractive) { + this.userInteractive = userInteractive; + CurrentNumber.MinValue = 0; CurrentNumber.MaxValue = 1; RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs index 6a2f2e4569..ca94078401 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/DownloadProgressBar.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels public DownloadProgressBar(BeatmapSetInfo beatmapSet) : base(beatmapSet) { - AddInternal(progressBar = new InteractionDisabledProgressBar + AddInternal(progressBar = new ProgressBar(false) { Height = 0, Alpha = 0, @@ -64,11 +64,5 @@ namespace osu.Game.Overlays.BeatmapListing.Panels } }, true); } - - private class InteractionDisabledProgressBar : ProgressBar - { - public override bool HandlePositionalInput => false; - public override bool HandleNonPositionalInput => false; - } } } diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 9beb859f28..d64c61044d 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -411,6 +411,11 @@ namespace osu.Game.Overlays private class HoverableProgressBar : ProgressBar { + public HoverableProgressBar() + : base(true) + { + } + protected override bool OnHover(HoverEvent e) { this.ResizeHeightTo(progress_height, 500, Easing.OutQuint); From 6deb10e0750423c60175975edf62e383535dc346 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Jan 2021 11:09:45 +0300 Subject: [PATCH 04/19] Add UI state display for each client's beatmap availability --- .../Participants/ParticipantPanel.cs | 2 +- .../Multiplayer/Participants/StateDisplay.cs | 193 +++++++++++------- 2 files changed, 119 insertions(+), 76 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index f99655e305..17bf3a58ec 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -143,7 +143,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants const double fade_time = 50; - userStateDisplay.Status = User.State; + userStateDisplay.UpdateStatus(User.State, User.BeatmapAvailability); if (Room.Host?.Equals(User) == true) crown.FadeIn(fade_time); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs index 8d2879fc93..4245628a59 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs @@ -1,6 +1,7 @@ // 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 osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -8,119 +9,161 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { public class StateDisplay : CompositeDrawable { + private const double fade_time = 50; + + private SpriteIcon icon; + private OsuSpriteText text; + private ProgressBar progressBar; + public StateDisplay() { AutoSizeAxes = Axes.Both; Alpha = 0; } - private MultiplayerUserState status; - - private OsuSpriteText text; - private SpriteIcon icon; - - private const double fade_time = 50; - - public MultiplayerUserState Status - { - set - { - if (value == status) - return; - - status = value; - - if (IsLoaded) - updateStatus(); - } - } - [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colours) { + this.colours = colours; + InternalChild = new FillFlowContainer { AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, Spacing = new Vector2(5), Children = new Drawable[] { - text = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 12), - Colour = Color4Extensions.FromHex("#DDFFFF") - }, icon = new SpriteIcon { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, Icon = FontAwesome.Solid.CheckCircle, Size = new Vector2(12), - } + }, + new CircularContainer + { + Masking = true, + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Children = new Drawable[] + { + progressBar = new ProgressBar(false) + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + BackgroundColour = Color4.Black.Opacity(0.4f), + FillColour = colours.Blue, + Alpha = 0f, + }, + text = new OsuSpriteText + { + Padding = new MarginPadding { Horizontal = 5f, Vertical = 1f }, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 12), + Colour = Color4Extensions.FromHex("#DDFFFF") + }, + } + }, } }; } - protected override void LoadComplete() - { - base.LoadComplete(); - updateStatus(); - } + private OsuColour colours; - [Resolved] - private OsuColour colours { get; set; } - - private void updateStatus() + public void UpdateStatus(MultiplayerUserState state, BeatmapAvailability availability) { - switch (status) + if (availability.State != DownloadState.LocallyAvailable) { - default: - this.FadeOut(fade_time); - return; + switch (availability.State) + { + case DownloadState.NotDownloaded: + progressBar.FadeOut(fade_time); + text.Text = "no map"; + icon.Icon = FontAwesome.Solid.MinusCircle; + icon.Colour = colours.RedLight; + break; - case MultiplayerUserState.Ready: - text.Text = "ready"; - icon.Icon = FontAwesome.Solid.CheckCircle; - icon.Colour = Color4Extensions.FromHex("#AADD00"); - break; + case DownloadState.Downloading: + Debug.Assert(availability.DownloadProgress != null); - case MultiplayerUserState.WaitingForLoad: - text.Text = "loading"; - icon.Icon = FontAwesome.Solid.PauseCircle; - icon.Colour = colours.Yellow; - break; + var progress = availability.DownloadProgress.Value; + progressBar.FadeIn(fade_time); + progressBar.CurrentTime = progress; - case MultiplayerUserState.Loaded: - text.Text = "loaded"; - icon.Icon = FontAwesome.Solid.DotCircle; - icon.Colour = colours.YellowLight; - break; + text.Text = "downloading map"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; + icon.Colour = colours.Blue; + break; - case MultiplayerUserState.Playing: - text.Text = "playing"; - icon.Icon = FontAwesome.Solid.PlayCircle; - icon.Colour = colours.BlueLight; - break; + case DownloadState.Importing: + progressBar.FadeOut(fade_time); + text.Text = "importing map"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; + icon.Colour = colours.Yellow; + break; + } + } + else + { + progressBar.FadeOut(fade_time); - case MultiplayerUserState.FinishedPlay: - text.Text = "results pending"; - icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; - icon.Colour = colours.BlueLighter; - break; + switch (state) + { + default: + this.FadeOut(fade_time); + return; - case MultiplayerUserState.Results: - text.Text = "results"; - icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; - icon.Colour = colours.BlueLighter; - break; + case MultiplayerUserState.Ready: + text.Text = "ready"; + icon.Icon = FontAwesome.Solid.CheckCircle; + icon.Colour = Color4Extensions.FromHex("#AADD00"); + break; + + case MultiplayerUserState.WaitingForLoad: + text.Text = "loading"; + icon.Icon = FontAwesome.Solid.PauseCircle; + icon.Colour = colours.Yellow; + break; + + case MultiplayerUserState.Loaded: + text.Text = "loaded"; + icon.Icon = FontAwesome.Solid.DotCircle; + icon.Colour = colours.YellowLight; + break; + + case MultiplayerUserState.Playing: + text.Text = "playing"; + icon.Icon = FontAwesome.Solid.PlayCircle; + icon.Colour = colours.BlueLight; + break; + + case MultiplayerUserState.FinishedPlay: + text.Text = "results pending"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; + icon.Colour = colours.BlueLighter; + break; + + case MultiplayerUserState.Results: + text.Text = "results"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; + icon.Colour = colours.BlueLighter; + break; + } } this.FadeIn(fade_time); From 5f2e9c5485d854c3a5a85dee64613226fd77cd38 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Jan 2021 11:10:38 +0300 Subject: [PATCH 05/19] Add visual test case for displaying beatmap availability states --- .../TestSceneMultiplayerParticipantsList.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index 968a869532..e2f1a13593 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -7,7 +7,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Online; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Multiplayer.Participants; using osu.Game.Users; using osuTK; @@ -73,6 +75,20 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("single panel is for second user", () => this.ChildrenOfType().Single().User.User == secondUser); } + [Test] + public void TestBeatmapDownloadingStates() + { + AddStep("set to no map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.NotDownloaded())); + AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0))); + AddRepeatStep("increment progress", () => + { + var progress = this.ChildrenOfType().Single().User.BeatmapAvailability.DownloadProgress ?? 0; + Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(progress + RNG.NextSingle(0.1f))); + }, 25); + AddStep("set to importing map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Importing())); + AddStep("set to available", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.LocallyAvailable())); + } + [Test] public void TestToggleReadyState() { @@ -120,6 +136,26 @@ namespace osu.Game.Tests.Visual.Multiplayer }); Client.ChangeUserState(i, (MultiplayerUserState)RNG.Next(0, (int)MultiplayerUserState.Results + 1)); + + if (RNG.NextBool()) + { + var beatmapState = (DownloadState)RNG.Next(0, (int)DownloadState.LocallyAvailable + 1); + + switch (beatmapState) + { + case DownloadState.NotDownloaded: + Client.ChangeUserBeatmapAvailability(i, BeatmapAvailability.NotDownloaded()); + break; + + case DownloadState.Downloading: + Client.ChangeUserBeatmapAvailability(i, BeatmapAvailability.Downloading(RNG.NextSingle())); + break; + + case DownloadState.Importing: + Client.ChangeUserBeatmapAvailability(i, BeatmapAvailability.Importing()); + break; + } + } } }); } From e6ceaad73233c8322f93554ebcbf136da5c47285 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 18 Jan 2021 17:23:51 +0300 Subject: [PATCH 06/19] Revert user state back to idle upon availability change --- .../Multiplayer/MultiplayerMatchSubScreen.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 94288673fb..826859c598 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.LoadComplete(); Playlist.BindCollectionChanged(onPlaylistChanged, true); - BeatmapAvailability.BindValueChanged(updateClientAvailability, true); + BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true); client.RoomUpdated += onRoomUpdated; client.LoadRequested += onLoadRequested; @@ -210,10 +210,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => SelectedItem.Value = Playlist.FirstOrDefault(); - private void updateClientAvailability(ValueChangedEvent _ = null) + private void updateBeatmapAvailability(ValueChangedEvent _ = null) { - if (client.Room != null) - client.ChangeBeatmapAvailability(BeatmapAvailability.Value).CatchUnobservedExceptions(true); + if (client.Room == null) + return; + + client.ChangeBeatmapAvailability(BeatmapAvailability.Value).CatchUnobservedExceptions(true); + + if (client.LocalUser?.State == MultiplayerUserState.Ready) + client.ChangeState(MultiplayerUserState.Idle).CatchUnobservedExceptions(true); } private void onRoomUpdated() @@ -222,7 +227,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return; if (client.LocalUser?.BeatmapAvailability.Equals(BeatmapAvailability.Value) == false) - updateClientAvailability(); + updateBeatmapAvailability(); } private void onReadyClick() From 4bc324f040b3bfaca1e57af88f00558a6237d6bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 15:29:32 +0900 Subject: [PATCH 07/19] Rename parameter to make more sense --- osu.Game/Graphics/UserInterface/ProgressBar.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs index 4ee1c73bf5..50367e600e 100644 --- a/osu.Game/Graphics/UserInterface/ProgressBar.cs +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -40,13 +40,18 @@ namespace osu.Game.Graphics.UserInterface set => CurrentNumber.Value = value; } - private readonly bool userInteractive; - public override bool HandlePositionalInput => userInteractive; - public override bool HandleNonPositionalInput => userInteractive; + private readonly bool allowSeek; - public ProgressBar(bool userInteractive) + public override bool HandlePositionalInput => allowSeek; + public override bool HandleNonPositionalInput => allowSeek; + + /// + /// Construct a new progress bar. + /// + /// Whether the user should be allowed to click/drag to adjust the value. + public ProgressBar(bool allowSeek) { - this.userInteractive = userInteractive; + this.allowSeek = allowSeek; CurrentNumber.MinValue = 0; CurrentNumber.MaxValue = 1; From d1f9aa52a4c528053d7ee45344ad5ec15dff4fe5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 15:33:48 +0900 Subject: [PATCH 08/19] Inline variable --- .../OnlinePlay/Multiplayer/Participants/StateDisplay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs index 4245628a59..c117c026dc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs @@ -101,9 +101,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants case DownloadState.Downloading: Debug.Assert(availability.DownloadProgress != null); - var progress = availability.DownloadProgress.Value; progressBar.FadeIn(fade_time); - progressBar.CurrentTime = progress; + progressBar.CurrentTime = availability.DownloadProgress.Value; text.Text = "downloading map"; icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; From 1b6a05279847569be9d5568bc9812fa55b7fe503 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 15:46:03 +0900 Subject: [PATCH 09/19] Refactor logic to suck a bit less --- .../Multiplayer/Participants/StateDisplay.cs | 161 +++++++++--------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs index c117c026dc..c571b51c83 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -87,85 +88,89 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants public void UpdateStatus(MultiplayerUserState state, BeatmapAvailability availability) { - if (availability.State != DownloadState.LocallyAvailable) - { - switch (availability.State) - { - case DownloadState.NotDownloaded: - progressBar.FadeOut(fade_time); - text.Text = "no map"; - icon.Icon = FontAwesome.Solid.MinusCircle; - icon.Colour = colours.RedLight; - break; - - case DownloadState.Downloading: - Debug.Assert(availability.DownloadProgress != null); - - progressBar.FadeIn(fade_time); - progressBar.CurrentTime = availability.DownloadProgress.Value; - - text.Text = "downloading map"; - icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; - icon.Colour = colours.Blue; - break; - - case DownloadState.Importing: - progressBar.FadeOut(fade_time); - text.Text = "importing map"; - icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; - icon.Colour = colours.Yellow; - break; - } - } - else - { - progressBar.FadeOut(fade_time); - - switch (state) - { - default: - this.FadeOut(fade_time); - return; - - case MultiplayerUserState.Ready: - text.Text = "ready"; - icon.Icon = FontAwesome.Solid.CheckCircle; - icon.Colour = Color4Extensions.FromHex("#AADD00"); - break; - - case MultiplayerUserState.WaitingForLoad: - text.Text = "loading"; - icon.Icon = FontAwesome.Solid.PauseCircle; - icon.Colour = colours.Yellow; - break; - - case MultiplayerUserState.Loaded: - text.Text = "loaded"; - icon.Icon = FontAwesome.Solid.DotCircle; - icon.Colour = colours.YellowLight; - break; - - case MultiplayerUserState.Playing: - text.Text = "playing"; - icon.Icon = FontAwesome.Solid.PlayCircle; - icon.Colour = colours.BlueLight; - break; - - case MultiplayerUserState.FinishedPlay: - text.Text = "results pending"; - icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; - icon.Colour = colours.BlueLighter; - break; - - case MultiplayerUserState.Results: - text.Text = "results"; - icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; - icon.Colour = colours.BlueLighter; - break; - } - } - + // the only case where the progress bar is used does its own local fade in. + // starting by fading out is a sane default. + progressBar.FadeOut(fade_time); this.FadeIn(fade_time); + + switch (state) + { + case MultiplayerUserState.Idle: + showBeatmapAvailability(availability); + break; + + case MultiplayerUserState.Ready: + text.Text = "ready"; + icon.Icon = FontAwesome.Solid.CheckCircle; + icon.Colour = Color4Extensions.FromHex("#AADD00"); + break; + + case MultiplayerUserState.WaitingForLoad: + text.Text = "loading"; + icon.Icon = FontAwesome.Solid.PauseCircle; + icon.Colour = colours.Yellow; + break; + + case MultiplayerUserState.Loaded: + text.Text = "loaded"; + icon.Icon = FontAwesome.Solid.DotCircle; + icon.Colour = colours.YellowLight; + break; + + case MultiplayerUserState.Playing: + text.Text = "playing"; + icon.Icon = FontAwesome.Solid.PlayCircle; + icon.Colour = colours.BlueLight; + break; + + case MultiplayerUserState.FinishedPlay: + text.Text = "results pending"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; + icon.Colour = colours.BlueLighter; + break; + + case MultiplayerUserState.Results: + text.Text = "results"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleUp; + icon.Colour = colours.BlueLighter; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(state), state, null); + } + } + + private void showBeatmapAvailability(BeatmapAvailability availability) + { + switch (availability.State) + { + default: + this.FadeOut(fade_time); + break; + + case DownloadState.NotDownloaded: + text.Text = "no map"; + icon.Icon = FontAwesome.Solid.MinusCircle; + icon.Colour = colours.RedLight; + break; + + case DownloadState.Downloading: + Debug.Assert(availability.DownloadProgress != null); + + progressBar.FadeIn(fade_time); + progressBar.CurrentTime = availability.DownloadProgress.Value; + + text.Text = "downloading map"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; + icon.Colour = colours.Blue; + break; + + case DownloadState.Importing: + text.Text = "importing map"; + icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; + icon.Colour = colours.Yellow; + break; + } } } } From 98c4573240670b7992894d2ddaf84c8f9acdf476 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 15:52:49 +0900 Subject: [PATCH 10/19] Add assertions covering new test --- .../Multiplayer/TestSceneMultiplayerParticipantsList.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index 4fec1c6dd8..b025440d04 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; @@ -82,12 +83,20 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("set to no map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.NotDownloaded())); AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0))); + + AddUntilStep("progress bar visible", () => this.ChildrenOfType().Single().IsPresent); + AddRepeatStep("increment progress", () => { var progress = this.ChildrenOfType().Single().User.BeatmapAvailability.DownloadProgress ?? 0; Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(progress + RNG.NextSingle(0.1f))); }, 25); + + AddAssert("progress bar increased", () => this.ChildrenOfType().Single().Current.Value > 0); + AddStep("set to importing map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Importing())); + AddUntilStep("progress bar not visible", () => !this.ChildrenOfType().Single().IsPresent); + AddStep("set to available", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.LocallyAvailable())); } From 1368d551529ac09ecb1d47c5d32c0ddbf5f313b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 15:58:27 +0900 Subject: [PATCH 11/19] Add test coverage of precedence of display --- .../TestSceneMultiplayerParticipantsList.cs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index b025440d04..c3852fafd4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -78,13 +78,27 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("single panel is for second user", () => this.ChildrenOfType().Single().User.User == secondUser); } + [Test] + public void TestGameStateHasPriorityOverDownloadState() + { + AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0))); + checkProgressBarVisibility(true); + + AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Results)); + checkProgressBarVisibility(false); + AddUntilStep("ready mark visible", () => this.ChildrenOfType().Single().IsPresent); + + AddStep("make user ready", () => Client.ChangeState(MultiplayerUserState.Idle)); + checkProgressBarVisibility(true); + } + [Test] public void TestBeatmapDownloadingStates() { AddStep("set to no map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.NotDownloaded())); AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0))); - AddUntilStep("progress bar visible", () => this.ChildrenOfType().Single().IsPresent); + checkProgressBarVisibility(true); AddRepeatStep("increment progress", () => { @@ -95,7 +109,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("progress bar increased", () => this.ChildrenOfType().Single().Current.Value > 0); AddStep("set to importing map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Importing())); - AddUntilStep("progress bar not visible", () => !this.ChildrenOfType().Single().IsPresent); + checkProgressBarVisibility(false); AddStep("set to available", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.LocallyAvailable())); } @@ -197,5 +211,9 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep($"set state: {state}", () => Client.ChangeUserState(0, state)); } } + + private void checkProgressBarVisibility(bool visible) => + AddUntilStep($"progress bar {(visible ? "is" : "is not")}visible", () => + this.ChildrenOfType().Single().IsPresent == visible); } } From 9ba5ae3db7c7f235fab1d44fd75a2e2a2f0ded94 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 16:17:02 +0900 Subject: [PATCH 12/19] Remove lots of unnecessary client side logic --- .../Multiplayer/MultiplayerMatchSubScreen.cs | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 5bcb1d6dc8..bd1ec9c54a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -270,7 +270,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true); UserMods.BindValueChanged(onUserModsChanged); - client.RoomUpdated += onRoomUpdated; client.LoadRequested += onLoadRequested; isConnected = client.IsConnected.GetBoundCopy(); @@ -323,24 +322,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer client.ChangeUserMods(mods.NewValue); } - private void updateBeatmapAvailability(ValueChangedEvent _ = null) + private void updateBeatmapAvailability(ValueChangedEvent availability) { if (client.Room == null) return; - client.ChangeBeatmapAvailability(BeatmapAvailability.Value); - - if (client.LocalUser?.State == MultiplayerUserState.Ready) - client.ChangeState(MultiplayerUserState.Idle); - } - - private void onRoomUpdated() - { - if (client.Room == null) - return; - - if (client.LocalUser?.BeatmapAvailability.Equals(BeatmapAvailability.Value) == false) - updateBeatmapAvailability(); + client.ChangeBeatmapAvailability(availability.NewValue); } private void onReadyClick() @@ -392,10 +379,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.Dispose(isDisposing); if (client != null) - { client.LoadRequested -= onLoadRequested; - client.RoomUpdated -= onRoomUpdated; - } } private class UserModSelectOverlay : ModSelectOverlay From be91f54349202c6a633f0de9728ede538b120c9d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 16:19:45 +0900 Subject: [PATCH 13/19] Add back edge case with comment --- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index bd1ec9c54a..39e179262e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -328,6 +328,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return; client.ChangeBeatmapAvailability(availability.NewValue); + + // while this flow is handled server-side, this covers the edge case of the local user being in a ready state and then deleting the current beatmap. + if (client.LocalUser?.State == MultiplayerUserState.Ready) + client.ChangeState(MultiplayerUserState.Idle); } private void onReadyClick() From 791cbb7f03e9637a123b83b77f339c3d44abbf1f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 17:17:29 +0900 Subject: [PATCH 14/19] Don't reset ready state if the map is locally available --- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 39e179262e..53c939115c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -330,7 +330,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer client.ChangeBeatmapAvailability(availability.NewValue); // while this flow is handled server-side, this covers the edge case of the local user being in a ready state and then deleting the current beatmap. - if (client.LocalUser?.State == MultiplayerUserState.Ready) + if (availability.NewValue != Online.Rooms.BeatmapAvailability.LocallyAvailable() + && client.LocalUser?.State == MultiplayerUserState.Ready) client.ChangeState(MultiplayerUserState.Idle); } From 110458612d730e449174fe533606faecc041785b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 17:19:23 +0900 Subject: [PATCH 15/19] Avoid handling null playlist items when updating avaialability display --- .../Rooms/OnlinePlayBeatmapAvailablilityTracker.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs index ad4b3c5151..dcb366ddab 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs @@ -36,7 +36,15 @@ namespace osu.Game.Online.Rooms { base.LoadComplete(); - SelectedItem.BindValueChanged(item => Model.Value = item.NewValue?.Beatmap.Value.BeatmapSet, true); + SelectedItem.BindValueChanged(item => + { + // the underlying playlist is regularly cleared for maintenance purposes (things which probably need to be fixed eventually). + // to avoid exposing a state change when there may actually be none, ignore all nulls for now. + if (item.NewValue == null) + return; + + Model.Value = item.NewValue.Beatmap.Value.BeatmapSet; + }, true); } protected override bool VerifyDatabasedModel(BeatmapSetInfo databasedSet) From dad32da4153e8cb18443c6c1f12c1a1847754936 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Feb 2021 17:34:05 +0900 Subject: [PATCH 16/19] Add rate limiting on sending download progress updates --- .../Rooms/OnlinePlayBeatmapAvailablilityTracker.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs index dcb366ddab..cfaf43451f 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Logging; +using osu.Framework.Threading; using osu.Game.Beatmaps; namespace osu.Game.Online.Rooms @@ -24,12 +25,20 @@ namespace osu.Game.Online.Rooms /// public IBindable Availability => availability; - private readonly Bindable availability = new Bindable(); + private readonly Bindable availability = new Bindable(BeatmapAvailability.LocallyAvailable()); + + private ScheduledDelegate progressUpdate; public OnlinePlayBeatmapAvailablilityTracker() { State.BindValueChanged(_ => updateAvailability()); - Progress.BindValueChanged(_ => updateAvailability(), true); + Progress.BindValueChanged(_ => + { + // incoming progress changes are going to be at a very high rate. + // we don't want to flood the network with this, so rate limit how often we send progress updates. + if (progressUpdate?.Completed != false) + progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500); + }); } protected override void LoadComplete() From a08c51f213594a02ea3d354c4e913f29723ab2fd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Feb 2021 19:23:10 +0900 Subject: [PATCH 17/19] Remove duplicate code --- .../OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index e29fb658a3..ae32295676 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -164,9 +164,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants userStateDisplay.UpdateStatus(User.State, User.BeatmapAvailability); - var ruleset = rulesets.GetRuleset(Room.Settings.RulesetID).CreateInstance(); - userModsDisplay.Current.Value = User.Mods.Select(m => m.ToMod(ruleset)).ToList(); - if (Room.Host?.Equals(User) == true) crown.FadeIn(fade_time); else From b87327841dec18cda4edcc9c6ee4a52d4b8ebf29 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Feb 2021 15:46:23 +0900 Subject: [PATCH 18/19] Add test covering initial state propagation --- .../TestSceneMultiplayerParticipantsList.cs | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index c3852fafd4..0f7a9b442d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -22,16 +22,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public class TestSceneMultiplayerParticipantsList : MultiplayerTestScene { [SetUp] - public new void Setup() => Schedule(() => - { - Child = new ParticipantsList - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Y, - Size = new Vector2(380, 0.7f) - }; - }); + public new void Setup() => Schedule(createNewParticipantsList); [Test] public void TestAddUser() @@ -92,6 +83,14 @@ namespace osu.Game.Tests.Visual.Multiplayer checkProgressBarVisibility(true); } + [Test] + public void TestCorrectInitialState() + { + AddStep("set to downloading map", () => Client.ChangeBeatmapAvailability(BeatmapAvailability.Downloading(0))); + AddStep("recreate list", createNewParticipantsList); + checkProgressBarVisibility(true); + } + [Test] public void TestBeatmapDownloadingStates() { @@ -212,6 +211,11 @@ namespace osu.Game.Tests.Visual.Multiplayer } } + private void createNewParticipantsList() + { + Child = new ParticipantsList { Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, Size = new Vector2(380, 0.7f) }; + } + private void checkProgressBarVisibility(bool visible) => AddUntilStep($"progress bar {(visible ? "is" : "is not")}visible", () => this.ChildrenOfType().Single().IsPresent == visible); From 04c243386b136359a81606c612686fe1a8754527 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Feb 2021 16:02:56 +0900 Subject: [PATCH 19/19] Fix initial state transfer regressing --- .../OnlinePlayBeatmapAvailablilityTracker.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs index cfaf43451f..d6f4c45a75 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailablilityTracker.cs @@ -29,18 +29,6 @@ namespace osu.Game.Online.Rooms private ScheduledDelegate progressUpdate; - public OnlinePlayBeatmapAvailablilityTracker() - { - State.BindValueChanged(_ => updateAvailability()); - Progress.BindValueChanged(_ => - { - // incoming progress changes are going to be at a very high rate. - // we don't want to flood the network with this, so rate limit how often we send progress updates. - if (progressUpdate?.Completed != false) - progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500); - }); - } - protected override void LoadComplete() { base.LoadComplete(); @@ -54,6 +42,16 @@ namespace osu.Game.Online.Rooms Model.Value = item.NewValue.Beatmap.Value.BeatmapSet; }, true); + + Progress.BindValueChanged(_ => + { + // incoming progress changes are going to be at a very high rate. + // we don't want to flood the network with this, so rate limit how often we send progress updates. + if (progressUpdate?.Completed != false) + progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500); + }); + + State.BindValueChanged(_ => updateAvailability(), true); } protected override bool VerifyDatabasedModel(BeatmapSetInfo databasedSet)