This design is about to get replaced, so I'm just making some minor
adjustments since a lot of people complained about the font size in the
last update.
Of note, I'm only changing the font size which is one pt size lower than
we'd usually use. Also overlapping the mod icons to create a bit more
space (since there's already cases where they don't fit).
Closes https://github.com/ppy/osu/issues/32055 as far as I'm concerned.
I can read everything fine at 0.8x UI scale.
For now, let's fetch on demand.
Note that song select local leaderboard has the same issue. I feel we should be
doing a lot more cached lookups (probaly with persisting across game restarts).
Maybe even replacing the realm user storage. An issue for another day.
This is a very special case where online beatmap/ruleset models are
being ferried via `ScoreInfo` in what appear to `BeatmapDifficultyCache`
as local `BeatmapInfo`/`RulesetInfo` models. Here, BDC will incorrectly
attempt to proceed with calculating true difficulty where it cannot, and
return 0.
This is fixed locally because `ScoreInfo` is a very weird model, and I'm
not sure whether BDC should contain logic to work around this.
Closes https://github.com/ppy/osu/issues/32052.
Sooooo... this is going to be a rant...
To understand why this is going to require a rant, dear reader, please
do the following:
1. Read the issue thread and follow the reproduction scenario (download
map linked, fire up autoplay, seek near end, wait for results, hear
the sample spam).
2. Now exit out to song select, *hide the toolbar*, and attempt
reproducing the issue again.
3. Depending on ambient mood, laugh or cry.
Now, *why on earth* would the *TOOLBAR* have any bearing on anything?
Well, the chain of failure is something like this:
- The toolbar hides for the duration of gameplay, naturally.
- When progressing to results, the toolbar gets automatically unhidden.
- This triggers invalidations on `ScrollingHitObjectContainer`. I'm not
precisely sure which property it is that triggers the invalidations,
but one clearly does. It may be position or size or whichever.
- When the invalidation is triggered on `layoutCache`, the next
`Update()` call is going to recompute lifetimes for ALL hitobject
entries.
- In case of swells, it happens that the calculated lifetime end of the
swell is larger than what it actually ended up being determined as at
the instant of judging the swell, and thus, the swell is *resurrected*,
reassigned a DHO, and the DHO calls `UpdateState()` and plays the
sample again despite the `samplePlayed` flag in `LegacySwell`, because
all of that is ephemeral state that does not survive a hitobject
getting resurrected.
Now I *could* just fix this locally to the swell, maybe, by having some
time lenience check, but the fact that hitobjects can be resurrected by
the *toolbar* appearing, of all possible causes in the world, feels
just completely wrong. So I'm adding a local check in SHOC to not
overwrite lifetime ends of judged object entries.
The reason why I'm making that check specific to end time is that I can
see valid reasons why you would want to recompute lifetime *start* even
on a judged object (such as playfield geometry changing in a significant
way). I can't think of a valid reason to do that to lifetime *end*.
The lack of this bricks chat completely due to newtonsoft
deserialisation errors:
2025-02-24 08:32:58 [verbose]: Processing response from https://dev.ppy.sh/api/v2/chat/updates failed with Newtonsoft.Json.JsonSerializationException: Error converting value "TEAM" to type 'osu.Game.Online.Chat.ChannelType'. Path 'presence[39].type', line 1, position 13765.
2025-02-24 08:32:58 [verbose]: ---> System.ArgumentException: Requested value 'TEAM' was not found.
2025-02-24 08:32:58 [verbose]: at Newtonsoft.Json.Utilities.EnumUtils.ParseEnum(Type enumType, NamingStrategy namingStrategy, String value, Boolean disallowNumber)
2025-02-24 08:32:58 [verbose]: at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)