Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
38 changes: 10 additions & 28 deletions osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
using osu.Game.Rulesets.Osu.Difficulty.Utils;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Game.Utils;

namespace osu.Game.Rulesets.Osu.Difficulty
Expand All @@ -30,22 +28,6 @@ public OsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
{
}

public static double CalculateRateAdjustedApproachRate(double approachRate, double clockRate)
{
double preempt = IBeatmapDifficultyInfo.DifficultyRange(approachRate, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN) / clockRate;
return IBeatmapDifficultyInfo.InverseDifficultyRange(preempt, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN);
}

public static double CalculateRateAdjustedOverallDifficulty(double overallDifficulty, double clockRate)
{
HitWindows hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(overallDifficulty);

double hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate;

return (79.5 - hitWindowGreat) / 6;
}

protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills)
{
if (beatmap.HitObjects.Count == 0)
Expand Down Expand Up @@ -78,28 +60,24 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat

double difficultSliders = aim.GetDifficultSliders();

double overallDifficulty = CalculateRateAdjustedOverallDifficulty(beatmap.Difficulty.OverallDifficulty, ModUtils.CalculateRateWithMods(mods));

int hitCircleCount = beatmap.HitObjects.Count(h => h is HitCircle);
int sliderCount = beatmap.HitObjects.Count(h => h is Slider);
int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner);

int totalHits = beatmap.HitObjects.Count;

double sliderFactor = aimDifficultyValue > 0
? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue)
? calculateDifficultyRating(aimNoSlidersDifficultyValue) / calculateDifficultyRating(aimDifficultyValue) // TODO: this is intentionally left incorrect
: 1;

var osuRatingCalculator = new OsuRatingCalculator(totalHits, overallDifficulty);

double aimRating = osuRatingCalculator.ComputeAimRating(aimDifficultyValue);
double speedRating = osuRatingCalculator.ComputeSpeedRating(speedDifficultyValue);
double readingRating = osuRatingCalculator.ComputeReadingRating(readingDifficultyValue);
double aimRating = calculateAimDifficultyRating(aimDifficultyValue);
double speedRating = calculateDifficultyRating(speedDifficultyValue);
double readingRating = calculateDifficultyRating(readingDifficultyValue);

double flashlightRating = 0.0;

if (flashlight is not null)
flashlightRating = osuRatingCalculator.ComputeFlashlightRating(flashlight.DifficultyValue());
flashlightRating = calculateDifficultyRating(flashlight.DifficultyValue());

double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits);
double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(WorkingBeatmap.Beatmap);
Expand Down Expand Up @@ -157,6 +135,10 @@ public static double SumCognitionDifficulty(double reading, double flashlight)
return DifficultyCalculationUtils.Norm(OsuPerformanceCalculator.PERFORMANCE_NORM_EXPONENT, reading, flashlight * Math.Clamp(flashlight / reading, 0.25, 1.0));
}

private double calculateAimDifficultyRating(double difficultyValue) => Math.Pow(difficultyValue, 0.63) * 0.02275;

private double calculateDifficultyRating(double difficultyValue) => Math.Sqrt(difficultyValue) * 0.0675;

private double calculateStarRating(double basePerformance)
{
return Math.Cbrt(basePerformance * OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER);
Expand Down Expand Up @@ -189,7 +171,7 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods)
};

if (mods.Any(h => h is OsuModFlashlight))
skills.Add(new Flashlight(mods));
skills.Add(new Flashlight(mods, beatmap.HitObjects.Count));

return skills.ToArray();
}
Expand Down
18 changes: 13 additions & 5 deletions osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Difficulty.Utils;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Difficulty.Skills;
using osu.Game.Rulesets.Difficulty.Utils;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Skills;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Utils;
Expand Down Expand Up @@ -99,8 +101,8 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s
okHitWindow = hitWindows.WindowFor(HitResult.Ok) / clockRate;
mehHitWindow = hitWindows.WindowFor(HitResult.Meh) / clockRate;

approachRate = OsuDifficultyCalculator.CalculateRateAdjustedApproachRate(difficulty.ApproachRate, clockRate);
overallDifficulty = OsuDifficultyCalculator.CalculateRateAdjustedOverallDifficulty(difficulty.OverallDifficulty, clockRate);
approachRate = calculateRateAdjustedApproachRate(difficulty.ApproachRate, clockRate);
overallDifficulty = (79.5 - greatHitWindow) / 6;
drainRate = difficulty.DrainRate;

double comboBasedEstimatedMissCount = calculateComboBasedEstimatedMissCount(osuAttributes);
Expand Down Expand Up @@ -536,6 +538,12 @@ private double calculateTraceableBonus(double sliderFactor = 1)
private double calculateMissPenalty(double missCount, double difficultStrainCount) => 0.93 / (missCount / (4 * Math.Log(difficultStrainCount)) + 1);
private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0);

private double calculateRateAdjustedApproachRate(double approachRate, double clockRate)
{
double preempt = IBeatmapDifficultyInfo.DifficultyRange(approachRate, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN) / clockRate;
return IBeatmapDifficultyInfo.InverseDifficultyRange(preempt, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN);
}

private int totalHits => countGreat + countOk + countMeh + countMiss;
private int totalSuccessfulHits => countGreat + countOk + countMeh;
private int totalImperfectHits => countOk + countMeh + countMiss;
Expand Down
67 changes: 0 additions & 67 deletions osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@ public class OsuDifficultyHitObject : DifficultyHitObject
/// </summary>
public double SmallCircleBonus { get; private set; }

/// <summary>
/// Object's immediate OverallDifficulty value calculated from the hitwindow.
/// </summary>
public double OverallDifficulty
{
get
{
double hitWindowGreat = BaseObject.HitWindows.WindowFor(HitResult.Great) / ClockRate;

return (79.5 - hitWindowGreat) / 6;
}
}

