diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 468cb7683c..89baaf228d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -863,5 +863,40 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(decoded.Difficulty.OverallDifficulty, Is.EqualTo(1)); } } + + [Test] + public void TestLegacyAdjacentImplicitCatmullSegmentsAreMerged() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + + using (var resStream = TestResources.OpenResource("adjacent-catmull-segments.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + var decoded = decoder.Decode(stream); + var controlPoints = ((IHasPath)decoded.HitObjects[0]).Path.ControlPoints; + + Assert.That(controlPoints.Count, Is.EqualTo(6)); + Assert.That(controlPoints.Single(c => c.Type != null).Type, Is.EqualTo(PathType.Catmull)); + } + } + + [Test] + public void TestNonLegacyAdjacentImplicitCatmullSegmentsAreNotMerged() + { + var decoder = new LegacyBeatmapDecoder(LegacyBeatmapEncoder.FIRST_LAZER_VERSION) { ApplyOffsets = false }; + + using (var resStream = TestResources.OpenResource("adjacent-catmull-segments.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + var decoded = decoder.Decode(stream); + var controlPoints = ((IHasPath)decoded.HitObjects[0]).Path.ControlPoints; + + Assert.That(controlPoints.Count, Is.EqualTo(4)); + Assert.That(controlPoints[0].Type, Is.EqualTo(PathType.Catmull)); + Assert.That(controlPoints[1].Type, Is.EqualTo(PathType.Catmull)); + Assert.That(controlPoints[2].Type, Is.EqualTo(PathType.Catmull)); + Assert.That(controlPoints[3].Type, Is.Null); + } + } } } diff --git a/osu.Game.Tests/Resources/adjacent-catmull-segments.osu b/osu.Game.Tests/Resources/adjacent-catmull-segments.osu new file mode 100644 index 0000000000..a436fe5228 --- /dev/null +++ b/osu.Game.Tests/Resources/adjacent-catmull-segments.osu @@ -0,0 +1,2 @@ +[HitObjects] +200,304,23875,6,0,C|288:304|288:304|288:208|288:208|352:208,1,260,8|0 \ No newline at end of file diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index b91a74c4a1..3b4200e7a9 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -22,7 +22,7 @@ namespace osu.Game.Beatmaps.Formats { public class LegacyBeatmapEncoder { - public const int LATEST_VERSION = 128; + public const int FIRST_LAZER_VERSION = 128; /// /// osu! is generally slower than taiko, so a factor is added to increase @@ -55,7 +55,7 @@ namespace osu.Game.Beatmaps.Formats public void Encode(TextWriter writer) { - writer.WriteLine($"osu file format v{LATEST_VERSION}"); + writer.WriteLine($"osu file format v{FIRST_LAZER_VERSION}"); writer.WriteLine(); handleGeneral(writer); diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index 2a7f2b037f..7cf68a2df7 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -336,10 +336,14 @@ namespace osu.Game.Rulesets.Objects.Legacy while (++endIndex < vertices.Length - endPointLength) { - // Keep incrementing while an implicit segment doesn't need to be started + // Keep incrementing while an implicit segment doesn't need to be started. if (vertices[endIndex].Position != vertices[endIndex - 1].Position) continue; + // Adjacent legacy Catmull segments should be treated as a single segment. + if (FormatVersion < LegacyBeatmapEncoder.FIRST_LAZER_VERSION && type == PathType.Catmull) + continue; + // The last control point of each segment is not allowed to start a new implicit segment. if (endIndex == vertices.Length - endPointLength - 1) continue;