From a2bae15db1d796d0b83f5e2eda46bdce0fb39a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 16 Oct 2025 14:09:52 +0200 Subject: [PATCH] Fix Hold Off mod changing scroll speed in rare scenarios (#35265) Reported (in a rather confusing manner) in https://discord.com/channels/188630481301012481/1097318920991559880/1426084740783538268. The relevant bit here is the following logic: https://github.com/ppy/osu/blob/32c60bfb36ae428e6fe56b077d9397c6bc57dd30/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs#L111-L118 which mania enables. --- osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs index 9a1f1948e9..6332e2a928 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Mods; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Beatmaps; @@ -34,6 +35,8 @@ namespace osu.Game.Rulesets.Mania.Mods { var maniaBeatmap = (ManiaBeatmap)beatmap; + double mostCommonBeatLengthBefore = beatmap.GetMostCommonBeatLength(); + var newObjects = new List(); foreach (var h in beatmap.HitObjects.OfType()) @@ -48,6 +51,17 @@ namespace osu.Game.Rulesets.Mania.Mods } maniaBeatmap.HitObjects = maniaBeatmap.HitObjects.OfType().Concat(newObjects).OrderBy(h => h.StartTime).ToList(); + + double mostCommonBeatLengthAfter = beatmap.GetMostCommonBeatLength(); + + // the process of removing hold notes can result in shortening the beatmap's play time, + // and therefore, as a side effect, changing the most common BPM, which will change scroll speed. + // to compensate for this, apply a multiplier to effect points in order to maintain the beatmap's original intended scroll speed. + if (!Precision.AlmostEquals(mostCommonBeatLengthBefore, mostCommonBeatLengthAfter)) + { + foreach (var effectPoint in beatmap.ControlPointInfo.EffectPoints) + effectPoint.ScrollSpeed *= mostCommonBeatLengthBefore / mostCommonBeatLengthAfter; + } } } }