Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add automatic downloading support when spectating a multiplayer room #29680

Merged
merged 4 commits into from
Sep 4, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System.Linq;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osuTK;

namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
public partial class MultiplayerSpectateButton : MultiplayerRoomComposite
{
[Resolved]
private OngoingOperationTracker ongoingOperationTracker { get; set; }
private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!;

[Resolved]
private OsuColour colours { get; set; }
private OsuColour colours { get; set; } = null!;

private IBindable<bool> operationInProgress;
private IBindable<bool> operationInProgress = null!;

private readonly RoundedButton button;

Expand All @@ -46,10 +51,11 @@ private void onClick()
}

[BackgroundDependencyLoader]
private void load()
private void load(OsuConfigManager config)
{
operationInProgress = ongoingOperationTracker.InProgress.GetBoundCopy();
operationInProgress.BindValueChanged(_ => updateState());
automaticallyDownload = config.GetBindable<bool>(OsuSetting.AutomaticallyDownloadMissingBeatmaps);
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this respond to changes of this setting? If it's initially disabled and the user enables it, it won't start the download.

}

protected override void OnRoomUpdated()
Expand Down Expand Up @@ -77,6 +83,70 @@ private void updateState()
button.Enabled.Value = Client.Room != null
&& Client.Room.State != MultiplayerRoomState.Closed
&& !operationInProgress.Value;

Scheduler.AddOnce(checkForAutomaticDownload);
}

#region Automatic download handling

[Resolved]
private BeatmapLookupCache beatmapLookupCache { get; set; } = null!;

[Resolved]
private BeatmapModelDownloader beatmapDownloader { get; set; } = null!;

[Resolved]
private BeatmapManager beatmaps { get; set; } = null!;

private Bindable<bool> automaticallyDownload = null!;

private CancellationTokenSource? downloadCheckCancellation;

protected override void PlaylistItemChanged(MultiplayerPlaylistItem item)
{
base.PlaylistItemChanged(item);
Scheduler.AddOnce(checkForAutomaticDownload);
}

private void checkForAutomaticDownload()
{
MultiplayerPlaylistItem? item = Client.Room?.Playlist.FirstOrDefault(i => !i.Expired);

downloadCheckCancellation?.Cancel();

if (item == null)
return;

if (!automaticallyDownload.Value)
return;

// While we can support automatic downloads when not spectating, there are some usability concerns.
// - In host rotate mode, this could potentially be unwanted by some users (even though they want automatic downloads everywhere else).
// - When first joining a room, the expectation should be that the user is checking out the room, and they may not immediately want to download the selected beatmap.
//
// Rather than over-complicating this flow, let's only auto-download when spectating for the time being.
// A potential path forward would be to have a local auto-download checkbox above the playlist item list area.
if (Client.LocalUser?.State != MultiplayerUserState.Spectating)
return;

// 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.BeatmapID, (downloadCheckCancellation = new CancellationTokenSource()).Token)
.ContinueWith(resolved => Schedule(() =>
{
var beatmapSet = resolved.GetResultSafely()?.BeatmapSet;

if (beatmapSet == null)
return;

if (beatmaps.IsAvailableLocally(new BeatmapSetInfo { OnlineID = beatmapSet.OnlineID }))
return;

beatmapDownloader.Download(beatmapSet);
}));
}

#endregion
}
}
Loading