From e0904e263f4c976e24277c19f380650fb025499f Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sun, 9 Oct 2022 11:25:47 +0200 Subject: [PATCH 1/5] Fix legacy BpmMultiplier clamp value --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 9c066ada08..360a91a7e5 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -178,7 +178,7 @@ namespace osu.Game.Beatmaps.Formats : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; GenerateTicks = !double.IsNaN(beatLength); } From f8036658c701e3f85b808c1b121ec9f35d50b0f0 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Mon, 10 Oct 2022 09:36:18 +0200 Subject: [PATCH 2/5] Move clamps directly to the usages in the conversion algorithm --- .../Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs | 2 +- osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 2bdd0e16ad..89b52a3c75 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; + beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 524565a863..33f1535437 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; + beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 360a91a7e5..9c066ada08 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -178,7 +178,7 @@ namespace osu.Game.Beatmaps.Formats : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; GenerateTicks = !double.IsNaN(beatLength); } From df0501235d21dee2e24c9801b099bf27a4e97725 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Wed, 12 Oct 2022 11:14:01 +0200 Subject: [PATCH 3/5] Introduce `BpmMultiplierMania`, remove after the fact clamps --- .../Legacy/DistanceObjectPatternGenerator.cs | 2 +- .../Beatmaps/TaikoBeatmapConverter.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 89b52a3c75..2bdd0e16ad 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); + beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 33f1535437..524565a863 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); + beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 9c066ada08..03819af149 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -168,6 +168,13 @@ namespace osu.Game.Beatmaps.Formats /// public double BpmMultiplier { get; private set; } + /// + /// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it. + /// This is to be used for taiko and mania specific beatmaps. + /// DO NOT USE THIS UNLESS 100% SURE. + /// + public double BpmMultiplierMania { get; private set; } + /// /// Whether or not slider ticks should be generated at this control point. /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). @@ -178,7 +185,8 @@ namespace osu.Game.Beatmaps.Formats : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; + BpmMultiplierMania = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; GenerateTicks = !double.IsNaN(beatLength); } @@ -196,6 +204,7 @@ namespace osu.Game.Beatmaps.Formats base.CopyFrom(other); BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier; + BpmMultiplierMania = ((LegacyDifficultyControlPoint)other).BpmMultiplierMania; GenerateTicks = ((LegacyDifficultyControlPoint)other).GenerateTicks; } @@ -206,10 +215,11 @@ namespace osu.Game.Beatmaps.Formats public bool Equals(LegacyDifficultyControlPoint? other) => base.Equals(other) && BpmMultiplier == other.BpmMultiplier + && BpmMultiplierMania == other.BpmMultiplierMania && GenerateTicks == other.GenerateTicks; // ReSharper disable twice NonReadonlyMemberInGetHashCode - public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, GenerateTicks); + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, BpmMultiplierMania, GenerateTicks); } internal class LegacySampleControlPoint : SampleControlPoint, IEquatable From 2579ed46ce552c3c610f5bacb8359e0f764616df Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Wed, 12 Oct 2022 11:22:54 +0200 Subject: [PATCH 4/5] Select multiplier per mode --- .../Beatmaps/TaikoBeatmapConverter.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 524565a863..613c41a59a 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,7 +162,14 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; + { + double bpmMultiplier; + if (beatmap.BeatmapInfo.OnlineID == 1 || beatmap.BeatmapInfo.OnlineID == 3) + bpmMultiplier = legacyDifficultyPoint.BpmMultiplierMania; + else + bpmMultiplier = legacyDifficultyPoint.BpmMultiplier; + beatLength = timingPoint.BeatLength * bpmMultiplier; + } else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; From 338115ff6a00d4eaf9ce90e061c71f9504307174 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 13 Oct 2022 15:05:15 +0900 Subject: [PATCH 5/5] Move check to LegacyDifficultyControlPoint --- .../Beatmaps/TaikoBeatmapConverter.cs | 9 +-------- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 6 +++--- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 20 +++++++------------ 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 613c41a59a..524565a863 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,14 +162,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - { - double bpmMultiplier; - if (beatmap.BeatmapInfo.OnlineID == 1 || beatmap.BeatmapInfo.OnlineID == 3) - bpmMultiplier = legacyDifficultyPoint.BpmMultiplierMania; - else - bpmMultiplier = legacyDifficultyPoint.BpmMultiplier; - beatLength = timingPoint.BeatLength * bpmMultiplier; - } + beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 75500fbc4e..683bc19ce6 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -427,8 +427,10 @@ namespace osu.Game.Beatmaps.Formats addControlPoint(time, controlPoint, true); } + int onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID; + #pragma warning disable 618 - addControlPoint(time, new LegacyDifficultyControlPoint(beatLength) + addControlPoint(time, new LegacyDifficultyControlPoint(onlineRulesetID, beatLength) #pragma warning restore 618 { SliderVelocity = speedMultiplier, @@ -440,8 +442,6 @@ namespace osu.Game.Beatmaps.Formats OmitFirstBarLine = omitFirstBarSignature, }; - int onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID; - // osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments. if (onlineRulesetID == 1 || onlineRulesetID == 3) effectPoint.ScrollSpeed = speedMultiplier; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 03819af149..ed7ca47cfd 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -168,25 +168,21 @@ namespace osu.Game.Beatmaps.Formats /// public double BpmMultiplier { get; private set; } - /// - /// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it. - /// This is to be used for taiko and mania specific beatmaps. - /// DO NOT USE THIS UNLESS 100% SURE. - /// - public double BpmMultiplierMania { get; private set; } - /// /// Whether or not slider ticks should be generated at this control point. /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). /// public bool GenerateTicks { get; private set; } = true; - public LegacyDifficultyControlPoint(double beatLength) + public LegacyDifficultyControlPoint(int rulesetId, double beatLength) : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; - BpmMultiplierMania = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + if (rulesetId == 1 || rulesetId == 3) + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + else + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; + GenerateTicks = !double.IsNaN(beatLength); } @@ -204,7 +200,6 @@ namespace osu.Game.Beatmaps.Formats base.CopyFrom(other); BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier; - BpmMultiplierMania = ((LegacyDifficultyControlPoint)other).BpmMultiplierMania; GenerateTicks = ((LegacyDifficultyControlPoint)other).GenerateTicks; } @@ -215,11 +210,10 @@ namespace osu.Game.Beatmaps.Formats public bool Equals(LegacyDifficultyControlPoint? other) => base.Equals(other) && BpmMultiplier == other.BpmMultiplier - && BpmMultiplierMania == other.BpmMultiplierMania && GenerateTicks == other.GenerateTicks; // ReSharper disable twice NonReadonlyMemberInGetHashCode - public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, BpmMultiplierMania, GenerateTicks); + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, GenerateTicks); } internal class LegacySampleControlPoint : SampleControlPoint, IEquatable