diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs index b94e9f38c6..08eea35425 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs @@ -19,6 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests [TestCase("basic")] [TestCase("colinear-perfect-curve")] [TestCase("slider-ticks")] + [TestCase("slider-ticks-edge-case")] [TestCase("repeat-slider")] [TestCase("uneven-repeat-slider")] [TestCase("old-stacking")] diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 8bf19f030f..e05dbd8ea6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -16,6 +16,7 @@ using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Scoring; @@ -166,9 +167,11 @@ namespace osu.Game.Rulesets.Osu.Objects TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); - double scoringDistance = BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * SliderVelocityMultiplier; + Velocity = BASE_SCORING_DISTANCE * difficulty.SliderMultiplier / LegacyRulesetExtensions.GetPrecisionAdjustedBeatLength(this, timingPoint, OsuRuleset.SHORT_NAME); + // WARNING: this is intentionally not computed as `BASE_SCORING_DISTANCE * difficulty.SliderMultiplier` + // for backwards compatibility reasons (intentionally introducing floating point errors to match stable). + double scoringDistance = Velocity * timingPoint.BeatLength; - Velocity = scoringDistance / timingPoint.BeatLength; TickDistance = GenerateTicks ? (scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier) : double.PositiveInfinity; } diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-edge-case-expected-conversion.json b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-edge-case-expected-conversion.json new file mode 100644 index 0000000000..6d97b643b1 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-edge-case-expected-conversion.json @@ -0,0 +1,39 @@ +{ + "Mappings": [ + { + "StartTime": 7493.0, + "Objects": [ + { + "StartTime": 7493.0, + "EndTime": 7493.0, + "X": 130.0, + "Y": 232.0, + "StackOffset": { + "X": 0.0, + "Y": 0.0 + } + }, + { + "StartTime": 7817.0, + "EndTime": 7817.0, + "X": 30.9946651, + "Y": 208.5157, + "StackOffset": { + "X": 0.0, + "Y": 0.0 + } + }, + { + "StartTime": 7843.0, + "EndTime": 7843.0, + "X": 33.7820168, + "Y": 208.9957, + "StackOffset": { + "X": 0.0, + "Y": 0.0 + } + } + ] + } + ] +} diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-edge-case.osu b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-edge-case.osu new file mode 100644 index 0000000000..daf35e1d2b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/slider-ticks-edge-case.osu @@ -0,0 +1,31 @@ +osu file format v14 + +[General] +StackLeniency: 0.7 + +[Difficulty] +HPDrainRate:3 +CircleSize:3.4 +OverallDifficulty:4 +ApproachRate:5.5 +SliderMultiplier:1.1 +SliderTickRate:1 + +[Events] +//Background and Video events +0,0,"aa.jpg",0,0 +//Break Periods +//Storyboard Layer 0 (Background) +//Storyboard Layer 1 (Fail) +//Storyboard Layer 2 (Pass) +//Storyboard Layer 3 (Foreground) +//Storyboard Layer 4 (Overlay) +//Storyboard Sound Samples + +[TimingPoints] +6967,350.877192982456,6,2,1,55,1,0 +6967,-100,3,2,1,55,0,0 +7493,-111.111111111111,3,2,1,55,0,0 + +[HitObjects] +130,232,7493,6,0,P|78:218|28:208,1,101.82149697876,0|0,3:2|2:0,2:0:0:0: