diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index 311e15116e..2a5564297c 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -11,6 +11,7 @@ using Newtonsoft.Json;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Beatmaps.Formats;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
@@ -50,9 +51,12 @@ namespace osu.Game.Rulesets.Catch.Objects
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
+#pragma warning disable 618
+ bool generateTicks = (DifficultyControlPoint as LegacyBeatmapDecoder.LegacyDifficultyControlPoint)?.GenerateTicks ?? true;
+#pragma warning restore 618
velocityFactor = base_scoring_distance * difficulty.SliderMultiplier / timingPoint.BeatLength;
- tickDistanceFactor = base_scoring_distance * difficulty.SliderMultiplier / difficulty.SliderTickRate;
+ tickDistanceFactor = generateTicks ? (base_scoring_distance * difficulty.SliderMultiplier / difficulty.SliderTickRate) : double.PositiveInfinity;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
index 4ec039c405..22fab15c1b 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
@@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Mania.Objects
private void createTicks(CancellationToken cancellationToken)
{
- if (tickSpacing == 0 || !DifficultyControlPoint.GenerateTicks)
+ if (tickSpacing == 0)
return;
for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing)
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index 0689c49085..df1252c060 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -14,6 +14,8 @@ using osu.Framework.Caching;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Beatmaps.Formats;
+using osu.Game.Beatmaps.Legacy;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
@@ -166,10 +168,16 @@ namespace osu.Game.Rulesets.Osu.Objects
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
+ var legacyInfo = controlPointInfo as LegacyControlPointInfo;
+#pragma warning disable 618
+ var legacyDifficultyPoint = legacyInfo?.DifficultyPointAt(StartTime) as LegacyBeatmapDecoder.LegacyDifficultyControlPoint;
+#pragma warning restore 618
+
double scoringDistance = BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * DifficultyControlPoint.SliderVelocity;
+ bool generateTicks = legacyDifficultyPoint?.GenerateTicks ?? true;
Velocity = scoringDistance / timingPoint.BeatLength;
- TickDistance = DifficultyControlPoint.GenerateTicks ? (scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier) : double.PositiveInfinity;
+ TickDistance = generateTicks ? (scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier) : double.PositiveInfinity;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
index 09e465c37b..e1619e2857 100644
--- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
@@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
private void createTicks(CancellationToken cancellationToken)
{
- if (tickSpacing == 0 || !DifficultyControlPoint.GenerateTicks)
+ if (tickSpacing == 0)
return;
bool first = true;
diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
index ddb2b1e95c..c199d1da59 100644
--- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
@@ -40,21 +40,13 @@ namespace osu.Game.Beatmaps.ControlPoints
set => SliderVelocityBindable.Value = value;
}
- ///
- /// 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; set; } = true;
-
public override bool IsRedundant(ControlPoint? existing)
=> existing is DifficultyControlPoint existingDifficulty
- && SliderVelocity == existingDifficulty.SliderVelocity
- && GenerateTicks == existingDifficulty.GenerateTicks;
+ && SliderVelocity == existingDifficulty.SliderVelocity;
public override void CopyFrom(ControlPoint other)
{
SliderVelocity = ((DifficultyControlPoint)other).SliderVelocity;
- GenerateTicks = ((DifficultyControlPoint)other).GenerateTicks;
base.CopyFrom(other);
}
@@ -65,10 +57,8 @@ namespace osu.Game.Beatmaps.ControlPoints
public bool Equals(DifficultyControlPoint? other)
=> base.Equals(other)
- && SliderVelocity == other.SliderVelocity
- && GenerateTicks == other.GenerateTicks;
+ && SliderVelocity == other.SliderVelocity;
- // ReSharper disable once NonReadonlyMemberInGetHashCode
- public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity, GenerateTicks);
+ public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity);
}
}
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
index 3d3661745a..f064d89e19 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
@@ -430,7 +430,6 @@ namespace osu.Game.Beatmaps.Formats
#pragma warning restore 618
{
SliderVelocity = speedMultiplier,
- GenerateTicks = !double.IsNaN(beatLength),
}, timingChange);
var effectPoint = new EffectControlPoint
diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
index 52e760a068..c3fd16e86f 100644
--- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs
@@ -168,11 +168,18 @@ namespace osu.Game.Beatmaps.Formats
///
public double BpmMultiplier { 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)
: 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;
+ GenerateTicks = !double.IsNaN(beatLength);
}
public LegacyDifficultyControlPoint()
@@ -180,11 +187,17 @@ namespace osu.Game.Beatmaps.Formats
SliderVelocityBindable.Precision = double.Epsilon;
}
+ public override bool IsRedundant(ControlPoint? existing)
+ => existing is LegacyDifficultyControlPoint existingLegacyDifficulty
+ && base.IsRedundant(existing)
+ && GenerateTicks == existingLegacyDifficulty.GenerateTicks;
+
public override void CopyFrom(ControlPoint other)
{
base.CopyFrom(other);
BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier;
+ GenerateTicks = ((LegacyDifficultyControlPoint)other).GenerateTicks;
}
public override bool Equals(ControlPoint? other)
@@ -193,10 +206,11 @@ namespace osu.Game.Beatmaps.Formats
public bool Equals(LegacyDifficultyControlPoint? other)
=> base.Equals(other)
- && BpmMultiplier == other.BpmMultiplier;
+ && BpmMultiplier == other.BpmMultiplier
+ && GenerateTicks == other.GenerateTicks;
- // ReSharper disable once NonReadonlyMemberInGetHashCode
- public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier);
+ // ReSharper disable twice NonReadonlyMemberInGetHashCode
+ public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, GenerateTicks);
}
internal class LegacySampleControlPoint : SampleControlPoint, IEquatable