Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use proportion of difficult sliders to better estimate sliderbreaks on classic accuracy scores #31234

Open
wants to merge 13 commits into
base: pp-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ public class OsuDifficultyAttributes : DifficultyAttributes
[JsonProperty("slider_factor")]
public double SliderFactor { get; set; }

/// <summary>
/// Describes how much of <see cref="AimDifficultStrainCount"/> is contributed to by hitcircles or sliders
/// A value closer to 0.0 indicates most of <see cref="AimDifficultStrainCount"/> is contributed by hitcircles
/// A value closer to Infinity indicates most of <see cref="AimDifficultStrainCount"/> is contributed by sliders
/// </summary>
[JsonProperty("aim_top_weighted_slider_factor")]
public double AimTopWeightedSliderFactor { get; set; }

/// <summary>
/// Describes how much of <see cref="SpeedDifficultStrainCount"/> is contributed to by hitcircles or sliders
/// A value closer to 0.0 indicates most of <see cref="SpeedDifficultStrainCount"/> is contributed by hitcircles
/// A value closer to Infinity indicates most of <see cref="SpeedDifficultStrainCount"/> is contributed by sliders
/// </summary>
[JsonProperty("speed_top_weighted_slider_factor")]
public double SpeedTopWeightedSliderFactor { get; set; }

[JsonProperty("aim_difficult_strain_count")]
public double AimDifficultStrainCount { get; set; }

Expand Down
8 changes: 8 additions & 0 deletions osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
double aimDifficultyStrainCount = ((OsuStrainSkill)skills[0]).CountTopWeightedStrains();
double speedDifficultyStrainCount = ((OsuStrainSkill)skills[2]).CountTopWeightedStrains();

double aimNoSlidersTopWeightedSliderCount = ((OsuStrainSkill)skills[1]).CountTopWeightedSliders();
double aimNoSlidersDifficultyStrainCount = ((OsuStrainSkill)skills[1]).CountTopWeightedStrains();
double aimTopWeightedSliderFactor = aimNoSlidersTopWeightedSliderCount / (aimNoSlidersDifficultyStrainCount - aimNoSlidersTopWeightedSliderCount);
double speedTopWeightedSliderCount = ((OsuStrainSkill)skills[2]).CountTopWeightedSliders();
double speedTopWeightedSliderFactor = speedTopWeightedSliderCount / (speedDifficultyStrainCount - speedTopWeightedSliderCount);

if (mods.Any(m => m is OsuModTouchDevice))
{
aimRating = Math.Pow(aimRating, 0.8);
Expand Down Expand Up @@ -106,6 +112,8 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
SliderFactor = sliderFactor,
AimDifficultStrainCount = aimDifficultyStrainCount,
SpeedDifficultStrainCount = speedDifficultyStrainCount,
AimTopWeightedSliderFactor = aimTopWeightedSliderFactor,
SpeedTopWeightedSliderFactor = speedTopWeightedSliderFactor,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
DrainRate = drainRate,
Expand Down
13 changes: 11 additions & 2 deletions osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Difficulty.Utils;
using osu.Game.Rulesets.Osu.Difficulty.Skills;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
Expand Down Expand Up @@ -165,7 +166,11 @@ private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attribut
aimValue *= lengthBonus;

if (effectiveMissCount > 0)
aimValue *= calculateMissPenalty(effectiveMissCount, attributes.AimDifficultStrainCount);
{
double missedComboPercent = 1.0 - (double)score.MaxCombo / attributes.MaxCombo;
double estimatedSliderbreaks = Math.Min(countMeh + countOk, countMiss * attributes.AimTopWeightedSliderFactor) * DifficultyCalculationUtils.Logistic(missedComboPercent, 0.33, 15);
aimValue *= calculateMissPenalty(effectiveMissCount + (usingClassicSliderAccuracy ? estimatedSliderbreaks : 0), attributes.AimDifficultStrainCount);
TextAdventurer12 marked this conversation as resolved.
Show resolved Hide resolved
}

double approachRateFactor = 0.0;
if (attributes.ApproachRate > 10.33)
Expand Down Expand Up @@ -205,7 +210,11 @@ private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attrib
speedValue *= lengthBonus;

if (effectiveMissCount > 0)
speedValue *= calculateMissPenalty(effectiveMissCount, attributes.SpeedDifficultStrainCount);
{
double missedComboPercent = 1.0 - (double)score.MaxCombo / attributes.MaxCombo;
double estimatedSliderbreaks = Math.Min(countMeh + countOk, countMiss * attributes.SpeedTopWeightedSliderFactor) * DifficultyCalculationUtils.Logistic(missedComboPercent, 0.33, 15);
speedValue *= calculateMissPenalty(effectiveMissCount + (usingClassicSliderAccuracy ? estimatedSliderbreaks : 0), attributes.SpeedDifficultStrainCount);
}

double approachRateFactor = 0.0;
if (attributes.ApproachRate > 10.33)
Expand Down
4 changes: 0 additions & 4 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;

Check failure on line 5 in osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Using directive is unnecessary. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0005)

Check failure on line 5 in osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Using directive is unnecessary. (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0005)
using System.Linq;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Mods;
Expand All @@ -29,8 +29,6 @@
private double skillMultiplier => 25.18;
private double strainDecayBase => 0.15;

private readonly List<double> sliderStrains = new List<double>();

private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000);

protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * strainDecay(time - current.Previous(0).StartTime);
Expand All @@ -41,9 +39,7 @@
currentStrain += AimEvaluator.EvaluateDifficultyOf(current, withSliders) * skillMultiplier;

if (current.BaseObject is Slider)
{
sliderStrains.Add(currentStrain);
}

return currentStrain;
}
Expand Down
16 changes: 16 additions & 0 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
/// </summary>
protected virtual double ReducedStrainBaseline => 0.75;

protected readonly List<double> sliderStrains = new List<double>();

Check failure on line 26 in osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Naming rule violation: These words must begin with upper case characters: sliderStrains (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide1006)

Check failure on line 26 in osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Naming rule violation: These words must begin with upper case characters: sliderStrains (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide1006)

protected OsuStrainSkill(Mod[] mods)
: base(mods)
{
Expand Down Expand Up @@ -57,6 +59,20 @@
return difficulty;
}

public double CountTopWeightedSliders()
{
if (sliderStrains.Count == 0)
return 0;

double consistentTopStrain = DifficultyValue() / 10; // What would the top strain be if all strain values were identical

if (consistentTopStrain == 0)
return 0;

// Use a weighted sum of all strains. Constants are arbitrary and give nice values
return sliderStrains.Sum(s => 1.1 / (1 + Math.Exp(-10 * (s / consistentTopStrain - 0.88))));
}

public static double DifficultyToPerformance(double difficulty) => Math.Pow(5.0 * Math.Max(1.0, difficulty / 0.0675) - 4.0, 3.0) / 100000.0;
}
}
3 changes: 3 additions & 0 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Evaluators;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Objects;
using System.Linq;

namespace osu.Game.Rulesets.Osu.Difficulty.Skills
Expand Down Expand Up @@ -40,6 +41,8 @@ protected override double StrainValueAt(DifficultyHitObject current)
currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current);

double totalStrain = currentStrain * currentRhythm;
if (current.BaseObject is Slider)
sliderStrains.Add(totalStrain);

return totalStrain;
}
Expand Down
Loading