mirror of
https://github.com/ppy/osu.git
synced 2026-05-17 00:23:24 +08:00
Merge pull request #34584 from Hiviexd/verify/refactor-verifier-context
Refactor `BeatmapVerifierContext`
This commit is contained in:
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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)
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Checks
|
||||
|
||||
public override IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var diff = context.Beatmap.Difficulty;
|
||||
var diff = context.CurrentDifficulty.Playable.Difficulty;
|
||||
Issue? issue;
|
||||
|
||||
if (HasMoreThanOneDecimalPlace("Approach rate", diff.ApproachRate, out issue))
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var diff = context.Beatmap.Difficulty;
|
||||
var diff = context.CurrentDifficulty.Playable.Difficulty;
|
||||
|
||||
if (diff.CircleSize < 4)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Checks
|
||||
|
||||
public override IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var diff = context.Beatmap.Difficulty;
|
||||
var diff = context.CurrentDifficulty.Playable.Difficulty;
|
||||
Issue? issue;
|
||||
|
||||
if (HasMoreThanOneDecimalPlace("Overall difficulty", diff.OverallDifficulty, out issue))
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Checks
|
||||
{
|
||||
public override IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var hitObjects = context.Beatmap.HitObjects;
|
||||
var hitObjects = context.CurrentDifficulty.Playable.HitObjects;
|
||||
|
||||
for (int i = 0; i < hitObjects.Count - 1; ++i)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
foreach (var hitobject in context.Beatmap.HitObjects)
|
||||
foreach (var hitobject in context.CurrentDifficulty.Playable.HitObjects)
|
||||
{
|
||||
switch (hitobject)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
|
||||
|
||||
public override IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var diff = context.Beatmap.Difficulty;
|
||||
var diff = context.CurrentDifficulty.Playable.Difficulty;
|
||||
Issue? issue;
|
||||
|
||||
if (HasMoreThanOneDecimalPlace("Approach rate", diff.ApproachRate, out issue))
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
|
||||
yield break;
|
||||
|
||||
var prevObservedTimeDistances = new List<ObservedTimeDistance>();
|
||||
var hitObjects = context.Beatmap.HitObjects;
|
||||
var hitObjects = context.CurrentDifficulty.Playable.HitObjects;
|
||||
|
||||
for (int i = 0; i < hitObjects.Count - 1; ++i)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -19,14 +19,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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;
|
||||
|
||||
+4
-6
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Edit.Checks
|
||||
|
||||
public override IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var diff = context.Beatmap.Difficulty;
|
||||
var diff = context.CurrentDifficulty.Playable.Difficulty;
|
||||
Issue? issue;
|
||||
|
||||
if (HasMoreThanOneDecimalPlace("Overall difficulty", diff.OverallDifficulty, out issue))
|
||||
|
||||
@@ -19,26 +19,23 @@ namespace osu.Game.Rulesets.Taiko.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IBeatmap> 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
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<IBeatmap>());
|
||||
|
||||
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<HitObject>
|
||||
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<HitObject>
|
||||
{
|
||||
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<HitObject>
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata { PreviewTime = 10 },
|
||||
BeatmapSet = new BeatmapSetInfo(new List<BeatmapInfo>
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// The playable beatmap instance of the current beatmap.
|
||||
/// Collects the constituent parts of a beatmap being verified.
|
||||
/// </summary>
|
||||
public readonly IBeatmap Beatmap;
|
||||
|
||||
/// <summary>
|
||||
/// The working beatmap instance of the current beatmap.
|
||||
/// </summary>
|
||||
public readonly IWorkingBeatmap WorkingBeatmap;
|
||||
/// <param name="Working">
|
||||
/// Use this to access beatmap resources like its track, storyboard, waveform, or similar.
|
||||
/// </param>
|
||||
/// <param name="Playable">
|
||||
/// The <see cref="IBeatmap"/> in its actual playable state after beatmap conversion.
|
||||
/// Use this to inspect the actual beatmap contents, like its hitobjects, timing points, breaks, etc.
|
||||
/// </param>
|
||||
public record VerifiedBeatmap(IWorkingBeatmap Working, IBeatmap Playable);
|
||||
|
||||
/// <summary>
|
||||
/// The difficulty level which the current beatmap is considered to be.
|
||||
@@ -29,43 +31,59 @@ namespace osu.Game.Rulesets.Edit
|
||||
public DifficultyRating InterpretedDifficulty;
|
||||
|
||||
/// <summary>
|
||||
/// All beatmap difficulties in the same beatmapset, including the current beatmap.
|
||||
/// The current beatmap being checked.
|
||||
/// </summary>
|
||||
public readonly IReadOnlyList<IBeatmap> 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<BeatmapInfo, IBeatmap?>? beatmapResolver = null)
|
||||
/// <summary>
|
||||
/// Other beatmaps in the same beatmapset.
|
||||
/// </summary>
|
||||
public readonly IReadOnlyList<VerifiedBeatmap> OtherDifficulties;
|
||||
|
||||
/// <summary>
|
||||
/// All beatmaps in the same beatmapset.
|
||||
/// </summary>
|
||||
public IEnumerable<VerifiedBeatmap> AllDifficulties => OtherDifficulties.Prepend(CurrentDifficulty);
|
||||
|
||||
public BeatmapVerifierContext(VerifiedBeatmap currentDifficulty, IReadOnlyList<VerifiedBeatmap> otherDifficulties, DifficultyRating difficultyRating)
|
||||
{
|
||||
Beatmap = beatmap;
|
||||
WorkingBeatmap = workingBeatmap;
|
||||
CurrentDifficulty = currentDifficulty;
|
||||
InterpretedDifficulty = difficultyRating;
|
||||
OtherDifficulties = otherDifficulties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Backwards-compatible constructor that allows creating a context from a single playable and working beatmap.
|
||||
/// </summary>
|
||||
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<IBeatmap>();
|
||||
if (beatmapSet?.Beatmaps == null || beatmapSet.Beatmaps.Count == 1)
|
||||
return new BeatmapVerifierContext(current, [], difficultyRating);
|
||||
|
||||
foreach (var beatmapInfo in beatmapSet.Beatmaps)
|
||||
var others = new List<VerifiedBeatmap>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var beatmapSet = context.Beatmap.BeatmapInfo.BeatmapSet;
|
||||
var beatmapSet = context.CurrentDifficulty.Playable.BeatmapInfo.BeatmapSet;
|
||||
var videoPaths = new List<string>();
|
||||
|
||||
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)
|
||||
|
||||
@@ -29,11 +29,11 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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();
|
||||
|
||||
@@ -33,11 +33,11 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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);
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public virtual IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var hitObjects = context.Beatmap.HitObjects;
|
||||
var hitObjects = context.CurrentDifficulty.Playable.HitObjects;
|
||||
|
||||
for (int i = 0; i < hitObjects.Count - 1; ++i)
|
||||
{
|
||||
|
||||
@@ -37,14 +37,14 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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));
|
||||
|
||||
@@ -48,16 +48,16 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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<HitObject>();
|
||||
|
||||
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)
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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;
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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;
|
||||
|
||||
@@ -21,12 +21,10 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<Issue> 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<Issue>();
|
||||
|
||||
@@ -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<T>.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
|
||||
));
|
||||
|
||||
@@ -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<Issue> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,27 +27,28 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
IReadOnlyList<IBeatmap> 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;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var metadata = context.Beatmap.BeatmapInfo.Metadata;
|
||||
var metadata = context.CurrentDifficulty.Playable.BeatmapInfo.Metadata;
|
||||
|
||||
string tags = metadata.Tags.ToLowerInvariant();
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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.
|
||||
|
||||
@@ -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<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var diffList = context.Beatmap.BeatmapInfo.BeatmapSet?.Beatmaps ?? new List<BeatmapInfo>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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)
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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)
|
||||
{
|
||||
|
||||
@@ -23,13 +23,13 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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;
|
||||
|
||||
@@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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" : "";
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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)
|
||||
{
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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;
|
||||
|
||||
@@ -19,13 +19,13 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> 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);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
foreach (var hitObject in context.Beatmap.HitObjects)
|
||||
foreach (var hitObject in context.CurrentDifficulty.Playable.HitObjects)
|
||||
{
|
||||
if (!(hitObject is IHasDuration hasDuration))
|
||||
continue;
|
||||
|
||||
@@ -46,13 +46,13 @@ namespace osu.Game.Rulesets.Edit.Checks.Components
|
||||
/// <returns>The ChannelType of the audio file, or <see cref="ChannelType.Unknown"/> if detection fails.</returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user