1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-24 04:09:53 +08:00

Move strain's influence in the difficulty of a note based on deltaTime to the evaluator level (#36417)

This PR moves the influence of d/t^2 from the skill (through strain)
directly into the evaluator level as a bonus applied at the end. This
makes it more clear what d/t^2 is, and the fact that it applies to *all*
bonuses in the evaluator. As well, the peak strain value of a note is
now equal to the evaluator value. This comes with a couple benefits:

1. The BPM weight is now subject to balance, and can be flattened easily
for a more "d/t" like system (previously this required hacky solutions)
2. StrainDecayBase becomes a much more useful variable now that it does
not affect the difficulty of the note itself. When adjusting this in
live, your star rating would double upon changing from 0.15 in aim to
0.3, and now it is intuitive what it does (makes strain take longer to
accumulate). This means that future balancing efforts can use evaluators
to dynamically adjust strainDecayBase (potentially letting large spikes
provide more strain for the same difficulty if they're wide angle, for
example).
3. In the object inspector, you get the actual maximum difficulty value
of a note as seen in the ObjectDifficulties list. This makes it easier
to tell what notes are deemed as harder by the system. For context,
previously, a note of difficulty 1 at 200bpm would cap out at 6 as a
result of strain, and a note of the same difficulty but at 300bpm would
cap out at 8.

The actual implementation is really really simple. I'm willing to move
this to flashlight if wanted (I don't think it's necessary), or even
abstract this away so that (1 - decay) doesn't look like a balancing
constant.

Side note: this is equivalent to live, except for notes with a deltaTime
of less than 25ms (since I am using AdjustedDeltaTime in the aim
evaluator for the bonus to avoid divisions by zero).
This commit is contained in:
Natelytle
2026-01-22 14:05:21 -05:00
committed by GitHub
Unverified
parent cda52cdae8
commit 2876cebdd7
4 changed files with 17 additions and 4 deletions
@@ -162,9 +162,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
if (withSliderTravelDistance)
aimStrain += sliderBonus * slider_multiplier;
aimStrain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime);
return aimStrain;
}
private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.15, ms / 1000));
private static double calcWideAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(40), double.DegreesToRadians(140));
private static double calcAcuteAngleBonus(double angle) => DifficultyCalculationUtils.Smoothstep(angle, double.DegreesToRadians(140), double.DegreesToRadians(40));
@@ -69,8 +69,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
// Base difficulty with all bonuses
double difficulty = (1 + speedBonus + distanceBonus) * 1000 / strainTime;
difficulty *= highBpmBonus(osuCurrObj.AdjustedDeltaTime);
// Apply penalty if there's doubletappable doubles
return difficulty * doubletapness;
}
private static double highBpmBonus(double ms) => 1 / (1 - Math.Pow(0.3, ms / 1000));
}
}
@@ -7,6 +7,7 @@ using System.Linq;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Evaluators;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Utils;
using osu.Game.Rulesets.Osu.Objects;
@@ -38,8 +39,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
protected override double StrainValueAt(DifficultyHitObject current)
{
currentStrain *= strainDecay(current.DeltaTime);
currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplier;
double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime);
currentStrain *= decay;
currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * (1 - decay) * skillMultiplier;
if (current.BaseObject is Slider)
sliderStrains.Add(currentStrain);
@@ -39,8 +39,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
protected override double StrainValueAt(DifficultyHitObject current)
{
currentStrain *= strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime);
currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * skillMultiplier;
double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime);
currentStrain *= decay;
currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * (1 - decay) * skillMultiplier;
currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current);