This fell out while investigating why the issue with online IDs
mismatching in the `.osu` could be worked around by importing the map
three times in total when starting from it not being available locally.
Here follows an explanation of why that "helped".
Import 1:
- The beatmap set is imported normally.
- Online metadata population sees the online ID mismatch and resets it
on the problematic beatmap.
Import 2:
- The existing beatmap set is found, but deemed not reusable
because of the single beatmap having its ID reset to -1.
- The existing beatmap set is marked deleted, and all the IDs of
its beatmaps are reset to -1.
- The beatmap set is reimported afresh.
- Online metadata population still sees the online ID mismatch
and resets it on the problematic beatmap.
Note that at this point the first import *is still physically present
in the database* but marked deleted.
Import 3:
- When trying to find the existing beatmap set to see if it can be
reused, *the one pending deletion and with its IDs reset -
- the remnant from import 1 - is returned*.
- Because of this, `validateOnlineIds()` resets online IDs
*on the model representing the current reimport*.
- The beatmap set is reimported yet again.
- With the online ID reset, the online metadata population check for
online ID mismatch does not run because *the IDs were reset to -1*
earlier.
Preferring undeleted models when picking the model instance for reuse
prevents this scenario.
Doing this alleviates https://github.com/ppy/osu/issues/29982, as the
currently online display utilises the user lookup cache, and currently
is hitting rate limits due to the amount of data retrieved from the `GET
/users` endpoint. Switching to `GET /users/lookup` reduces the chance of
this happening.
People keep asking why https://github.com/ppy/osu/pull/29553 didn't fix
their databases (as stated in the PR, it didn't intend to), so this
should do it for them.
This is going to be used by server-side flows. Note that the server-side
overload of `UpdateFromLegacy()` was not calling
`LegacyScoreDecoder.PopulateTotalScoreWithoutMods()`.
Computing the score without mods inline reduces reflection overheads
from constructing mod instances, which feels pretty important for
server-side flows.
There is one weird kink in the treatment of stable scores with score V2
active - they get the *legacy* multipliers unapplied for them because
that made the most sense. For all intents and purposes this matters
mostly for client-side replays with score V2. I'm not sure whether
scores with SV2 ever make it to submission in stable.
There may be minute differences in converted score due to rounding
shenanigans but I don't think it's worth doing a reverify for this.
Closes https://github.com/ppy/osu/issues/28209.
Yes this means that such scores will have a zero total score without
mods in DB and thus might up getting their total recalculated to zero
when we try a mod multiplier rebalance (unless we skip scores with zero
completely I suppose). I also don't really care about that right now.