This was not fatal but with this change it should recover in a slightly
better way.
Also incidentally fixes the cache refetch potentially being attempted
twice by each of the two background population tasks that use it.
This change refactors `GetAdjustedDisplayDifficulty()` and
`GetBeatmapAttributesToDisplay()` in two ways:
- Both methods now accept `IBeatmapInfo` instead of
`IBeatmapDifficultyInfo`. This is done in order to make mania key
count display to work, wherein `IBeatmapDifficultyInfo` is not enough
to calculate the final key count.
- `GetAdjustedDisplayDifficulty()` now applies all
`IApplicableToDifficulty` mods itself. I did this after noticing that
every real consumer of this method had to do that themselves for very
little reason.
The way that this works is that it plugs into the online request to
retrieve the beatmap set that the client is already performing, and
stores user tag data to the local realm database.
This means that for now user tags will only populate for beatmaps that
the user has displayed on song select which is obviously subpar. I plan
to follow this change up by adding user tag state dumps to `online.db`
and using that data for initial tag population to make the majority case
(ranked beatmaps) work.
Note that several decisions were made here that are potential discussion
points:
- `RealmPopulatingOnlineLookupSource` is set up such that it can be the
middle man / redirection point for similar flows that we need and we
are currently missing, such as storing guest difficulty information,
or storing the user's current best score on a beatmap (handy for rank
achieved sorting / filtering / etc.)
- The user tags are stored in `BeatmapMetadata` which breaks the
longstanding assumption that you can arbitrarily pull out a metadata
instance from any of the beatmaps in a set and get essentially the
same object back.
I've attempted to constrain this some by not adding user tags to
the `IBeatmapMetadataInfo` interface through which `BeatmapSetInfo`
exposes metadata further, but I warn in advance that this is
a temporary state of affairs and I will make it worse in the future
when `BeatmapMetadata.Author` becomes `Authors` plural in order to
support guest mapper display (and direct guest difficulty submission).
- The syntax for searching via user tags is chosen to mostly match web -
it's `tag=`, with support for all of the string matching modes song
select already has (bare word for substring, `""` quotes for phrase
isolated by whitespace, `""!` for exact full match).
In stable mania, Hard Rock and Easy mods do not work the same way as
they do on all of the rulesets. The difference is that mania HR and EZ,
rather than apply a multiplier to the map's original Overall Difficulty,
apply multipliers to *the durations of hit windows themselves*.
Prior to the last release, lazer was oblivious to this reality and just
treated mania HR / EZ as it did every other ruleset. Last release, for
the sake for gameplay parity across rulesets, the mods in question were
adjusted to match stable, but in the process, it started looking like HR
/ EZ did not change OD anymore.
The problem is that they do, but applying a multiplier to the map's OD
and applying a multiplier to the hit window duration is not the same
thing. The second thing is actually *much harsher* in magnitude, to the
point where applying HR to any map is almost guaranteed to exceed "the
effective OD" of 10, and applying EZ to any map is almost guaranteed to
result in "negative effective OD".
This change attempts to convey that reality by displaying "effective
OD", similar to what's already done in other rulesets when rate-changing
mods are active. Note that the values this will display *do not match*
stable *and that is correct*, because stable song select *lies* about
the actual impact on OD by just assuming it can treat all rulesets in
the same way.
---
Would close https://github.com/ppy/osu/issues/34150 I guess.
And yes I would like *all of the above* to land on the changelog if
possible if this is merged.
For further convincing that this makes any semblance of sense please see
the following: https://www.desmos.com/calculator/yigt7jycdv
This change pulls back a significant degree of overspecialisation and
rigidity in the class structure of `HitWindows` to make subsequent
changes to hit windows, whose purpose is to improve replay playback
accuracy, possible to do cleanly.
Notably:
- `HitWindows` is full abstract now. In a few use cases, and as a
reference for ruleset implementors, `DefaultHitWindows` is provided as
a separate class instead.
This fixes the weirdness wherein `HitWindows` always declared 6 fields
for result types but some of them would never be set to a non-zero
value or read.
- `HitWindow.GetRanges()` is deleted because it is overspecialised and
prevents being able to adjust hitwindows by ±0.5ms cleanly which will
be required later.
The fallout of this is that the assertion that used `GetRanges()` in
the `HitWindows` ctor must use something else now, and the closest
thing to it was `GetAllAvailableWindows()`, which didn't return
the miss window - so I made it return the miss window and fixed the
one consumer that didn't want it (bar hit error meter) to skip it.
- Diff also contains some clean-up around `DifficultyRange` to unify
handling of it.
By falling back to the default of 40% of track duration in such cases.
Also added a safety for the restart point exceeding acceptable bounds in
case of a non-zero offset.
Closes https://github.com/ppy/osu/issues/33308.