1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-05 19:36:03 +08:00

Merge pull request #34766 from bdach/remove-double-lookup

Pull up online beatmap set lookup to song select level to avoid two components doing the same fetch independently
This commit is contained in:
Dean Herbert
2025-08-23 20:50:17 +09:00
committed by GitHub
Unverified
7 changed files with 183 additions and 285 deletions
@@ -7,6 +7,7 @@ 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.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
@@ -42,7 +43,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
private DialogOverlay dialogOverlay = null!;
private LeaderboardManager leaderboardManager = null!;
private RealmPopulatingOnlineLookupSource lookupSource = null!;
private readonly IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
@@ -52,7 +54,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get<AudioManager>(), Resources, dependencies.Get<GameHost>(), Beatmap.Default));
dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, API));
dependencies.Cache(leaderboardManager = new LeaderboardManager());
dependencies.Cache(lookupSource = new RealmPopulatingOnlineLookupSource());
dependencies.CacheAs(onlineLookupResult);
Dependencies.Cache(Realm);
@@ -68,7 +70,6 @@ namespace osu.Game.Tests.Visual.SongSelectV2
});
LoadComponent(leaderboardManager);
LoadComponent(lookupSource);
Child = contentContainer = new OsuContextMenuContainer
{
@@ -4,13 +4,12 @@
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Models;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens.SelectV2;
@@ -18,64 +17,25 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
public partial class TestSceneBeatmapMetadataWedge : SongSelectComponentsTestScene
{
private APIBeatmapSet? currentOnlineSet;
private BeatmapMetadataWedge wedge = null!;
[Cached(typeof(IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
protected override void LoadComplete()
{
base.LoadComplete();
var lookupSource = new RealmPopulatingOnlineLookupSource();
Child = new DependencyProvidingContainer
Child = wedge = new BeatmapMetadataWedge
{
RelativeSizeAxes = Axes.Both,
CachedDependencies = [(typeof(RealmPopulatingOnlineLookupSource), lookupSource)],
Children =
[
lookupSource,
wedge = new BeatmapMetadataWedge
{
State = { Value = Visibility.Visible },
}
]
State = { Value = Visibility.Visible },
};
}
[SetUpSteps]
public override void SetUpSteps()
{
AddStep("register request handling", () =>
{
((DummyAPIAccess)API).HandleRequest = request =>
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
return false;
default:
return false;
}
};
});
}
[Test]
public void TestShowHide()
{
AddStep("all metrics", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("all metrics", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("hide wedge", () => wedge.Hide());
AddStep("show wedge", () => wedge.Show());
@@ -84,67 +44,63 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestVariousMetrics()
{
AddStep("all metrics", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("all metrics", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
AddStep("null beatmap", () => Beatmap.SetDefault());
AddStep("no source", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
working.Metadata.Source = string.Empty;
currentOnlineSet = onlineSet;
onlineLookupResult.Value = online;
Beatmap.Value = working;
});
AddStep("no success rate", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.Beatmaps.Single().PlayCount = 0;
onlineSet.Beatmaps.Single().PassCount = 0;
online.Result!.Beatmaps.Single().PlayCount = 0;
online.Result!.Beatmaps.Single().PassCount = 0;
currentOnlineSet = onlineSet;
onlineLookupResult.Value = online;
Beatmap.Value = working;
});
AddStep("no user ratings", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.Ratings = Array.Empty<int>();
online.Result!.Ratings = Array.Empty<int>();
currentOnlineSet = onlineSet;
onlineLookupResult.Value = online;
Beatmap.Value = working;
});
AddStep("no fail times", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.Beatmaps.Single().FailTimes = null;
online.Result!.Beatmaps.Single().FailTimes = null;
currentOnlineSet = onlineSet;
onlineLookupResult.Value = online;
Beatmap.Value = working;
});
AddStep("no metrics", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.Ratings = Array.Empty<int>();
onlineSet.Beatmaps.Single().FailTimes = null;
online.Result!.Ratings = Array.Empty<int>();
online.Result!.Beatmaps.Single().FailTimes = null;
currentOnlineSet = onlineSet;
onlineLookupResult.Value = online;
Beatmap.Value = working;
});
AddStep("local beatmap", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, _) = createTestBeatmap();
working.BeatmapInfo.OnlineID = 0;
currentOnlineSet = onlineSet;
onlineLookupResult.Value = null;
Beatmap.Value = working;
});
}
@@ -154,16 +110,16 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
AddStep("long text", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
working.BeatmapInfo.Metadata.Author = new RealmUser { Username = "Verrrrryyyy llooonngggggg author" };
working.BeatmapInfo.Metadata.Source = "Verrrrryyyy llooonngggggg source";
working.BeatmapInfo.Metadata.Tags = string.Join(' ', Enumerable.Repeat(working.BeatmapInfo.Metadata.Tags, 3));
onlineSet.Genre = new BeatmapSetOnlineGenre { Id = 12, Name = "Verrrrryyyy llooonngggggg genre" };
onlineSet.Language = new BeatmapSetOnlineLanguage { Id = 12, Name = "Verrrrryyyy llooonngggggg language" };
onlineSet.Beatmaps.Single().TopTags = Enumerable.Repeat(onlineSet.Beatmaps.Single().TopTags, 3).SelectMany(t => t!).ToArray();
online.Result!.Genre = new BeatmapSetOnlineGenre { Id = 12, Name = "Verrrrryyyy llooonngggggg genre" };
online.Result!.Language = new BeatmapSetOnlineLanguage { Id = 12, Name = "Verrrrryyyy llooonngggggg language" };
online.Result!.Beatmaps.Single().TopTags = Enumerable.Repeat(online.Result!.Beatmaps.Single().TopTags, 3).SelectMany(t => t!).ToArray();
currentOnlineSet = onlineSet;
onlineLookupResult.Value = online;
Beatmap.Value = working;
});
}
@@ -171,22 +127,17 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestOnlineAvailability()
{
AddStep("online beatmapset", () =>
{
var (working, onlineSet) = createTestBeatmap();
AddStep("online beatmapset", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddUntilStep("rating wedge visible", () => wedge.RatingsVisible);
AddUntilStep("fail time wedge visible", () => wedge.FailRetryVisible);
AddStep("online beatmapset with local diff", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, lookupResult) = createTestBeatmap();
working.BeatmapInfo.ResetOnlineInfo();
currentOnlineSet = onlineSet;
onlineLookupResult.Value = lookupResult;
Beatmap.Value = working;
});
AddUntilStep("rating wedge hidden", () => !wedge.RatingsVisible);
@@ -195,7 +146,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
var (working, _) = createTestBeatmap();
currentOnlineSet = null;
onlineLookupResult.Value = null;
Beatmap.Value = working;
});
AddAssert("rating wedge still hidden", () => !wedge.RatingsVisible);
@@ -205,21 +156,17 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestUserTags()
{
AddStep("user tags", () =>
{
var (working, onlineSet) = createTestBeatmap();
AddStep("user tags", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddStep("no user tags", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.Beatmaps.Single().TopTags = null;
onlineSet.RelatedTags = null;
online.Result!.Beatmaps.Single().TopTags = null;
online.Result!.RelatedTags = null;
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
currentOnlineSet = onlineSet;
onlineLookupResult.Value = online;
Beatmap.Value = working;
});
}
@@ -227,72 +174,60 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestLoading()
{
AddStep("override request handling", () =>
{
currentOnlineSet = null;
((DummyAPIAccess)API).HandleRequest = request =>
{
switch (request)
{
case GetBeatmapSetRequest set:
Scheduler.AddDelayed(() => set.TriggerSuccess(currentOnlineSet!), 500);
return true;
default:
return false;
}
};
});
AddStep("set beatmap", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
currentOnlineSet = onlineSet;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
AddStep("set beatmap", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.RelatedTags![0].Name = "other/tag";
onlineSet.RelatedTags[1].Name = "another/tag";
onlineSet.RelatedTags[2].Name = "some/tag";
online.Result!.RelatedTags![0].Name = "other/tag";
online.Result!.RelatedTags[1].Name = "another/tag";
online.Result!.RelatedTags[2].Name = "some/tag";
currentOnlineSet = onlineSet;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
AddStep("no user tags", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.Beatmaps.Single().TopTags = null;
onlineSet.RelatedTags = null;
online.Result!.Beatmaps.Single().TopTags = null;
online.Result!.RelatedTags = null;
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
currentOnlineSet = onlineSet;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
AddStep("no user tags", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, online) = createTestBeatmap();
onlineSet.Beatmaps.Single().TopTags = null;
onlineSet.RelatedTags = null;
online.Result!.Beatmaps.Single().TopTags = null;
online.Result!.RelatedTags = null;
working.BeatmapSetInfo.Beatmaps.Single().Metadata.UserTags.Clear();
currentOnlineSet = onlineSet;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.InProgress();
Scheduler.AddDelayed(() => onlineLookupResult.Value = online, 500);
Beatmap.Value = working;
});
AddWaitStep("wait", 5);
}
private (WorkingBeatmap, APIBeatmapSet) createTestBeatmap()
private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
{
var working = CreateWorkingBeatmap(Ruleset.Value);
var onlineSet = new APIBeatmapSet
@@ -346,7 +281,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now;
working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now;
return (working, onlineSet);
working.Metadata.UserTags.AddRange(onlineSet.RelatedTags.Select(t => t.Name));
return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
}
}
}
@@ -11,6 +11,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
@@ -41,10 +42,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
private BeatmapTitleWedge titleWedge = null!;
private BeatmapTitleWedge.DifficultyDisplay difficultyDisplay => titleWedge.ChildrenOfType<BeatmapTitleWedge.DifficultyDisplay>().Single();
private APIBeatmapSet? currentOnlineSet;
[Cached]
private RealmPopulatingOnlineLookupSource lookupSource = new RealmPopulatingOnlineLookupSource();
[Cached(typeof(IBindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>))]
private Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?> onlineLookupResult = new Bindable<Screens.SelectV2.SongSelect.BeatmapSetLookupResult?>();
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
@@ -58,7 +57,6 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddRange(new Drawable[]
{
lookupSource,
new Container
{
RelativeSizeAxes = Axes.Both,
@@ -142,44 +140,18 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestOnlineAvailability()
{
AddStep("set up request handler", () =>
{
((DummyAPIAccess)API).HandleRequest = request =>
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
AddStep("online beatmapset", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
return false;
default:
return false;
}
};
});
AddStep("online beatmapset", () =>
{
var (working, onlineSet) = createTestBeatmap();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddUntilStep("play count is 10000", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("10,000"));
AddUntilStep("favourites count is 2345", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("2,345"));
AddStep("online beatmapset with local diff", () =>
{
var (working, onlineSet) = createTestBeatmap();
var (working, lookupResult) = createTestBeatmap();
working.BeatmapInfo.ResetOnlineInfo();
currentOnlineSet = onlineSet;
Beatmap.Value = working;
onlineLookupResult.Value = lookupResult;
});
AddUntilStep("play count is -", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("-"));
AddUntilStep("favourites count is 2345", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("2,345"));
@@ -187,8 +159,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
var (working, _) = createTestBeatmap();
currentOnlineSet = null;
Beatmap.Value = working;
onlineLookupResult.Value = Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(null);
});
AddUntilStep("play count is -", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("-"));
AddUntilStep("favourites count is -", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("-"));
@@ -205,15 +177,6 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
return false;
case PostBeatmapFavouriteRequest favourite:
Task.Run(() =>
{
@@ -228,13 +191,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
};
});
AddStep("online beatmapset", () =>
{
var (working, onlineSet) = createTestBeatmap();
AddStep("online beatmapset", () => (Beatmap.Value, onlineLookupResult.Value) = createTestBeatmap());
currentOnlineSet = onlineSet;
Beatmap.Value = working;
});
AddUntilStep("play count is 10000", () => this.ChildrenOfType<BeatmapTitleWedge.Statistic>().ElementAt(0).Text.ToString(), () => Is.EqualTo("10,000"));
AddUntilStep("favourites count is 2345", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("2,345"));
@@ -251,13 +209,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2
AddStep("click favourite button", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().TriggerClick());
AddStep("change to another beatmap", () =>
{
var (working, onlineSet) = createTestBeatmap();
onlineSet.FavouriteCount = 9999;
onlineSet.HasFavourited = true;
working.BeatmapSetInfo.OnlineID = onlineSet.OnlineID = 99999;
var (working, online) = createTestBeatmap();
online.Result!.FavouriteCount = 9999;
online.Result!.HasFavourited = true;
working.BeatmapSetInfo.OnlineID = online.Result!.OnlineID = 99999;
currentOnlineSet = onlineSet;
Beatmap.Value = working;
onlineLookupResult.Value = online;
});
AddStep("allow request to complete", () => resetEvent.Set());
AddUntilStep("favourites count is 9999", () => this.ChildrenOfType<BeatmapTitleWedge.FavouriteButton>().Single().Text.ToString(), () => Is.EqualTo("9,999"));
@@ -268,15 +226,6 @@ namespace osu.Game.Tests.Visual.SongSelectV2
{
switch (request)
{
case GetBeatmapSetRequest set:
if (set.ID == currentOnlineSet?.OnlineID)
{
set.TriggerSuccess(currentOnlineSet);
return true;
}
return false;
case PostBeatmapFavouriteRequest favourite:
Task.Run(() =>
{
@@ -350,7 +299,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
});
}
private (WorkingBeatmap, APIBeatmapSet) createTestBeatmap()
private (WorkingBeatmap, Screens.SelectV2.SongSelect.BeatmapSetLookupResult) createTestBeatmap()
{
var working = CreateWorkingBeatmap(Ruleset.Value);
var onlineSet = new APIBeatmapSet
@@ -371,7 +320,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
working.BeatmapSetInfo.DateSubmitted = DateTimeOffset.Now;
working.BeatmapSetInfo.DateRanked = DateTimeOffset.Now;
return (working, onlineSet);
return (working, Screens.SelectV2.SongSelect.BeatmapSetLookupResult.Completed(onlineSet));
}
private class TestHitObject : ConvertHitObject;
@@ -3,16 +3,12 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Database;
@@ -20,7 +16,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Localisation;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Resources.Localisation.Web;
using osuTK;
@@ -55,10 +50,10 @@ namespace osu.Game.Screens.SelectV2
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
[Resolved]
private IAPIProvider api { get; set; } = null!;
private IBindable<SongSelect.BeatmapSetLookupResult> onlineLookupResult { get; set; } = null!;
[Resolved]
private RealmPopulatingOnlineLookupSource onlineLookupSource { get; set; } = null!;
private IAPIProvider api { get; set; } = null!;
[Resolved]
private RealmAccess realm { get; set; } = null!;
@@ -254,6 +249,7 @@ namespace osu.Game.Screens.SelectV2
{
base.LoadComplete();
beatmap.BindValueChanged(_ => updateDisplay());
onlineLookupResult.BindValueChanged(_ => updateDisplay());
apiState = api.State.GetBoundCopy();
apiState.BindValueChanged(_ => Scheduler.AddOnce(updateDisplay), true);
@@ -283,7 +279,7 @@ namespace osu.Game.Screens.SelectV2
// Needs some experimentation on what looks good.
var beatmapInfo = beatmap.Value.BeatmapInfo;
var currentOnlineBeatmap = currentOnlineBeatmapSet?.Beatmaps.SingleOrDefault(b => b.OnlineID == beatmapInfo.OnlineID);
var currentOnlineBeatmap = onlineLookupResult.Value?.Result?.Beatmaps.SingleOrDefault(b => b.OnlineID == beatmapInfo.OnlineID);
if (State.Value == Visibility.Visible && currentOnlineBeatmap != null)
{
@@ -365,41 +361,12 @@ namespace osu.Game.Screens.SelectV2
submitted.Date = beatmapSetInfo.DateSubmitted;
ranked.Date = beatmapSetInfo.DateRanked;
if (currentOnlineBeatmapSet == null || currentOnlineBeatmapSet.OnlineID != beatmapSetInfo.OnlineID)
refetchBeatmapSet();
updateOnlineDisplay();
}
private APIBeatmapSet? currentOnlineBeatmapSet;
private CancellationTokenSource? cancellationTokenSource;
private Task<APIBeatmapSet?>? currentFetchTask;
private void refetchBeatmapSet()
{
var beatmapSetInfo = beatmap.Value.BeatmapSetInfo;
cancellationTokenSource?.Cancel();
currentOnlineBeatmapSet = null;
if (beatmapSetInfo.OnlineID >= 1)
{
cancellationTokenSource = new CancellationTokenSource();
currentFetchTask = onlineLookupSource.GetBeatmapSetAsync(beatmapSetInfo.OnlineID);
currentFetchTask.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
currentOnlineBeatmapSet = t.GetResultSafely();
if (t.Exception != null)
Logger.Log($"Error when fetching online beatmap set: {t.Exception}", LoggingTarget.Network);
Scheduler.AddOnce(updateOnlineDisplay);
});
}
}
private void updateOnlineDisplay()
{
if (currentFetchTask?.IsCompleted == false)
if (onlineLookupResult.Value?.Status != SongSelect.BeatmapSetLookupStatus.Completed)
{
genre.Data = null;
language.Data = null;
@@ -407,7 +374,7 @@ namespace osu.Game.Screens.SelectV2
return;
}
if (currentOnlineBeatmapSet == null)
if (onlineLookupResult.Value.Result == null)
{
genre.Data = ("-", null);
language.Data = ("-", null);
@@ -416,7 +383,7 @@ namespace osu.Game.Screens.SelectV2
{
var beatmapInfo = beatmap.Value.BeatmapInfo;
var onlineBeatmapSet = currentOnlineBeatmapSet;
var onlineBeatmapSet = onlineLookupResult.Value.Result;
var onlineBeatmap = onlineBeatmapSet.Beatmaps.SingleOrDefault(b => b.OnlineID == beatmapInfo.OnlineID);
genre.Data = (onlineBeatmapSet.Genre.Name, () => songSelect?.Search(onlineBeatmapSet.Genre.Name));
+7 -40
View File
@@ -8,11 +8,9 @@ using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Configuration;
@@ -21,7 +19,6 @@ using osu.Game.Extensions;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
@@ -43,6 +40,9 @@ namespace osu.Game.Screens.SelectV2
[Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; } = null!;
[Resolved]
private IBindable<SongSelect.BeatmapSetLookupResult?> onlineLookupResult { get; set; } = null!;
protected override bool StartHidden => true;
private ModSettingChangeTracker? settingChangeTracker;
@@ -69,16 +69,9 @@ namespace osu.Game.Screens.SelectV2
[Resolved]
private LocalisationManager localisation { get; set; } = null!;
[Resolved]
private RealmPopulatingOnlineLookupSource onlineLookupSource { get; set; } = null!;
[Resolved]
private RealmAccess realm { get; set; } = null!;
private APIBeatmapSet? currentOnlineBeatmapSet;
private CancellationTokenSource? cancellationTokenSource;
private Task<APIBeatmapSet?>? currentFetchTask;
private FillFlowContainer statisticsFlow = null!;
public BeatmapTitleWedge()
@@ -190,6 +183,7 @@ namespace osu.Game.Screens.SelectV2
working.BindValueChanged(_ => updateDisplay());
ruleset.BindValueChanged(_ => updateDisplay());
onlineLookupResult.BindValueChanged(_ => updateDisplay());
mods.BindValueChanged(m =>
{
@@ -230,7 +224,6 @@ namespace osu.Game.Screens.SelectV2
{
var metadata = working.Value.Metadata;
var beatmapInfo = working.Value.BeatmapInfo;
var beatmapSetInfo = working.Value.BeatmapSetInfo;
statusPill.Status = beatmapInfo.Status;
@@ -243,10 +236,6 @@ namespace osu.Game.Screens.SelectV2
artistLink.Action = () => songSelect?.Search(artistText.GetPreferred(localisation.CurrentParameters.Value.PreferOriginalScript));
updateLengthAndBpmStatistics();
if (currentOnlineBeatmapSet == null || currentOnlineBeatmapSet.OnlineID != beatmapSetInfo.OnlineID)
refetchBeatmapSet();
updateOnlineDisplay();
}
@@ -289,40 +278,18 @@ namespace osu.Game.Screens.SelectV2
}, token);
}
private void refetchBeatmapSet()
{
var beatmapSetInfo = working.Value.BeatmapSetInfo;
cancellationTokenSource?.Cancel();
currentOnlineBeatmapSet = null;
if (beatmapSetInfo.OnlineID >= 1)
{
cancellationTokenSource = new CancellationTokenSource();
currentFetchTask = onlineLookupSource.GetBeatmapSetAsync(beatmapSetInfo.OnlineID);
currentFetchTask.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
currentOnlineBeatmapSet = t.GetResultSafely();
if (t.Exception != null)
Logger.Log($"Error when fetching online beatmap set: {t.Exception}", LoggingTarget.Network);
Scheduler.AddOnce(updateOnlineDisplay);
});
}
}
private void updateOnlineDisplay()
{
if (currentFetchTask?.IsCompleted == false)
if (onlineLookupResult.Value?.Status != SongSelect.BeatmapSetLookupStatus.Completed)
{
playCount.Value = null;
favouriteButton.SetLoading();
}
else
{
var onlineBeatmap = currentOnlineBeatmapSet?.Beatmaps.SingleOrDefault(b => b.OnlineID == working.Value.BeatmapInfo.OnlineID);
var onlineBeatmap = onlineLookupResult.Value.Result?.Beatmaps.SingleOrDefault(b => b.OnlineID == working.Value.BeatmapInfo.OnlineID);
playCount.Value = new StatisticPlayCount.Data(onlineBeatmap?.PlayCount ?? -1, onlineBeatmap?.UserPlayCount ?? -1);
favouriteButton.SetBeatmapSet(currentOnlineBeatmapSet);
favouriteButton.SetBeatmapSet(onlineLookupResult.Value.Result);
// the online fetch may have also updated the beatmap's status.
// this needs to be checked against the *local* beatmap model rather than the online one, because it's not known here whether the status change has occurred or not
@@ -229,7 +229,10 @@ namespace osu.Game.Screens.SelectV2
bool hasFavourited = favouriteRequest.Action == BeatmapFavouriteAction.Favourite;
beatmapSet.HasFavourited = hasFavourited;
beatmapSet.FavouriteCount += hasFavourited ? 1 : -1;
setBeatmapSet(beatmapSet, withHeartAnimation: hasFavourited);
// if the beatmap set reference changed under the callback, abort visual updates to avoid showing stale data
if (onlineBeatmapSet == null || ReferenceEquals(beatmapSet, onlineBeatmapSet))
setBeatmapSet(beatmapSet, withHeartAnimation: hasFavourited);
};
favouriteRequest.Failure += e =>
{
@@ -238,7 +241,10 @@ namespace osu.Game.Screens.SelectV2
Text = e.Message,
Icon = FontAwesome.Solid.Times,
});
setBeatmapSet(beatmapSet, withHeartAnimation: false);
// if the beatmap set reference changed under the callback, abort visual updates to avoid showing stale data
if (onlineBeatmapSet == null || ReferenceEquals(beatmapSet, onlineBeatmapSet))
setBeatmapSet(beatmapSet, withHeartAnimation: false);
};
api.Queue(favouriteRequest);
setLoading();
+74 -2
View File
@@ -5,11 +5,14 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
@@ -34,6 +37,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Localisation;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Volume;
@@ -133,8 +137,7 @@ namespace osu.Game.Screens.SelectV2
[Resolved]
private IDialogOverlay? dialogOverlay { get; set; }
[Cached]
private RealmPopulatingOnlineLookupSource onlineLookupSource = new RealmPopulatingOnlineLookupSource();
private readonly RealmPopulatingOnlineLookupSource onlineLookupSource = new RealmPopulatingOnlineLookupSource();
private Bindable<bool> configBackgroundBlur = null!;
@@ -349,6 +352,7 @@ namespace osu.Game.Screens.SelectV2
ensurePlayingSelected();
updateBackgroundDim();
updateWedgeVisibility();
fetchOnlineInfo();
});
}
@@ -954,6 +958,74 @@ namespace osu.Game.Screens.SelectV2
#endregion
#region Online lookups
public enum BeatmapSetLookupStatus
{
InProgress,
Completed,
}
public class BeatmapSetLookupResult
{
public BeatmapSetLookupStatus Status { get; }
public APIBeatmapSet? Result { get; }
private BeatmapSetLookupResult(BeatmapSetLookupStatus status, APIBeatmapSet? result)
{
Status = status;
Result = result;
}
public static BeatmapSetLookupResult InProgress() => new BeatmapSetLookupResult(BeatmapSetLookupStatus.InProgress, null);
public static BeatmapSetLookupResult Completed(APIBeatmapSet? beatmapSet) => new BeatmapSetLookupResult(BeatmapSetLookupStatus.Completed, beatmapSet);
}
/// <summary>
/// Result of the latest online beatmap set lookup.
/// Note that this being <see langword="null"/> or <see cref="BeatmapSetLookupResult.InProgress"/> is different from
/// being a <see cref="BeatmapSetLookupResult.Completed"/> with a <see cref="BeatmapSetLookupResult.Result"/> of null.
/// The former indicates a lookup never occurring or being in progress, while the latter indicates a completed lookup with no result.
/// </summary>
[Cached(typeof(IBindable<BeatmapSetLookupResult?>))]
private readonly Bindable<BeatmapSetLookupResult?> lastLookupResult = new Bindable<BeatmapSetLookupResult?>();
private CancellationTokenSource? onlineLookupCancellation;
private Task<APIBeatmapSet?>? currentOnlineLookup;
private void fetchOnlineInfo()
{
var beatmapSetInfo = Beatmap.Value.BeatmapSetInfo;
if (lastLookupResult.Value?.Result?.OnlineID == beatmapSetInfo.OnlineID)
return;
onlineLookupCancellation?.Cancel();
if (beatmapSetInfo.OnlineID < 0)
{
lastLookupResult.Value = BeatmapSetLookupResult.Completed(null);
return;
}
lastLookupResult.Value = BeatmapSetLookupResult.InProgress();
onlineLookupCancellation = new CancellationTokenSource();
currentOnlineLookup = onlineLookupSource.GetBeatmapSetAsync(beatmapSetInfo.OnlineID);
currentOnlineLookup.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
Schedule(() => lastLookupResult.Value = BeatmapSetLookupResult.Completed(t.GetResultSafely()));
if (t.Exception != null)
{
Logger.Log($"Error when fetching online beatmap set: {t.Exception}", LoggingTarget.Network);
Schedule(() => lastLookupResult.Value = BeatmapSetLookupResult.Completed(null));
}
});
}
#endregion
#region Implementation of ISongSelect
void ISongSelect.Search(string query) => filterControl.Search(query);