mirror of
https://github.com/ppy/osu.git
synced 2024-11-13 16:13:34 +08:00
Merge pull request #26471 from bdach/fix-incorrect-difficulty-peppy-stars
Fix incorrect score conversion on selected beatmaps due to incorrect `difficultyPeppyStars` rounding
This commit is contained in:
commit
02975b9498
@ -10,6 +10,7 @@ using osu.Game.Rulesets.Catch.Objects;
|
||||
using osu.Game.Rulesets.Catch.Scoring;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Scoring.Legacy;
|
||||
@ -62,13 +63,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
drainLength = ((int)Math.Round(baseBeatmap.HitObjects[^1].StartTime) - (int)Math.Round(baseBeatmap.HitObjects[0].StartTime) - breakLength) / 1000;
|
||||
}
|
||||
|
||||
int difficultyPeppyStars = (int)Math.Round(
|
||||
(baseBeatmap.Difficulty.DrainRate
|
||||
+ baseBeatmap.Difficulty.OverallDifficulty
|
||||
+ baseBeatmap.Difficulty.CircleSize
|
||||
+ Math.Clamp((float)objectCount / drainLength * 8, 0, 16)) / 38 * 5);
|
||||
|
||||
scoreMultiplier = difficultyPeppyStars;
|
||||
scoreMultiplier = LegacyRulesetExtensions.CalculateDifficultyPeppyStars(baseBeatmap.Difficulty, objectCount, drainLength);
|
||||
|
||||
LegacyScoreAttributes attributes = new LegacyScoreAttributes();
|
||||
|
||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
@ -62,13 +63,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
drainLength = ((int)Math.Round(baseBeatmap.HitObjects[^1].StartTime) - (int)Math.Round(baseBeatmap.HitObjects[0].StartTime) - breakLength) / 1000;
|
||||
}
|
||||
|
||||
int difficultyPeppyStars = (int)Math.Round(
|
||||
(baseBeatmap.Difficulty.DrainRate
|
||||
+ baseBeatmap.Difficulty.OverallDifficulty
|
||||
+ baseBeatmap.Difficulty.CircleSize
|
||||
+ Math.Clamp((float)objectCount / drainLength * 8, 0, 16)) / 38 * 5);
|
||||
|
||||
scoreMultiplier = difficultyPeppyStars;
|
||||
scoreMultiplier = LegacyRulesetExtensions.CalculateDifficultyPeppyStars(baseBeatmap.Difficulty, objectCount, drainLength);
|
||||
|
||||
LegacyScoreAttributes attributes = new LegacyScoreAttributes();
|
||||
|
||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Scoring.Legacy;
|
||||
@ -65,11 +66,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||
drainLength = ((int)Math.Round(baseBeatmap.HitObjects[^1].StartTime) - (int)Math.Round(baseBeatmap.HitObjects[0].StartTime) - breakLength) / 1000;
|
||||
}
|
||||
|
||||
difficultyPeppyStars = (int)Math.Round(
|
||||
(baseBeatmap.Difficulty.DrainRate
|
||||
+ baseBeatmap.Difficulty.OverallDifficulty
|
||||
+ baseBeatmap.Difficulty.CircleSize
|
||||
+ Math.Clamp((float)objectCount / drainLength * 8, 0, 16)) / 38 * 5);
|
||||
difficultyPeppyStars = LegacyRulesetExtensions.CalculateDifficultyPeppyStars(baseBeatmap.Difficulty, objectCount, drainLength);
|
||||
|
||||
LegacyScoreAttributes attributes = new LegacyScoreAttributes();
|
||||
|
||||
|
@ -57,5 +57,40 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
|
||||
return (float)(1.0f - 0.7f * IBeatmapDifficultyInfo.DifficultyRange(circleSize)) / 2 * (applyFudge ? broken_gamefield_rounding_allowance : 1);
|
||||
}
|
||||
|
||||
public static int CalculateDifficultyPeppyStars(BeatmapDifficulty difficulty, int objectCount, int drainLength)
|
||||
{
|
||||
/*
|
||||
* WARNING: DO NOT TOUCH IF YOU DO NOT KNOW WHAT YOU ARE DOING
|
||||
*
|
||||
* It so happens that in stable, due to .NET Framework internals, float math would be performed
|
||||
* using x87 registers and opcodes.
|
||||
* .NET (Core) however uses SSE instructions on 32- and 64-bit words.
|
||||
* x87 registers are _80 bits_ wide. Which is notably wider than _both_ float and double.
|
||||
* Therefore, on a significant number of beatmaps, the rounding would not produce correct values.
|
||||
*
|
||||
* Thus, to crudely - but, seemingly *mostly* accurately, after checking across all ranked maps - emulate this,
|
||||
* use `decimal`, which is slow, but has bigger precision than `double`.
|
||||
* At the time of writing, there is _one_ ranked exception to this - namely https://osu.ppy.sh/beatmapsets/1156087#osu/2625853 -
|
||||
* but it is considered an "acceptable casualty", since in that case scores aren't inflated by _that_ much compared to others.
|
||||
*/
|
||||
|
||||
decimal objectToDrainRatio = drainLength != 0
|
||||
? Math.Clamp((decimal)objectCount / drainLength * 8, 0, 16)
|
||||
: 16;
|
||||
|
||||
/*
|
||||
* Notably, THE `double` CASTS BELOW ARE IMPORTANT AND MUST REMAIN.
|
||||
* Their goal is to trick the compiler / runtime into NOT promoting from single-precision float, as doing so would prompt it
|
||||
* to attempt to "silently" fix the single-precision values when converting to decimal,
|
||||
* which is NOT what the x87 FPU does.
|
||||
*/
|
||||
|
||||
decimal drainRate = (decimal)(double)difficulty.DrainRate;
|
||||
decimal overallDifficulty = (decimal)(double)difficulty.OverallDifficulty;
|
||||
decimal circleSize = (decimal)(double)difficulty.CircleSize;
|
||||
|
||||
return (int)Math.Round((drainRate + overallDifficulty + circleSize + objectToDrainRatio) / 38 * 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Extensions;
|
||||
using osu.Game.IO.Legacy;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Replays.Legacy;
|
||||
using osu.Game.Rulesets.Objects.Legacy;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Replays.Types;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
@ -38,9 +39,13 @@ namespace osu.Game.Scoring.Legacy
|
||||
/// <item><description>30000009: Fix edge cases in conversion for scores which have 0.0x mod multiplier on stable. Reconvert all scores.</description></item>
|
||||
/// <item><description>30000010: Fix mania score V1 conversion using score V1 accuracy rather than V2 accuracy. Reconvert all scores.</description></item>
|
||||
/// <item><description>30000011: Re-do catch scoring to mirror stable Score V2 as closely as feasible. Reconvert all scores.</description></item>
|
||||
/// <item><description>
|
||||
/// 30000012: Fix incorrect total score conversion on selected beatmaps after implementing the more correct
|
||||
/// <see cref="LegacyRulesetExtensions.CalculateDifficultyPeppyStars"/> method. Reconvert all scores.
|
||||
/// </description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public const int LATEST_VERSION = 30000011;
|
||||
public const int LATEST_VERSION = 30000012;
|
||||
|
||||
/// <summary>
|
||||
/// The first stable-compatible YYYYMMDD format version given to lazer usage of replays.
|
||||
|
Loading…
Reference in New Issue
Block a user