private readonly OsuDifficultyHitObject? lastLastDifficultyObject;
private readonly OsuDifficultyHitObject? lastDifficultyObject;

Expand Down
6 changes: 4 additions & 2 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ protected override double StrainValueAt(DifficultyHitObject current)
double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime);

currentStrain *= decay;
currentStrain += calculateModAdjustedDifficulty(current) * (1 - decay);
currentStrain += calculateAdjustedDifficulty(current) * (1 - decay);

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

return currentStrain;
}

private double calculateModAdjustedDifficulty(DifficultyHitObject current)
private double calculateAdjustedDifficulty(DifficultyHitObject current)
{
double snapDifficulty = SnapAimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplierSnap;
double agilityDifficulty = AgilityEvaluator.EvaluateDifficultyOf(current) * skillMultiplierAgility;
Expand All @@ -85,6 +85,8 @@ private double calculateModAdjustedDifficulty(DifficultyHitObject current)
totalDifficulty *= 1.0 - magnetisedStrength;
}

totalDifficulty *= 0.99 + Math.Pow(Math.Max(0, ((OsuDifficultyHitObject)current).OverallDifficulty), 2) / 5500;

return totalDifficulty;
}

Expand Down
23 changes: 19 additions & 4 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using osu.Game.Rulesets.Difficulty.Utils;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Evaluators;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Mods;

namespace osu.Game.Rulesets.Osu.Difficulty.Skills
Expand All @@ -17,9 +18,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
/// </summary>
public class Flashlight : StrainSkill
{
public Flashlight(Mod[] mods)
private readonly int totalObjects;

public Flashlight(Mod[] mods, int totalObjects)
: base(mods)
{
this.totalObjects = totalObjects;
}

private double skillMultiplier => 0.056;
Expand All @@ -37,12 +41,12 @@ protected override double StrainValueAt(DifficultyHitObject current)
return 0;

currentStrain *= strainDecay(current.DeltaTime);
currentStrain += calculateModAdjustedDifficulty(current) * skillMultiplier;
currentStrain += calculateAdjustedDifficulty(current) * skillMultiplier;

return currentStrain;
}

private double calculateModAdjustedDifficulty(DifficultyHitObject current)
private double calculateAdjustedDifficulty(DifficultyHitObject current)
{
double difficulty = FlashlightEvaluator.EvaluateDifficultyOf(current, Mods);

Expand All @@ -67,10 +71,21 @@ private double calculateModAdjustedDifficulty(DifficultyHitObject current)
if (Mods.Any(m => m is OsuModAutopilot))
difficulty *= 0.4;

difficulty *= 0.99 + Math.Pow(Math.Max(0, ((OsuDifficultyHitObject)current).OverallDifficulty), 2) / 5500;

return difficulty;
}

public override double DifficultyValue() => GetCurrentStrainPeaks().Sum();
public override double DifficultyValue()
{
double sum = GetCurrentStrainPeaks().Sum();

// Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius.
sum *= Math.Sqrt(0.7 + 0.1 * Math.Min(1.0, totalObjects / 200.0) +
(totalObjects > 200 ? 0.2 * Math.Min(1.0, (totalObjects - 200) / 200.0) : 0.0));

return sum;
}

public static double DifficultyToPerformance(double difficulty) => 25 * Math.Pow(difficulty, 2);
}
Expand Down
16 changes: 14 additions & 2 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using osu.Game.Rulesets.Difficulty.Utils;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Difficulty.Evaluators;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Mods;

namespace osu.Game.Rulesets.Osu.Difficulty.Skills
Expand Down Expand Up @@ -40,12 +41,12 @@ protected override double ObjectDifficultyOf(DifficultyHitObject current)
double decay = strainDecay(current.DeltaTime);

currentStrain *= decay;
currentStrain += calculateModAdjustedDifficulty(current) * (1 - decay) * skillMultiplier;
currentStrain += calculateAdjustedDifficulty(current) * (1 - decay) * skillMultiplier;

return currentStrain;
}

private double calculateModAdjustedDifficulty(DifficultyHitObject current)
private double calculateAdjustedDifficulty(DifficultyHitObject current)
{
double difficulty = ReadingEvaluator.EvaluateDifficultyOf(current, hasHiddenMod);

Expand Down Expand Up @@ -117,5 +118,16 @@ public override double CountTopWeightedObjectDifficulties(double difficultyValue

return ObjectDifficulties.Sum(d => DifficultyCalculationUtils.Logistic(d / consistentTopNote, 1.15, 5, 1.1));
}

public override double DifficultyValue()
{
double difficulty = base.DifficultyValue();

// TODO: this should be replaced with a per-object adjustment, but it requires extra considerations
if (objectList.Count > 0)
difficulty *= 0.825 + Math.Pow(Math.Max(0, ((OsuDifficultyHitObject)objectList.First()).OverallDifficulty), 2.2) / 1125.0;

return difficulty;
}
}
}
4 changes: 2 additions & 2 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected override double ObjectDifficultyOf(DifficultyHitObject current)
double decay = strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime);

currentStrain *= decay;
currentStrain += calculateModAdjustedDifficulty(current) * (1 - decay) * skillMultiplier;
currentStrain += calculateAdjustedDifficulty(current) * (1 - decay) * skillMultiplier;

double currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current);

Expand All @@ -58,7 +58,7 @@ protected override double ObjectDifficultyOf(DifficultyHitObject current)
return totalStrain;
}

private double calculateModAdjustedDifficulty(DifficultyHitObject current)
private double calculateAdjustedDifficulty(DifficultyHitObject current)
{
double difficulty = SpeedEvaluator.EvaluateDifficultyOf(current);

Expand Down
Loading