Before:
https://github.com/user-attachments/assets/95b19bdb-12c5-4ee7-b7e2-f9098aecd2fa
After:
https://github.com/user-attachments/assets/937081c5-92cb-4bea-a774-e53afbdbb1fb
---
This is a subjective diff and can be closed on the spot with no
discussion if deemed incorrect. I mostly just want to get it off my list
of unresolved forum threads.
The catalyst for this change is [this
thread](https://osu.ppy.sh/community/forums/topics/2171493?n=1), wherein
the complaint is that you can get jumpscared by a slider repeat in a
combo because the slider repeats do not fade in with the rest of the
combo. Which means that you don't immediately know whether a slider will
need to be repeated or not and you have to watch out for potential
slider repeats fading in, which could happen at an *arbitrary* time
because it's still dependent on the map's original AR.
This seems pretty anti-user so I made it fade in with the rest of the
combo. The original comment cited "broken layering" which I guess refers
to the fact that sliders can repeat *more* than once and the second
repeat will show *under the slider head*. It's pretty broken, sure, but
I don't think it's *that* bad, and I *do* think that it's better than
the current behaviour.
The reason it shows only the first two repeats is that there's no point
in showing more for reasons that are hopefully obvious.
Effectively closing https://github.com/ppy/osu/issues/21471 as a
wontfix.
The issue is demonstrated by the following test case:
<details>
<summary>patch</summary>
```diff
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs
index 31498295da..36b4fe5122 100644
--- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs
@@ -55,5 +55,49 @@ public void TestSkipToFirstSpinnerNotSuppressed()
PassCondition = () => Player.GameplayClockContainer.GameplayStartTime > 0
});
}
+
+ [Test]
+ public void TestFreezeFrameAppliedBeforeHidden()
+ {
+ CreateModTest(new ModTestData
+ {
+ Mods =
+ [
+ new OsuModFreezeFrame(),
+ new OsuModHidden(),
+ ],
+ CreateBeatmap = () => new OsuBeatmap
+ {
+ HitObjects =
+ {
+ new HitCircle { StartTime = 3000, Position = OsuPlayfield.BASE_SIZE / 2, NewCombo = true },
+ new HitCircle { StartTime = 5000, Position = OsuPlayfield.BASE_SIZE / 2 },
+ }
+ },
+ PassCondition = () => ((HitCircle)Player.GameplayState.Beatmap.HitObjects[1]).TimeFadeIn == 480
+ });
+ }
+
+ [Test]
+ public void TestFreezeFrameAppliedAfterHidden()
+ {
+ CreateModTest(new ModTestData
+ {
+ Mods =
+ [
+ new OsuModHidden(),
+ new OsuModFreezeFrame(),
+ ],
+ CreateBeatmap = () => new OsuBeatmap
+ {
+ HitObjects =
+ {
+ new HitCircle { StartTime = 3000, Position = OsuPlayfield.BASE_SIZE / 2, NewCombo = true },
+ new HitCircle { StartTime = 5000, Position = OsuPlayfield.BASE_SIZE / 2 },
+ }
+ },
+ PassCondition = () => ((HitCircle)Player.GameplayState.Beatmap.HitObjects[1]).TimeFadeIn == 480
+ });
+ }
}
}
```
</details>
The reason that this is happening is a data dependency. Freeze Frame
modifies `TimePreempt` of hitobjects:
https://github.com/ppy/osu/blob/54c0b2c20c3209f1f17be81b8883ef66ec8a83bb/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs#L53
while Hidden uses `TimePreempt` to set `TimeFadeIn`:
https://github.com/ppy/osu/blob/54c0b2c20c3209f1f17be81b8883ef66ec8a83bb/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs#L45
Therefore the final value of `TimeFadeIn` with these two mods active
depends on the order of application.
The reason why I'm bothering to do this is that I was pinged from the PP
development server about this again in the context of some ongoing
'rework' and I wish to get ahead of this before it becomes a bigger
problem than it already is.
The current order of application of these mods as done in `Player` is
constant, but essentially undefined. I'm not even sure what even
enforces the current order. It's currently Hidden, then Freeze Frame. If
I were to guess, the thing "enforcing" (insert 400 tonne solid lead air
quotes) it is probably the mod select overlay with its "I need to own
all of the mod instances in the global bindable" substitution logic.
I'm already getting pushback for this from the PP server crowd who are
attempting to justify the current "behaviour" by saying that the player
base wants this or by saying that it's already broken so it should
remain that way forever. I am however not willing to accept
[stable-taiko-tier stupidity
again](https://github.com/ppy/osu/pull/27136#issuecomment-1957055402)
and am not willing to accept the complexity this would invite everywhere
else.
I do not see any other easy way of fixing this problem at this point in
time. I had hoped that I could inline the `TimePreempt` read in
`OsuModHidden`, but it's not that easy because it's set in multiple
places.
Existing HDFF scores would probably need to be delisted from the
leaderboards. I'm not even sure I can get myself to pretend to care.