Song Select V2: Updating a beatmap does not preserve selected beatmap
Type
Game behaviour
Bug description
~~Just because a ruleset has more difficulties doesn't mean that the user wants to play that.~~ The selected beatmap is not preserved!
Screenshots or videos
(song select v1 because it was originally reported as that)
https://github.com/user-attachments/assets/f563b389-78f3-4549-9ecc-10b8ab4bd421
Version
2025.424.0-lazer
Logs
~~compressed-logs.zip~~ Irrelevant as this is for SongSelectV1
I would hope I could say "wontfix because song select v2 already handles this" but unfortunately song select v2 fails even harder at this. Selection isn't even preserved over there.
I've tried a few approaches in resolving this. The biggest issue in implementing this correctly is the sheer number of layers involved. A beatmap update operation is very obscured behind things like
BeatmapManager.DownloadAsUpdate()being more or less fire-and-forget (returns void, gives no access to update result)DetachedBeatmapStorerunning one layer of detachment from the raw realm change callbacks, andBeatmapCarouselpiling another on top
That said I did try a few approaches:
- Attempting to make
BeatmapManager.DownloadAsUpdate()not fire-and-forget and make it return the updated import instead, which then could be used to re-present the beatmap viaOsuGame(branch) - abandoned because it was broken and my confidence in making it work was very low. The present operation was getting overridden by something and my hopes in undoing that in a sane way were not high. Maybe this could be salvaged by lifting the re-selection logic out of the update button to the carousel itself somehow or something. - Preserving selection locally to
BeatmapCarouselby storing the last deleted beatmap and checking if any added beatmaps after match it (branch) - sort of works, but is probably too busted to pass serious review - Hijacking
DetachedBeatmapStoreand doing some tricks to basically masquerade a beatmap-delete-and-insert that happens on a beatmap update into a beatmap move-and-replace to detached store consumers (branch) - sort of dodgy like (2) as well, but presents the most promise at present to me at least. Notably, it just-works in new song select, but required a bit of a nudge for old song select to not break.
@peppy would you mind taking a few minutes to examine the branches above and seeing if you have a particular direction you'd prefer to continue down?
- This would have been my preferred method – in fact I feel like I tried the same thing while working on the song select v2 implementation and may have hit similar roadblocks to what you did.
Out of curiosity, did you see how this was handled in the original beatmap carousel? It's similar to your second two attempts.
Of 2 and 3, I agree that 3 is the best approach, since I'd hope that DetachedBetamapStore is fixing realm/transactional stuff so we don't have to worry about it (it's intended to be a "simplify everything" component). Let's go with that one?
Should be closed via https://github.com/ppy/osu/pull/35240.