1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 05:22:54 +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.Legacy;
using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;
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!
score.Accuracy = computeAccuracy(score, scoreProcessor);
score.Rank = computeRank(score, scoreProcessor);
score.TotalScore = convertFromLegacyTotalScore(score, ruleset, beatmap);
LegacyScoreDecoder.PopulateTotalScoreWithoutMods(score);
(score.TotalScoreWithoutMods, score.TotalScore) = convertFromLegacyTotalScore(score, ruleset, beatmap);
}
/// <summary>
@ -273,7 +271,7 @@ namespace osu.Game.Database
// warning: ordering is important here - both total score and ranks are dependent on accuracy!
score.Accuracy = computeAccuracy(score, scoreProcessor);
score.Rank = computeRank(score, scoreProcessor);
score.TotalScore = convertFromLegacyTotalScore(score, ruleset, difficulty, attributes);
(score.TotalScoreWithoutMods, score.TotalScore) = convertFromLegacyTotalScore(score, ruleset, difficulty, attributes);
}
/// <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="beatmap">The <see cref="WorkingBeatmap"/> applicable for this score.</param>
/// <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)
return score.TotalScore;
return (score.TotalScoreWithoutMods, score.TotalScore);
if (ruleset is not ILegacyRuleset legacyRuleset)
return score.TotalScore;
var mods = score.Mods;
if (mods.Any(mod => mod is ModScoreV2))
return score.TotalScore;
return (score.TotalScoreWithoutMods, score.TotalScore);
var playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods);
@ -302,8 +296,13 @@ namespace osu.Game.Database
ILegacyScoreSimulator sv1Simulator = legacyRuleset.CreateLegacyScoreSimulator();
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>
@ -314,15 +313,15 @@ namespace osu.Game.Database
/// <param name="difficulty">The beatmap difficulty.</param>
/// <param name="attributes">The legacy scoring attributes for the beatmap which the score was set on.</param>
/// <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)
return score.TotalScore;
return (score.TotalScoreWithoutMods, score.TotalScore);
Debug.Assert(score.LegacyTotalScore != null);
if (ruleset is not ILegacyRuleset legacyRuleset)
return score.TotalScore;
return (score.TotalScoreWithoutMods, score.TotalScore);
double legacyModMultiplier = legacyRuleset.CreateLegacyScoreSimulator().GetLegacyScoreMultiplier(score.Mods, difficulty);
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);
long convertedTotalScore;
long convertedTotalScoreWithoutMods;
switch (score.Ruleset.OnlineID)
{
case 0:
if (score.MaxCombo == 0 || score.Accuracy == 0)
{
return (long)Math.Round((
convertedTotalScoreWithoutMods = (long)Math.Round(
0
+ 500000 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier);
+ bonusProportion);
break;
}
// see similar check above.
@ -372,10 +372,11 @@ namespace osu.Game.Database
// are either pointless or wildly wrong.
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 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier);
+ bonusProportion);
break;
}
// Assumptions:
@ -472,17 +473,17 @@ namespace osu.Game.Database
double newComboScoreProportion = estimatedComboPortionInStandardisedScore / maximumAchievableComboPortionInStandardisedScore;
convertedTotalScore = (long)Math.Round((
convertedTotalScoreWithoutMods = (long)Math.Round(
500000 * newComboScoreProportion * score.Accuracy
+ 500000 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier);
+ bonusProportion);
break;
case 1:
convertedTotalScore = (long)Math.Round((
convertedTotalScoreWithoutMods = (long)Math.Round(
250000 * comboProportion
+ 750000 * Math.Pow(score.Accuracy, 3.6)
+ bonusProportion) * modMultiplier);
+ bonusProportion);
break;
case 2:
@ -507,28 +508,28 @@ namespace osu.Game.Database
? 0
: (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))
+ dropletsPortion * dropletsHit
+ bonusProportion) * modMultiplier);
+ bonusProportion);
break;
case 3:
convertedTotalScore = (long)Math.Round((
convertedTotalScoreWithoutMods = (long)Math.Round(
850000 * comboProportion
+ 150000 * Math.Pow(score.Accuracy, 2 + 2 * score.Accuracy)
+ bonusProportion) * modMultiplier);
+ bonusProportion);
break;
default:
convertedTotalScore = score.TotalScore;
break;
return (score.TotalScoreWithoutMods, score.TotalScore);
}
if (convertedTotalScore < 0)
throw new InvalidOperationException($"Total score conversion operation returned invalid total of {convertedTotalScore}");
if (convertedTotalScoreWithoutMods < 0)
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>