diff --git a/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs index 4b2933c0e1..8e4fe3d3c2 100644 --- a/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs +++ b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var hitObjects = context.Beatmap.HitObjects; + var hitObjects = context.CurrentDifficulty.Playable.HitObjects; (int expectedStartDelta, int expectedEndDelta) = spinner_delta_threshold[context.InterpretedDifficulty]; for (int i = 0; i < hitObjects.Count - 1; ++i) diff --git a/osu.Game.Rulesets.Catch/Edit/Checks/CheckCatchAbnormalDifficultySettings.cs b/osu.Game.Rulesets.Catch/Edit/Checks/CheckCatchAbnormalDifficultySettings.cs index d2c3df0872..cb1d5fd9cb 100644 --- a/osu.Game.Rulesets.Catch/Edit/Checks/CheckCatchAbnormalDifficultySettings.cs +++ b/osu.Game.Rulesets.Catch/Edit/Checks/CheckCatchAbnormalDifficultySettings.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Checks public override IEnumerable Run(BeatmapVerifierContext context) { - var diff = context.Beatmap.Difficulty; + var diff = context.CurrentDifficulty.Playable.Difficulty; Issue? issue; if (HasMoreThanOneDecimalPlace("Approach rate", diff.ApproachRate, out issue)) diff --git a/osu.Game.Rulesets.Mania/Edit/Checks/CheckKeyCount.cs b/osu.Game.Rulesets.Mania/Edit/Checks/CheckKeyCount.cs index 51ead5f423..09394b2046 100644 --- a/osu.Game.Rulesets.Mania/Edit/Checks/CheckKeyCount.cs +++ b/osu.Game.Rulesets.Mania/Edit/Checks/CheckKeyCount.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var diff = context.Beatmap.Difficulty; + var diff = context.CurrentDifficulty.Playable.Difficulty; if (diff.CircleSize < 4) { diff --git a/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaAbnormalDifficultySettings.cs b/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaAbnormalDifficultySettings.cs index 233c602c21..cdea7c88a7 100644 --- a/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaAbnormalDifficultySettings.cs +++ b/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaAbnormalDifficultySettings.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Checks public override IEnumerable Run(BeatmapVerifierContext context) { - var diff = context.Beatmap.Difficulty; + var diff = context.CurrentDifficulty.Playable.Difficulty; Issue? issue; if (HasMoreThanOneDecimalPlace("Overall difficulty", diff.OverallDifficulty, out issue)) diff --git a/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaConcurrentObjects.cs b/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaConcurrentObjects.cs index 5c73a6b676..4cf44e27ac 100644 --- a/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaConcurrentObjects.cs +++ b/osu.Game.Rulesets.Mania/Edit/Checks/CheckManiaConcurrentObjects.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Checks { public override IEnumerable Run(BeatmapVerifierContext context) { - var hitObjects = context.Beatmap.HitObjects; + var hitObjects = context.CurrentDifficulty.Playable.HitObjects; for (int i = 0; i < hitObjects.Count - 1; ++i) { diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs index 084a3e5ea1..565499fc58 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks if (context.InterpretedDifficulty > DifficultyRating.Easy) yield break; - var hitObjects = context.Beatmap.HitObjects; + var hitObjects = context.CurrentDifficulty.Playable.HitObjects; for (int i = 0; i < hitObjects.Count - 1; ++i) { diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs index a342c2a821..6910c721ac 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - foreach (var hitobject in context.Beatmap.HitObjects) + foreach (var hitobject in context.CurrentDifficulty.Playable.HitObjects) { switch (hitobject) { diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOsuAbnormalDifficultySettings.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOsuAbnormalDifficultySettings.cs index 1c44d54633..a53c6bf7a1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOsuAbnormalDifficultySettings.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOsuAbnormalDifficultySettings.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks public override IEnumerable Run(BeatmapVerifierContext context) { - var diff = context.Beatmap.Difficulty; + var diff = context.CurrentDifficulty.Playable.Difficulty; Issue? issue; if (HasMoreThanOneDecimalPlace("Approach rate", diff.ApproachRate, out issue)) diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs index 585bd35bd9..ac3faa1a09 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs @@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks yield break; var prevObservedTimeDistances = new List(); - var hitObjects = context.Beatmap.HitObjects; + var hitObjects = context.CurrentDifficulty.Playable.HitObjects; for (int i = 0; i < hitObjects.Count - 1; ++i) { diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs index 159498c479..8752920b44 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks if (context.InterpretedDifficulty > DifficultyRating.Easy) yield break; - foreach (var hitObject in context.Beatmap.HitObjects) + foreach (var hitObject in context.CurrentDifficulty.Playable.HitObjects) { if (hitObject is Slider slider && slider.SpanDuration < span_duration_threshold) yield return new IssueTemplateTooShort(this).Create(slider); diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs index f0aade1b7f..a1ba0cf530 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs @@ -19,14 +19,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - double od = context.Beatmap.Difficulty.OverallDifficulty; + double od = context.CurrentDifficulty.Playable.Difficulty.OverallDifficulty; // These are meant to reflect the duration necessary for auto to score at least 1000 points on the spinner. // It's difficult to eliminate warnings here, as auto achieving 1000 points depends on the approach angle on some spinners. double warningThreshold = 500 + (od < 5 ? (5 - od) * -21.8 : (od - 5) * 20); // Anything above this is always ok. double problemThreshold = 450 + (od < 5 ? (5 - od) * -17 : (od - 5) * 17); // Anything below this is never ok. - foreach (var hitObject in context.Beatmap.HitObjects) + foreach (var hitObject in context.CurrentDifficulty.Playable.HitObjects) { if (!(hitObject is Spinner spinner)) continue; diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/Checks/CheckTaikoInconsistentSkipBarLineTest.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/Checks/CheckTaikoInconsistentSkipBarLineTest.cs index 45c5bf3985..7ebbde0360 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Editor/Checks/CheckTaikoInconsistentSkipBarLineTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Editor/Checks/CheckTaikoInconsistentSkipBarLineTest.cs @@ -211,12 +211,10 @@ namespace osu.Game.Rulesets.Taiko.Tests.Editor.Checks private BeatmapVerifierContext createContextWithMultipleDifficulties(IBeatmap currentBeatmap, IBeatmap[] allDifficulties) { - return new BeatmapVerifierContext( - currentBeatmap, - new TestWorkingBeatmap(currentBeatmap), - DifficultyRating.ExpertPlus, - beatmapInfo => allDifficulties.FirstOrDefault(b => b.BeatmapInfo.Equals(beatmapInfo)) - ); + var verifiedCurrentBeatmap = new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(currentBeatmap), currentBeatmap); + var verifiedOtherBeatmaps = allDifficulties.Select(b => new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(b), b)).ToList(); + + return new BeatmapVerifierContext(verifiedCurrentBeatmap, verifiedOtherBeatmaps, DifficultyRating.ExpertPlus); } } } diff --git a/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoAbnormalDifficultySettings.cs b/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoAbnormalDifficultySettings.cs index 38ba7b1b01..edf4d29e38 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoAbnormalDifficultySettings.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoAbnormalDifficultySettings.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Edit.Checks public override IEnumerable Run(BeatmapVerifierContext context) { - var diff = context.Beatmap.Difficulty; + var diff = context.CurrentDifficulty.Playable.Difficulty; Issue? issue; if (HasMoreThanOneDecimalPlace("Overall difficulty", diff.OverallDifficulty, out issue)) diff --git a/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoInconsistentSkipBarLine.cs b/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoInconsistentSkipBarLine.cs index 0d12476e30..621d336f85 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoInconsistentSkipBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Checks/CheckTaikoInconsistentSkipBarLine.cs @@ -19,26 +19,23 @@ namespace osu.Game.Rulesets.Taiko.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var difficulties = context.BeatmapsetDifficulties; - - if (difficulties.Count <= 1) + if (context.AllDifficulties.Count() <= 1) yield break; // Inconsistent bar line omission only matters for osu!taiko difficulties, so only check those - var taikoBeatmaps = difficulties.Where(b => b.BeatmapInfo.Ruleset.ShortName == "taiko").ToList(); + var taikoBeatmaps = context.AllDifficulties.Where(b => b.Playable.BeatmapInfo.Ruleset.ShortName == "taiko").ToList(); if (taikoBeatmaps.Count <= 1) yield break; - var referenceBeatmap = context.Beatmap; + var referenceBeatmap = context.CurrentDifficulty.Playable; var referenceTimingPoints = referenceBeatmap.ControlPointInfo.TimingPoints; - foreach (var beatmap in taikoBeatmaps) - { - if (beatmap == referenceBeatmap) - continue; + var otherTaikoBeatmaps = taikoBeatmaps.Where(b => b.Playable != referenceBeatmap).ToList(); - var timingPoints = beatmap.ControlPointInfo.TimingPoints; + foreach (var beatmap in otherTaikoBeatmaps) + { + var timingPoints = beatmap.Playable.ControlPointInfo.TimingPoints; foreach (var referencePoint in referenceTimingPoints) { @@ -50,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Edit.Checks if (referencePoint.OmitFirstBarLine != matchingPoint.OmitFirstBarLine) { - yield return new IssueTemplateInconsistentOmitFirstBarLine(this).Create(referencePoint.Time, beatmap.BeatmapInfo.DifficultyName); + yield return new IssueTemplateInconsistentOmitFirstBarLine(this).Create(referencePoint.Time, beatmap.Playable.BeatmapInfo.DifficultyName); } } } diff --git a/osu.Game.Tests/Editing/Checks/CheckInconsistentMetadataTest.cs b/osu.Game.Tests/Editing/Checks/CheckInconsistentMetadataTest.cs index ebf90766b2..09d731152d 100644 --- a/osu.Game.Tests/Editing/Checks/CheckInconsistentMetadataTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckInconsistentMetadataTest.cs @@ -206,12 +206,10 @@ namespace osu.Game.Tests.Editing.Checks private BeatmapVerifierContext createContextWithMultipleDifficulties(IBeatmap currentBeatmap, IBeatmap[] allDifficulties) { - return new BeatmapVerifierContext( - currentBeatmap, - new TestWorkingBeatmap(currentBeatmap), - DifficultyRating.ExpertPlus, - beatmapInfo => allDifficulties.FirstOrDefault(b => b.BeatmapInfo.Equals(beatmapInfo)) - ); + var verifiedCurrentBeatmap = new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(currentBeatmap), currentBeatmap); + var verifiedOtherBeatmaps = allDifficulties.Select(b => new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(b), b)).ToList(); + + return new BeatmapVerifierContext(verifiedCurrentBeatmap, verifiedOtherBeatmaps, DifficultyRating.ExpertPlus); } } } diff --git a/osu.Game.Tests/Editing/Checks/CheckInconsistentSettingsTest.cs b/osu.Game.Tests/Editing/Checks/CheckInconsistentSettingsTest.cs index bf92068a77..079c6855a9 100644 --- a/osu.Game.Tests/Editing/Checks/CheckInconsistentSettingsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckInconsistentSettingsTest.cs @@ -263,12 +263,10 @@ namespace osu.Game.Tests.Editing.Checks storyboard.GetLayer("Background").Add(new StoryboardSprite("test.png", Anchor.Centre, Vector2.Zero)); } - return new BeatmapVerifierContext( - currentBeatmap, - new TestWorkingBeatmap(currentBeatmap, storyboard), - DifficultyRating.ExpertPlus, - beatmapInfo => allDifficulties.FirstOrDefault(b => b.BeatmapInfo.Equals(beatmapInfo)) - ); + var verifiedCurrentBeatmap = new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(currentBeatmap, storyboard), currentBeatmap); + var verifiedOtherBeatmaps = allDifficulties.Select(b => new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(b, storyboard), b)).ToList(); + + return new BeatmapVerifierContext(verifiedCurrentBeatmap, verifiedOtherBeatmaps, DifficultyRating.ExpertPlus); } } } diff --git a/osu.Game.Tests/Editing/Checks/CheckInconsistentTimingControlPointsTest.cs b/osu.Game.Tests/Editing/Checks/CheckInconsistentTimingControlPointsTest.cs index 899a59a24f..afcb38c858 100644 --- a/osu.Game.Tests/Editing/Checks/CheckInconsistentTimingControlPointsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckInconsistentTimingControlPointsTest.cs @@ -245,12 +245,10 @@ namespace osu.Game.Tests.Editing.Checks private BeatmapVerifierContext createContext(IBeatmap currentBeatmap, IBeatmap[] allDifficulties) { - return new BeatmapVerifierContext( - currentBeatmap, - new TestWorkingBeatmap(currentBeatmap), - DifficultyRating.ExpertPlus, - beatmapInfo => allDifficulties.FirstOrDefault(b => b.BeatmapInfo.Equals(beatmapInfo)) - ); + var verifiedCurrentBeatmap = new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(currentBeatmap), currentBeatmap); + var verifiedOtherBeatmaps = allDifficulties.Select(b => new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(b), b)).ToList(); + + return new BeatmapVerifierContext(verifiedCurrentBeatmap, verifiedOtherBeatmaps, DifficultyRating.ExpertPlus); } } } diff --git a/osu.Game.Tests/Editing/Checks/CheckLowestDiffDrainTimeTest.cs b/osu.Game.Tests/Editing/Checks/CheckLowestDiffDrainTimeTest.cs index 6b46378c5a..91333d2916 100644 --- a/osu.Game.Tests/Editing/Checks/CheckLowestDiffDrainTimeTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckLowestDiffDrainTimeTest.cs @@ -7,7 +7,6 @@ using System.Linq; using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Timing; -using osu.Game.Extensions; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; using osu.Game.Rulesets.Objects; @@ -229,25 +228,13 @@ namespace osu.Game.Tests.Editing.Checks private BeatmapVerifierContext createContextWithMultipleDifficulties(IBeatmap currentBeatmap, IEnumerable allDifficulties) { - var beatmapSet = new BeatmapSetInfo(); - var beatmapInfos = allDifficulties.Select(d => d.BeatmapInfo).ToList(); - - // Set up the beatmapset with all difficulties - beatmapSet.Beatmaps.AddRange(beatmapInfos); - currentBeatmap.BeatmapInfo.BeatmapSet = beatmapSet; - - // Create a resolver that returns the appropriate working beatmap for each difficulty - var difficultyDict = allDifficulties.ToDictionary(d => d.BeatmapInfo, d => new TestWorkingBeatmap(d)); - - // Use the current beatmap's star rating to determine its difficulty rating + var difficultiesArray = allDifficulties.ToArray(); var currentDifficultyRating = StarDifficulty.GetDifficultyRating(currentBeatmap.BeatmapInfo.StarRating); - return new BeatmapVerifierContext( - currentBeatmap, - new TestWorkingBeatmap(currentBeatmap), - currentDifficultyRating, - beatmapInfo => difficultyDict.TryGetValue(beatmapInfo, out var workingBeatmap) ? workingBeatmap.Beatmap : null - ); + var verifiedCurrentBeatmap = new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(currentBeatmap), currentBeatmap); + var verifiedOtherBeatmaps = difficultiesArray.Select(b => new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(b), b)).ToList(); + + return new BeatmapVerifierContext(verifiedCurrentBeatmap, verifiedOtherBeatmaps, currentDifficultyRating); } private class TestCheckLowestDiffDrainTime : CheckLowestDiffDrainTime diff --git a/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs index 37b01da6ee..7fbe822e8d 100644 --- a/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs @@ -1,7 +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.Collections.Generic; +using System; using System.Linq; using NUnit.Framework; using osu.Game.Beatmaps; @@ -16,8 +16,6 @@ namespace osu.Game.Tests.Editing.Checks { private CheckPreviewTime check = null!; - private IBeatmap beatmap = null!; - [SetUp] public void Setup() { @@ -27,62 +25,69 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestPreviewTimeNotSet() { - setNoPreviewTimeBeatmap(); - var content = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap)); + // single difficulty with no preview time + var current = createBeatmapWithPreviewPoint(-1, "Current"); + var context = createContext(current, Array.Empty()); - var issues = check.Run(content).ToList(); + var issues = check.Run(context).ToList(); Assert.That(issues, Has.Count.EqualTo(1)); Assert.That(issues.Single().Template is CheckPreviewTime.IssueTemplateHasNoPreviewTime); } [Test] - public void TestPreviewTimeconflict() + public void TestPreviewTimeConflict() { - setPreviewTimeConflictBeatmap(); + var beatmaps = createBeatmapSetWithPreviewPoint( + ("Current", 10), + ("Test1", 5), + ("Test2", 10) + ); - var content = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap)); + var context = createContext(beatmaps[0], new[] { beatmaps[1], beatmaps[2] }); - var issues = check.Run(content).ToList(); + var issues = check.Run(context).ToList(); Assert.That(issues, Has.Count.EqualTo(1)); Assert.That(issues.Single().Template is CheckPreviewTime.IssueTemplatePreviewTimeConflict); Assert.That(issues.Single().Arguments.FirstOrDefault()?.ToString() == "Test1"); } - private void setNoPreviewTimeBeatmap() + private IBeatmap[] createBeatmapSetWithPreviewPoint(params (string name, int preview)[] entries) { - beatmap = new Beatmap + var beatmapSet = new BeatmapSetInfo(); + var beatmaps = new IBeatmap[entries.Length]; + + for (int i = 0; i < entries.Length; i++) + { + beatmaps[i] = createBeatmapWithPreviewPoint(entries[i].preview, entries[i].name); + beatmaps[i].BeatmapInfo.BeatmapSet = beatmapSet; + } + + foreach (var b in beatmaps) + beatmapSet.Beatmaps.Add(b.BeatmapInfo); + + return beatmaps; + } + + private IBeatmap createBeatmapWithPreviewPoint(int previewTime, string difficultyName) + { + return new Beatmap { BeatmapInfo = new BeatmapInfo { - Metadata = new BeatmapMetadata { PreviewTime = -1 }, + DifficultyName = difficultyName, + Metadata = new BeatmapMetadata { PreviewTime = previewTime } } }; } - private void setPreviewTimeConflictBeatmap() + private BeatmapVerifierContext createContext(IBeatmap currentBeatmap, IBeatmap[] otherDifficulties) { - beatmap = new Beatmap - { - BeatmapInfo = new BeatmapInfo - { - Metadata = new BeatmapMetadata { PreviewTime = 10 }, - BeatmapSet = new BeatmapSetInfo(new List - { - new BeatmapInfo - { - DifficultyName = "Test1", - Metadata = new BeatmapMetadata { PreviewTime = 5 }, - }, - new BeatmapInfo - { - DifficultyName = "Test2", - Metadata = new BeatmapMetadata { PreviewTime = 10 }, - }, - }) - } - }; + var verifiedCurrentBeatmap = new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(currentBeatmap), currentBeatmap); + var verifiedOtherBeatmaps = otherDifficulties.Select(b => new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(b), b)).ToList(); + + return new BeatmapVerifierContext(verifiedCurrentBeatmap, verifiedOtherBeatmaps, DifficultyRating.ExpertPlus); } } } diff --git a/osu.Game/Rulesets/Edit/BeatmapVerifierContext.cs b/osu.Game/Rulesets/Edit/BeatmapVerifierContext.cs index 9761212b55..731a33b3ca 100644 --- a/osu.Game/Rulesets/Edit/BeatmapVerifierContext.cs +++ b/osu.Game/Rulesets/Edit/BeatmapVerifierContext.cs @@ -1,8 +1,8 @@ // 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.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; namespace osu.Game.Rulesets.Edit @@ -14,14 +14,16 @@ namespace osu.Game.Rulesets.Edit public class BeatmapVerifierContext { /// - /// The playable beatmap instance of the current beatmap. + /// Collects the constituent parts of a beatmap being verified. /// - public readonly IBeatmap Beatmap; - - /// - /// The working beatmap instance of the current beatmap. - /// - public readonly IWorkingBeatmap WorkingBeatmap; + /// + /// Use this to access beatmap resources like its track, storyboard, waveform, or similar. + /// + /// + /// The in its actual playable state after beatmap conversion. + /// Use this to inspect the actual beatmap contents, like its hitobjects, timing points, breaks, etc. + /// + public record VerifiedBeatmap(IWorkingBeatmap Working, IBeatmap Playable); /// /// The difficulty level which the current beatmap is considered to be. @@ -29,43 +31,59 @@ namespace osu.Game.Rulesets.Edit public DifficultyRating InterpretedDifficulty; /// - /// All beatmap difficulties in the same beatmapset, including the current beatmap. + /// The current beatmap being checked. /// - public readonly IReadOnlyList BeatmapsetDifficulties; + public readonly VerifiedBeatmap CurrentDifficulty; - // TODO: Refactor this to have a simple constructor that only stores data and move the beatmap resolution logic to a static factory method. - public BeatmapVerifierContext(IBeatmap beatmap, IWorkingBeatmap workingBeatmap, DifficultyRating difficultyRating = DifficultyRating.ExpertPlus, Func? beatmapResolver = null) + /// + /// Other beatmaps in the same beatmapset. + /// + public readonly IReadOnlyList OtherDifficulties; + + /// + /// All beatmaps in the same beatmapset. + /// + public IEnumerable AllDifficulties => OtherDifficulties.Prepend(CurrentDifficulty); + + public BeatmapVerifierContext(VerifiedBeatmap currentDifficulty, IReadOnlyList otherDifficulties, DifficultyRating difficultyRating) { - Beatmap = beatmap; - WorkingBeatmap = workingBeatmap; + CurrentDifficulty = currentDifficulty; InterpretedDifficulty = difficultyRating; + OtherDifficulties = otherDifficulties; + } + /// + /// Backwards-compatible constructor that allows creating a context from a single playable and working beatmap. + /// + public BeatmapVerifierContext(IBeatmap beatmap, IWorkingBeatmap workingBeatmap, DifficultyRating difficultyRating = DifficultyRating.ExpertPlus) + : this(new VerifiedBeatmap(workingBeatmap, beatmap), [], difficultyRating) + { + } + + public static BeatmapVerifierContext Create(IBeatmap beatmap, IWorkingBeatmap workingBeatmap, DifficultyRating difficultyRating = DifficultyRating.ExpertPlus, BeatmapManager? beatmapManager = null) + { var beatmapSet = beatmap.BeatmapInfo.BeatmapSet; - if (beatmapSet?.Beatmaps == null) - { - BeatmapsetDifficulties = new[] { beatmap }; - return; - } + var current = new VerifiedBeatmap(workingBeatmap, beatmap); - var difficulties = new List(); + if (beatmapSet?.Beatmaps == null || beatmapSet.Beatmaps.Count == 1) + return new BeatmapVerifierContext(current, [], difficultyRating); - foreach (var beatmapInfo in beatmapSet.Beatmaps) + var others = new List(); + + foreach (var info in beatmapSet.Beatmaps) { - // Use the current beatmap if it matches this BeatmapInfo - if (beatmapInfo.Equals(beatmap.BeatmapInfo)) - { - difficulties.Add(beatmap); + if (info.Equals(beatmap.BeatmapInfo)) continue; - } - // Try to resolve other difficulties using the provided resolver - var resolvedBeatmap = beatmapResolver?.Invoke(beatmapInfo); - if (resolvedBeatmap != null) - difficulties.Add(resolvedBeatmap); + var otherWorking = beatmapManager?.GetWorkingBeatmap(info); + var otherPlayable = otherWorking?.GetPlayableBeatmap(info.Ruleset); + + if (otherWorking != null && otherPlayable != null) + others.Add(new VerifiedBeatmap(otherWorking, otherPlayable)); } - BeatmapsetDifficulties = difficulties; + return new BeatmapVerifierContext(current, others, difficultyRating); } } } diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs index a7e54528d2..6c400c5de8 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs @@ -27,10 +27,10 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; var videoPaths = new List(); - foreach (var layer in context.WorkingBeatmap.Storyboard.Layers) + foreach (var layer in context.CurrentDifficulty.Working.Storyboard.Layers) { foreach (var element in layer.Elements) { @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Edit.Checks try { // We use TagLib here for platform invariance; BASS cannot detect audio presence on Linux. - using (Stream data = context.WorkingBeatmap.GetStream(storagePath)) + using (Stream data = context.CurrentDifficulty.Working.GetStream(storagePath)) using (File tagFile = TagLibUtils.GetTagLibFile(filename, data)) { if (tagFile.Properties.AudioChannels == 0) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs index 32af1ceba4..26021716a0 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs @@ -29,11 +29,11 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - string audioFile = context.Beatmap.Metadata.AudioFile; + string audioFile = context.CurrentDifficulty.Playable.Metadata.AudioFile; if (string.IsNullOrEmpty(audioFile)) yield break; - var track = context.WorkingBeatmap.Track; + var track = context.CurrentDifficulty.Working.Track; if (track?.Bitrate == null || track.Bitrate.Value == 0) yield return new IssueTemplateNoBitrate(this).Create(); diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs index c1351d053b..1147ff9663 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs @@ -33,11 +33,11 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - string backgroundFile = context.Beatmap.Metadata.BackgroundFile; + string backgroundFile = context.CurrentDifficulty.Playable.Metadata.BackgroundFile; if (string.IsNullOrEmpty(backgroundFile)) yield break; - var texture = context.WorkingBeatmap.GetBackground(); + var texture = context.CurrentDifficulty.Working.GetBackground(); if (texture == null) yield break; @@ -49,9 +49,9 @@ namespace osu.Game.Rulesets.Edit.Checks else if (texture.Width < low_width || texture.Height < low_height) yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.Height); - string? storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(backgroundFile); + string? storagePath = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet?.GetPathForFile(backgroundFile); - using (Stream stream = context.WorkingBeatmap.GetStream(storagePath)) + using (Stream stream = context.CurrentDifficulty.Working.GetStream(storagePath)) { double filesizeMb = stream.Length / (1024d * 1024d); diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBreaks.cs b/osu.Game/Rulesets/Edit/Checks/CheckBreaks.cs index f7be36beab..e16629d760 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckBreaks.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckBreaks.cs @@ -25,10 +25,10 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var startTimes = context.Beatmap.HitObjects.Select(ho => ho.StartTime).Order().ToList(); - var endTimes = context.Beatmap.HitObjects.Select(ho => ho.GetEndTime()).Order().ToList(); + var startTimes = context.CurrentDifficulty.Playable.HitObjects.Select(ho => ho.StartTime).Order().ToList(); + var endTimes = context.CurrentDifficulty.Playable.HitObjects.Select(ho => ho.GetEndTime()).Order().ToList(); - foreach (var breakPeriod in context.Beatmap.Breaks) + foreach (var breakPeriod in context.CurrentDifficulty.Playable.Breaks) { if (breakPeriod.Duration < BreakPeriod.MIN_BREAK_DURATION) yield return new IssueTemplateTooShort(this).Create(breakPeriod.StartTime); diff --git a/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs index c23a944ffb..75b5b08c7f 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Edit.Checks public virtual IEnumerable Run(BeatmapVerifierContext context) { - var hitObjects = context.Beatmap.HitObjects; + var hitObjects = context.CurrentDifficulty.Playable.HitObjects; for (int i = 0; i < hitObjects.Count - 1; ++i) { diff --git a/osu.Game/Rulesets/Edit/Checks/CheckDelayedHitsounds.cs b/osu.Game/Rulesets/Edit/Checks/CheckDelayedHitsounds.cs index a78a16953e..4f64f8838f 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckDelayedHitsounds.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckDelayedHitsounds.cs @@ -37,14 +37,14 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; if (beatmapSet == null) yield break; foreach (var file in beatmapSet.Files) { - using (Stream? stream = context.WorkingBeatmap.GetStream(file.File.GetStoragePath())) + using (Stream? stream = context.CurrentDifficulty.Working.GetStream(file.File.GetStoragePath())) { if (stream == null) continue; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckDrainLength.cs b/osu.Game/Rulesets/Edit/Checks/CheckDrainLength.cs index ac65dfadff..3115f80e66 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckDrainLength.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckDrainLength.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - double drainTime = context.Beatmap.CalculateDrainLength(); + double drainTime = context.CurrentDifficulty.Playable.CalculateDrainLength(); if (drainTime < min_drain_threshold) yield return new IssueTemplateTooShort(this).Create((int)(drainTime / 1000)); diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs b/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs index 97c1519c24..941cebdb4f 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs @@ -48,16 +48,16 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - if (!context.Beatmap.HitObjects.Any()) + if (!context.CurrentDifficulty.Playable.HitObjects.Any()) yield break; mapHasHitsounds = false; objectsWithoutHitsounds = 0; - lastHitsoundTime = context.Beatmap.HitObjects.First().StartTime; + lastHitsoundTime = context.CurrentDifficulty.Playable.HitObjects.First().StartTime; var hitObjectsIncludingNested = new List(); - foreach (var hitObject in context.Beatmap.HitObjects) + foreach (var hitObject in context.CurrentDifficulty.Playable.HitObjects) { // Samples play on the end of objects. Some objects have nested objects to accomplish playing them elsewhere (e.g. slider head/repeat). foreach (var nestedHitObject in hitObject.NestedHitObjects) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs index 346b79c8af..158811044c 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - string? filename = GetFilename(context.Beatmap); + string? filename = GetFilename(context.CurrentDifficulty.Playable); if (string.IsNullOrEmpty(filename)) { @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Edit.Checks } // If the file is set, also make sure it still exists. - string? storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(filename); + string? storagePath = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet?.GetPathForFile(filename); if (storagePath != null) yield break; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckHitsoundsFormat.cs b/osu.Game/Rulesets/Edit/Checks/CheckHitsoundsFormat.cs index 30973cfa76..b498cf0c52 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckHitsoundsFormat.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckHitsoundsFormat.cs @@ -23,8 +23,8 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; - var audioFile = beatmapSet?.GetFile(context.Beatmap.Metadata.AudioFile); + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; + var audioFile = beatmapSet?.GetFile(context.CurrentDifficulty.Playable.Metadata.AudioFile); if (beatmapSet == null) yield break; @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Edit.Checks { if (audioFile != null && ReferenceEquals(file.File, audioFile.File)) continue; - using (Stream data = context.WorkingBeatmap.GetStream(file.File.GetStoragePath())) + using (Stream data = context.CurrentDifficulty.Working.GetStream(file.File.GetStoragePath())) { if (data == null) continue; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckInconsistentMetadata.cs b/osu.Game/Rulesets/Edit/Checks/CheckInconsistentMetadata.cs index d320dae0c9..fdb72a3871 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckInconsistentMetadata.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckInconsistentMetadata.cs @@ -21,12 +21,10 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var difficulties = context.BeatmapsetDifficulties; - - if (difficulties.Count <= 1) + if (context.AllDifficulties.Count() <= 1) yield break; - var referenceBeatmap = context.Beatmap; + var referenceBeatmap = context.CurrentDifficulty.Playable; var referenceMetadata = referenceBeatmap.Metadata; // Define metadata fields to check @@ -40,12 +38,9 @@ namespace osu.Game.Rulesets.Edit.Checks ("creator", m => m.Author.Username) }; - foreach (var beatmap in difficulties) + foreach (var beatmap in context.OtherDifficulties) { - if (beatmap == referenceBeatmap) - continue; - - var currentMetadata = beatmap.Metadata; + var currentMetadata = beatmap.Playable.Metadata; // Check each metadata field for inconsistencies foreach ((string fieldName, var fieldSelector) in fieldsToCheck) @@ -58,7 +53,7 @@ namespace osu.Game.Rulesets.Edit.Checks yield return new IssueTemplateInconsistentOtherFields(this).Create( fieldName, referenceBeatmap.BeatmapInfo.DifficultyName, - beatmap.BeatmapInfo.DifficultyName, + beatmap.Playable.BeatmapInfo.DifficultyName, referenceField, currentField ); @@ -77,7 +72,7 @@ namespace osu.Game.Rulesets.Edit.Checks { yield return new IssueTemplateInconsistentTags(this).Create( referenceBeatmap.BeatmapInfo.DifficultyName, - beatmap.BeatmapInfo.DifficultyName, + beatmap.Playable.BeatmapInfo.DifficultyName, difference ); } diff --git a/osu.Game/Rulesets/Edit/Checks/CheckInconsistentSettings.cs b/osu.Game/Rulesets/Edit/Checks/CheckInconsistentSettings.cs index 2fda33dfc6..caab0c5ff4 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckInconsistentSettings.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckInconsistentSettings.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit.Checks.Components; @@ -20,14 +21,12 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var difficulties = context.BeatmapsetDifficulties; - - if (difficulties.Count <= 1) + if (context.AllDifficulties.Count() <= 1) return []; - var referenceBeatmap = context.Beatmap; + var referenceBeatmap = context.CurrentDifficulty.Playable; - bool hasStoryboard = ResourcesCheckUtils.HasAnyStoryboardElementPresent(context.WorkingBeatmap); + bool hasStoryboard = ResourcesCheckUtils.HasAnyStoryboardElementPresent(context.CurrentDifficulty.Working); var issues = new List(); @@ -50,19 +49,16 @@ namespace osu.Game.Rulesets.Edit.Checks { var referenceValue = fieldSelector(referenceBeatmap); - foreach (var beatmap in difficulties) + foreach (var beatmap in context.OtherDifficulties) { - if (beatmap == referenceBeatmap) - continue; - - var currentValue = fieldSelector(beatmap); + var currentValue = fieldSelector(beatmap.Playable); if (!EqualityComparer.Default.Equals(currentValue, referenceValue)) { issues.Add(new IssueTemplateInconsistentSetting(this, issueType).Create( fieldName, referenceBeatmap.BeatmapInfo.DifficultyName, - beatmap.BeatmapInfo.DifficultyName, + beatmap.Playable.BeatmapInfo.DifficultyName, referenceValue.ToString() ?? string.Empty, currentValue.ToString() ?? string.Empty )); diff --git a/osu.Game/Rulesets/Edit/Checks/CheckInconsistentTimingControlPoints.cs b/osu.Game/Rulesets/Edit/Checks/CheckInconsistentTimingControlPoints.cs index def1086525..d30f575fc7 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckInconsistentTimingControlPoints.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckInconsistentTimingControlPoints.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Rulesets.Edit.Checks.Components; namespace osu.Game.Rulesets.Edit.Checks @@ -22,21 +23,16 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var difficulties = context.BeatmapsetDifficulties; - - if (difficulties.Count <= 1) + if (context.AllDifficulties.Count() <= 1) yield break; // Use the current difficulty as reference - var referenceBeatmap = context.Beatmap; + var referenceBeatmap = context.CurrentDifficulty.Playable; var referenceTimingPoints = referenceBeatmap.ControlPointInfo.TimingPoints; - foreach (var beatmap in difficulties) + foreach (var beatmap in context.OtherDifficulties) { - if (beatmap == referenceBeatmap) - continue; - - var timingPoints = beatmap.ControlPointInfo.TimingPoints; + var timingPoints = beatmap.Playable.ControlPointInfo.TimingPoints; // Check each timing point in the reference against this difficulty foreach (var referencePoint in referenceTimingPoints) @@ -44,28 +40,30 @@ namespace osu.Game.Rulesets.Edit.Checks var matchingPoint = TimingCheckUtils.FindMatchingTimingPoint(timingPoints, referencePoint.Time); var exactMatchingPoint = TimingCheckUtils.FindExactMatchingTimingPoint(timingPoints, referencePoint.Time); + string currentDifficultyName = beatmap.Playable.BeatmapInfo.DifficultyName; + if (matchingPoint == null) { - yield return new IssueTemplateMissingTimingPoint(this).Create(referencePoint.Time, beatmap.BeatmapInfo.DifficultyName); + yield return new IssueTemplateMissingTimingPoint(this).Create(referencePoint.Time, currentDifficultyName); } else { // Check for meter signature inconsistency if (!referencePoint.TimeSignature.Equals(matchingPoint.TimeSignature)) { - yield return new IssueTemplateInconsistentMeter(this).Create(referencePoint.Time, beatmap.BeatmapInfo.DifficultyName); + yield return new IssueTemplateInconsistentMeter(this).Create(referencePoint.Time, currentDifficultyName); } // Check for BPM inconsistency if (Math.Abs(referencePoint.BeatLength - matchingPoint.BeatLength) > TimingCheckUtils.TIME_OFFSET_TOLERANCE_MS) { - yield return new IssueTemplateInconsistentBPM(this).Create(referencePoint.Time, beatmap.BeatmapInfo.DifficultyName); + yield return new IssueTemplateInconsistentBPM(this).Create(referencePoint.Time, currentDifficultyName); } // Check for exact timing match (decimal precision) if (exactMatchingPoint == null) { - yield return new IssueTemplateMissingTimingPointMinor(this).Create(referencePoint.Time, beatmap.BeatmapInfo.DifficultyName); + yield return new IssueTemplateMissingTimingPointMinor(this).Create(referencePoint.Time, currentDifficultyName); } } } @@ -78,11 +76,11 @@ namespace osu.Game.Rulesets.Edit.Checks if (matchingReferencePoint == null) { - yield return new IssueTemplateExtraTimingPoint(this).Create(timingPoint.Time, beatmap.BeatmapInfo.DifficultyName); + yield return new IssueTemplateExtraTimingPoint(this).Create(timingPoint.Time, beatmap.Playable.BeatmapInfo.DifficultyName); } else if (exactMatchingReferencePoint == null) { - yield return new IssueTemplateMissingTimingPointMinor(this).Create(timingPoint.Time, beatmap.BeatmapInfo.DifficultyName); + yield return new IssueTemplateMissingTimingPointMinor(this).Create(timingPoint.Time, beatmap.Playable.BeatmapInfo.DifficultyName); } } } diff --git a/osu.Game/Rulesets/Edit/Checks/CheckLowestDiffDrainTime.cs b/osu.Game/Rulesets/Edit/Checks/CheckLowestDiffDrainTime.cs index f4b9cc7ecb..7a17eac3ea 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckLowestDiffDrainTime.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckLowestDiffDrainTime.cs @@ -27,27 +27,28 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - IReadOnlyList difficulties = context.BeatmapsetDifficulties - .Where(d => d.BeatmapInfo.Ruleset.Equals(context.Beatmap.BeatmapInfo.Ruleset)) - .ToList(); + // Filter to only include difficulties with the same ruleset as the current one + var difficulties = context.AllDifficulties + .Where(d => d.Playable.BeatmapInfo.Ruleset.Equals(context.CurrentDifficulty.Playable.BeatmapInfo.Ruleset)) + .ToList(); if (difficulties.Count == 0) yield break; - var lowestDifficulty = difficulties.OrderBy(b => b.BeatmapInfo.StarRating).First(); + var lowestDifficulty = difficulties.OrderBy(b => b.Playable.BeatmapInfo.StarRating).First(); // Get difficulty rating for the lowest difficulty - DifficultyRating lowestDifficultyRating = lowestDifficulty == context.Beatmap + DifficultyRating lowestDifficultyRating = lowestDifficulty.Playable == context.CurrentDifficulty.Playable ? context.InterpretedDifficulty - : StarDifficulty.GetDifficultyRating(lowestDifficulty.BeatmapInfo.StarRating); + : StarDifficulty.GetDifficultyRating(lowestDifficulty.Playable.BeatmapInfo.StarRating); - double drainTime = context.Beatmap.CalculateDrainLength(); - double playTime = context.Beatmap.CalculatePlayableLength(); + double drainTime = context.CurrentDifficulty.Playable.CalculateDrainLength(); + double playTime = context.CurrentDifficulty.Playable.CalculatePlayableLength(); - bool isHighestDifficulty = difficulties.OrderByDescending(b => b.BeatmapInfo.StarRating).First() == context.Beatmap; + bool isHighestDifficulty = difficulties.OrderByDescending(b => b.Playable.BeatmapInfo.StarRating).First() == context.CurrentDifficulty; // Use play time unless it's the highest difficulty and has significant breaks - bool canUsePlayTime = !isHighestDifficulty || context.Beatmap.TotalBreakTime < break_time_leniency; + bool canUsePlayTime = !isHighestDifficulty || context.CurrentDifficulty.Playable.TotalBreakTime < break_time_leniency; double effectiveTime = canUsePlayTime ? playTime : drainTime; double thresholdReduction = canUsePlayTime ? 0 : break_time_leniency; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckMissingGenreLanguage.cs b/osu.Game/Rulesets/Edit/Checks/CheckMissingGenreLanguage.cs index b7a727c4d5..e70aa3831b 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckMissingGenreLanguage.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckMissingGenreLanguage.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var metadata = context.Beatmap.BeatmapInfo.Metadata; + var metadata = context.CurrentDifficulty.Playable.BeatmapInfo.Metadata; string tags = metadata.Tags.ToLowerInvariant(); diff --git a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs index a2ae1764dd..60f159bc9c 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - foreach (var hitObject in context.Beatmap.HitObjects) + foreach (var hitObject in context.CurrentDifficulty.Playable.HitObjects) { // Worth keeping in mind: The samples of an object always play at its end time. // Objects like spinners have no sound at its start because of this, while hold notes have nested objects to accomplish this. diff --git a/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs index d4f9c1feaf..8260f4c245 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit.Checks.Components; namespace osu.Game.Rulesets.Edit.Checks @@ -19,19 +18,15 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var diffList = context.Beatmap.BeatmapInfo.BeatmapSet?.Beatmaps ?? new List(); - int previewTime = context.Beatmap.BeatmapInfo.Metadata.PreviewTime; + int previewTime = context.CurrentDifficulty.Playable.BeatmapInfo.Metadata.PreviewTime; if (previewTime == -1) yield return new IssueTemplateHasNoPreviewTime(this).Create(); - foreach (var diff in diffList) + foreach (var beatmap in context.OtherDifficulties) { - if (diff.Equals(context.Beatmap.BeatmapInfo)) - continue; - - if (diff.Metadata.PreviewTime != previewTime) - yield return new IssueTemplatePreviewTimeConflict(this).Create(diff.DifficultyName, previewTime, diff.Metadata.PreviewTime); + if (beatmap.Playable.BeatmapInfo.Metadata.PreviewTime != previewTime) + yield return new IssueTemplatePreviewTimeConflict(this).Create(beatmap.Playable.BeatmapInfo.DifficultyName, previewTime, beatmap.Playable.BeatmapInfo.Metadata.PreviewTime); } } diff --git a/osu.Game/Rulesets/Edit/Checks/CheckSongFormat.cs b/osu.Game/Rulesets/Edit/Checks/CheckSongFormat.cs index 5871cf51ff..3f3b95d95b 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckSongFormat.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckSongFormat.cs @@ -27,13 +27,13 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; - var audioFile = beatmapSet?.GetFile(context.Beatmap.Metadata.AudioFile); + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; + var audioFile = beatmapSet?.GetFile(context.CurrentDifficulty.Playable.Metadata.AudioFile); if (beatmapSet == null) yield break; if (audioFile == null) yield break; - var audioFormat = AudioCheckUtils.GetAudioFormatFromFile(context, context.Beatmap.Metadata.AudioFile); + var audioFormat = AudioCheckUtils.GetAudioFormatFromFile(context, context.CurrentDifficulty.Playable.Metadata.AudioFile); // If the format is not supported by BASS if (audioFormat == 0) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckTitleMarkers.cs b/osu.Game/Rulesets/Edit/Checks/CheckTitleMarkers.cs index 742054777e..58cfe558e5 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckTitleMarkers.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckTitleMarkers.cs @@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - string romanisedTitle = context.Beatmap.Metadata.Title; - string unicodeTitle = context.Beatmap.Metadata.TitleUnicode; + string romanisedTitle = context.CurrentDifficulty.Playable.Metadata.Title; + string unicodeTitle = context.CurrentDifficulty.Playable.Metadata.TitleUnicode; foreach (var check in markerChecks) { diff --git a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs index 7991797ddd..563e18848b 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs @@ -23,13 +23,13 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; if (beatmapSet != null) { foreach (var file in beatmapSet.Files) { - using (Stream data = context.WorkingBeatmap.GetStream(file.File.GetStoragePath())) + using (Stream data = context.CurrentDifficulty.Working.GetStream(file.File.GetStoragePath())) { if (data == null) continue; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs index ded1bb54ca..35900cdcd0 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs @@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var controlPointInfo = context.Beatmap.ControlPointInfo; + var controlPointInfo = context.CurrentDifficulty.Playable.ControlPointInfo; - foreach (var hitobject in context.Beatmap.HitObjects) + foreach (var hitobject in context.CurrentDifficulty.Playable.HitObjects) { double startUnsnap = hitobject.StartTime - controlPointInfo.GetClosestSnappedTime(hitobject.StartTime); string startPostfix = hitobject is IHasDuration ? "start" : ""; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckUnusedAudioAtEnd.cs b/osu.Game/Rulesets/Edit/Checks/CheckUnusedAudioAtEnd.cs index 0cb00a1a67..a69dd324f9 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckUnusedAudioAtEnd.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckUnusedAudioAtEnd.cs @@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - double mappedLength = context.Beatmap.HitObjects.Any() ? context.Beatmap.GetLastObjectTime() : 0; - double trackLength = context.WorkingBeatmap.Track.Length; + double mappedLength = context.CurrentDifficulty.Playable.HitObjects.Any() ? context.CurrentDifficulty.Playable.GetLastObjectTime() : 0; + double trackLength = context.CurrentDifficulty.Working.Track.Length; double mappedPercentage = Math.Round(mappedLength / trackLength * 100); @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Edit.Checks { double percentageLeft = Math.Abs(mappedPercentage - 100); - bool storyboardIsPresent = ResourcesCheckUtils.HasAnyStoryboardElementPresent(context.WorkingBeatmap); + bool storyboardIsPresent = ResourcesCheckUtils.HasAnyStoryboardElementPresent(context.CurrentDifficulty.Working); if (storyboardIsPresent) { diff --git a/osu.Game/Rulesets/Edit/Checks/CheckVideoResolution.cs b/osu.Game/Rulesets/Edit/Checks/CheckVideoResolution.cs index 344dddec3e..7a1e87954b 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckVideoResolution.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckVideoResolution.cs @@ -30,8 +30,8 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; - var videoPaths = getVideoPaths(context.WorkingBeatmap.Storyboard); + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; + var videoPaths = getVideoPaths(context.CurrentDifficulty.Working.Storyboard); foreach (string filename in videoPaths) { @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Edit.Checks try { - using (Stream data = context.WorkingBeatmap.GetStream(storagePath)) + using (Stream data = context.CurrentDifficulty.Working.GetStream(storagePath)) using (File tagFile = TagLibUtils.GetTagLibFile(filename, data)) { int height = tagFile.Properties.VideoHeight; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs b/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs index 7048e944dd..d9de49a910 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs @@ -19,13 +19,13 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; if (beatmapSet != null) { foreach (var file in beatmapSet.Files) { - using (Stream data = context.WorkingBeatmap.GetStream(file.File.GetStoragePath())) + using (Stream data = context.CurrentDifficulty.Working.GetStream(file.File.GetStoragePath())) { if (data?.Length == 0) yield return new IssueTemplateZeroBytes(this).Create(file.Filename); diff --git a/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs index b9be94736b..a10dd43e74 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - foreach (var hitObject in context.Beatmap.HitObjects) + foreach (var hitObject in context.CurrentDifficulty.Playable.HitObjects) { if (!(hitObject is IHasDuration hasDuration)) continue; diff --git a/osu.Game/Rulesets/Edit/Checks/Components/AudioCheckUtils.cs b/osu.Game/Rulesets/Edit/Checks/Components/AudioCheckUtils.cs index c72e0288c2..746f2bf256 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/AudioCheckUtils.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/AudioCheckUtils.cs @@ -46,13 +46,13 @@ namespace osu.Game.Rulesets.Edit.Checks.Components /// The ChannelType of the audio file, or if detection fails. public static ChannelType GetAudioFormatFromFile(BeatmapVerifierContext context, string filename) { - var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet; + var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet; var audioFile = beatmapSet?.GetFile(filename); if (beatmapSet == null || audioFile == null) return ChannelType.Unknown; - using (Stream data = context.WorkingBeatmap.GetStream(audioFile.File.GetStoragePath())) + using (Stream data = context.CurrentDifficulty.Working.GetStream(audioFile.File.GetStoragePath())) return GetAudioFormat(data); } } diff --git a/osu.Game/Screens/Edit/Verify/IssueList.cs b/osu.Game/Screens/Edit/Verify/IssueList.cs index 415a46c583..8222e5633e 100644 --- a/osu.Game/Screens/Edit/Verify/IssueList.cs +++ b/osu.Game/Screens/Edit/Verify/IssueList.cs @@ -46,11 +46,11 @@ namespace osu.Game.Screens.Edit.Verify generalVerifier = new BeatmapVerifier(); rulesetVerifier = beatmap.BeatmapInfo.Ruleset.CreateInstance().CreateBeatmapVerifier(); - context = new BeatmapVerifierContext( + context = BeatmapVerifierContext.Create( beatmap, workingBeatmap.Value, verify.InterpretedDifficulty.Value, - beatmapInfo => beatmapManager.GetWorkingBeatmap(beatmapInfo).GetPlayableBeatmap(beatmapInfo.Ruleset) + beatmapManager ); verify.InterpretedDifficulty.BindValueChanged(difficulty => context.InterpretedDifficulty = difficulty.NewValue);