1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 03:15:36 +08:00

Merge pull request #28277 from bdach/total-score-without-mods-once-more

Compute total score without mods during standardised score conversion
This commit is contained in:
Dan Balasescu 2024-05-28 07:49:27 +09:00 committed by GitHub
commit e2b4e25ffa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -16,7 +16,6 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Scoring.Legacy; using osu.Game.Rulesets.Scoring.Legacy;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;
namespace osu.Game.Database namespace osu.Game.Database
{ {
@ -248,8 +247,7 @@ namespace osu.Game.Database
// warning: ordering is important here - both total score and ranks are dependent on accuracy! // warning: ordering is important here - both total score and ranks are dependent on accuracy!
score.Accuracy = computeAccuracy(score, scoreProcessor); score.Accuracy = computeAccuracy(score, scoreProcessor);
score.Rank = computeRank(score, scoreProcessor); score.Rank = computeRank(score, scoreProcessor);
score.TotalScore = convertFromLegacyTotalScore(score, ruleset, beatmap); (score.TotalScoreWithoutMods, score.TotalScore) = convertFromLegacyTotalScore(score, ruleset, beatmap);
LegacyScoreDecoder.PopulateTotalScoreWithoutMods(score);
} }
/// <summary> /// <summary>
@ -273,7 +271,7 @@ namespace osu.Game.Database
// warning: ordering is important here - both total score and ranks are dependent on accuracy! // warning: ordering is important here - both total score and ranks are dependent on accuracy!
score.Accuracy = computeAccuracy(score, scoreProcessor); score.Accuracy = computeAccuracy(score, scoreProcessor);
score.Rank = computeRank(score, scoreProcessor); score.Rank = computeRank(score, scoreProcessor);
score.TotalScore = convertFromLegacyTotalScore(score, ruleset, difficulty, attributes); (score.TotalScoreWithoutMods, score.TotalScore) = convertFromLegacyTotalScore(score, ruleset, difficulty, attributes);
} }
/// <summary> /// <summary>
@ -283,17 +281,13 @@ namespace osu.Game.Database
/// <param name="ruleset">The <see cref="Ruleset"/> in which the score was set.</param> /// <param name="ruleset">The <see cref="Ruleset"/> in which the score was set.</param>
/// <param name="beatmap">The <see cref="WorkingBeatmap"/> applicable for this score.</param> /// <param name="beatmap">The <see cref="WorkingBeatmap"/> applicable for this score.</param>
/// <returns>The standardised total score.</returns> /// <returns>The standardised total score.</returns>
private static long convertFromLegacyTotalScore(ScoreInfo score, Ruleset ruleset, WorkingBeatmap beatmap) private static (long withoutMods, long withMods) convertFromLegacyTotalScore(ScoreInfo score, Ruleset ruleset, WorkingBeatmap beatmap)
{ {
if (!score.IsLegacyScore) if (!score.IsLegacyScore)
return score.TotalScore; return (score.TotalScoreWithoutMods, score.TotalScore);
if (ruleset is not ILegacyRuleset legacyRuleset) if (ruleset is not ILegacyRuleset legacyRuleset)
return score.TotalScore; return (score.TotalScoreWithoutMods, score.TotalScore);
var mods = score.Mods;
if (mods.Any(mod => mod is ModScoreV2))
return score.TotalScore;
var playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods); var playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods);
@ -302,8 +296,13 @@ namespace osu.Game.Database
ILegacyScoreSimulator sv1Simulator = legacyRuleset.CreateLegacyScoreSimulator(); ILegacyScoreSimulator sv1Simulator = legacyRuleset.CreateLegacyScoreSimulator();
LegacyScoreAttributes attributes = sv1Simulator.Simulate(beatmap, playableBeatmap); LegacyScoreAttributes attributes = sv1Simulator.Simulate(beatmap, playableBeatmap);
var legacyBeatmapConversionDifficultyInfo = LegacyBeatmapConversionDifficultyInfo.FromBeatmap(beatmap.Beatmap);
return convertFromLegacyTotalScore(score, ruleset, LegacyBeatmapConversionDifficultyInfo.FromBeatmap(beatmap.Beatmap), attributes); var mods = score.Mods;
if (mods.Any(mod => mod is ModScoreV2))
return ((long)Math.Round(score.TotalScore / sv1Simulator.GetLegacyScoreMultiplier(mods, legacyBeatmapConversionDifficultyInfo)), score.TotalScore);
return convertFromLegacyTotalScore(score, ruleset, legacyBeatmapConversionDifficultyInfo, attributes);
} }
/// <summary> /// <summary>
@ -314,15 +313,15 @@ namespace osu.Game.Database
/// <param name="difficulty">The beatmap difficulty.</param> /// <param name="difficulty">The beatmap difficulty.</param>
/// <param name="attributes">The legacy scoring attributes for the beatmap which the score was set on.</param> /// <param name="attributes">The legacy scoring attributes for the beatmap which the score was set on.</param>
/// <returns>The standardised total score.</returns> /// <returns>The standardised total score.</returns>
private static long convertFromLegacyTotalScore(ScoreInfo score, Ruleset ruleset, LegacyBeatmapConversionDifficultyInfo difficulty, LegacyScoreAttributes attributes) private static (long withoutMods, long withMods) convertFromLegacyTotalScore(ScoreInfo score, Ruleset ruleset, LegacyBeatmapConversionDifficultyInfo difficulty, LegacyScoreAttributes attributes)
{ {
if (!score.IsLegacyScore) if (!score.IsLegacyScore)
return score.TotalScore; return (score.TotalScoreWithoutMods, score.TotalScore);
Debug.Assert(score.LegacyTotalScore != null); Debug.Assert(score.LegacyTotalScore != null);
if (ruleset is not ILegacyRuleset legacyRuleset) if (ruleset is not ILegacyRuleset legacyRuleset)
return score.TotalScore; return (score.TotalScoreWithoutMods, score.TotalScore);
double legacyModMultiplier = legacyRuleset.CreateLegacyScoreSimulator().GetLegacyScoreMultiplier(score.Mods, difficulty); double legacyModMultiplier = legacyRuleset.CreateLegacyScoreSimulator().GetLegacyScoreMultiplier(score.Mods, difficulty);
int maximumLegacyAccuracyScore = attributes.AccuracyScore; int maximumLegacyAccuracyScore = attributes.AccuracyScore;
@ -354,17 +353,18 @@ namespace osu.Game.Database
double modMultiplier = score.Mods.Select(m => m.ScoreMultiplier).Aggregate(1.0, (c, n) => c * n); double modMultiplier = score.Mods.Select(m => m.ScoreMultiplier).Aggregate(1.0, (c, n) => c * n);
long convertedTotalScore; long convertedTotalScoreWithoutMods;
switch (score.Ruleset.OnlineID) switch (score.Ruleset.OnlineID)
{ {
case 0: case 0:
if (score.MaxCombo == 0 || score.Accuracy == 0) if (score.MaxCombo == 0 || score.Accuracy == 0)
{ {
return (long)Math.Round(( convertedTotalScoreWithoutMods = (long)Math.Round(
0 0
+ 500000 * Math.Pow(score.Accuracy, 5) + 500000 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier); + bonusProportion);
break;
} }
// see similar check above. // see similar check above.
@ -372,10 +372,11 @@ namespace osu.Game.Database
// are either pointless or wildly wrong. // are either pointless or wildly wrong.
if (maximumLegacyComboScore + maximumLegacyBonusScore == 0) if (maximumLegacyComboScore + maximumLegacyBonusScore == 0)
{ {
return (long)Math.Round(( convertedTotalScoreWithoutMods = (long)Math.Round(
500000 * comboProportion // as above, zero if mods result in zero multiplier, one otherwise 500000 * comboProportion // as above, zero if mods result in zero multiplier, one otherwise
+ 500000 * Math.Pow(score.Accuracy, 5) + 500000 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier); + bonusProportion);
break;
} }
// Assumptions: // Assumptions:
@ -472,17 +473,17 @@ namespace osu.Game.Database
double newComboScoreProportion = estimatedComboPortionInStandardisedScore / maximumAchievableComboPortionInStandardisedScore; double newComboScoreProportion = estimatedComboPortionInStandardisedScore / maximumAchievableComboPortionInStandardisedScore;
convertedTotalScore = (long)Math.Round(( convertedTotalScoreWithoutMods = (long)Math.Round(
500000 * newComboScoreProportion * score.Accuracy 500000 * newComboScoreProportion * score.Accuracy
+ 500000 * Math.Pow(score.Accuracy, 5) + 500000 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier); + bonusProportion);
break; break;
case 1: case 1:
convertedTotalScore = (long)Math.Round(( convertedTotalScoreWithoutMods = (long)Math.Round(
250000 * comboProportion 250000 * comboProportion
+ 750000 * Math.Pow(score.Accuracy, 3.6) + 750000 * Math.Pow(score.Accuracy, 3.6)
+ bonusProportion) * modMultiplier); + bonusProportion);
break; break;
case 2: case 2:
@ -507,28 +508,28 @@ namespace osu.Game.Database
? 0 ? 0
: (double)score.Statistics.GetValueOrDefault(HitResult.SmallTickHit) / score.MaximumStatistics.GetValueOrDefault(HitResult.SmallTickHit); : (double)score.Statistics.GetValueOrDefault(HitResult.SmallTickHit) / score.MaximumStatistics.GetValueOrDefault(HitResult.SmallTickHit);
convertedTotalScore = (long)Math.Round(( convertedTotalScoreWithoutMods = (long)Math.Round(
comboPortion * estimateComboProportionForCatch(attributes.MaxCombo, score.MaxCombo, score.Statistics.GetValueOrDefault(HitResult.Miss)) comboPortion * estimateComboProportionForCatch(attributes.MaxCombo, score.MaxCombo, score.Statistics.GetValueOrDefault(HitResult.Miss))
+ dropletsPortion * dropletsHit + dropletsPortion * dropletsHit
+ bonusProportion) * modMultiplier); + bonusProportion);
break; break;
case 3: case 3:
convertedTotalScore = (long)Math.Round(( convertedTotalScoreWithoutMods = (long)Math.Round(
850000 * comboProportion 850000 * comboProportion
+ 150000 * Math.Pow(score.Accuracy, 2 + 2 * score.Accuracy) + 150000 * Math.Pow(score.Accuracy, 2 + 2 * score.Accuracy)
+ bonusProportion) * modMultiplier); + bonusProportion);
break; break;
default: default:
convertedTotalScore = score.TotalScore; return (score.TotalScoreWithoutMods, score.TotalScore);
break;
} }
if (convertedTotalScore < 0) if (convertedTotalScoreWithoutMods < 0)
throw new InvalidOperationException($"Total score conversion operation returned invalid total of {convertedTotalScore}"); throw new InvalidOperationException($"Total score conversion operation returned invalid total of {convertedTotalScoreWithoutMods}");
return convertedTotalScore; long convertedTotalScore = (long)Math.Round(convertedTotalScoreWithoutMods * modMultiplier);
return (convertedTotalScoreWithoutMods, convertedTotalScore);
} }
/// <summary> /// <summary>