From c2e5d767f9838c3d2d4e97bf4510908083f1c317 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Thu, 7 Mar 2024 18:32:54 +0200 Subject: [PATCH] Fixed reading cap Now it's bound to HDFL difficulty instead of FL This means that adding HD to a AR12 map will not increase pp from nothing --- .../Difficulty/OsuDifficultyAttributes.cs | 6 ++++++ .../Difficulty/OsuDifficultyCalculator.cs | 15 +++++++++------ .../Difficulty/OsuPerformanceCalculator.cs | 19 ++++++++++++------- .../Preprocessing/OsuDifficultyHitObject.cs | 4 ++-- .../Difficulty/Skills/Flashlight.cs | 15 ++++++++++++++- .../Difficulty/Skills/Reading.cs | 2 ++ osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 2 ++ 7 files changed, 47 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 09424e741a..a9640e5791 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -62,6 +62,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("flashlight_difficulty")] public double FlashlightDifficulty { get; set; } + /// + /// The difficulty corresponding to the flashlight skill with HD (used in capping cognition performance). + /// + [JsonProperty("hidden_flashlight_difficulty")] + public double HiddenFlashlightDifficulty { get; set; } + /// /// Describes how much of is contributed to by hitcircles or sliders. /// A value closer to 1.0 indicates most of is contributed by hitcircles. diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index c04455f232..b16ad5a21f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -47,6 +47,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double readingHighARRating = Math.Sqrt(skills[5].DifficultyValue()) * DIFFICULTY_MULTIPLIER; double readingSlidersRating = 0; double hiddenRating = Math.Sqrt(skills[6].DifficultyValue()) * DIFFICULTY_MULTIPLIER; + double hiddenFlashlightRating = Math.Sqrt(skills[7].DifficultyValue()) * DIFFICULTY_MULTIPLIER; double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; @@ -69,7 +70,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Cognition double baseFlashlightPerformance = 0.0; if (mods.Any(h => h is OsuModFlashlight)) - baseFlashlightPerformance = Math.Pow(flashlightRating, 2.0) * 25.0; + baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); double baseReadingLowARPerformance = ReadingLowAR.DifficultyToPerformance(readingLowARRating); double baseReadingHighARPerformance = OsuStrainSkill.DifficultyToPerformance(readingHighARRating); @@ -79,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double baseReadingHiddenPerformance = 0; if (mods.Any(h => h is OsuModHidden)) - baseReadingHiddenPerformance = Math.Pow(hiddenRating, 2.0) * 25.0; + baseReadingHiddenPerformance = ReadingHidden.DifficultyToPerformance(hiddenRating); double baseReadingSliderPerformance = 0; double baseReadingNonARPerformance = baseReadingHiddenPerformance + baseReadingSliderPerformance; @@ -96,8 +97,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Limit cognition by full memorisation difficulty double cognitionPerformance = Math.Pow(Math.Pow(baseFlashlightARPerformance, SUM_POWER) + Math.Pow(baseReadingNonARPerformance, SUM_POWER), 1.0 / SUM_POWER); double mechanicalPerformance = Math.Pow(Math.Pow(baseAimPerformance, SUM_POWER) + Math.Pow(baseSpeedPerformance, SUM_POWER), 1.0 / SUM_POWER); - double potentialFlashlightPerformance = OsuPerformanceCalculator.ComputePerfectFlashlightValue(flashlightRating, hitCirclesCount + sliderCount); - cognitionPerformance = OsuPerformanceCalculator.AdjustCognitionPerformance(cognitionPerformance, mechanicalPerformance, potentialFlashlightPerformance); + + double maxHiddenFlashlightPerformance = OsuPerformanceCalculator.ComputePerfectFlashlightValue(hiddenFlashlightRating, hitCirclesCount + sliderCount); + + cognitionPerformance = OsuPerformanceCalculator.AdjustCognitionPerformance(cognitionPerformance, mechanicalPerformance, maxHiddenFlashlightPerformance); double basePerformance = Math.Pow( @@ -115,8 +118,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty double hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate; - //var test = ((ReadingHighAR)skills[5]).GetAimSpeed(); - OsuDifficultyAttributes attributes = new OsuDifficultyAttributes { StarRating = starRating, @@ -129,6 +130,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty ReadingDifficultySliders = readingSlidersRating, HiddenDifficulty = hiddenRating, FlashlightDifficulty = flashlightRating, + HiddenFlashlightDifficulty = hiddenFlashlightRating, SliderFactor = sliderFactor, ApproachRate = IBeatmapDifficultyInfo.InverseDifficultyRange(preempt, 1800, 1200, 450), OverallDifficulty = (80 - hitWindowGreat) / 6, @@ -168,6 +170,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty new ReadingLowAR(mods), new ReadingHighAR(mods), new ReadingHidden(mods), + new HiddenFlashlight(mods), }; if (mods.Any(h => h is OsuModFlashlight)) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 23045f4331..8e3ab1a2ba 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -69,8 +69,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Cognition + // Preferably this value should be used for capping low AR reading performance + // Because it should have lower cap (you can actually see) + // But it will make formula really weird and overcomplicated double potentialFlashlightValue = computeFlashlightValue(score, osuAttributes); + // Get HDFL value for capping reading performance + double potentialHiddenFlashlightValue = computeFlashlightValue(score, osuAttributes, true); + double flashlightValue = potentialFlashlightValue; if (!score.Mods.Any(h => h is OsuModFlashlight)) flashlightValue = 0.0; @@ -91,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double readingNonARValue = readingHDValue + readingSlidersValue; double cognitionValue = Math.Pow(Math.Pow(flashlightARValue, power) + Math.Pow(readingNonARValue, power), 1.0 / power); - cognitionValue = AdjustCognitionPerformance(cognitionValue, mechanicalValue, potentialFlashlightValue); + cognitionValue = AdjustCognitionPerformance(cognitionValue, mechanicalValue, potentialHiddenFlashlightValue); double accuracyValue = computeAccuracyValue(score, osuAttributes); @@ -222,9 +228,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty return accuracyValue; } - private double computeFlashlightValue(ScoreInfo score, OsuDifficultyAttributes attributes) + private double computeFlashlightValue(ScoreInfo score, OsuDifficultyAttributes attributes, bool alwaysUseHD = false) { - double flashlightValue = Math.Pow(attributes.FlashlightDifficulty, 2.0) * 25.0; + double flashlightValue = Math.Pow(alwaysUseHD ? attributes.HiddenFlashlightDifficulty : attributes.FlashlightDifficulty, 2.0) * 25.0; // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. if (effectiveMissCount > 0) @@ -246,7 +252,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty public static double ComputePerfectFlashlightValue(double flashlightDifficulty, int objectsCount) { - double flashlightValue = Math.Pow(flashlightDifficulty, 2.0) * 25.0; + double flashlightValue = Flashlight.DifficultyToPerformance(flashlightDifficulty); flashlightValue *= 0.7 + 0.1 * Math.Min(1.0, objectsCount / 200.0) + (objectsCount > 200 ? 0.2 * Math.Min(1.0, (objectsCount - 200) / 200.0) : 0.0); @@ -341,8 +347,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty return 0.0; double rawReading = attributes.HiddenDifficulty; - //double readingValue = Math.Pow(rawReading, 2.0) * 25.0; - double readingValue = Math.Pow(rawReading, 2.0) * 25.0; + double readingValue = ReadingHidden.DifficultyToPerformance(attributes.HiddenDifficulty); // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. if (effectiveMissCount > 0) @@ -386,7 +391,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Avoid it being broken on millions of pp, ruins it being continious, but it will never happen on normal circumstances if (capPerformance > 10000 || cognitionPerformance > 10000) cognitionPerformance = Math.Min(capPerformance, cognitionPerformance); - else cognitionPerformance = 100 * softmin(capPerformance / 100, cognitionPerformance / 100, 100); + else cognitionPerformance = 1000 * softmin(capPerformance / 1000, cognitionPerformance / 1000, 100); return cognitionPerformance; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 19478cd753..e1431d6978 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -263,12 +263,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing } double fadeInStartTime = BaseObject.StartTime - BaseObject.TimePreempt; - double fadeInDuration = BaseObject.TimeFadeIn; + double fadeInDuration = BaseObject.TimeFadeInRaw; if (hidden) { // Taken from OsuModHidden. - double fadeOutStartTime = BaseObject.StartTime - BaseObject.TimePreempt + BaseObject.TimeFadeIn; + double fadeOutStartTime = BaseObject.StartTime - BaseObject.TimePreempt + BaseObject.TimeFadeInRaw; double fadeOutDuration = BaseObject.TimePreempt * OsuModHidden.FADE_OUT_DURATION_MULTIPLIER; return Math.Min diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 3d6d3f99c1..9fafeacb9c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills public class Flashlight : StrainSkill { private readonly bool hasHiddenMod; + protected virtual bool HasHiddenMod => hasHiddenMod; public Flashlight(Mod[] mods) : base(mods) @@ -36,11 +37,23 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double StrainValueAt(DifficultyHitObject current) { currentStrain *= strainDecay(current.DeltaTime); - currentStrain += FlashlightEvaluator.EvaluateDifficultyOf(current, hasHiddenMod) * skillMultiplier; + currentStrain += FlashlightEvaluator.EvaluateDifficultyOf(current, HasHiddenMod) * skillMultiplier; return currentStrain; } public override double DifficultyValue() => GetCurrentStrainPeaks().Sum() * OsuStrainSkill.DEFAULT_DIFFICULTY_MULTIPLIER; + + public static double DifficultyToPerformance(double difficulty) => Math.Pow(difficulty, 2) * 25.0; + } + + public class HiddenFlashlight : Flashlight + { + protected override bool HasHiddenMod => true; + + public HiddenFlashlight(Mod[] mods) + : base(mods) + { + } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs index 592db63144..dcfe624db2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Reading.cs @@ -113,5 +113,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return currentStrain; } + + public static double DifficultyToPerformance(double difficulty) => Math.Pow(difficulty, 2) * 25.0; } } diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 74631400ca..84487ec0bd 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -49,6 +49,7 @@ namespace osu.Game.Rulesets.Osu.Objects public double TimePreempt = 600; public double TimeFadeIn = 400; + public double TimeFadeInRaw = 400; private HitObjectProperty position; @@ -165,6 +166,7 @@ namespace osu.Game.Rulesets.Osu.Objects // Note that this doesn't exactly match the AR>10 visuals as they're classically known, but it feels good. // This adjustment is necessary for AR>10, otherwise TimePreempt can become smaller leading to hitcircles not fully fading in. TimeFadeIn = 400 * Math.Min(1, TimePreempt / PREEMPT_MIN); + TimeFadeInRaw = TimeFadeIn; Scale = LegacyRulesetExtensions.CalculateScaleFromCircleSize(difficulty.CircleSize, true); }