diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 4985aa9365..1628423fe8 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(string.Empty, metadata.Source); Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", metadata.Tags); Assert.AreEqual(557821, beatmapInfo.OnlineBeatmapID); - Assert.AreEqual(241526, metadata.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmapInfo.BeatmapSet.OnlineBeatmapSetID); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index 489c38c420..b834be71f1 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Beatmaps.Formats { var beatmap = decodeAsJson(normal); var meta = beatmap.BeatmapInfo.Metadata; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs index f9b055ed55..0039516c0c 100644 --- a/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/OszArchiveReaderTest.cs @@ -48,11 +48,14 @@ namespace osu.Game.Tests.Beatmaps.IO { var reader = new ZipArchiveReader(osz); - BeatmapMetadata meta; - using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) - meta = Decoder.GetDecoder(stream).Decode(stream).Metadata; + Beatmap beatmap; - Assert.AreEqual(241526, meta.OnlineBeatmapSetID); + using (var stream = new StreamReader(reader.GetStream("Soleily - Renatus (Deif) [Platter].osu"))) + beatmap = Decoder.GetDecoder(stream).Decode(stream); + + var meta = beatmap.Metadata; + + Assert.AreEqual(241526, beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID); Assert.AreEqual("Soleily", meta.Artist); Assert.AreEqual("Soleily", meta.ArtistUnicode); Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile); diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs index 4679fca855..6d2b37d981 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs @@ -449,7 +449,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = id, // Create random metadata, then we can check if sorting works based on these Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Title = $"test set #{id}!", @@ -503,7 +502,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = id, // Create random metadata, then we can check if sorting works based on these Artist = $"peppy{id.ToString().PadLeft(6, '0')}", Title = $"test set #{id}!", diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs index 3f63bacfa6..d3098864f4 100644 --- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs +++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual AddStep("remove scores", () => scoresContainer.Scores = null); AddStep("resize to big", () => container.ResizeWidthTo(1, 300)); AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300)); - AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapSetID = 1, OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); + AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo }); scores = new[] diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs index 10121738f1..dab7f7e037 100644 --- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs @@ -122,7 +122,6 @@ namespace osu.Game.Tests.Visual Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(), Metadata = new BeatmapMetadata { - OnlineBeatmapSetID = 1234 + i, // Create random metadata, then we can check if sorting works based on these Artist = "MONACA " + RNG.Next(0, 9), Title = "Black Song " + RNG.Next(0, 9), diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 40d62103a8..3afc3c4d32 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -23,7 +23,6 @@ namespace osu.Game.Beatmaps public int BeatmapVersion; private int? onlineBeatmapID; - private int? onlineBeatmapSetID; [JsonProperty("id")] public int? OnlineBeatmapID @@ -32,19 +31,10 @@ namespace osu.Game.Beatmaps set { onlineBeatmapID = value > 0 ? value : null; } } - [JsonProperty("beatmapset_id")] - [NotMapped] - public int? OnlineBeatmapSetID - { - get { return onlineBeatmapSetID; } - set { onlineBeatmapSetID = value > 0 ? value : null; } - } - [JsonIgnore] public int BeatmapSetInfoID { get; set; } [Required] - [JsonIgnore] public BeatmapSetInfo BeatmapSet { get; set; } public BeatmapMetadata Metadata { get; set; } @@ -141,8 +131,8 @@ namespace osu.Game.Beatmaps (Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile; public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null && - BeatmapSet.Hash == other.BeatmapSet.Hash && - (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; + BeatmapSet.Hash == other.BeatmapSet.Hash && + (Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile; /// /// Returns a shallow-clone of this . diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 806bcc4132..895b47d62b 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -81,12 +81,31 @@ namespace osu.Game.Beatmaps protected override void Populate(BeatmapSetInfo model, ArchiveReader archive) { - model.Beatmaps = createBeatmapDifficulties(model, archive); + model.Beatmaps = createBeatmapDifficulties(archive); - // remove metadata from difficulties where it matches the set foreach (BeatmapInfo b in model.Beatmaps) + { + // remove metadata from difficulties where it matches the set if (model.Metadata.Equals(b.Metadata)) b.Metadata = null; + + // by setting the model here, we can update the noline set id below. + b.BeatmapSet = model; + + fetchAndPopulateOnlineIDs(b); + } + + // check if a set already exists with the same online id, delete if it does. + if (model.OnlineBeatmapSetID != null) + { + var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID); + if (existingOnlineId != null) + { + Delete(existingOnlineId); + beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); + Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); + } + } } protected override BeatmapSetInfo CheckForExisting(BeatmapSetInfo model) @@ -99,18 +118,6 @@ namespace osu.Game.Beatmaps return existingHashMatch; } - // check if a set already exists with the same online id - if (model.OnlineBeatmapSetID != null) - { - var existingOnlineId = beatmaps.ConsumableItems.FirstOrDefault(b => b.OnlineBeatmapSetID == model.OnlineBeatmapSetID); - if (existingOnlineId != null) - { - Delete(existingOnlineId); - beatmaps.PurgeDeletable(s => s.ID == existingOnlineId.ID); - Logger.Log($"Found existing beatmap set with same OnlineBeatmapSetID ({model.OnlineBeatmapSetID}). It has been purged.", LoggingTarget.Database); - } - } - return null; } @@ -306,29 +313,29 @@ namespace osu.Game.Beatmaps return hashable.ComputeSHA2Hash(); } - protected override BeatmapSetInfo CreateModel(ArchiveReader reader) + protected override BeatmapSetInfo CreateModel(ArchiveReader reader) { // let's make sure there are actually .osu files to import. string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu")); if (string.IsNullOrEmpty(mapName)) throw new InvalidOperationException("No beatmap files found in this beatmap archive."); - BeatmapMetadata metadata; + Beatmap beatmap; using (var stream = new StreamReader(reader.GetStream(mapName))) - metadata = Decoder.GetDecoder(stream).Decode(stream).Metadata; + beatmap = Decoder.GetDecoder(stream).Decode(stream); return new BeatmapSetInfo { - OnlineBeatmapSetID = metadata.OnlineBeatmapSetID, + OnlineBeatmapSetID = beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID, Beatmaps = new List(), Hash = computeBeatmapSetHash(reader), - Metadata = metadata + Metadata = beatmap.Metadata }; } /// /// Create all required s for the provided archive. /// - private List createBeatmapDifficulties(BeatmapSetInfo model, ArchiveReader reader) + private List createBeatmapDifficulties(ArchiveReader reader) { var beatmapInfos = new List(); @@ -348,10 +355,6 @@ namespace osu.Game.Beatmaps beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash(); beatmap.BeatmapInfo.MD5Hash = ms.ComputeMD5Hash(); - // ensure we have the same online set ID as the set itself. - beatmap.BeatmapInfo.OnlineBeatmapSetID = model.OnlineBeatmapSetID; - beatmap.BeatmapInfo.Metadata.OnlineBeatmapSetID = model.OnlineBeatmapSetID; - // check that no existing beatmap exists that is imported with the same online beatmap ID. if so, give it precedence. if (beatmap.BeatmapInfo.OnlineBeatmapID.HasValue && QueryBeatmap(b => b.OnlineBeatmapID.Value == beatmap.BeatmapInfo.OnlineBeatmapID.Value) != null) beatmap.BeatmapInfo.OnlineBeatmapID = null; @@ -376,6 +379,40 @@ namespace osu.Game.Beatmaps return beatmapInfos; } + /// + /// Query the API to populate mising OnlineBeatmapID / OnlineBeatmapSetID properties. + /// + /// The beatmap to populate. + /// Whether to re-query if the provided beatmap already has populated values. + /// True if population was successful. + private bool fetchAndPopulateOnlineIDs(BeatmapInfo beatmap, bool force = false) + { + if (!force && beatmap.OnlineBeatmapID != null && beatmap.BeatmapSet.OnlineBeatmapSetID != null) + return true; + + Logger.Log("Attempting online lookup for IDs...", LoggingTarget.Database); + + try + { + var req = new GetBeatmapRequest(beatmap); + + req.Perform(api); + + var res = req.Result; + + Logger.Log($"Successfully mapped to {res.OnlineBeatmapSetID} / {res.OnlineBeatmapID}.", LoggingTarget.Database); + + beatmap.BeatmapSet.OnlineBeatmapSetID = res.OnlineBeatmapSetID; + beatmap.OnlineBeatmapID = res.OnlineBeatmapID; + return true; + } + catch (Exception e) + { + Logger.Log($"Failed ({e})", LoggingTarget.Database); + return false; + } + } + /// /// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation. /// diff --git a/osu.Game/Beatmaps/BeatmapMetadata.cs b/osu.Game/Beatmaps/BeatmapMetadata.cs index 34147c18d2..6c1bcd0531 100644 --- a/osu.Game/Beatmaps/BeatmapMetadata.cs +++ b/osu.Game/Beatmaps/BeatmapMetadata.cs @@ -17,16 +17,6 @@ namespace osu.Game.Beatmaps [JsonIgnore] public int ID { get; set; } - private int? onlineBeatmapSetID; - - [NotMapped] - [JsonProperty(@"id")] - public int? OnlineBeatmapSetID - { - get { return onlineBeatmapSetID; } - set { onlineBeatmapSetID = value > 0 ? value : null; } - } - public string Title { get; set; } public string TitleUnicode { get; set; } public string Artist { get; set; } @@ -82,8 +72,7 @@ namespace osu.Game.Beatmaps if (other == null) return false; - return onlineBeatmapSetID == other.onlineBeatmapSetID - && Title == other.Title + return Title == other.Title && TitleUnicode == other.TitleUnicode && Artist == other.Artist && ArtistUnicode == other.ArtistUnicode diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index fa08c6cb68..ed8fbdbb26 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -22,18 +22,18 @@ namespace osu.Game.Beatmaps [NotMapped] public BeatmapSetOnlineInfo OnlineInfo { get; set; } - public double MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty); + public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0; [NotMapped] public bool DeletePending { get; set; } public string Hash { get; set; } - public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; + public string StoryboardFile => Files?.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; public List Files { get; set; } - public override string ToString() => Metadata.ToString(); + public override string ToString() => Metadata?.ToString() ?? base.ToString(); public bool Protected { get; set; } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index a83ac26fb3..581207607a 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -34,7 +34,8 @@ namespace osu.Game.Beatmaps.Formats private readonly int offset; - public LegacyBeatmapDecoder(int version = LATEST_VERSION) : base(version) + public LegacyBeatmapDecoder(int version = LATEST_VERSION) + : base(version) { // BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off) offset = FormatVersion < 5 ? 24 : 0; @@ -135,6 +136,7 @@ namespace osu.Game.Beatmaps.Formats parser = new Rulesets.Objects.Legacy.Mania.ConvertHitObjectParser(); break; } + break; case @"LetterboxInBreaks": beatmap.BeatmapInfo.LetterboxInBreaks = int.Parse(pair.Value) == 1; @@ -207,8 +209,7 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.OnlineBeatmapID = int.Parse(pair.Value); break; case @"BeatmapSetID": - beatmap.BeatmapInfo.OnlineBeatmapSetID = int.Parse(pair.Value); - metadata.OnlineBeatmapSetID = int.Parse(pair.Value); + beatmap.BeatmapInfo.BeatmapSet = new BeatmapSetInfo { OnlineBeatmapSetID = int.Parse(pair.Value) }; break; } } diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index dfd181b98a..adbedb2aac 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -14,16 +14,19 @@ namespace osu.Game.Online.API { protected override WebRequest CreateWebRequest() => new JsonWebRequest(Uri); + public T Result => ((JsonWebRequest)WebRequest).ResponseObject; + protected APIRequest() { base.Success += onSuccess; } - private void onSuccess() - { - Success?.Invoke(((JsonWebRequest)WebRequest).ResponseObject); - } + private void onSuccess() => Success?.Invoke(Result); + /// + /// Invoked on successful completion of an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public new event APISuccessHandler Success; } @@ -52,7 +55,16 @@ namespace osu.Game.Online.API protected APIAccess API; protected WebRequest WebRequest; + /// + /// Invoked on successful completion of an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public event APISuccessHandler Success; + + /// + /// Invoked on failure to complete an API request. + /// This will be scheduled to the API's internal scheduler (run on update thread automatically). + /// public event APIFailureHandler Failure; private bool cancelled; diff --git a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs index ab840d054f..e3865be5fb 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapDetailsRequest.cs @@ -10,13 +10,11 @@ namespace osu.Game.Online.API.Requests { private readonly BeatmapInfo beatmap; - private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; - public GetBeatmapDetailsRequest(BeatmapInfo beatmap) { this.beatmap = beatmap; } - protected override string Target => $@"beatmaps/{lookupString}"; + protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}"; } } diff --git a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs new file mode 100644 index 0000000000..9d254ce29d --- /dev/null +++ b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Game.Beatmaps; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetBeatmapRequest : APIRequest + { + private readonly BeatmapInfo beatmap; + + private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.MD5Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}"; + + public GetBeatmapRequest(BeatmapInfo beatmap) + { + this.beatmap = beatmap; + } + + protected override string Target => $@"beatmaps/{lookupString}"; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index f75d320a46..99e4392374 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -10,7 +10,10 @@ namespace osu.Game.Online.API.Requests.Responses public class APIBeatmap : BeatmapMetadata { [JsonProperty(@"id")] - private int onlineBeatmapID { get; set; } + public int OnlineBeatmapID { get; set; } + + [JsonProperty(@"beatmapset_id")] + public int OnlineBeatmapSetID { get; set; } [JsonProperty(@"playcount")] private int playCount { get; set; } @@ -55,7 +58,11 @@ namespace osu.Game.Online.API.Requests.Responses Metadata = this, Ruleset = rulesets.GetRuleset(ruleset), StarDifficulty = starDifficulty, - OnlineBeatmapID = onlineBeatmapID, + OnlineBeatmapID = OnlineBeatmapID, + BeatmapSet = new BeatmapSetInfo + { + OnlineBeatmapSetID = OnlineBeatmapSetID, + }, Version = version, BaseDifficulty = new BeatmapDifficulty { diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index f57de016a2..3b6bb565b0 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -15,6 +15,15 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"covers")] private BeatmapSetOnlineCovers covers { get; set; } + private int? onlineBeatmapSetID; + + [JsonProperty(@"id")] + public int? OnlineBeatmapSetID + { + get { return onlineBeatmapSetID; } + set { onlineBeatmapSetID = value > 0 ? value : null; } + } + [JsonProperty(@"preview_url")] private string preview { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs index d49613eab7..8a5aea9e97 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUserMostPlayedBeatmap.cs @@ -25,7 +25,6 @@ namespace osu.Game.Online.API.Requests.Responses { BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets); beatmap.BeatmapSet = setInfo; - beatmap.OnlineBeatmapSetID = setInfo.OnlineBeatmapSetID; beatmap.Metadata = setInfo.Metadata; return beatmap; } diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 97079c77f3..359bfc7564 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Sections { Action = () => { - if (beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.OnlineBeatmapSetID.Value); + if (beatmap.BeatmapSet?.OnlineBeatmapSetID != null) beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmap.BeatmapSet.OnlineBeatmapSetID.Value); }; Child = new FillFlowContainer