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

Fix clockrate adjusted difficulty calculations bug in strain decay

When starting a new section, the starting strain value was calculated using the unadjusted timing value, meaning decay curves were essentially being stretched or squashed according to the clockrate.

This caused incorrect strain peaks for any section where the peak occurs at the start of the section (none of the objects in the section added enough strain after decay to exceed the starting strain).

This bug caused star ratings with clockrates above 1 to be lower than they should and below 1 to be higher than they should.
This commit is contained in:
Samuel Cattini-Schultz 2021-02-19 18:04:25 +11:00
parent 303c6bcda7
commit 442347df8e
4 changed files with 12 additions and 6 deletions

View File

@ -71,8 +71,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills
} }
protected override double GetPeakStrain(double offset) protected override double GetPeakStrain(double offset)
=> applyDecay(individualStrain, offset - Previous[0].BaseObject.StartTime, individual_decay_base) => applyDecay(individualStrain, offset - Previous[0].StartTime, individual_decay_base)
+ applyDecay(overallStrain, offset - Previous[0].BaseObject.StartTime, overall_decay_base); + applyDecay(overallStrain, offset - Previous[0].StartTime, overall_decay_base);
private double applyDecay(double value, double deltaTime, double decayBase) private double applyDecay(double value, double deltaTime, double decayBase)
=> value * Math.Pow(decayBase, deltaTime / 1000); => value * Math.Pow(decayBase, deltaTime / 1000);

View File

@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Difficulty
foreach (Skill s in skills) foreach (Skill s in skills)
{ {
s.SaveCurrentPeak(); s.SaveCurrentPeak();
s.StartNewSectionFrom(currentSectionEnd); s.StartNewSectionFrom(currentSectionEnd / clockRate);
} }
currentSectionEnd += sectionLength; currentSectionEnd += sectionLength;

View File

@ -25,6 +25,11 @@ namespace osu.Game.Rulesets.Difficulty.Preprocessing
/// </summary> /// </summary>
public readonly double DeltaTime; public readonly double DeltaTime;
/// <summary>
/// Start time of <see cref="BaseObject"/>.
/// </summary>
public readonly double StartTime;
/// <summary> /// <summary>
/// Creates a new <see cref="DifficultyHitObject"/>. /// Creates a new <see cref="DifficultyHitObject"/>.
/// </summary> /// </summary>
@ -36,6 +41,7 @@ namespace osu.Game.Rulesets.Difficulty.Preprocessing
BaseObject = hitObject; BaseObject = hitObject;
LastObject = lastObject; LastObject = lastObject;
DeltaTime = (hitObject.StartTime - lastObject.StartTime) / clockRate; DeltaTime = (hitObject.StartTime - lastObject.StartTime) / clockRate;
StartTime = hitObject.StartTime / clockRate;
} }
} }
} }

View File

@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills
/// <summary> /// <summary>
/// Sets the initial strain level for a new section. /// Sets the initial strain level for a new section.
/// </summary> /// </summary>
/// <param name="time">The beginning of the new section in milliseconds.</param> /// <param name="time">The beginning of the new section in milliseconds, adjusted by clockrate.</param>
public void StartNewSectionFrom(double time) public void StartNewSectionFrom(double time)
{ {
// The maximum strain of the new section is not zero by default, strain decays as usual regardless of section boundaries. // The maximum strain of the new section is not zero by default, strain decays as usual regardless of section boundaries.
@ -87,9 +87,9 @@ namespace osu.Game.Rulesets.Difficulty.Skills
/// <summary> /// <summary>
/// Retrieves the peak strain at a point in time. /// Retrieves the peak strain at a point in time.
/// </summary> /// </summary>
/// <param name="time">The time to retrieve the peak strain at.</param> /// <param name="time">The time to retrieve the peak strain at, adjusted by clockrate.</param>
/// <returns>The peak strain.</returns> /// <returns>The peak strain.</returns>
protected virtual double GetPeakStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].BaseObject.StartTime); protected virtual double GetPeakStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime);
/// <summary> /// <summary>
/// Returns the calculated difficulty value representing all processed <see cref="DifficultyHitObject"/>s. /// Returns the calculated difficulty value representing all processed <see cref="DifficultyHitObject"/>s.