1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 10:33:30 +08:00

Fix Score V1 simulation in scoring test scene incorrectly applying multiplier

`TestSceneScoring` included a local simulation of stable's Score V1
algorithm. One of the parts of said algorithm is a mysterious
"score multiplier", influenced by - among others - the beatmap's drain
rate, overall difficulty, circle size, object count, drain length,
and active mods. (An implementation of this already exists in lazer
source, in `OsuLegacyScoreSimulator`, but more on this later.)

However, `TestSceneScoring` had this multiplier in _two_ places, with
_two_ distinct values, one of which being 1 (i.e. basically off).
Unfortunately, the place that had 1 as the multiplier was the wrong one.

Stable calculates the score increase for every hit in two stages;
first, it takes the raw numerical value of the judgement, but then
applies a combo-based bonus on top of it:

    scoreIncrease += (int)(Math.Max(0, ComboCounter.HitCombo - 1) * (scoreIncrease / 25 * ScoreMultiplier));

On the face of it, it may appear that the `ScoreMultiplier` factor
can be factored out and applied at the end only when returning total
score. However, once the above formula is rewritten as:

    scoreIncrease = scoreIncrease + (int)(Math.Max(0, ComboCounter.HitCombo - 1) * (scoreIncrease / 25 * ScoreMultiplier));
                  = scoreIncrease * (1 + (Math.Max(0, ComboCounter.HitCombo - 1) / 25 * ScoreMultiplier))

it becomes clear that that assumption is actually _incorrect_,
and the `ScoreMultiplier` _must_ be applied to every score increase
individually.

The above was cross-checked experimentally against stable source
on an example test map with 100 objects, and a replay hitting them
perfectly.
This commit is contained in:
Bartłomiej Dach 2023-09-12 20:31:49 +02:00
parent 2bc6759704
commit 7c65a9de75
No known key found for this signature in database

View File

@ -190,7 +190,9 @@ namespace osu.Game.Tests.Visual.Gameplay
return;
}
const float score_multiplier = 1;
// this corresponds to stable's `ScoreMultiplier`.
// value is chosen arbitrarily, towards the upper range.
const float score_multiplier = 4;
totalScore += baseScore;
@ -208,13 +210,7 @@ namespace osu.Game.Tests.Visual.Gameplay
ApplyHit = () => applyHitV1(base_great),
ApplyNonPerfect = () => applyHitV1(base_ok),
ApplyMiss = () => applyHitV1(0),
GetTotalScore = () =>
{
// Arbitrary value chosen towards the upper range.
const double score_multiplier = 4;
return (int)(totalScore * score_multiplier);
},
GetTotalScore = () => totalScore,
Visible = scoreV1Visible
});
}