1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 11:27:24 +08:00

Merge pull request #15879 from peppy/multiplayer-delayed-playlist-load-broken

Load playlist panels on demand to reduce initial load time when joining a room
This commit is contained in:
Dan Balasescu 2021-12-08 00:42:20 +09:00 committed by GitHub
commit 86eacfdbd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 38 deletions

View File

@ -163,7 +163,7 @@ namespace osu.Game.Online.Multiplayer
Debug.Assert(joinedRoom != null); Debug.Assert(joinedRoom != null);
// Populate playlist items. // Populate playlist items.
var playlistItems = await Task.WhenAll(joinedRoom.Playlist.Select(createPlaylistItem)).ConfigureAwait(false); var playlistItems = await Task.WhenAll(joinedRoom.Playlist.Select(item => createPlaylistItem(item, item.ID == joinedRoom.Settings.PlaylistItemId))).ConfigureAwait(false);
// Populate users. // Populate users.
Debug.Assert(joinedRoom.Users != null); Debug.Assert(joinedRoom.Users != null);
@ -470,7 +470,32 @@ namespace osu.Game.Online.Multiplayer
Task IMultiplayerClient.SettingsChanged(MultiplayerRoomSettings newSettings) Task IMultiplayerClient.SettingsChanged(MultiplayerRoomSettings newSettings)
{ {
Scheduler.Add(() => updateLocalRoomSettings(newSettings)); Debug.Assert(APIRoom != null);
Debug.Assert(Room != null);
Scheduler.Add(() =>
{
// ensure the new selected item is populated immediately.
var playlistItem = APIRoom.Playlist.Single(p => p.ID == newSettings.PlaylistItemId);
if (playlistItem != null)
{
GetAPIBeatmap(playlistItem.BeatmapID).ContinueWith(b =>
{
// Should be called outside of the `Scheduler` logic (and specifically accessing `Exception`) to suppress an exception from firing outwards.
bool success = b.Exception == null;
Scheduler.Add(() =>
{
if (success)
playlistItem.Beatmap.Value = b.Result;
updateLocalRoomSettings(newSettings);
});
});
}
});
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -629,7 +654,7 @@ namespace osu.Game.Online.Multiplayer
if (Room == null) if (Room == null)
return; return;
var playlistItem = await createPlaylistItem(item).ConfigureAwait(false); var playlistItem = await createPlaylistItem(item, true).ConfigureAwait(false);
Scheduler.Add(() => Scheduler.Add(() =>
{ {
@ -673,7 +698,7 @@ namespace osu.Game.Online.Multiplayer
if (Room == null) if (Room == null)
return; return;
var playlistItem = await createPlaylistItem(item).ConfigureAwait(false); var playlistItem = await createPlaylistItem(item, true).ConfigureAwait(false);
Scheduler.Add(() => Scheduler.Add(() =>
{ {
@ -728,10 +753,8 @@ namespace osu.Game.Online.Multiplayer
CurrentMatchPlayingItem.Value = APIRoom.Playlist.SingleOrDefault(p => p.ID == settings.PlaylistItemId); CurrentMatchPlayingItem.Value = APIRoom.Playlist.SingleOrDefault(p => p.ID == settings.PlaylistItemId);
} }
private async Task<PlaylistItem> createPlaylistItem(MultiplayerPlaylistItem item) private async Task<PlaylistItem> createPlaylistItem(MultiplayerPlaylistItem item, bool populateBeatmapImmediately)
{ {
var apiBeatmap = await GetAPIBeatmap(item.BeatmapID).ConfigureAwait(false);
var ruleset = Rulesets.GetRuleset(item.RulesetID); var ruleset = Rulesets.GetRuleset(item.RulesetID);
Debug.Assert(ruleset != null); Debug.Assert(ruleset != null);
@ -741,8 +764,8 @@ namespace osu.Game.Online.Multiplayer
var playlistItem = new PlaylistItem var playlistItem = new PlaylistItem
{ {
ID = item.ID, ID = item.ID,
BeatmapID = item.BeatmapID,
OwnerID = item.OwnerID, OwnerID = item.OwnerID,
Beatmap = { Value = apiBeatmap },
Ruleset = { Value = ruleset }, Ruleset = { Value = ruleset },
Expired = item.Expired, Expired = item.Expired,
PlaylistOrder = item.PlaylistOrder, PlaylistOrder = item.PlaylistOrder,
@ -752,6 +775,9 @@ namespace osu.Game.Online.Multiplayer
playlistItem.RequiredMods.AddRange(item.RequiredMods.Select(m => m.ToMod(rulesetInstance))); playlistItem.RequiredMods.AddRange(item.RequiredMods.Select(m => m.ToMod(rulesetInstance)));
playlistItem.AllowedMods.AddRange(item.AllowedMods.Select(m => m.ToMod(rulesetInstance))); playlistItem.AllowedMods.AddRange(item.AllowedMods.Select(m => m.ToMod(rulesetInstance)));
if (populateBeatmapImmediately)
playlistItem.Beatmap.Value = await GetAPIBeatmap(item.BeatmapID).ConfigureAwait(false);
return playlistItem; return playlistItem;
} }

View File

@ -80,7 +80,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
private void updateRange(object sender, NotifyCollectionChangedEventArgs e) private void updateRange(object sender, NotifyCollectionChangedEventArgs e)
{ {
var orderedDifficulties = Playlist.Select(p => p.Beatmap.Value).OrderBy(b => b.StarRating).ToArray(); var orderedDifficulties = Playlist.Where(p => p.Beatmap.Value != null).Select(p => p.Beatmap.Value).OrderBy(b => b.StarRating).ToArray();
StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarRating : 0, 0); StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarRating : 0, 0);
StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarRating : 0, 0); StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarRating : 0, 0);

View File

@ -16,6 +16,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Database; using osu.Game.Database;
@ -50,6 +51,7 @@ namespace osu.Game.Screens.OnlinePlay
private LinkFlowContainer authorText; private LinkFlowContainer authorText;
private ExplicitContentBeatmapPill explicitContentPill; private ExplicitContentBeatmapPill explicitContentPill;
private ModDisplay modDisplay; private ModDisplay modDisplay;
private FillFlowContainer buttonsFlow;
private UpdateableAvatar ownerAvatar; private UpdateableAvatar ownerAvatar;
private readonly IBindable<bool> valid = new Bindable<bool>(); private readonly IBindable<bool> valid = new Bindable<bool>();
@ -66,10 +68,19 @@ namespace osu.Game.Screens.OnlinePlay
[Resolved] [Resolved]
private UserLookupCache userLookupCache { get; set; } private UserLookupCache userLookupCache { get; set; }
[Resolved]
private BeatmapLookupCache beatmapLookupCache { get; set; }
private PanelBackground panelBackground;
private readonly DelayedLoadWrapper onScreenLoader = new DelayedLoadWrapper(Empty) { RelativeSizeAxes = Axes.Both };
private readonly bool allowEdit; private readonly bool allowEdit;
private readonly bool allowSelection; private readonly bool allowSelection;
private readonly bool showItemOwner; private readonly bool showItemOwner;
private FillFlowContainer mainFillFlow;
protected override bool ShouldBeConsideredForInput(Drawable child) => allowEdit || !allowSelection || SelectedItem.Value == Model; protected override bool ShouldBeConsideredForInput(Drawable child) => allowEdit || !allowSelection || SelectedItem.Value == Model;
public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection, bool showItemOwner) public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection, bool showItemOwner)
@ -130,10 +141,33 @@ namespace osu.Game.Screens.OnlinePlay
valid.BindValueChanged(_ => Scheduler.AddOnce(refresh)); valid.BindValueChanged(_ => Scheduler.AddOnce(refresh));
requiredMods.CollectionChanged += (_, __) => Scheduler.AddOnce(refresh); requiredMods.CollectionChanged += (_, __) => Scheduler.AddOnce(refresh);
refresh(); onScreenLoader.DelayedLoadStarted += _ =>
{
Task.Run(async () =>
{
try
{
if (showItemOwner)
{
var foundUser = await userLookupCache.GetUserAsync(Item.OwnerID).ConfigureAwait(false);
Schedule(() => ownerAvatar.User = foundUser);
} }
private PanelBackground panelBackground; if (Item.Beatmap.Value == null)
{
var foundBeatmap = await beatmapLookupCache.GetBeatmapAsync(Item.BeatmapID).ConfigureAwait(false);
Schedule(() => Item.Beatmap.Value = foundBeatmap);
}
}
catch (Exception e)
{
Logger.Log($"Error while populating playlist item {e}");
}
});
};
refresh();
}
private void refresh() private void refresh()
{ {
@ -143,22 +177,22 @@ namespace osu.Game.Screens.OnlinePlay
maskingContainer.BorderColour = colours.Red; maskingContainer.BorderColour = colours.Red;
} }
if (showItemOwner) if (Item.Beatmap.Value != null)
{
ownerAvatar.Show();
userLookupCache.GetUserAsync(Item.OwnerID)
.ContinueWith(u => Schedule(() => ownerAvatar.User = u.Result), TaskContinuationOptions.OnlyOnRanToCompletion);
}
difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(ICON_HEIGHT) }; difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(ICON_HEIGHT) };
else
difficultyIconContainer.Clear();
panelBackground.Beatmap.Value = Item.Beatmap.Value; panelBackground.Beatmap.Value = Item.Beatmap.Value;
beatmapText.Clear(); beatmapText.Clear();
if (Item.Beatmap.Value != null)
{
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineID.ToString(), null, text => beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineID.ToString(), null, text =>
{ {
text.Truncate = true; text.Truncate = true;
}); });
}
authorText.Clear(); authorText.Clear();
@ -168,10 +202,16 @@ namespace osu.Game.Screens.OnlinePlay
authorText.AddUserLink(Item.Beatmap.Value.Metadata.Author); authorText.AddUserLink(Item.Beatmap.Value.Metadata.Author);
} }
bool hasExplicitContent = (Item.Beatmap.Value.BeatmapSet as IBeatmapSetOnlineInfo)?.HasExplicitContent == true; bool hasExplicitContent = (Item.Beatmap.Value?.BeatmapSet as IBeatmapSetOnlineInfo)?.HasExplicitContent == true;
explicitContentPill.Alpha = hasExplicitContent ? 1 : 0; explicitContentPill.Alpha = hasExplicitContent ? 1 : 0;
modDisplay.Current.Value = requiredMods.ToArray(); modDisplay.Current.Value = requiredMods.ToArray();
buttonsFlow.Clear();
buttonsFlow.ChildrenEnumerable = CreateButtons();
difficultyIconContainer.FadeInFromZero(500, Easing.OutQuint);
mainFillFlow.FadeInFromZero(500, Easing.OutQuint);
} }
protected override Drawable CreateContent() protected override Drawable CreateContent()
@ -192,6 +232,7 @@ namespace osu.Game.Screens.OnlinePlay
Alpha = 0, Alpha = 0,
AlwaysPresent = true AlwaysPresent = true
}, },
onScreenLoader,
panelBackground = new PanelBackground panelBackground = new PanelBackground
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -217,7 +258,7 @@ namespace osu.Game.Screens.OnlinePlay
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Left = 8, Right = 8 }, Margin = new MarginPadding { Left = 8, Right = 8 },
}, },
new FillFlowContainer mainFillFlow = new FillFlowContainer
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
@ -273,7 +314,7 @@ namespace osu.Game.Screens.OnlinePlay
} }
} }
}, },
new FillFlowContainer buttonsFlow = new FillFlowContainer
{ {
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
@ -305,9 +346,9 @@ namespace osu.Game.Screens.OnlinePlay
} }
protected virtual IEnumerable<Drawable> CreateButtons() => protected virtual IEnumerable<Drawable> CreateButtons() =>
new Drawable[] new[]
{ {
new PlaylistDownloadButton(Item), Item.Beatmap.Value == null ? Empty() : new PlaylistDownloadButton(Item),
new PlaylistRemoveButton new PlaylistRemoveButton
{ {
Size = new Vector2(30, 30), Size = new Vector2(30, 30),

View File

@ -4,9 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms; using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -89,15 +87,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true)); getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true));
return true; return true;
case GetBeatmapSetRequest getBeatmapSetRequest:
var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type);
onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res);
onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e);
// Get the online API from the game's dependencies.
game.Dependencies.Get<IAPIProvider>().Queue(onlineReq);
return true;
case CreateRoomScoreRequest createRoomScoreRequest: case CreateRoomScoreRequest createRoomScoreRequest:
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 }); createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
return true; return true;