Closes https://github.com/ppy/osu/issues/28587.
As outlined in the issue thread, the tail volume wasn't saving because
it wasn't actually attached to a hitobject properly, and as such the
`LegacyBeatmapEncoder` logic, which is based on hitobjects, did not
pick them up on save.
To fix that, switch to using `NodeSamples` for objects that are
`IHasRepeats`. That has one added complication in that having it work
properly requires changes to the decode side too. That is because the
intent is to allow the user to change the sample settings for each node
(which are specified via `NodeSamples`), as well as "the rest of the
object", which generally means ticks or auxiliary samples like
`sliderslide` (which are specified by `Samples`).
However, up until now, `Samples` always queried the control point
which was _active at the end time of the slider_. This obviously can't
work anymore when converting `NodeSamples` to legacy control points,
because the last node's sample is _also_ at the end time of the slider.
To bypass that, add extra sample points after each node (just out of
reach of the 5ms leniency), which are supposed to control volume of
ticks and/or slides.
Upon testing, this *sort of* has the intended effect in stable, with
the exception of `sliderslide`, which seems to either respect or _not_
respect the relevant volume spec dependent on... not sure what, and not
sure I want to be debugging that. It might be frame alignment, or it
might be the phase of the moon.
Same deal with this class. Fully qualifying the type names because this
has `#nullable disable` and makes use of `NotNull` which is also present
in the `System.Diagnostics.CodeAnalysis` namespace and AAAAAAARGH
NAMESPACE CONFLICTS.
Due to the way `ModelBackedDrawable` works, the default starts to get
loaded even though a final `Beatmap` has been set. This avoids loading
the default fallback unless a beatmap has been set (and has no
background itself).
Was added in cc76c58f5f without any
specific reasoning. Likely not required (and will fix some storyboard
elements inside `.osu` files from not being correctly saved).
Related to: https://github.com/ppy/osu/issues/27674
Relevant log output for that particular case:
[network] 2024-03-20 07:25:30 [verbose]: Performing request osu.Game.Online.API.Requests.GetBeatmapRequest
[network] 2024-03-20 07:25:30 [verbose]: Request to https://dev.ppy.sh/api/v2/beatmaps/lookup successfully completed!
[network] 2024-03-20 07:25:30 [verbose]: GetBeatmapRequest finished with response size of 3,170 bytes
[database] 2024-03-20 07:25:30 [verbose]: [4fe02] [APIBeatmapMetadataSource] Online retrieval mapped Tsukiyama Sae - Hana Saku Iro wa Koi no Gotoshi (Log Off Now) [Destiny] to 744883 / 1613507.
[database] 2024-03-20 07:25:30 [verbose]: Discarding metadata lookup result due to mismatching online ID (expected: 1570982 actual: 1613507)
[network] 2024-03-20 07:25:30 [verbose]: Performing request osu.Game.Online.API.Requests.GetBeatmapRequest
[network] 2024-03-20 07:25:30 [verbose]: Request to https://dev.ppy.sh/api/v2/beatmaps/lookup successfully completed!
[network] 2024-03-20 07:25:30 [verbose]: GetBeatmapRequest finished with response size of 2,924 bytes
[database] 2024-03-20 07:25:30 [verbose]: [4fe02] [APIBeatmapMetadataSource] Online retrieval mapped Tsukiyama Sae - Hana Saku Iro wa Koi no Gotoshi (Log Off Now) [Easy] to 744883 / 1570982.
[database] 2024-03-20 07:25:30 [verbose]: Discarding metadata lookup result due to mismatching online ID (expected: 1613507 actual: 1570982)
Note that the online IDs are swapped.
Assuming that the global audio offset is set perfectly, such that
any audio latency is fully accounted for, if a specific beatmap
still sounds out of sync, that would no longer be a latency issue.
Instead, it would indicate a misalignment between the beatmap's
track and time codes, the correction for which should be a
virtual-time offset, not a real-time offset.
After https://github.com/ppy/osu/pull/23362 I'm not sure the
`LocallyModified` check is doing anything useful. It was confusing me
really hard when trying to parse this logic, and it can misbehave (as
`None` will also pass the check).
- Change difficultyicon mods parameter docstring to be more professional
- Add a parameter for controlling whether the difficulty statistics show or not. Defaults to false
- Round the BPM in the tooltip to make sure it displays correctly