diff --git a/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs new file mode 100644 index 0000000000..37b01da6ee --- /dev/null +++ b/osu.Game.Tests/Editing/Checks/CheckPreviewTimeTest.cs @@ -0,0 +1,88 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Edit.Checks; +using osu.Game.Rulesets.Objects; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Tests.Editing.Checks +{ + public class CheckPreviewTimeTest + { + private CheckPreviewTime check = null!; + + private IBeatmap beatmap = null!; + + [SetUp] + public void Setup() + { + check = new CheckPreviewTime(); + } + + [Test] + public void TestPreviewTimeNotSet() + { + setNoPreviewTimeBeatmap(); + var content = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap)); + + var issues = check.Run(content).ToList(); + + Assert.That(issues, Has.Count.EqualTo(1)); + Assert.That(issues.Single().Template is CheckPreviewTime.IssueTemplateHasNoPreviewTime); + } + + [Test] + public void TestPreviewTimeconflict() + { + setPreviewTimeConflictBeatmap(); + + var content = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap)); + + var issues = check.Run(content).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() + { + beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + Metadata = new BeatmapMetadata { PreviewTime = -1 }, + } + }; + } + + private void setPreviewTimeConflictBeatmap() + { + 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 }, + }, + }) + } + }; + } + } +} diff --git a/osu.Game/Rulesets/Edit/BeatmapVerifier.cs b/osu.Game/Rulesets/Edit/BeatmapVerifier.cs index a89a0e76a9..5f5aba26bb 100644 --- a/osu.Game/Rulesets/Edit/BeatmapVerifier.cs +++ b/osu.Game/Rulesets/Edit/BeatmapVerifier.cs @@ -36,6 +36,9 @@ namespace osu.Game.Rulesets.Edit new CheckUnsnappedObjects(), new CheckConcurrentObjects(), new CheckZeroLengthObjects(), + + // Timing + new CheckPreviewTime(), }; public IEnumerable Run(BeatmapVerifierContext context) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs new file mode 100644 index 0000000000..d4f9c1feaf --- /dev/null +++ b/osu.Game/Rulesets/Edit/Checks/CheckPreviewTime.cs @@ -0,0 +1,62 @@ +// 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 osu.Game.Beatmaps; +using osu.Game.Rulesets.Edit.Checks.Components; + +namespace osu.Game.Rulesets.Edit.Checks +{ + public class CheckPreviewTime : ICheck + { + public CheckMetadata Metadata => new CheckMetadata(CheckCategory.Timing, "Inconsistent or unset preview time"); + + public IEnumerable PossibleTemplates => new IssueTemplate[] + { + new IssueTemplatePreviewTimeConflict(this), + new IssueTemplateHasNoPreviewTime(this), + }; + + public IEnumerable Run(BeatmapVerifierContext context) + { + var diffList = context.Beatmap.BeatmapInfo.BeatmapSet?.Beatmaps ?? new List(); + int previewTime = context.Beatmap.BeatmapInfo.Metadata.PreviewTime; + + if (previewTime == -1) + yield return new IssueTemplateHasNoPreviewTime(this).Create(); + + foreach (var diff in diffList) + { + if (diff.Equals(context.Beatmap.BeatmapInfo)) + continue; + + if (diff.Metadata.PreviewTime != previewTime) + yield return new IssueTemplatePreviewTimeConflict(this).Create(diff.DifficultyName, previewTime, diff.Metadata.PreviewTime); + } + } + + public class IssueTemplatePreviewTimeConflict : IssueTemplate + { + public IssueTemplatePreviewTimeConflict(ICheck check) + : base(check, IssueType.Problem, "Audio preview time ({1}) doesn't match the time specified in \"{0}\" ({2})") + { + } + + public Issue Create(string diffName, int originalTime, int conflictTime) => + // preview time should show (not set) when it is not set. + new Issue(this, diffName, + originalTime != -1 ? $"{originalTime:N0} ms" : "not set", + conflictTime != -1 ? $"{conflictTime:N0} ms" : "not set"); + } + + public class IssueTemplateHasNoPreviewTime : IssueTemplate + { + public IssueTemplateHasNoPreviewTime(ICheck check) + : base(check, IssueType.Problem, "A preview point for this map is not set. Consider setting one from the Timing menu.") + { + } + + public Issue Create() => new Issue(this); + } + } +}