mirror of
https://github.com/ppy/osu.git
synced 2025-01-18 14:52:56 +08:00
Remove problematic total deviation scaling, rebalance aim (#31515)
* Remove problematic total deviation scaling, rebalance aim * Fix tests
This commit is contained in:
parent
c53188cf45
commit
6cf15e3e5a
@ -15,21 +15,21 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu.Tests";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu.Tests";
|
||||||
|
|
||||||
[TestCase(6.7443067697205539d, 239, "diffcalc-test")]
|
[TestCase(6.7331304290522747d, 239, "diffcalc-test")]
|
||||||
[TestCase(1.4630292101418947d, 54, "zero-length-sliders")]
|
[TestCase(1.4602604078137214d, 54, "zero-length-sliders")]
|
||||||
[TestCase(0.43052813047866129d, 4, "very-fast-slider")]
|
[TestCase(0.43052813047866129d, 4, "very-fast-slider")]
|
||||||
[TestCase(0.14143808967817237d, 2, "nan-slider")]
|
[TestCase(0.14143808967817237d, 2, "nan-slider")]
|
||||||
public void Test(double expectedStarRating, int expectedMaxCombo, string name)
|
public void Test(double expectedStarRating, int expectedMaxCombo, string name)
|
||||||
=> base.Test(expectedStarRating, expectedMaxCombo, name);
|
=> base.Test(expectedStarRating, expectedMaxCombo, name);
|
||||||
|
|
||||||
[TestCase(9.7058844423552308d, 239, "diffcalc-test")]
|
[TestCase(9.6779397290273756d, 239, "diffcalc-test")]
|
||||||
[TestCase(1.7724929629205366d, 54, "zero-length-sliders")]
|
[TestCase(1.7691451263718989d, 54, "zero-length-sliders")]
|
||||||
[TestCase(0.55785578988249407d, 4, "very-fast-slider")]
|
[TestCase(0.55785578988249407d, 4, "very-fast-slider")]
|
||||||
public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
|
public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name)
|
||||||
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime());
|
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime());
|
||||||
|
|
||||||
[TestCase(6.7443067697205539d, 239, "diffcalc-test")]
|
[TestCase(6.7331304290522747d, 239, "diffcalc-test")]
|
||||||
[TestCase(1.4630292101418947d, 54, "zero-length-sliders")]
|
[TestCase(1.4602604078137214d, 54, "zero-length-sliders")]
|
||||||
[TestCase(0.43052813047866129d, 4, "very-fast-slider")]
|
[TestCase(0.43052813047866129d, 4, "very-fast-slider")]
|
||||||
public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name)
|
public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name)
|
||||||
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic());
|
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic());
|
||||||
|
@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
|||||||
|
|
||||||
// Penalize angle repetition.
|
// Penalize angle repetition.
|
||||||
wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3));
|
wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3));
|
||||||
acuteAngleBonus *= 0.09 + 0.91 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3)));
|
acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3)));
|
||||||
|
|
||||||
// Apply full wide angle bonus for distance more than one diameter
|
// Apply full wide angle bonus for distance more than one diameter
|
||||||
wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter);
|
wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter);
|
||||||
|
@ -24,9 +24,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
[JsonProperty("effective_miss_count")]
|
[JsonProperty("effective_miss_count")]
|
||||||
public double EffectiveMissCount { get; set; }
|
public double EffectiveMissCount { get; set; }
|
||||||
|
|
||||||
[JsonProperty("total_deviation")]
|
|
||||||
public double? TotalDeviation { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("speed_deviation")]
|
[JsonProperty("speed_deviation")]
|
||||||
public double? SpeedDeviation { get; set; }
|
public double? SpeedDeviation { get; set; }
|
||||||
|
|
||||||
|
@ -42,7 +42,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double effectiveMissCount;
|
private double effectiveMissCount;
|
||||||
|
|
||||||
private double? totalDeviation;
|
|
||||||
private double? speedDeviation;
|
private double? speedDeviation;
|
||||||
|
|
||||||
public OsuPerformanceCalculator()
|
public OsuPerformanceCalculator()
|
||||||
@ -115,7 +114,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits);
|
effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits);
|
||||||
}
|
}
|
||||||
|
|
||||||
totalDeviation = calculateTotalDeviation(osuAttributes);
|
|
||||||
speedDeviation = calculateSpeedDeviation(osuAttributes);
|
speedDeviation = calculateSpeedDeviation(osuAttributes);
|
||||||
|
|
||||||
double aimValue = computeAimValue(score, osuAttributes);
|
double aimValue = computeAimValue(score, osuAttributes);
|
||||||
@ -138,7 +136,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
Accuracy = accuracyValue,
|
Accuracy = accuracyValue,
|
||||||
Flashlight = flashlightValue,
|
Flashlight = flashlightValue,
|
||||||
EffectiveMissCount = effectiveMissCount,
|
EffectiveMissCount = effectiveMissCount,
|
||||||
TotalDeviation = totalDeviation,
|
|
||||||
SpeedDeviation = speedDeviation,
|
SpeedDeviation = speedDeviation,
|
||||||
Total = totalValue
|
Total = totalValue
|
||||||
};
|
};
|
||||||
@ -149,9 +146,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
if (score.Mods.Any(h => h is OsuModAutopilot))
|
if (score.Mods.Any(h => h is OsuModAutopilot))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
if (totalDeviation == null)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
double aimDifficulty = attributes.AimDifficulty;
|
double aimDifficulty = attributes.AimDifficulty;
|
||||||
|
|
||||||
if (attributes.SliderCount > 0 && attributes.AimDifficultSliderCount > 0)
|
if (attributes.SliderCount > 0 && attributes.AimDifficultSliderCount > 0)
|
||||||
@ -203,7 +197,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
aimValue *= 1.0 + 0.04 * (12.0 - attributes.ApproachRate);
|
aimValue *= 1.0 + 0.04 * (12.0 - attributes.ApproachRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
aimValue *= SpecialFunctions.Erf(25.0 / (Math.Sqrt(2) * totalDeviation.Value));
|
aimValue *= accuracy;
|
||||||
|
// It is important to consider accuracy difficulty when scaling with accuracy.
|
||||||
|
aimValue *= 0.98 + Math.Pow(Math.Max(0, attributes.OverallDifficulty), 2) / 2500;
|
||||||
|
|
||||||
return aimValue;
|
return aimValue;
|
||||||
}
|
}
|
||||||
@ -322,48 +318,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
return flashlightValue;
|
return flashlightValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Using <see cref="calculateDeviation"/> estimates player's deviation on accuracy objects.
|
|
||||||
/// Returns deviation for circles and sliders if score was set with slideracc.
|
|
||||||
/// Returns the min between deviation of circles and deviation on circles and sliders (assuming slider hits are 50s), if score was set without slideracc.
|
|
||||||
/// </summary>
|
|
||||||
private double? calculateTotalDeviation(OsuDifficultyAttributes attributes)
|
|
||||||
{
|
|
||||||
if (totalSuccessfulHits == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
int accuracyObjectCount = attributes.HitCircleCount;
|
|
||||||
|
|
||||||
if (!usingClassicSliderAccuracy)
|
|
||||||
accuracyObjectCount += attributes.SliderCount;
|
|
||||||
|
|
||||||
// Assume worst case: all mistakes was on accuracy objects
|
|
||||||
int relevantCountMiss = Math.Min(countMiss, accuracyObjectCount);
|
|
||||||
int relevantCountMeh = Math.Min(countMeh, accuracyObjectCount - relevantCountMiss);
|
|
||||||
int relevantCountOk = Math.Min(countOk, accuracyObjectCount - relevantCountMiss - relevantCountMeh);
|
|
||||||
int relevantCountGreat = Math.Max(0, accuracyObjectCount - relevantCountMiss - relevantCountMeh - relevantCountOk);
|
|
||||||
|
|
||||||
// Calculate deviation on accuracy objects
|
|
||||||
double? deviation = calculateDeviation(attributes, relevantCountGreat, relevantCountOk, relevantCountMeh, relevantCountMiss);
|
|
||||||
if (deviation == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (!usingClassicSliderAccuracy)
|
|
||||||
return deviation.Value;
|
|
||||||
|
|
||||||
// If score was set without slider accuracy - also compute deviation with sliders
|
|
||||||
// Assume that all hits was 50s
|
|
||||||
int totalCountWithSliders = attributes.HitCircleCount + attributes.SliderCount;
|
|
||||||
int missCountWithSliders = Math.Min(totalCountWithSliders, countMiss);
|
|
||||||
int hitCountWithSliders = totalCountWithSliders - missCountWithSliders;
|
|
||||||
|
|
||||||
double hitProbabilityWithSliders = hitCountWithSliders / (totalCountWithSliders + 1.0);
|
|
||||||
double deviationWithSliders = attributes.MehHitWindow / (Math.Sqrt(2) * SpecialFunctions.ErfInv(hitProbabilityWithSliders));
|
|
||||||
|
|
||||||
// Min is needed for edgecase maps with 1 circle and 999 sliders, as deviation on sliders can be lower in this case
|
|
||||||
return Math.Min(deviation.Value, deviationWithSliders);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Estimates player's deviation on speed notes using <see cref="calculateDeviation"/>, assuming worst-case.
|
/// Estimates player's deviation on speed notes using <see cref="calculateDeviation"/>, assuming worst-case.
|
||||||
/// Treats all speed notes as hit circles.
|
/// Treats all speed notes as hit circles.
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
|||||||
|
|
||||||
private double currentStrain;
|
private double currentStrain;
|
||||||
|
|
||||||
private double skillMultiplier => 25.7;
|
private double skillMultiplier => 25.6;
|
||||||
private double strainDecayBase => 0.15;
|
private double strainDecayBase => 0.15;
|
||||||
|
|
||||||
private readonly List<double> sliderStrains = new List<double>();
|
private readonly List<double> sliderStrains = new List<double>();
|
||||||
|
Loading…
Reference in New Issue
Block a user