1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 09:27:29 +08:00

Scoring : Implement v1 to v3 conversion.

This commit is contained in:
Zyf 2023-07-15 23:20:49 +02:00
parent ecb633f8fb
commit b672b49e02
4 changed files with 92 additions and 9 deletions

View File

@ -20,9 +20,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty
public int ComboScore { get; private set; }
public double BonusScoreRatio => legacyBonusScore == 0 ? 0 : (double)modernBonusScore / legacyBonusScore;
public int LegacyBonusScore { get; private set; }
public int MaxCombo { get; private set; }
public double BonusScoreRatio => LegacyBonusScore == 0 ? 0 : (double)modernBonusScore / LegacyBonusScore;
private int legacyBonusScore;
private int modernBonusScore;
private int combo;
@ -77,6 +80,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
foreach (var obj in playableBeatmap.HitObjects)
simulateHit(obj);
MaxCombo = combo;
}
private void simulateHit(HitObject hitObject)
@ -164,7 +168,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (isBonus)
{
legacyBonusScore += scoreIncrease;
LegacyBonusScore += scoreIncrease;
modernBonusScore += Judgement.ToNumericResult(bonusResult);
}
else

View File

@ -218,7 +218,9 @@ namespace osu.Game.Database
{
LegacyAccuracyScore = sv1Simulator.AccuracyScore,
LegacyComboScore = sv1Simulator.ComboScore,
LegacyBonusScoreRatio = sv1Simulator.BonusScoreRatio
LegacyBonusScoreRatio = sv1Simulator.BonusScoreRatio,
LegacyBonusScore = sv1Simulator.LegacyBonusScore,
LegacyMaxCombo = sv1Simulator.MaxCombo,
});
}
@ -240,13 +242,16 @@ namespace osu.Game.Database
int maximumLegacyAccuracyScore = attributes.LegacyAccuracyScore;
int maximumLegacyComboScore = attributes.LegacyComboScore;
double maximumLegacyBonusRatio = attributes.LegacyBonusScoreRatio;
int maximumLegacyBonusScore = attributes.LegacyBonusScore;
int maximumLegacyCombo = attributes.LegacyMaxCombo;
double modMultiplier = score.Mods.Select(m => m.ScoreMultiplier).Aggregate(1.0, (c, n) => c * n);
// The part of total score that doesn't include bonus.
int maximumLegacyBaseScore = maximumLegacyAccuracyScore + maximumLegacyComboScore;
int maximumLegacyTotalScore = maximumLegacyBaseScore + maximumLegacyBonusScore;
// The combo proportion is calculated as a proportion of maximumLegacyBaseScore.
double comboProportion = Math.Min(1, (double)score.LegacyTotalScore / maximumLegacyBaseScore);
// The combo proportion is calculated as a proportion of maximumLegacyTotalScore.
double comboProportion = (double)score.LegacyTotalScore / maximumLegacyTotalScore;
// The bonus proportion makes up the rest of the score that exceeds maximumLegacyBaseScore.
double bonusProportion = Math.Max(0, ((long)score.LegacyTotalScore - maximumLegacyBaseScore) * maximumLegacyBonusRatio);
@ -254,9 +259,63 @@ namespace osu.Game.Database
switch (score.Ruleset.OnlineID)
{
case 0:
if(score.MaxCombo == 0 || score.Accuracy == 0)
return (long)Math.Round((
0
+ 300000 * Math.Pow(score.Accuracy, 8)
+ bonusProportion) * modMultiplier);
double v3exp = 0.5; // Scorev3 combo exponent
// Assumption :
// - sliders and slider-ticks are uniformly spread arround the beatmap
// thus we can ignore them without losing much precision (consider a map of hit-circles only !)
// - the Ok/Meh hit results are uniformly spread in the score
// thus we can simplify and consider each hit result to be score.Accuracy without losing much precision
// What is strippedV1/strippedV3 :
// This is the ComboScore of v1/v3 were we remove all (map-)constant multipliers and accuracy multipliers (including hit results),
// based on the previous assumptions. For Scorev1, this is basically the sum of squared combos (because without sliders: object_count == combo).
double maxStrippedV1 = Math.Pow(maximumLegacyCombo, 2);
double maxStrippedV3 = Math.Pow(maximumLegacyCombo, 1 + v3exp);
double strippedV1 = maxStrippedV1 * comboProportion / score.Accuracy;
double strippedV1FromMaxCombo = Math.Pow(score.MaxCombo, 2);
double strippedV3FromMaxCombo = Math.Pow(score.MaxCombo, 1 + v3exp);
// Compute approximate lower estimate scorev3 for that play
// That is, a play were we made biggest amount of big combos (Repeat MaxCombo + 1 remaining big combo)
// And didn't combo anything in the reminder of the map
double possibleMaxComboRepeat = Math.Floor(strippedV1 / strippedV1FromMaxCombo);
double strippedV1FromMaxComboRepeat = possibleMaxComboRepeat * strippedV1FromMaxCombo;
double remainingStrippedV1 = strippedV1 - strippedV1FromMaxComboRepeat;
double remainingCombo = Math.Sqrt(remainingStrippedV1);
double remainingStrippedV3 = Math.Pow(remainingCombo, 1 + v3exp);
double newLowerStrippedV3 = (possibleMaxComboRepeat * strippedV3FromMaxCombo) + remainingStrippedV3;
// Compute approximate upper estimate scorev3 for that play
// That is, a play were all combos were equal (except MaxCombo)
remainingStrippedV1 = strippedV1 - strippedV1FromMaxCombo;
double remainingComboObjects = maximumLegacyCombo - score.MaxCombo - score.Statistics[HitResult.Miss];
double remainingAverageCombo = remainingComboObjects > 0 ? remainingStrippedV1 / remainingComboObjects : 0;
remainingStrippedV3 = remainingComboObjects * Math.Pow(remainingAverageCombo, v3exp);
double newUpperStrippedV3 = strippedV3FromMaxCombo + remainingStrippedV3;
// Approximate by combining lower and upper estimates
// As the lower-estimate is very pessimistic, we use a 30/70 ratio
// And cap it with 1.2 times the middle-point to avoid overstimates
double strippedV3 = Math.Min(
0.3 * newLowerStrippedV3 + 0.7 * newUpperStrippedV3,
1.2 * (newLowerStrippedV3 + newUpperStrippedV3) / 2
);
double newComboScoreProportion = (strippedV3 / maxStrippedV3) * score.Accuracy;
return (long)Math.Round((
700000 * comboProportion
+ 300000 * Math.Pow(score.Accuracy, 10)
700000 * newComboScoreProportion * score.Accuracy
+ 300000 * Math.Pow(score.Accuracy, 8)
+ bonusProportion) * modMultiplier);
case 1:

View File

@ -64,6 +64,16 @@ namespace osu.Game.Rulesets.Difficulty
/// </summary>
public double LegacyBonusScoreRatio { get; set; }
/// <summary>
/// The bonus portion of the legacy (ScoreV1) total score.
/// </summary>
public int LegacyBonusScore { get; set; }
/// <summary>
/// The maximum combo of the legacy (ScoreV1) total score.
/// </summary>
public int LegacyMaxCombo { get; set; }
/// <summary>
/// Creates new <see cref="DifficultyAttributes"/>.
/// </summary>

View File

@ -23,9 +23,19 @@ namespace osu.Game.Rulesets.Scoring
int ComboScore { get; }
/// <summary>
/// A ratio of <c>new_bonus_score / old_bonus_score</c> for converting the bonus score of legacy scores to the new scoring.
/// The bonus portion of the legacy (ScoreV1) total score.
/// This is made up of all judgements that would be <see cref="HitResult.SmallBonus"/> or <see cref="HitResult.LargeBonus"/>.
/// </summary>
int LegacyBonusScore { get; }
/// <summary>
/// The maximum combo of the legacy (ScoreV1) total score.
/// </summary>
int MaxCombo { get; }
/// <summary>
/// A ratio of <c>new_bonus_score / old_bonus_score</c> for converting the bonus score of legacy scores to the new scoring.
/// </summary>
double BonusScoreRatio { get; }
/// <summary>