Fix rate change hotkeys sometimes losing track of adjust pitch setting

Fixes https://osu.ppy.sh/community/forums/topics/1983327.

The cause of the bug is a bit convoluted, and stems from the fact that
the mod select overlay controls all of the game-global mod instances if
present. `ModSpeedHotkeyHandler` would store the last spotted instance
of a rate adjust mod - which in this case is a problem, because on
deselection of a mod, the mod select overlay resets its settings to
defaults:

	a258059d43/osu.Game/Overlays/Mods/ModSelectOverlay.cs (L424-L425)

A way to defend against this is a clone, but this reveals another issue,
in that the existing code was *relying* on the reference to the mod
remaining the same in any other case, to read the latest valid settings
of the mod. This basically only mattered in the edge case wherein Double
Time would swap places with Half Time and vice versa (think [0.95,1.05]
range). Therefore, track mod settings too explicitly to ensure that the
stored clone is as up-to-date as possible.
This commit is contained in:
Bartłomiej Dach 2024-09-30 08:47:02 +02:00
parent 23b8354af4
commit 5e5bb49cd8
No known key found for this signature in database
1 changed files with 11 additions and 1 deletions

View File

@ -27,6 +27,7 @@ public partial class ModSpeedHotkeyHandler : Component
private OnScreenDisplay? onScreenDisplay { get; set; }
private ModRateAdjust? lastActiveRateAdjustMod;
private ModSettingChangeTracker? settingChangeTracker;
protected override void LoadComplete()
{
@ -34,10 +35,19 @@ protected override void LoadComplete()
selectedMods.BindValueChanged(val =>
{
lastActiveRateAdjustMod = val.NewValue.OfType<ModRateAdjust>().SingleOrDefault() ?? lastActiveRateAdjustMod;
storeLastActiveRateAdjustMod();
settingChangeTracker?.Dispose();
settingChangeTracker = new ModSettingChangeTracker(val.NewValue);
settingChangeTracker.SettingChanged += _ => storeLastActiveRateAdjustMod();
}, true);
}
private void storeLastActiveRateAdjustMod()
{
lastActiveRateAdjustMod = (ModRateAdjust?)selectedMods.Value.OfType<ModRateAdjust>().SingleOrDefault()?.DeepClone() ?? lastActiveRateAdjustMod;
}
public bool ChangeSpeed(double delta, IEnumerable<Mod> availableMods)
{
double targetSpeed = (selectedMods.Value.OfType<ModRateAdjust>().SingleOrDefault()?.SpeedChange.Value ?? 1) + delta;