From 66ebdbbe4cf0e2aa9614c086ce1efb600dde7035 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 May 2019 18:13:07 +0900 Subject: [PATCH 1/7] Fix control points with same timestamp potentially being parsed incorrectly --- osu.Game/Beatmaps/ControlPoints/ControlPoint.cs | 5 +++++ osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 14 +++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index 825b60ae5f..5e538126b3 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -12,6 +12,11 @@ namespace osu.Game.Beatmaps.ControlPoints /// public double Time; + /// + /// Whether this timing point was generated internally, as opposed to parsed from the underlying beatmap. + /// + internal bool AutoGenerated; + public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time); /// diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index b489b5e6d9..46a6197546 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -374,14 +374,16 @@ namespace osu.Game.Beatmaps.Formats handleDifficultyControlPoint(new DifficultyControlPoint { Time = time, - SpeedMultiplier = speedMultiplier + SpeedMultiplier = speedMultiplier, + AutoGenerated = timingChange }); handleEffectControlPoint(new EffectControlPoint { Time = time, KiaiMode = kiaiMode, - OmitFirstBarLine = omitFirstBarSignature + OmitFirstBarLine = omitFirstBarSignature, + AutoGenerated = timingChange }); handleSampleControlPoint(new LegacySampleControlPoint @@ -389,7 +391,8 @@ namespace osu.Game.Beatmaps.Formats Time = time, SampleBank = stringSampleSet, SampleVolume = sampleVolume, - CustomSampleBank = customSampleBank + CustomSampleBank = customSampleBank, + AutoGenerated = timingChange }); } catch (FormatException) @@ -419,6 +422,11 @@ namespace osu.Game.Beatmaps.Formats if (newPoint.EquivalentTo(existing)) return; + // autogenerated points should not replace non-autogenerated. + // this allows for incorrectly ordered timing points to still be correctly handled. + if (newPoint.AutoGenerated && !existing.AutoGenerated) + return; + if (existing.Time == newPoint.Time) beatmap.ControlPointInfo.DifficultyPoints.Remove(existing); From 92f6f4d21a858ad6319c7849e6cab33d5a5a6282 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 May 2019 19:04:12 +0900 Subject: [PATCH 2/7] Apply same fix to other methods which were missed --- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 46a6197546..a5c3d8a4de 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -410,7 +410,14 @@ namespace osu.Game.Beatmaps.Formats var existing = beatmap.ControlPointInfo.TimingPointAt(newPoint.Time); if (existing.Time == newPoint.Time) + { + // autogenerated points should not replace non-autogenerated. + // this allows for incorrectly ordered timing points to still be correctly handled. + if (newPoint.AutoGenerated && !existing.AutoGenerated) + return; + beatmap.ControlPointInfo.TimingPoints.Remove(existing); + } beatmap.ControlPointInfo.TimingPoints.Add(newPoint); } @@ -422,13 +429,15 @@ namespace osu.Game.Beatmaps.Formats if (newPoint.EquivalentTo(existing)) return; - // autogenerated points should not replace non-autogenerated. - // this allows for incorrectly ordered timing points to still be correctly handled. - if (newPoint.AutoGenerated && !existing.AutoGenerated) - return; - if (existing.Time == newPoint.Time) + { + // autogenerated points should not replace non-autogenerated. + // this allows for incorrectly ordered timing points to still be correctly handled. + if (newPoint.AutoGenerated && !existing.AutoGenerated) + return; + beatmap.ControlPointInfo.DifficultyPoints.Remove(existing); + } beatmap.ControlPointInfo.DifficultyPoints.Add(newPoint); } @@ -441,7 +450,14 @@ namespace osu.Game.Beatmaps.Formats return; if (existing.Time == newPoint.Time) + { + // autogenerated points should not replace non-autogenerated. + // this allows for incorrectly ordered timing points to still be correctly handled. + if (newPoint.AutoGenerated && !existing.AutoGenerated) + return; + beatmap.ControlPointInfo.EffectPoints.Remove(existing); + } beatmap.ControlPointInfo.EffectPoints.Add(newPoint); } @@ -454,7 +470,14 @@ namespace osu.Game.Beatmaps.Formats return; if (existing.Time == newPoint.Time) + { + // autogenerated points should not replace non-autogenerated. + // this allows for incorrectly ordered timing points to still be correctly handled. + if (newPoint.AutoGenerated && !existing.AutoGenerated) + return; + beatmap.ControlPointInfo.SamplePoints.Remove(existing); + } beatmap.ControlPointInfo.SamplePoints.Add(newPoint); } From 7aa10956b582f741f006f4df959041c5b873f93a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 May 2019 09:46:42 +0900 Subject: [PATCH 3/7] Add unit test --- .../Formats/LegacyBeatmapDecoderTest.cs | 28 +++++++++++++++++++ .../Resources/overlapping-control-points.osu | 11 ++++++++ 2 files changed, 39 insertions(+) create mode 100644 osu.Game.Tests/Resources/overlapping-control-points.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 3c1f48b7a4..7e7ddb12d2 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -194,6 +194,34 @@ namespace osu.Game.Tests.Beatmaps.Formats } } + [Test] + public void TestDecodeOverlappingTimingPoints() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + + using (var resStream = TestResources.OpenResource("overlapping-control-points.osu")) + using (var stream = new StreamReader(resStream)) + { + var controlPoints = decoder.Decode(stream).ControlPointInfo; + + Assert.That(controlPoints.DifficultyPoints, Has.Count.EqualTo(2)); + Assert.That(controlPoints.DifficultyPoints[0].SpeedMultiplier, Is.EqualTo(1.5).Within(0.1)); + Assert.That(controlPoints.DifficultyPoints[1].SpeedMultiplier, Is.EqualTo(0.75).Within(0.1)); + + Assert.That(controlPoints.EffectPoints, Has.Count.EqualTo(2)); + Assert.That(controlPoints.EffectPoints[0].KiaiMode, Is.True); + Assert.That(controlPoints.EffectPoints[1].KiaiMode, Is.True); + + Assert.That(controlPoints.SamplePoints, Has.Count.EqualTo(2)); + Assert.That(controlPoints.SamplePoints[0].SampleBank, Is.EqualTo("drum")); + Assert.That(controlPoints.SamplePoints[1].SampleBank, Is.EqualTo("normal")); + + Assert.That(controlPoints.TimingPoints, Has.Count.EqualTo(2)); + Assert.That(controlPoints.TimingPoints[0].BeatLength, Is.EqualTo(500)); + Assert.That(controlPoints.TimingPoints[1].BeatLength, Is.EqualTo(250)); + } + } + [Test] public void TestDecodeBeatmapColours() { diff --git a/osu.Game.Tests/Resources/overlapping-control-points.osu b/osu.Game.Tests/Resources/overlapping-control-points.osu new file mode 100644 index 0000000000..d96db72bd7 --- /dev/null +++ b/osu.Game.Tests/Resources/overlapping-control-points.osu @@ -0,0 +1,11 @@ +osu file format v14 + +[TimingPoints] + +// Timing -> Inherited +0,500,4,2,0,100,1,0 +0,-66.6666666666667,4,3,0,100,0,1 + +// Inherited -> Timing +1000,-133.333333333333,4,1,0,100,0,1 +1000,250,4,2,0,100,1,0 From 19bc6b72cc7ef1a9a059322ae0e76ed19b601705 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 May 2019 10:13:42 +0900 Subject: [PATCH 4/7] More tests to showcase failures --- .../Formats/LegacyBeatmapDecoderTest.cs | 28 +++++++++++-------- .../Resources/overlapping-control-points.osu | 16 ++++++++--- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 7e7ddb12d2..42e421d1ad 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -204,21 +204,25 @@ namespace osu.Game.Tests.Beatmaps.Formats { var controlPoints = decoder.Decode(stream).ControlPointInfo; - Assert.That(controlPoints.DifficultyPoints, Has.Count.EqualTo(2)); - Assert.That(controlPoints.DifficultyPoints[0].SpeedMultiplier, Is.EqualTo(1.5).Within(0.1)); - Assert.That(controlPoints.DifficultyPoints[1].SpeedMultiplier, Is.EqualTo(0.75).Within(0.1)); + Assert.That(controlPoints.DifficultyPointAt(500).SpeedMultiplier, Is.EqualTo(1.5).Within(0.1)); + Assert.That(controlPoints.DifficultyPointAt(1500).SpeedMultiplier, Is.EqualTo(1.5).Within(0.1)); + Assert.That(controlPoints.DifficultyPointAt(2500).SpeedMultiplier, Is.EqualTo(0.75).Within(0.1)); + Assert.That(controlPoints.DifficultyPointAt(3500).SpeedMultiplier, Is.EqualTo(1.5).Within(0.1)); - Assert.That(controlPoints.EffectPoints, Has.Count.EqualTo(2)); - Assert.That(controlPoints.EffectPoints[0].KiaiMode, Is.True); - Assert.That(controlPoints.EffectPoints[1].KiaiMode, Is.True); + Assert.That(controlPoints.EffectPointAt(500).KiaiMode, Is.True); + Assert.That(controlPoints.EffectPointAt(1500).KiaiMode, Is.True); + Assert.That(controlPoints.EffectPointAt(2500).KiaiMode, Is.False); + Assert.That(controlPoints.EffectPointAt(3500).KiaiMode, Is.True); - Assert.That(controlPoints.SamplePoints, Has.Count.EqualTo(2)); - Assert.That(controlPoints.SamplePoints[0].SampleBank, Is.EqualTo("drum")); - Assert.That(controlPoints.SamplePoints[1].SampleBank, Is.EqualTo("normal")); + Assert.That(controlPoints.SamplePointAt(500).SampleBank, Is.EqualTo("drum")); + Assert.That(controlPoints.SamplePointAt(1500).SampleBank, Is.EqualTo("drum")); + Assert.That(controlPoints.SamplePointAt(2500).SampleBank, Is.EqualTo("normal")); + Assert.That(controlPoints.SamplePointAt(3500).SampleBank, Is.EqualTo("drum")); - Assert.That(controlPoints.TimingPoints, Has.Count.EqualTo(2)); - Assert.That(controlPoints.TimingPoints[0].BeatLength, Is.EqualTo(500)); - Assert.That(controlPoints.TimingPoints[1].BeatLength, Is.EqualTo(250)); + Assert.That(controlPoints.TimingPointAt(500).BeatLength, Is.EqualTo(500)); + Assert.That(controlPoints.TimingPointAt(1500).BeatLength, Is.EqualTo(500)); + Assert.That(controlPoints.TimingPointAt(2500).BeatLength, Is.EqualTo(250)); + Assert.That(controlPoints.TimingPointAt(3500).BeatLength, Is.EqualTo(500)); } } diff --git a/osu.Game.Tests/Resources/overlapping-control-points.osu b/osu.Game.Tests/Resources/overlapping-control-points.osu index d96db72bd7..31d38a3d01 100644 --- a/osu.Game.Tests/Resources/overlapping-control-points.osu +++ b/osu.Game.Tests/Resources/overlapping-control-points.osu @@ -2,10 +2,18 @@ osu file format v14 [TimingPoints] -// Timing -> Inherited +// Timing then inherited 0,500,4,2,0,100,1,0 0,-66.6666666666667,4,3,0,100,0,1 -// Inherited -> Timing -1000,-133.333333333333,4,1,0,100,0,1 -1000,250,4,2,0,100,1,0 +// Inherited then timing (equivalent to previous) +1000,-66.6666666666667,4,3,0,100,0,1 +1000,500,4,2,0,100,1,0 + +// Inherited then timing (different to previous) +2000,-133.333333333333,4,1,0,100,0,0 +2000,250,4,2,0,100,1,0 + +// Timing then inherited (different to previous) +3000,500,4,2,0,100,1,0 +3000,-66.6666666666667,4,3,0,100,0,1 From e3ae858c876cc5f7db899d8c78e609be6184e718 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 May 2019 14:01:41 +0900 Subject: [PATCH 5/7] Adjust testcase to avoid potential rounding issues --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 42e421d1ad..d6259a1fdf 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -219,10 +219,10 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(controlPoints.SamplePointAt(2500).SampleBank, Is.EqualTo("normal")); Assert.That(controlPoints.SamplePointAt(3500).SampleBank, Is.EqualTo("drum")); - Assert.That(controlPoints.TimingPointAt(500).BeatLength, Is.EqualTo(500)); - Assert.That(controlPoints.TimingPointAt(1500).BeatLength, Is.EqualTo(500)); - Assert.That(controlPoints.TimingPointAt(2500).BeatLength, Is.EqualTo(250)); - Assert.That(controlPoints.TimingPointAt(3500).BeatLength, Is.EqualTo(500)); + Assert.That(controlPoints.TimingPointAt(500).BeatLength, Is.EqualTo(500).Within(0.1)); + Assert.That(controlPoints.TimingPointAt(1500).BeatLength, Is.EqualTo(500).Within(0.1)); + Assert.That(controlPoints.TimingPointAt(2500).BeatLength, Is.EqualTo(250).Within(0.1)); + Assert.That(controlPoints.TimingPointAt(3500).BeatLength, Is.EqualTo(500).Within(0.1)); } } From 7e38aabe7518e47ef3dd010c4f77241a424bfc5a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 May 2019 14:27:41 +0900 Subject: [PATCH 6/7] Remove equivalence check from controlpoint parsing --- .../Formats/LegacyBeatmapDecoderTest.cs | 57 ++++++++++++++++--- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 9 --- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index d6259a1fdf..5fd5fe342d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -170,27 +170,66 @@ namespace osu.Game.Tests.Beatmaps.Formats var controlPoints = beatmap.ControlPointInfo; Assert.AreEqual(4, controlPoints.TimingPoints.Count); - var timingPoint = controlPoints.TimingPoints[0]; + Assert.AreEqual(42, controlPoints.DifficultyPoints.Count); + Assert.AreEqual(42, controlPoints.SamplePoints.Count); + Assert.AreEqual(42, controlPoints.EffectPoints.Count); + + var timingPoint = controlPoints.TimingPointAt(0); + Assert.AreEqual(956, timingPoint.Time); + Assert.AreEqual(329.67032967033, timingPoint.BeatLength); + Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature); + + timingPoint = controlPoints.TimingPointAt(48428); Assert.AreEqual(956, timingPoint.Time); Assert.AreEqual(329.67032967033d, timingPoint.BeatLength); Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature); - Assert.AreEqual(5, controlPoints.DifficultyPoints.Count); - var difficultyPoint = controlPoints.DifficultyPoints[0]; - Assert.AreEqual(116999, difficultyPoint.Time); - Assert.AreEqual(0.75000000000000189d, difficultyPoint.SpeedMultiplier); + timingPoint = controlPoints.TimingPointAt(119637); + Assert.AreEqual(119637, timingPoint.Time); + Assert.AreEqual(659.340659340659, timingPoint.BeatLength); + Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature); - Assert.AreEqual(34, controlPoints.SamplePoints.Count); - var soundPoint = controlPoints.SamplePoints[0]; + var difficultyPoint = controlPoints.DifficultyPointAt(0); + Assert.AreEqual(0, difficultyPoint.Time); + Assert.AreEqual(1.0, difficultyPoint.SpeedMultiplier); + + difficultyPoint = controlPoints.DifficultyPointAt(48428); + Assert.AreEqual(48428, difficultyPoint.Time); + Assert.AreEqual(1.0, difficultyPoint.SpeedMultiplier); + + difficultyPoint = controlPoints.DifficultyPointAt(116999); + Assert.AreEqual(116999, difficultyPoint.Time); + Assert.AreEqual(0.75, difficultyPoint.SpeedMultiplier, 0.1); + + var soundPoint = controlPoints.SamplePointAt(0); Assert.AreEqual(956, soundPoint.Time); Assert.AreEqual("soft", soundPoint.SampleBank); Assert.AreEqual(60, soundPoint.SampleVolume); - Assert.AreEqual(8, controlPoints.EffectPoints.Count); - var effectPoint = controlPoints.EffectPoints[0]; + soundPoint = controlPoints.SamplePointAt(53373); + Assert.AreEqual(53373, soundPoint.Time); + Assert.AreEqual("soft", soundPoint.SampleBank); + Assert.AreEqual(60, soundPoint.SampleVolume); + + soundPoint = controlPoints.SamplePointAt(119637); + Assert.AreEqual(119637, soundPoint.Time); + Assert.AreEqual("soft", soundPoint.SampleBank); + Assert.AreEqual(80, soundPoint.SampleVolume); + + var effectPoint = controlPoints.EffectPointAt(0); + Assert.AreEqual(0, effectPoint.Time); + Assert.IsFalse(effectPoint.KiaiMode); + Assert.IsFalse(effectPoint.OmitFirstBarLine); + + effectPoint = controlPoints.EffectPointAt(53703); Assert.AreEqual(53703, effectPoint.Time); Assert.IsTrue(effectPoint.KiaiMode); Assert.IsFalse(effectPoint.OmitFirstBarLine); + + effectPoint = controlPoints.EffectPointAt(119637); + Assert.AreEqual(119637, effectPoint.Time); + Assert.IsFalse(effectPoint.KiaiMode); + Assert.IsFalse(effectPoint.OmitFirstBarLine); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index a5c3d8a4de..3cd425ea44 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -426,9 +426,6 @@ namespace osu.Game.Beatmaps.Formats { var existing = beatmap.ControlPointInfo.DifficultyPointAt(newPoint.Time); - if (newPoint.EquivalentTo(existing)) - return; - if (existing.Time == newPoint.Time) { // autogenerated points should not replace non-autogenerated. @@ -446,9 +443,6 @@ namespace osu.Game.Beatmaps.Formats { var existing = beatmap.ControlPointInfo.EffectPointAt(newPoint.Time); - if (newPoint.EquivalentTo(existing)) - return; - if (existing.Time == newPoint.Time) { // autogenerated points should not replace non-autogenerated. @@ -466,9 +460,6 @@ namespace osu.Game.Beatmaps.Formats { var existing = beatmap.ControlPointInfo.SamplePointAt(newPoint.Time); - if (newPoint.EquivalentTo(existing)) - return; - if (existing.Time == newPoint.Time) { // autogenerated points should not replace non-autogenerated. From 7a56fe84f20433063d811290c5afedb381cd7d5f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 May 2019 14:27:57 +0900 Subject: [PATCH 7/7] Remove ControlPoint.EquivalentTo --- osu.Game/Beatmaps/ControlPoints/ControlPoint.cs | 10 +--------- .../Beatmaps/ControlPoints/DifficultyControlPoint.cs | 10 +++++----- .../Beatmaps/ControlPoints/EffectControlPoint.cs | 12 ++++++------ .../Beatmaps/ControlPoints/SampleControlPoint.cs | 11 +++++------ .../Beatmaps/ControlPoints/TimingControlPoint.cs | 11 +++++------ osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 9 ++++----- 6 files changed, 26 insertions(+), 37 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index 5e538126b3..abe7e5e803 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -19,15 +19,7 @@ namespace osu.Game.Beatmaps.ControlPoints public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time); - /// - /// Whether this provides the same parametric changes as another . - /// Basically an equality check without considering the . - /// - /// The to compare to. - /// Whether this is equivalent to . - public virtual bool EquivalentTo(ControlPoint other) => true; - public bool Equals(ControlPoint other) - => EquivalentTo(other) && Time.Equals(other?.Time); + => Time.Equals(other?.Time); } } diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index 013271d597..a3e3121575 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -1,11 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osuTK; namespace osu.Game.Beatmaps.ControlPoints { - public class DifficultyControlPoint : ControlPoint + public class DifficultyControlPoint : ControlPoint, IEquatable { /// /// The speed multiplier at this control point. @@ -18,9 +19,8 @@ namespace osu.Game.Beatmaps.ControlPoints private double speedMultiplier = 1; - public override bool EquivalentTo(ControlPoint other) - => base.EquivalentTo(other) - && other is DifficultyControlPoint difficulty - && SpeedMultiplier.Equals(difficulty.SpeedMultiplier); + public bool Equals(DifficultyControlPoint other) + => base.Equals(other) + && SpeedMultiplier.Equals(other?.SpeedMultiplier); } } diff --git a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs index 3978b7b4b0..354d86dc13 100644 --- a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; + namespace osu.Game.Beatmaps.ControlPoints { - public class EffectControlPoint : ControlPoint + public class EffectControlPoint : ControlPoint, IEquatable { /// /// Whether this control point enables Kiai mode. @@ -15,10 +17,8 @@ namespace osu.Game.Beatmaps.ControlPoints /// public bool OmitFirstBarLine; - public override bool EquivalentTo(ControlPoint other) - => base.EquivalentTo(other) - && other is EffectControlPoint effect - && KiaiMode.Equals(effect.KiaiMode) - && OmitFirstBarLine.Equals(effect.OmitFirstBarLine); + public bool Equals(EffectControlPoint other) + => base.Equals(other) + && KiaiMode == other?.KiaiMode && OmitFirstBarLine == other.OmitFirstBarLine; } } diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index 241ce90740..4c45bef862 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -1,11 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Game.Audio; namespace osu.Game.Beatmaps.ControlPoints { - public class SampleControlPoint : ControlPoint + public class SampleControlPoint : ControlPoint, IEquatable { public const string DEFAULT_BANK = "normal"; @@ -44,10 +45,8 @@ namespace osu.Game.Beatmaps.ControlPoints return newSampleInfo; } - public override bool EquivalentTo(ControlPoint other) - => base.EquivalentTo(other) - && other is SampleControlPoint sample - && SampleBank.Equals(sample.SampleBank) - && SampleVolume.Equals(sample.SampleVolume); + public bool Equals(SampleControlPoint other) + => base.Equals(other) + && string.Equals(SampleBank, other?.SampleBank) && SampleVolume == other?.SampleVolume; } } diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index 9ec27bdfdf..e5815a3f3b 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -1,12 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osuTK; using osu.Game.Beatmaps.Timing; namespace osu.Game.Beatmaps.ControlPoints { - public class TimingControlPoint : ControlPoint + public class TimingControlPoint : ControlPoint, IEquatable { /// /// The time signature at this control point. @@ -24,10 +25,8 @@ namespace osu.Game.Beatmaps.ControlPoints private double beatLength = 1000; - public override bool EquivalentTo(ControlPoint other) - => base.EquivalentTo(other) - && other is TimingControlPoint timing - && TimeSignature.Equals(timing.TimeSignature) - && BeatLength.Equals(timing.BeatLength); + public bool Equals(TimingControlPoint other) + => base.Equals(other) + && TimeSignature == other?.TimeSignature && beatLength.Equals(other.beatLength); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index ad5089958c..854d3b41d6 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -189,7 +189,7 @@ namespace osu.Game.Beatmaps.Formats Foreground = 3 } - internal class LegacySampleControlPoint : SampleControlPoint + internal class LegacySampleControlPoint : SampleControlPoint, IEquatable { public int CustomSampleBank; @@ -203,10 +203,9 @@ namespace osu.Game.Beatmaps.Formats return baseInfo; } - public override bool EquivalentTo(ControlPoint other) - => base.EquivalentTo(other) - && other is LegacySampleControlPoint legacy - && CustomSampleBank == legacy.CustomSampleBank; + public bool Equals(LegacySampleControlPoint other) + => base.Equals(other) + && CustomSampleBank == other?.CustomSampleBank; } } }