mirror of
https://github.com/ppy/osu.git
synced 2025-03-05 16:02:56 +08:00
Merge pull request #12492 from Naxesss/bg-audio-quality-checks
Add background and audio checks
This commit is contained in:
commit
26430e3cb5
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using osu.Game.Rulesets.Osu.Edit.Checks;
|
using osu.Game.Rulesets.Osu.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
||||||
@ -30,25 +31,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCircleInCenter()
|
public void TestCircleInCenter()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOk(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
new HitCircle
|
new HitCircle
|
||||||
{
|
{
|
||||||
StartTime = 3000,
|
StartTime = 3000,
|
||||||
Position = playfield_centre // Playfield is 640 x 480.
|
Position = playfield_centre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap), Is.Empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCircleNearEdge()
|
public void TestCircleNearEdge()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOk(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -58,15 +57,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
Position = new Vector2(5, 5)
|
Position = new Vector2(5, 5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap), Is.Empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCircleNearEdgeStackedOffscreen()
|
public void TestCircleNearEdgeStackedOffscreen()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOffscreenCircle(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -77,15 +74,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
StackHeight = 5
|
StackHeight = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
assertOffscreenCircle(beatmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCircleOffscreen()
|
public void TestCircleOffscreen()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOffscreenCircle(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -95,15 +90,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
Position = new Vector2(0, 0)
|
Position = new Vector2(0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
assertOffscreenCircle(beatmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSliderInCenter()
|
public void TestSliderInCenter()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOk(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -118,15 +111,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap), Is.Empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSliderNearEdge()
|
public void TestSliderNearEdge()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOk(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -141,15 +132,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
Assert.That(check.Run(beatmap), Is.Empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSliderNearEdgeStackedOffscreen()
|
public void TestSliderNearEdgeStackedOffscreen()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOffscreenSlider(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -165,15 +154,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
StackHeight = 5
|
StackHeight = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
assertOffscreenSlider(beatmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSliderOffscreenStart()
|
public void TestSliderOffscreenStart()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOffscreenSlider(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -188,15 +175,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
assertOffscreenSlider(beatmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSliderOffscreenEnd()
|
public void TestSliderOffscreenEnd()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOffscreenSlider(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -211,15 +196,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
assertOffscreenSlider(beatmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSliderOffscreenPath()
|
public void TestSliderOffscreenPath()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<HitObject>
|
assertOffscreenSlider(new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
HitObjects = new List<HitObject>
|
HitObjects = new List<HitObject>
|
||||||
{
|
{
|
||||||
@ -236,14 +219,17 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
|
||||||
assertOffscreenSlider(beatmap);
|
private void assertOk(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
Assert.That(check.Run(beatmap, new TestWorkingBeatmap(beatmap)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertOffscreenCircle(IBeatmap beatmap)
|
private void assertOffscreenCircle(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var issues = check.Run(beatmap).ToList();
|
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenCircle);
|
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenCircle);
|
||||||
@ -251,7 +237,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks
|
|||||||
|
|
||||||
private void assertOffscreenSlider(IBeatmap beatmap)
|
private void assertOffscreenSlider(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
var issues = check.Run(beatmap).ToList();
|
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenSlider);
|
Assert.That(issues.Single().Template is CheckOffscreenObjects.IssueTemplateOffscreenSlider);
|
||||||
|
@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Checks
|
|||||||
new IssueTemplateOffscreenSlider(this)
|
new IssueTemplateOffscreenSlider(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap beatmap)
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
||||||
{
|
{
|
||||||
foreach (var hitobject in beatmap.HitObjects)
|
foreach (var hitobject in playableBeatmap.HitObjects)
|
||||||
{
|
{
|
||||||
switch (hitobject)
|
switch (hitobject)
|
||||||
{
|
{
|
||||||
|
@ -17,6 +17,9 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
new CheckOffscreenObjects()
|
new CheckOffscreenObjects()
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap beatmap) => checks.SelectMany(check => check.Run(beatmap));
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, WorkingBeatmap workingBeatmap)
|
||||||
|
{
|
||||||
|
return checks.SelectMany(check => check.Run(playableBeatmap, workingBeatmap));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
protected override Texture GetBackground() => throw new NotImplementedException();
|
protected override Texture GetBackground() => throw new NotImplementedException();
|
||||||
|
|
||||||
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override Stream GetStream(string storagePath) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs
Normal file
114
osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CheckAudioQualityTest
|
||||||
|
{
|
||||||
|
private CheckAudioQuality check;
|
||||||
|
private IBeatmap beatmap;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
check = new CheckAudioQuality();
|
||||||
|
beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
{
|
||||||
|
Metadata = new BeatmapMetadata { AudioFile = "abc123.jpg" }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMissing()
|
||||||
|
{
|
||||||
|
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||||
|
beatmap.Metadata.AudioFile = null;
|
||||||
|
|
||||||
|
var mock = new Mock<IWorkingBeatmap>();
|
||||||
|
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||||
|
mock.SetupGet(w => w.Track).Returns((Track)null);
|
||||||
|
|
||||||
|
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAcceptable()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(192);
|
||||||
|
|
||||||
|
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNullBitrate()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(null);
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestZeroBitrate()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(0);
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateNoBitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTooHighBitrate()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(320);
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooHighBitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTooLowBitrate()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(64);
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckAudioQuality.IssueTemplateTooLowBitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the mock of the working beatmap with the given audio properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="audioBitrate">The bitrate of the audio file the beatmap uses.</param>
|
||||||
|
private Mock<IWorkingBeatmap> getMockWorkingBeatmap(int? audioBitrate)
|
||||||
|
{
|
||||||
|
var mockTrack = new Mock<Track>();
|
||||||
|
mockTrack.SetupGet(t => t.Bitrate).Returns(audioBitrate);
|
||||||
|
|
||||||
|
var mockWorkingBeatmap = new Mock<IWorkingBeatmap>();
|
||||||
|
mockWorkingBeatmap.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||||
|
mockWorkingBeatmap.SetupGet(w => w.Track).Returns(mockTrack.Object);
|
||||||
|
|
||||||
|
return mockWorkingBeatmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
Normal file
130
osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// 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.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using FileInfo = osu.Game.IO.FileInfo;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class CheckBackgroundQualityTest
|
||||||
|
{
|
||||||
|
private CheckBackgroundQuality check;
|
||||||
|
private IBeatmap beatmap;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
check = new CheckBackgroundQuality();
|
||||||
|
beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
{
|
||||||
|
Metadata = new BeatmapMetadata { BackgroundFile = "abc123.jpg" },
|
||||||
|
BeatmapSet = new BeatmapSetInfo
|
||||||
|
{
|
||||||
|
Files = new List<BeatmapSetFileInfo>(new[]
|
||||||
|
{
|
||||||
|
new BeatmapSetFileInfo
|
||||||
|
{
|
||||||
|
Filename = "abc123.jpg",
|
||||||
|
FileInfo = new FileInfo
|
||||||
|
{
|
||||||
|
Hash = "abcdef"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMissing()
|
||||||
|
{
|
||||||
|
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||||
|
beatmap.Metadata.BackgroundFile = null;
|
||||||
|
var mock = getMockWorkingBeatmap(null, System.Array.Empty<byte>());
|
||||||
|
|
||||||
|
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAcceptable()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(new Texture(1920, 1080));
|
||||||
|
|
||||||
|
Assert.That(check.Run(beatmap, mock.Object), Is.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTooHighResolution()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(new Texture(3840, 2160));
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooHighResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLowResolution()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(new Texture(640, 480));
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateLowResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTooLowResolution()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(new Texture(100, 100));
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooLowResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTooUncompressed()
|
||||||
|
{
|
||||||
|
var mock = getMockWorkingBeatmap(new Texture(1920, 1080), new byte[1024 * 1024 * 3]);
|
||||||
|
|
||||||
|
var issues = check.Run(beatmap, mock.Object).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBackgroundQuality.IssueTemplateTooUncompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the mock of the working beatmap with the given background and filesize.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="background">The texture of the background.</param>
|
||||||
|
/// <param name="fileBytes">The bytes that represent the background file.</param>
|
||||||
|
private Mock<IWorkingBeatmap> getMockWorkingBeatmap(Texture background, [CanBeNull] byte[] fileBytes = null)
|
||||||
|
{
|
||||||
|
var stream = new MemoryStream(fileBytes ?? new byte[1024 * 1024]);
|
||||||
|
|
||||||
|
var mock = new Mock<IWorkingBeatmap>();
|
||||||
|
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||||
|
mock.SetupGet(w => w.Background).Returns(background);
|
||||||
|
mock.Setup(w => w.GetStream(It.IsAny<string>())).Returns(stream);
|
||||||
|
|
||||||
|
return mock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,21 +5,23 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.IO;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Editing.Checks
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class CheckBackgroundTest
|
public class CheckFilePresenceTest
|
||||||
{
|
{
|
||||||
private CheckBackground check;
|
private CheckBackgroundPresence check;
|
||||||
private IBeatmap beatmap;
|
private IBeatmap beatmap;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
check = new CheckBackground();
|
check = new CheckBackgroundPresence();
|
||||||
beatmap = new Beatmap<HitObject>
|
beatmap = new Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
BeatmapInfo = new BeatmapInfo
|
BeatmapInfo = new BeatmapInfo
|
||||||
@ -29,7 +31,11 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
Files = new List<BeatmapSetFileInfo>(new[]
|
Files = new List<BeatmapSetFileInfo>(new[]
|
||||||
{
|
{
|
||||||
new BeatmapSetFileInfo { Filename = "abc123.jpg" }
|
new BeatmapSetFileInfo
|
||||||
|
{
|
||||||
|
Filename = "abc123.jpg",
|
||||||
|
FileInfo = new FileInfo { Hash = "abcdef" }
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +45,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestBackgroundSetAndInFiles()
|
public void TestBackgroundSetAndInFiles()
|
||||||
{
|
{
|
||||||
Assert.That(check.Run(beatmap), Is.Empty);
|
Assert.That(check.Run(beatmap, new TestWorkingBeatmap(beatmap)), Is.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -47,10 +53,10 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
|
beatmap.BeatmapInfo.BeatmapSet.Files.Clear();
|
||||||
|
|
||||||
var issues = check.Run(beatmap).ToList();
|
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackground.IssueTemplateDoesNotExist);
|
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateDoesNotExist);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -58,10 +64,10 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
beatmap.Metadata.BackgroundFile = null;
|
beatmap.Metadata.BackgroundFile = null;
|
||||||
|
|
||||||
var issues = check.Run(beatmap).ToList();
|
var issues = check.Run(beatmap, new TestWorkingBeatmap(beatmap)).ToList();
|
||||||
|
|
||||||
Assert.That(issues, Has.Count.EqualTo(1));
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
Assert.That(issues.Single().Template is CheckBackground.IssueTemplateNoneSet);
|
Assert.That(issues.Single().Template is CheckFilePresence.IssueTemplateNoneSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -52,6 +52,8 @@ namespace osu.Game.Tests
|
|||||||
|
|
||||||
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
|
protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile));
|
||||||
|
|
||||||
|
public override Stream GetStream(string storagePath) => null;
|
||||||
|
|
||||||
protected override Track GetBeatmapTrack() => trackStore.Get(firstAudioFile);
|
protected override Track GetBeatmapTrack() => trackStore.Get(firstAudioFile);
|
||||||
|
|
||||||
private string firstAudioFile
|
private string firstAudioFile
|
||||||
|
@ -526,6 +526,7 @@ namespace osu.Game.Beatmaps
|
|||||||
protected override IBeatmap GetBeatmap() => beatmap;
|
protected override IBeatmap GetBeatmap() => beatmap;
|
||||||
protected override Texture GetBackground() => null;
|
protected override Texture GetBackground() => null;
|
||||||
protected override Track GetBeatmapTrack() => null;
|
protected override Track GetBeatmapTrack() => null;
|
||||||
|
public override Stream GetStream(string storagePath) => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.IO;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
@ -36,7 +36,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var stream = new LineBufferedReader(resources.Files.GetStream(getPathForFile(BeatmapInfo.Path))))
|
using (var stream = new LineBufferedReader(GetStream(BeatmapSetInfo.GetPathForFile(BeatmapInfo.Path))))
|
||||||
return Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
|
return Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -46,8 +46,6 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getPathForFile(string filename) => BeatmapSetInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
|
|
||||||
|
|
||||||
protected override bool BackgroundStillValid(Texture b) => false; // bypass lazy logic. we want to return a new background each time for refcounting purposes.
|
protected override bool BackgroundStillValid(Texture b) => false; // bypass lazy logic. we want to return a new background each time for refcounting purposes.
|
||||||
|
|
||||||
protected override Texture GetBackground()
|
protected override Texture GetBackground()
|
||||||
@ -57,7 +55,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return resources.LargeTextureStore.Get(getPathForFile(Metadata.BackgroundFile));
|
return resources.LargeTextureStore.Get(BeatmapSetInfo.GetPathForFile(Metadata.BackgroundFile));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -73,7 +71,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return resources.Tracks.Get(getPathForFile(Metadata.AudioFile));
|
return resources.Tracks.Get(BeatmapSetInfo.GetPathForFile(Metadata.AudioFile));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -89,7 +87,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var trackData = resources.Files.GetStream(getPathForFile(Metadata.AudioFile));
|
var trackData = GetStream(BeatmapSetInfo.GetPathForFile(Metadata.AudioFile));
|
||||||
return trackData == null ? null : new Waveform(trackData);
|
return trackData == null ? null : new Waveform(trackData);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -105,7 +103,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var stream = new LineBufferedReader(resources.Files.GetStream(getPathForFile(BeatmapInfo.Path))))
|
using (var stream = new LineBufferedReader(GetStream(BeatmapSetInfo.GetPathForFile(BeatmapInfo.Path))))
|
||||||
{
|
{
|
||||||
var decoder = Decoder.GetDecoder<Storyboard>(stream);
|
var decoder = Decoder.GetDecoder<Storyboard>(stream);
|
||||||
|
|
||||||
@ -114,7 +112,7 @@ namespace osu.Game.Beatmaps
|
|||||||
storyboard = decoder.Decode(stream);
|
storyboard = decoder.Decode(stream);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (var secondaryStream = new LineBufferedReader(resources.Files.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile))))
|
using (var secondaryStream = new LineBufferedReader(GetStream(BeatmapSetInfo.GetPathForFile(BeatmapSetInfo.StoryboardFile))))
|
||||||
storyboard = decoder.Decode(stream, secondaryStream);
|
storyboard = decoder.Decode(stream, secondaryStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,6 +140,8 @@ namespace osu.Game.Beatmaps
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Stream GetStream(string storagePath) => resources.Files.GetStream(storagePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,13 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename;
|
public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb", StringComparison.OrdinalIgnoreCase))?.Filename;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null.
|
||||||
|
/// The path returned is relative to the user file storage.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The name of the file to get the storage path of.</param>
|
||||||
|
public string GetPathForFile(string filename) => Files?.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
|
||||||
|
|
||||||
public List<BeatmapSetFileInfo> Files { get; set; }
|
public List<BeatmapSetFileInfo> Files { get; set; }
|
||||||
|
|
||||||
public override string ToString() => Metadata?.ToString() ?? base.ToString();
|
public override string ToString() => Metadata?.ToString() ?? base.ToString();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
@ -48,6 +49,8 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
protected override Track GetBeatmapTrack() => GetVirtualTrack();
|
protected override Track GetBeatmapTrack() => GetVirtualTrack();
|
||||||
|
|
||||||
|
public override Stream GetStream(string storagePath) => null;
|
||||||
|
|
||||||
private class DummyRulesetInfo : RulesetInfo
|
private class DummyRulesetInfo : RulesetInfo
|
||||||
{
|
{
|
||||||
public override Ruleset CreateInstance() => new DummyRuleset();
|
public override Ruleset CreateInstance() => new DummyRuleset();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -41,6 +42,11 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
ISkin Skin { get; }
|
ISkin Skin { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the <see cref="Track"/> which this <see cref="WorkingBeatmap"/> has loaded.
|
||||||
|
/// </summary>
|
||||||
|
Track Track { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a playable <see cref="IBeatmap"/> from <see cref="Beatmap"/> using the applicable converters for a specific <see cref="RulesetInfo"/>.
|
/// Constructs a playable <see cref="IBeatmap"/> from <see cref="Beatmap"/> using the applicable converters for a specific <see cref="RulesetInfo"/>.
|
||||||
/// <para>
|
/// <para>
|
||||||
@ -67,5 +73,11 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>A fresh track instance, which will also be available via <see cref="Track"/>.</returns>
|
/// <returns>A fresh track instance, which will also be available via <see cref="Track"/>.</returns>
|
||||||
Track LoadTrack();
|
Track LoadTrack();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the stream of the file from the given storage path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="storagePath">The storage path to the file.</param>
|
||||||
|
Stream GetStream(string storagePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -326,6 +327,8 @@ namespace osu.Game.Beatmaps
|
|||||||
protected virtual ISkin GetSkin() => new DefaultSkin();
|
protected virtual ISkin GetSkin() => new DefaultSkin();
|
||||||
private readonly RecyclableLazy<ISkin> skin;
|
private readonly RecyclableLazy<ISkin> skin;
|
||||||
|
|
||||||
|
public abstract Stream GetStream(string storagePath);
|
||||||
|
|
||||||
public class RecyclableLazy<T>
|
public class RecyclableLazy<T>
|
||||||
{
|
{
|
||||||
private Lazy<T> lazy;
|
private Lazy<T> lazy;
|
||||||
|
@ -16,9 +16,18 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
private readonly List<ICheck> checks = new List<ICheck>
|
private readonly List<ICheck> checks = new List<ICheck>
|
||||||
{
|
{
|
||||||
new CheckBackground(),
|
// Resources
|
||||||
|
new CheckBackgroundPresence(),
|
||||||
|
new CheckBackgroundQuality(),
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
new CheckAudioPresence(),
|
||||||
|
new CheckAudioQuality()
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap beatmap) => checks.SelectMany(check => check.Run(beatmap));
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, WorkingBeatmap workingBeatmap)
|
||||||
|
{
|
||||||
|
return checks.SelectMany(check => check.Run(playableBeatmap, workingBeatmap));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs
Normal file
15
osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// 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 osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
|
{
|
||||||
|
public class CheckAudioPresence : CheckFilePresence
|
||||||
|
{
|
||||||
|
protected override CheckCategory Category => CheckCategory.Audio;
|
||||||
|
protected override string TypeOfFile => "audio";
|
||||||
|
protected override string GetFilename(IBeatmap playableBeatmap) => playableBeatmap.Metadata?.AudioFile;
|
||||||
|
}
|
||||||
|
}
|
75
osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs
Normal file
75
osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
|
{
|
||||||
|
public class CheckAudioQuality : ICheck
|
||||||
|
{
|
||||||
|
// This is a requirement as stated in the Ranking Criteria.
|
||||||
|
// See https://osu.ppy.sh/wiki/en/Ranking_Criteria#rules.4
|
||||||
|
private const int max_bitrate = 192;
|
||||||
|
|
||||||
|
// "A song's audio file /.../ must be of reasonable quality. Try to find the highest quality source file available"
|
||||||
|
// There not existing a version with a bitrate of 128 kbps or higher is extremely rare.
|
||||||
|
private const int min_bitrate = 128;
|
||||||
|
|
||||||
|
public CheckMetadata Metadata { get; } = new CheckMetadata(CheckCategory.Audio, "Too high or low audio bitrate");
|
||||||
|
|
||||||
|
public IEnumerable<IssueTemplate> PossibleTemplates => new IssueTemplate[]
|
||||||
|
{
|
||||||
|
new IssueTemplateTooHighBitrate(this),
|
||||||
|
new IssueTemplateTooLowBitrate(this),
|
||||||
|
new IssueTemplateNoBitrate(this)
|
||||||
|
};
|
||||||
|
|
||||||
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
||||||
|
{
|
||||||
|
var audioFile = playableBeatmap.Metadata?.AudioFile;
|
||||||
|
if (audioFile == null)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
var track = workingBeatmap.Track;
|
||||||
|
|
||||||
|
if (track?.Bitrate == null || track.Bitrate.Value == 0)
|
||||||
|
yield return new IssueTemplateNoBitrate(this).Create();
|
||||||
|
else if (track.Bitrate.Value > max_bitrate)
|
||||||
|
yield return new IssueTemplateTooHighBitrate(this).Create(track.Bitrate.Value);
|
||||||
|
else if (track.Bitrate.Value < min_bitrate)
|
||||||
|
yield return new IssueTemplateTooLowBitrate(this).Create(track.Bitrate.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateTooHighBitrate : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateTooHighBitrate(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "The audio bitrate ({0} kbps) exceeds {1} kbps.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(int bitrate) => new Issue(this, bitrate, max_bitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateTooLowBitrate : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateTooLowBitrate(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "The audio bitrate ({0} kbps) is lower than {1} kbps.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(int bitrate) => new Issue(this, bitrate, min_bitrate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateNoBitrate : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateNoBitrate(ICheck check)
|
||||||
|
: base(check, IssueType.Error, "The audio bitrate could not be retrieved.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create() => new Issue(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,61 +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.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Edit.Checks
|
|
||||||
{
|
|
||||||
public class CheckBackground : ICheck
|
|
||||||
{
|
|
||||||
public CheckMetadata Metadata { get; } = new CheckMetadata(CheckCategory.Resources, "Missing background");
|
|
||||||
|
|
||||||
public IEnumerable<IssueTemplate> PossibleTemplates => new IssueTemplate[]
|
|
||||||
{
|
|
||||||
new IssueTemplateNoneSet(this),
|
|
||||||
new IssueTemplateDoesNotExist(this)
|
|
||||||
};
|
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
if (beatmap.Metadata.BackgroundFile == null)
|
|
||||||
{
|
|
||||||
yield return new IssueTemplateNoneSet(this).Create();
|
|
||||||
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the background is set, also make sure it still exists.
|
|
||||||
|
|
||||||
var set = beatmap.BeatmapInfo.BeatmapSet;
|
|
||||||
var file = set.Files.FirstOrDefault(f => f.Filename == beatmap.Metadata.BackgroundFile);
|
|
||||||
|
|
||||||
if (file != null)
|
|
||||||
yield break;
|
|
||||||
|
|
||||||
yield return new IssueTemplateDoesNotExist(this).Create(beatmap.Metadata.BackgroundFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IssueTemplateNoneSet : IssueTemplate
|
|
||||||
{
|
|
||||||
public IssueTemplateNoneSet(ICheck check)
|
|
||||||
: base(check, IssueType.Problem, "No background has been set.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Issue Create() => new Issue(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IssueTemplateDoesNotExist : IssueTemplate
|
|
||||||
{
|
|
||||||
public IssueTemplateDoesNotExist(ICheck check)
|
|
||||||
: base(check, IssueType.Problem, "The background file \"{0}\" does not exist.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Issue Create(string filename) => new Issue(this, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
15
osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs
Normal file
15
osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// 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 osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
|
{
|
||||||
|
public class CheckBackgroundPresence : CheckFilePresence
|
||||||
|
{
|
||||||
|
protected override CheckCategory Category => CheckCategory.Resources;
|
||||||
|
protected override string TypeOfFile => "background";
|
||||||
|
protected override string GetFilename(IBeatmap playableBeatmap) => playableBeatmap.Metadata?.BackgroundFile;
|
||||||
|
}
|
||||||
|
}
|
98
osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs
Normal file
98
osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
|
{
|
||||||
|
public class CheckBackgroundQuality : ICheck
|
||||||
|
{
|
||||||
|
// These are the requirements as stated in the Ranking Criteria.
|
||||||
|
// See https://osu.ppy.sh/wiki/en/Ranking_Criteria#rules.5
|
||||||
|
private const int min_width = 160;
|
||||||
|
private const int max_width = 2560;
|
||||||
|
private const int min_height = 120;
|
||||||
|
private const int max_height = 1440;
|
||||||
|
private const double max_filesize_mb = 2.5d;
|
||||||
|
|
||||||
|
// It's usually possible to find a higher resolution of the same image if lower than these.
|
||||||
|
private const int low_width = 960;
|
||||||
|
private const int low_height = 540;
|
||||||
|
|
||||||
|
public CheckMetadata Metadata { get; } = new CheckMetadata(CheckCategory.Resources, "Too high or low background resolution");
|
||||||
|
|
||||||
|
public IEnumerable<IssueTemplate> PossibleTemplates => new IssueTemplate[]
|
||||||
|
{
|
||||||
|
new IssueTemplateTooHighResolution(this),
|
||||||
|
new IssueTemplateTooLowResolution(this),
|
||||||
|
new IssueTemplateTooUncompressed(this)
|
||||||
|
};
|
||||||
|
|
||||||
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
||||||
|
{
|
||||||
|
var backgroundFile = playableBeatmap.Metadata?.BackgroundFile;
|
||||||
|
if (backgroundFile == null)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
var texture = workingBeatmap.Background;
|
||||||
|
if (texture == null)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
if (texture.Width > max_width || texture.Height > max_height)
|
||||||
|
yield return new IssueTemplateTooHighResolution(this).Create(texture.Width, texture.Height);
|
||||||
|
|
||||||
|
if (texture.Width < min_width || texture.Height < min_height)
|
||||||
|
yield return new IssueTemplateTooLowResolution(this).Create(texture.Width, texture.Height);
|
||||||
|
else if (texture.Width < low_width || texture.Height < low_height)
|
||||||
|
yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.Height);
|
||||||
|
|
||||||
|
string storagePath = playableBeatmap.BeatmapInfo.BeatmapSet.GetPathForFile(backgroundFile);
|
||||||
|
double filesizeMb = workingBeatmap.GetStream(storagePath).Length / (1024d * 1024d);
|
||||||
|
|
||||||
|
if (filesizeMb > max_filesize_mb)
|
||||||
|
yield return new IssueTemplateTooUncompressed(this).Create(filesizeMb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateTooHighResolution : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateTooHighResolution(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "The background resolution ({0} x {1}) exceeds {2} x {3}.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(double width, double height) => new Issue(this, width, height, max_width, max_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateTooLowResolution : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateTooLowResolution(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "The background resolution ({0} x {1}) is lower than {2} x {3}.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(double width, double height) => new Issue(this, width, height, min_width, min_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateLowResolution : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateLowResolution(ICheck check)
|
||||||
|
: base(check, IssueType.Warning, "The background resolution ({0} x {1}) is lower than {2} x {3}.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(double width, double height) => new Issue(this, width, height, low_width, low_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateTooUncompressed : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateTooUncompressed(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "The background filesize ({0:0.##} MB) exceeds {1} MB.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(double actualMb) => new Issue(this, actualMb, max_filesize_mb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs
Normal file
63
osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
|
{
|
||||||
|
public abstract class CheckFilePresence : ICheck
|
||||||
|
{
|
||||||
|
protected abstract CheckCategory Category { get; }
|
||||||
|
protected abstract string TypeOfFile { get; }
|
||||||
|
protected abstract string GetFilename(IBeatmap playableBeatmap);
|
||||||
|
|
||||||
|
public CheckMetadata Metadata => new CheckMetadata(Category, $"Missing {TypeOfFile}");
|
||||||
|
|
||||||
|
public IEnumerable<IssueTemplate> PossibleTemplates => new IssueTemplate[]
|
||||||
|
{
|
||||||
|
new IssueTemplateNoneSet(this),
|
||||||
|
new IssueTemplateDoesNotExist(this)
|
||||||
|
};
|
||||||
|
|
||||||
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
|
||||||
|
{
|
||||||
|
var filename = GetFilename(playableBeatmap);
|
||||||
|
|
||||||
|
if (filename == null)
|
||||||
|
{
|
||||||
|
yield return new IssueTemplateNoneSet(this).Create(TypeOfFile);
|
||||||
|
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the file is set, also make sure it still exists.
|
||||||
|
var storagePath = playableBeatmap.BeatmapInfo.BeatmapSet.GetPathForFile(filename);
|
||||||
|
if (storagePath != null)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
yield return new IssueTemplateDoesNotExist(this).Create(TypeOfFile, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateNoneSet : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateNoneSet(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "No {0} has been set.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(string typeOfFile) => new Issue(this, typeOfFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateDoesNotExist : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateDoesNotExist(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "The {0} file \"{1}\" does not exist.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(string typeOfFile, string filename) => new Issue(this, typeOfFile, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,8 @@ namespace osu.Game.Rulesets.Edit.Checks.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs this check and returns any issues detected for the provided beatmap.
|
/// Runs this check and returns any issues detected for the provided beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmap">The beatmap to run the check on.</param>
|
/// <param name="playableBeatmap">The playable beatmap of the beatmap to run the check on.</param>
|
||||||
public IEnumerable<Issue> Run(IBeatmap beatmap);
|
/// <param name="workingBeatmap">The working beatmap of the beatmap to run the check on.</param>
|
||||||
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IBeatmapVerifier
|
public interface IBeatmapVerifier
|
||||||
{
|
{
|
||||||
public IEnumerable<Issue> Run(IBeatmap beatmap);
|
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, WorkingBeatmap workingBeatmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
protected override Texture GetBackground() => throw new NotImplementedException();
|
protected override Texture GetBackground() => throw new NotImplementedException();
|
||||||
|
|
||||||
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override Stream GetStream(string storagePath) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
@ -60,7 +61,10 @@ namespace osu.Game.Screens.Edit.Verify
|
|||||||
private EditorClock clock { get; set; }
|
private EditorClock clock { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected EditorBeatmap Beatmap { get; private set; }
|
private IBindable<WorkingBeatmap> workingBeatmap { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private EditorBeatmap beatmap { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private Bindable<Issue> selectedIssue { get; set; }
|
private Bindable<Issue> selectedIssue { get; set; }
|
||||||
@ -72,7 +76,7 @@ namespace osu.Game.Screens.Edit.Verify
|
|||||||
private void load(OverlayColourProvider colours)
|
private void load(OverlayColourProvider colours)
|
||||||
{
|
{
|
||||||
generalVerifier = new BeatmapVerifier();
|
generalVerifier = new BeatmapVerifier();
|
||||||
rulesetVerifier = Beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateBeatmapVerifier();
|
rulesetVerifier = beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateBeatmapVerifier();
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
@ -118,10 +122,10 @@ namespace osu.Game.Screens.Edit.Verify
|
|||||||
|
|
||||||
private void refresh()
|
private void refresh()
|
||||||
{
|
{
|
||||||
var issues = generalVerifier.Run(Beatmap);
|
var issues = generalVerifier.Run(beatmap, workingBeatmap.Value);
|
||||||
|
|
||||||
if (rulesetVerifier != null)
|
if (rulesetVerifier != null)
|
||||||
issues = issues.Concat(rulesetVerifier.Run(Beatmap));
|
issues = issues.Concat(rulesetVerifier.Run(beatmap, workingBeatmap.Value));
|
||||||
|
|
||||||
table.Issues = issues
|
table.Issues = issues
|
||||||
.OrderBy(issue => issue.Template.Type)
|
.OrderBy(issue => issue.Template.Type)
|
||||||
|
@ -215,6 +215,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public override Stream GetStream(string storagePath) => throw new NotImplementedException();
|
||||||
|
|
||||||
protected override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
|
protected override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
|
||||||
{
|
{
|
||||||
var converter = base.CreateBeatmapConverter(beatmap, ruleset);
|
var converter = base.CreateBeatmapConverter(beatmap, ruleset);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
@ -35,6 +36,8 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard();
|
protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard();
|
||||||
|
|
||||||
|
public override Stream GetStream(string storagePath) => null;
|
||||||
|
|
||||||
protected override Texture GetBackground() => null;
|
protected override Texture GetBackground() => null;
|
||||||
|
|
||||||
protected override Track GetBeatmapTrack() => null;
|
protected override Track GetBeatmapTrack() => null;
|
||||||
|
Loading…
Reference in New Issue
Block a user