1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 05:22:54 +08:00

Fix incorrect accuracy and rank population when decoding lazer replays

Closes https://github.com/ppy/osu/issues/24061.

The gist of this change is that if the `LegacyReplaySoloScoreInfo`
bolt-on is present in the replay, then it can (and is) used to recompute
the accuracy, and rank is computed based on that.

This was the missing part of
https://github.com/ppy/osu/issues/24061#issuecomment-1888438151.
The accuracy would change on import before that because the encode
process is _lossy_ if the `LegacyReplaySoloScoreInfo` bolt-on is not
used, as the legacy format only has 6 fields for encoding judgement
counts, and some judgements that affect accuracy in lazer do not fit
into that.

Note that this _only_ fixes _relatively_ new lazer scores looking wrong
after reimport.

- Very old lazer scores, i.e. ones that don't have the
  `LegacyReplaySoloScoreInfo` bolt-on, obviously can't use it
  to repopulate. There's really not much good that can be done there,
  so the stable pathways are used as a fallback that always works.

- For stable replays, `ScoreImporter` recalculates the accuracy of
  the score _again_ in

  15a5fd7e4c/osu.Game/Scoring/ScoreImporter.cs (L106-L110)

  as `StandardisedScoreMigrationTools.UpdateFromLegacy()` recomputes
  _both_ total score and accuracy.

  This makes a _semblance_ of sense as it attempts to make the accuracy
  of stable and lazer replays comparable. In most cases it also won't
  matter, as the only ruleset where accuracy changed between the legacy
  implementation and current lazer accuracy is mania.

  But it is also an inaccurate process (as, again, some of the required
  data is not in the replay, namely judgement counts of ticks
  and so on).

  For whatever's worth, a similar thing happens server-side in

  106c2948db/osu.Server.Queues.ScoreStatisticsProcessor/Commands/Queue/BatchInserter.cs (L319)

- However, _ranks_ of stable scores will still use the local stable
  reimplementation of ranks, i.e. a 1-miss stable score in osu! ruleset
  will be an A rather than an S. See importer:

  106c2948db/osu.Server.Queues.ScoreStatisticsProcessor/Commands/Queue/BatchInserter.cs (L237)

  (it's the same method which is renamed
  to `PopulateLegacyAccuracyAndRank()` in this commit).

  That is all a bit of a mess honestly, but I'm not sure where to even
  begin there...
This commit is contained in:
Bartłomiej Dach 2024-01-16 21:08:02 +01:00
parent 1075b87fb8
commit 17b9d842ab
No known key found for this signature in database

View File

@ -11,6 +11,7 @@ using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Database;
using osu.Game.IO.Legacy;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Replays;
@ -37,6 +38,7 @@ namespace osu.Game.Scoring.Legacy
};
WorkingBeatmap workingBeatmap;
byte[] compressedScoreInfo = null;
using (SerializationReader sr = new SerializationReader(stream))
{
@ -105,8 +107,6 @@ namespace osu.Game.Scoring.Legacy
else if (version >= 20121008)
scoreInfo.LegacyOnlineID = sr.ReadInt32();
byte[] compressedScoreInfo = null;
if (version >= 30000001)
compressedScoreInfo = sr.ReadByteArray();
@ -130,7 +130,10 @@ namespace osu.Game.Scoring.Legacy
}
}
PopulateAccuracy(score.ScoreInfo);
if (score.ScoreInfo.IsLegacyScore || compressedScoreInfo == null)
PopulateLegacyAccuracyAndRank(score.ScoreInfo);
else
populateLazerAccuracyAndRank(score.ScoreInfo);
// before returning for database import, we must restore the database-sourced BeatmapInfo.
// if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception.
@ -174,7 +177,7 @@ namespace osu.Game.Scoring.Legacy
/// Legacy use only.
/// </remarks>
/// <param name="score">The <see cref="ScoreInfo"/> to populate.</param>
public static void PopulateAccuracy(ScoreInfo score)
public static void PopulateLegacyAccuracyAndRank(ScoreInfo score)
{
int countMiss = score.GetCountMiss() ?? 0;
int count50 = score.GetCount50() ?? 0;
@ -273,6 +276,18 @@ namespace osu.Game.Scoring.Legacy
}
}
private void populateLazerAccuracyAndRank(ScoreInfo scoreInfo)
{
scoreInfo.Accuracy = StandardisedScoreMigrationTools.ComputeAccuracy(scoreInfo);
var rank = currentRuleset.CreateScoreProcessor().RankFromAccuracy(scoreInfo.Accuracy);
foreach (var mod in scoreInfo.Mods.OfType<IApplicableToScoreProcessor>())
rank = mod.AdjustRank(rank, scoreInfo.Accuracy);
scoreInfo.Rank = rank;
}
private void readLegacyReplay(Replay replay, StreamReader reader)
{
float lastTime = beatmapOffset;