mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 20:53:04 +08:00
Add check/issue classes
This commit is contained in:
parent
d58ef5310b
commit
b24ce66a0d
25
osu.Game/Rulesets/Edit/Checker.cs
Normal file
25
osu.Game/Rulesets/Edit/Checker.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Checks;
|
||||||
|
using osu.Game.Screens.Edit.Verify.Components;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit
|
||||||
|
{
|
||||||
|
public abstract class Checker
|
||||||
|
{
|
||||||
|
// These are all mode-invariant, hence here instead of in e.g. `OsuChecker`.
|
||||||
|
private readonly List<BeatmapCheck> beatmapChecks = new List<BeatmapCheck>
|
||||||
|
{
|
||||||
|
new CheckMetadataVowels()
|
||||||
|
};
|
||||||
|
|
||||||
|
public virtual IEnumerable<Issue> Run(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
return beatmapChecks.SelectMany(check => check.Run(beatmap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
osu.Game/Screens/Edit/Verify/Components/BeatmapCheck.cs
Normal file
19
osu.Game/Screens/Edit/Verify/Components/BeatmapCheck.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// 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 osu.Game.Beatmaps;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Verify.Components
|
||||||
|
{
|
||||||
|
public abstract class BeatmapCheck : Check<IBeatmap>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns zero, one, or several issues detected by this
|
||||||
|
/// check on the given beatmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to run the check on.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract override IEnumerable<Issue> Run(IBeatmap beatmap);
|
||||||
|
}
|
||||||
|
}
|
41
osu.Game/Screens/Edit/Verify/Components/Check.cs
Normal file
41
osu.Game/Screens/Edit/Verify/Components/Check.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Verify.Components
|
||||||
|
{
|
||||||
|
public abstract class Check
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the <see cref="CheckMetadata"/> for this check.
|
||||||
|
/// Basically, its information.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract CheckMetadata Metadata();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The templates for issues that this check may use.
|
||||||
|
/// Basically, what issues this check can detect.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract IEnumerable<IssueTemplate> Templates();
|
||||||
|
|
||||||
|
protected Check()
|
||||||
|
{
|
||||||
|
foreach (var template in Templates())
|
||||||
|
template.Origin = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class Check<T> : Check
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns zero, one, or several issues detected by
|
||||||
|
/// this check on the given object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to run the check on.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public abstract IEnumerable<Issue> Run(T obj);
|
||||||
|
}
|
||||||
|
}
|
62
osu.Game/Screens/Edit/Verify/Components/CheckMetadata.cs
Normal file
62
osu.Game/Screens/Edit/Verify/Components/CheckMetadata.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Verify
|
||||||
|
{
|
||||||
|
public class CheckMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The category of an issue.
|
||||||
|
/// </summary>
|
||||||
|
public enum CheckCategory
|
||||||
|
{
|
||||||
|
/// <summary> Anything to do with control points. </summary>
|
||||||
|
Timing,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with artist, title, creator, etc. </summary>
|
||||||
|
Metadata,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with non-audio files, e.g. background, skin, sprites, and video. </summary>
|
||||||
|
Resources,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with audio files, e.g. song and hitsounds. </summary>
|
||||||
|
Audio,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with files that don't fit into the above, e.g. unused, osu, or osb. </summary>
|
||||||
|
Files,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with hitobjects unrelated to spread. </summary>
|
||||||
|
Compose,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with difficulty levels or their progression. </summary>
|
||||||
|
Spread,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with variables like CS, OD, AR, HP, and global SV. </summary>
|
||||||
|
Settings,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with hitobject feedback. </summary>
|
||||||
|
Hitsounds,
|
||||||
|
|
||||||
|
/// <summary> Anything to do with storyboarding, breaks, video offset, etc. </summary>
|
||||||
|
Events
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The category this check belongs to. E.g. <see cref="CheckCategory.Metadata"/>,
|
||||||
|
/// <see cref="CheckCategory.Timing"/>, or <see cref="CheckCategory.Compose"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly CheckCategory Category;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describes the issue(s) that this check looks for. Keep this brief, such that
|
||||||
|
/// it fits into "No {description}". E.g. "Offscreen objects" / "Too short sliders".
|
||||||
|
/// </summary>
|
||||||
|
public readonly string Description;
|
||||||
|
|
||||||
|
public CheckMetadata(CheckCategory category, string description)
|
||||||
|
{
|
||||||
|
Category = category;
|
||||||
|
Description = description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
83
osu.Game/Screens/Edit/Verify/Components/Issue.cs
Normal file
83
osu.Game/Screens/Edit/Verify/Components/Issue.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.Extensions;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Verify.Components
|
||||||
|
{
|
||||||
|
public class Issue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The time which this issue is associated with, if any, otherwise null.
|
||||||
|
/// </summary>
|
||||||
|
public double? Time;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hitobjects which this issue is associated with. Empty by default.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<HitObject> HitObjects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The template which this issue is using. This provides properties
|
||||||
|
/// such as the <see cref="IssueTemplate.IssueType"/>, and the
|
||||||
|
/// <see cref="IssueTemplate.UnformattedMessage"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IssueTemplate Template;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The arguments that give this issue its context, based on the
|
||||||
|
/// <see cref="IssueTemplate"/>. These are then substituted into the
|
||||||
|
/// <see cref="IssueTemplate.UnformattedMessage"/>.
|
||||||
|
/// E.g. timestamps, which diff is being compared to, what some volume is, etc.
|
||||||
|
/// </summary>
|
||||||
|
public object[] Arguments;
|
||||||
|
|
||||||
|
public Issue(IssueTemplate template, params object[] args)
|
||||||
|
{
|
||||||
|
Time = null;
|
||||||
|
HitObjects = System.Array.Empty<HitObject>();
|
||||||
|
Template = template;
|
||||||
|
Arguments = args;
|
||||||
|
|
||||||
|
if (template.Origin == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
"A template had no origin. Make sure the `Templates()` method contains all templates used."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue(double? time, IssueTemplate template, params object[] args)
|
||||||
|
: this(template, args)
|
||||||
|
{
|
||||||
|
Time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue(IEnumerable<HitObject> hitObjects, IssueTemplate template, params object[] args)
|
||||||
|
: this(template, args)
|
||||||
|
{
|
||||||
|
Time = hitObjects.FirstOrDefault()?.StartTime;
|
||||||
|
HitObjects = hitObjects.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Template.Message(Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetEditorTimestamp()
|
||||||
|
{
|
||||||
|
// TODO: Editor timestamp formatting is handled in https://github.com/ppy/osu/pull/12030
|
||||||
|
// We may be able to use that here too (if we decouple it from the HitObjectComposer class).
|
||||||
|
|
||||||
|
if (Time == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return Time.Value.ToEditorFormattedString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
osu.Game/Screens/Edit/Verify/Components/IssueTemplate.cs
Normal file
84
osu.Game/Screens/Edit/Verify/Components/IssueTemplate.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// 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 Humanizer;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Verify.Components
|
||||||
|
{
|
||||||
|
public class IssueTemplate
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type, or severity, of an issue. This decides its priority.
|
||||||
|
/// </summary>
|
||||||
|
public enum IssueType
|
||||||
|
{
|
||||||
|
/// <summary> A must-fix in the vast majority of cases. </summary>
|
||||||
|
Problem = 3,
|
||||||
|
|
||||||
|
/// <summary> A possible mistake. Often requires critical thinking. </summary>
|
||||||
|
Warning = 2,
|
||||||
|
|
||||||
|
// TODO: Try/catch all checks run and return error templates if exceptions occur.
|
||||||
|
/// <summary> An error occurred and a complete check could not be made. </summary>
|
||||||
|
Error = 1,
|
||||||
|
|
||||||
|
// TODO: Negligible issues should be hidden by default.
|
||||||
|
/// <summary> A possible mistake so minor/unlikely that it can often be safely ignored. </summary>
|
||||||
|
Negligible = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The check that this template originates from.
|
||||||
|
/// </summary>
|
||||||
|
public Check Origin;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of the issue. E.g. <see cref="IssueType.Problem"/>,
|
||||||
|
/// <see cref="IssueType.Warning"/>, or <see cref="IssueType.Negligible"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly IssueType Type;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The unformatted message given when this issue is detected.
|
||||||
|
/// This gets populated later when an issue is constructed with this template.
|
||||||
|
/// E.g. "Inconsistent snapping (1/{0}) with [{1}] (1/{2})."
|
||||||
|
/// </summary>
|
||||||
|
public readonly string UnformattedMessage;
|
||||||
|
|
||||||
|
public IssueTemplate(IssueType type, string unformattedMessage)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
UnformattedMessage = unformattedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the formatted message given the arguments used to format it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The arguments used to format the message.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string Message(params object[] args) => UnformattedMessage.FormatWith(args);
|
||||||
|
|
||||||
|
public static readonly Color4 PROBLEM_RED = new Colour4(1.0f, 0.4f, 0.4f, 1.0f);
|
||||||
|
public static readonly Color4 WARNING_YELLOW = new Colour4(1.0f, 0.8f, 0.2f, 1.0f);
|
||||||
|
public static readonly Color4 NEGLIGIBLE_GREEN = new Colour4(0.33f, 0.8f, 0.5f, 1.0f);
|
||||||
|
public static readonly Color4 ERROR_GRAY = new Colour4(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the colour corresponding to the type of this issue.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Colour4 TypeColour()
|
||||||
|
{
|
||||||
|
return Type switch
|
||||||
|
{
|
||||||
|
IssueType.Problem => PROBLEM_RED,
|
||||||
|
IssueType.Warning => WARNING_YELLOW,
|
||||||
|
IssueType.Negligible => NEGLIGIBLE_GREEN,
|
||||||
|
IssueType.Error => ERROR_GRAY,
|
||||||
|
_ => Color4.White
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Verify
|
|
||||||
{
|
|
||||||
public class Issue
|
|
||||||
{
|
|
||||||
public readonly double Time;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user