Skip to content

Commit 1a522a1

Browse files
authored
Disallow zero-length sliders from specifying a non-zero number of repeats (#35220)
1 parent a08f732 commit 1a522a1

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,12 +476,30 @@ private ConvertHitObject createHitCircle(Vector2 position, bool newCombo, int co
476476
private ConvertHitObject createSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount,
477477
IList<IList<HitSampleInfo>> nodeSamples)
478478
{
479+
var path = new SliderPath(controlPoints, length);
480+
481+
// there are known instances of beatmaps (https://osu.ppy.sh/beatmapsets/594828#osu/1258033) which contain zero-length sliders with non-zero numbers of repeats.
482+
// this was exploiting a bug in stable in which the slider repeats would be generated as objects but never actually judged as a hit *or* miss during gameplay,
483+
// therefore increasing the theoretical possible max combo to be gained from a slider while in practice never giving that extra combo.
484+
// due to lazer ensuring that an object has its nested part fully judged, this would result in broken behaviours
485+
// (either the zero-length slider giving hundreds of combo for nothing if the repeats are judged as hit, or insta-failing the player due to HP if judged as miss).
486+
// to remedy this in a way that seems least damaging, detect this situation via a heuristic and reset the number of repeats to zero.
487+
// this technically *does not* match stable beatmap parsing or conversion, *does not* match in-gameplay behaviour of such broken sliders,
488+
// and *will* fail conversion mapping tests, but again, this is supposed to be a least-worst measure to prevent exploits.
489+
// it is also applied centrally to all rulesets rather than in specific ruleset converters because this failure scenario
490+
// translates across rulesets (osu! and catch are both affected).
491+
if (Precision.AlmostEquals(path.Distance, 0))
492+
{
493+
repeatCount = 0;
494+
nodeSamples = [nodeSamples[0], nodeSamples[^1]];
495+
}
496+
479497
return lastObject = new ConvertSlider
480498
{
481499
Position = position,
482500
NewCombo = firstObject || lastObject is ConvertSpinner || newCombo,
483501
ComboOffset = newCombo ? comboOffset : 0,
484-
Path = new SliderPath(controlPoints, length),
502+
Path = path,
485503
NodeSamples = nodeSamples,
486504
RepeatCount = repeatCount
487505
};

0 commit comments

Comments
 (0)