Probably closes https://github.com/ppy/osu/issues/34645.
Obviously this is only good if the score has managed to process online
and slot into a leaderboard before the user requested a retry. I can't
make miracles happen.
Notably this is not applied to quick retry, because it would make quick
retry slower, and the presumption is that if the user is quick-retrying
their last score is likely useless for global leaderboards anyway. (The
one exception to that last part is possibly quick-retrying from results
screen, which is a flow that we have, but maybe fine to ignore it...?)
This is super haphazard in the first place but I'm going to look past
that for now.
Basically, due to the order of operation, the tags could be initialised
via `updateTags()` before the perform search action was initialised,
leading to clicks doing nothing.
This is still a workaround but arguably it's something we could leave in
place without much loss. I think this at least feels better than the
previous code.
Notably, you could argue the test coverage of the fail case is lower
since made it implicit that all tests will avoid the "backwards seek"
detections. But we never really had tests correctly- fail on the original
so I don't see any loss of value.
Other textual keyword filters also worked like that, wherein if you did
`artist=a artist=b` the second filter would overwrite the second, but in
those cases the query is against a single field, so attempting to put
multiple search criteria in conjunction on a single field is kind of
nonsensical, so it was sort of fine to do that.
Which is not the case for user tags, which are multi-valued.
Because of greedy matching, a filter of
tag="style/clean"! tag="song representation/simple"!
would not parse into 2 separate filters like
(tag, =, "style/clean"!)
(tag, =, "song representation/simple"!)
but rather a single one like
(tag, =, "style/clean"! tag="song representation/simple"!)
This sort of matches what web did in
https://github.com/ppy/osu-web/pull/12044, except web does some stuff
with quote escaping that I'd rather not, and also the search syntax
seems to slightly deviate because web seems to be using single quotes
and double quotes to open the value part of the filter. I'm not sure
what the difference is and I'd rather not go into all that right now.
As indicated in the inline comment this is very best effort, just to
make the HP bar not very obviously stuck in a very obviously incorrect
state after the replay is rewound from a failure. There's likely to be a
bunch of replay accuracy issues related to this, but I'm just making the
minimum effort to get this to work semi-acceptably for now.
This indicator allows the player to either rewind to an earlier part of
the replay, or to proceed to results. It also plays a shortened variant
of the failure animation SFX.
Before this commit, there was `AllowFailAnimation` (used by multiplayer)
and `OnFail()` (used by score submitting implementations of player to
ensure a failed play submits).
The former is replaced by `PerformFail()` which allows for arbitrary
operations on failure, which replay player shall leverage in subsequent
commits. The latter would ideally be replaced by nothing, but it's
placed in a very awkward place behind a schedule, so by force of
necessity to avoid code duplication it's replaced by
`ConcludeFailedScore()` which is overridden to submit the score in all
submitting players --- except for multiplayer, which is never supposed
to be calling it, so in that case it just throws an exception.