mirror of
https://github.com/ppy/osu.git
synced 2025-02-15 16:22:55 +08:00
Merge pull request #25876 from bdach/fix-standardised-score-conversion
Fix osu! standardised score conversion sometimes exceeding bounds
This commit is contained in:
commit
72274041eb
@ -127,8 +127,11 @@ namespace osu.Game.Tests.Database
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(30000001)]
|
||||||
[TestCase(30000002)]
|
[TestCase(30000002)]
|
||||||
[TestCase(30000003)]
|
[TestCase(30000003)]
|
||||||
|
[TestCase(30000004)]
|
||||||
|
[TestCase(30000005)]
|
||||||
public void TestScoreUpgradeSuccess(int scoreVersion)
|
public void TestScoreUpgradeSuccess(int scoreVersion)
|
||||||
{
|
{
|
||||||
ScoreInfo scoreInfo = null!;
|
ScoreInfo scoreInfo = null!;
|
||||||
|
@ -316,8 +316,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
HashSet<Guid> scoreIds = realmAccess.Run(r => new HashSet<Guid>(r.All<ScoreInfo>()
|
HashSet<Guid> scoreIds = realmAccess.Run(r => new HashSet<Guid>(r.All<ScoreInfo>()
|
||||||
.Where(s => !s.BackgroundReprocessingFailed && s.BeatmapInfo != null
|
.Where(s => !s.BackgroundReprocessingFailed && s.BeatmapInfo != null
|
||||||
&& (s.TotalScoreVersion == 30000002
|
&& s.TotalScoreVersion < LegacyScoreEncoder.LATEST_VERSION)
|
||||||
|| s.TotalScoreVersion == 30000003))
|
|
||||||
.AsEnumerable().Select(s => s.ID)));
|
.AsEnumerable().Select(s => s.ID)));
|
||||||
|
|
||||||
Logger.Log($"Found {scoreIds.Count} scores which require total score conversion.");
|
Logger.Log($"Found {scoreIds.Count} scores which require total score conversion.");
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Database
|
|||||||
if (score.IsLegacyScore)
|
if (score.IsLegacyScore)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (score.TotalScoreVersion > 30000004)
|
if (score.TotalScoreVersion > 30000002)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Recalculate the old-style standardised score to see if this was an old lazer score.
|
// Recalculate the old-style standardised score to see if this was an old lazer score.
|
||||||
@ -293,13 +293,23 @@ namespace osu.Game.Database
|
|||||||
// Roughly corresponds to integrating f(combo) = combo ^ COMBO_EXPONENT (omitting constants)
|
// Roughly corresponds to integrating f(combo) = combo ^ COMBO_EXPONENT (omitting constants)
|
||||||
double maximumAchievableComboPortionInStandardisedScore = Math.Pow(maximumLegacyCombo, 1 + ScoreProcessor.COMBO_EXPONENT);
|
double maximumAchievableComboPortionInStandardisedScore = Math.Pow(maximumLegacyCombo, 1 + ScoreProcessor.COMBO_EXPONENT);
|
||||||
|
|
||||||
double comboPortionInScoreV1 = maximumAchievableComboPortionInScoreV1 * comboProportion / score.Accuracy;
|
|
||||||
|
|
||||||
// This is - roughly - how much score, in the combo portion, the longest combo on this particular play would gain in score V1.
|
// This is - roughly - how much score, in the combo portion, the longest combo on this particular play would gain in score V1.
|
||||||
double comboPortionFromLongestComboInScoreV1 = Math.Pow(score.MaxCombo, 2);
|
double comboPortionFromLongestComboInScoreV1 = Math.Pow(score.MaxCombo, 2);
|
||||||
// Same for standardised score.
|
// Same for standardised score.
|
||||||
double comboPortionFromLongestComboInStandardisedScore = Math.Pow(score.MaxCombo, 1 + ScoreProcessor.COMBO_EXPONENT);
|
double comboPortionFromLongestComboInStandardisedScore = Math.Pow(score.MaxCombo, 1 + ScoreProcessor.COMBO_EXPONENT);
|
||||||
|
|
||||||
|
// We estimate the combo portion of the score in score V1 terms.
|
||||||
|
// The division by accuracy is supposed to lessen the impact of accuracy on the combo portion,
|
||||||
|
// but in some edge cases it cannot sanely undo it.
|
||||||
|
// Therefore the resultant value is clamped from both sides for sanity.
|
||||||
|
// The clamp from below to `comboPortionFromLongestComboInScoreV1` targets near-FC scores wherein
|
||||||
|
// the player had bad accuracy at the end of their longest combo, which causes the division by accuracy
|
||||||
|
// to underestimate the combo portion.
|
||||||
|
// Ideally, this would be clamped from above to `maximumAchievableComboPortionInScoreV1` too,
|
||||||
|
// but in practice this appears to fail for some scores (https://github.com/ppy/osu/pull/25876#issuecomment-1862248413).
|
||||||
|
// TODO: investigate the above more closely
|
||||||
|
double comboPortionInScoreV1 = Math.Max(maximumAchievableComboPortionInScoreV1 * comboProportion / score.Accuracy, comboPortionFromLongestComboInScoreV1);
|
||||||
|
|
||||||
// Calculate how many times the longest combo the user has achieved in the play can repeat
|
// Calculate how many times the longest combo the user has achieved in the play can repeat
|
||||||
// without exceeding the combo portion in score V1 as achieved by the player.
|
// without exceeding the combo portion in score V1 as achieved by the player.
|
||||||
// This is a pessimistic estimate; it intentionally does not operate on object count and uses only score instead.
|
// This is a pessimistic estimate; it intentionally does not operate on object count and uses only score instead.
|
||||||
|
@ -32,9 +32,10 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
/// <item><description>30000003: First version after converting legacy total score to standardised.</description></item>
|
/// <item><description>30000003: First version after converting legacy total score to standardised.</description></item>
|
||||||
/// <item><description>30000004: Fixed mod multipliers during legacy score conversion. Reconvert all scores.</description></item>
|
/// <item><description>30000004: Fixed mod multipliers during legacy score conversion. Reconvert all scores.</description></item>
|
||||||
/// <item><description>30000005: Introduce combo exponent in the osu! gamemode. Reconvert all scores.</description></item>
|
/// <item><description>30000005: Introduce combo exponent in the osu! gamemode. Reconvert all scores.</description></item>
|
||||||
|
/// <item><description>30000006: Fix edge cases in conversion after combo exponent introduction that lead to NaNs. Reconvert all scores.</description></item>
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public const int LATEST_VERSION = 30000005;
|
public const int LATEST_VERSION = 30000006;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The first stable-compatible YYYYMMDD format version given to lazer usage of replays.
|
/// The first stable-compatible YYYYMMDD format version given to lazer usage of replays.
|
||||||
|
Loading…
Reference in New Issue
Block a user