Retrieve great hit window from the hit object

This commit is contained in:
apollo-dw 2022-09-06 17:10:32 +01:00
parent 604fc0fb97
commit b5779508d0
5 changed files with 29 additions and 18 deletions

View File

@ -18,7 +18,7 @@ public static class RhythmEvaluator
/// <summary> /// <summary>
/// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current <see cref="OsuDifficultyHitObject"/>. /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current <see cref="OsuDifficultyHitObject"/>.
/// </summary> /// </summary>
public static double EvaluateDifficultyOf(DifficultyHitObject current, double greatWindow) public static double EvaluateDifficultyOf(DifficultyHitObject current)
{ {
if (current.BaseObject is Spinner) if (current.BaseObject is Spinner)
return 0; return 0;
@ -53,7 +53,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, double gr
double lastDelta = lastObj.StrainTime; double lastDelta = lastObj.StrainTime;
double currRatio = 1.0 + 6.0 * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / (Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta))), 2)); // fancy function to calculate rhythmbonuses. double currRatio = 1.0 + 6.0 * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / (Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta))), 2)); // fancy function to calculate rhythmbonuses.
double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - greatWindow * 0.6) / (greatWindow * 0.6)); double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - currObj.HitWindowGreat * 0.6) / (currObj.HitWindowGreat * 0.6));
windowPenalty = Math.Min(1, windowPenalty); windowPenalty = Math.Min(1, windowPenalty);

View File

@ -24,7 +24,7 @@ public static class SpeedEvaluator
/// <item><description>and how easily they can be cheesed.</description></item> /// <item><description>and how easily they can be cheesed.</description></item>
/// </list> /// </list>
/// </summary> /// </summary>
public static double EvaluateDifficultyOf(DifficultyHitObject current, double greatWindow) public static double EvaluateDifficultyOf(DifficultyHitObject current)
{ {
if (current.BaseObject is Spinner) if (current.BaseObject is Spinner)
return 0; return 0;
@ -35,7 +35,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, double gr
var osuNextObj = (OsuDifficultyHitObject)current.Next(0); var osuNextObj = (OsuDifficultyHitObject)current.Next(0);
double strainTime = osuCurrObj.StrainTime; double strainTime = osuCurrObj.StrainTime;
double greatWindowFull = greatWindow * 2;
double doubletapness = 1; double doubletapness = 1;
// Nerf doubletappable doubles. // Nerf doubletappable doubles.
@ -45,13 +44,13 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, double gr
double nextDeltaTime = Math.Max(1, osuNextObj.DeltaTime); double nextDeltaTime = Math.Max(1, osuNextObj.DeltaTime);
double deltaDifference = Math.Abs(nextDeltaTime - currDeltaTime); double deltaDifference = Math.Abs(nextDeltaTime - currDeltaTime);
double speedRatio = currDeltaTime / Math.Max(currDeltaTime, deltaDifference); double speedRatio = currDeltaTime / Math.Max(currDeltaTime, deltaDifference);
double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / greatWindowFull), 2); double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / osuCurrObj.HitWindowGreat), 2);
doubletapness = Math.Pow(speedRatio, 1 - windowRatio); doubletapness = Math.Pow(speedRatio, 1 - windowRatio);
} }
// Cap deltatime to the OD 300 hitwindow. // Cap deltatime to the OD 300 hitwindow.
// 0.93 is derived from making sure 260bpm OD8 streams aren't nerfed harshly, whilst 0.92 limits the effect of the cap. // 0.93 is derived from making sure 260bpm OD8 streams aren't nerfed harshly, whilst 0.92 limits the effect of the cap.
strainTime /= Math.Clamp((strainTime / greatWindowFull) / 0.93, 0.92, 1); strainTime /= Math.Clamp((strainTime / osuCurrObj.HitWindowGreat) / 0.93, 0.92, 1);
// derive speedBonus for calculation // derive speedBonus for calculation
double speedBonus = 1.0; double speedBonus = 1.0;

View File

@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
public class OsuDifficultyCalculator : DifficultyCalculator public class OsuDifficultyCalculator : DifficultyCalculator
{ {
private const double difficulty_multiplier = 0.0675; private const double difficulty_multiplier = 0.0675;
private double hitWindowGreat;
public override int Version => 20220902; public override int Version => 20220902;
@ -76,6 +75,11 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
int sliderCount = beatmap.HitObjects.Count(h => h is Slider); int sliderCount = beatmap.HitObjects.Count(h => h is Slider);
int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner); int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner);
HitWindows hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
double hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate;
return new OsuDifficultyAttributes return new OsuDifficultyAttributes
{ {
StarRating = starRating, StarRating = starRating,
@ -112,16 +116,11 @@ protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(I
protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate)
{ {
HitWindows hitWindows = new OsuHitWindows();
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate;
return new Skill[] return new Skill[]
{ {
new Aim(mods, true), new Aim(mods, true),
new Aim(mods, false), new Aim(mods, false),
new Speed(mods, hitWindowGreat), new Speed(mods),
new Flashlight(mods) new Flashlight(mods)
}; };
} }

View File

@ -9,6 +9,7 @@
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
using osuTK; using osuTK;
namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
@ -78,6 +79,11 @@ public class OsuDifficultyHitObject : DifficultyHitObject
/// </summary> /// </summary>
public double? Angle { get; private set; } public double? Angle { get; private set; }
/// <summary>
/// Retrieves the full hit window for a Great <see cref="HitResult"/>.
/// </summary>
public double HitWindowGreat { get; private set; }
private readonly OsuHitObject lastLastObject; private readonly OsuHitObject lastLastObject;
private readonly OsuHitObject lastObject; private readonly OsuHitObject lastObject;
@ -90,6 +96,15 @@ public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObje
// Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects. // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects.
StrainTime = Math.Max(DeltaTime, min_delta_time); StrainTime = Math.Max(DeltaTime, min_delta_time);
if (BaseObject is Slider sliderObject)
{
HitWindowGreat = 2 * sliderObject.HeadCircle.HitWindows.WindowFor(HitResult.Great) / clockRate;
}
else
{
HitWindowGreat = 2 * BaseObject.HitWindows.WindowFor(HitResult.Great) / clockRate;
}
setDistances(clockRate); setDistances(clockRate);
} }

View File

@ -26,14 +26,12 @@ public class Speed : OsuStrainSkill
protected override int ReducedSectionCount => 5; protected override int ReducedSectionCount => 5;
protected override double DifficultyMultiplier => 1.04; protected override double DifficultyMultiplier => 1.04;
private readonly double greatWindow;
private readonly List<double> objectStrains = new List<double>(); private readonly List<double> objectStrains = new List<double>();
public Speed(Mod[] mods, double hitWindowGreat) public Speed(Mod[] mods)
: base(mods) : base(mods)
{ {
greatWindow = hitWindowGreat;
} }
private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000);
@ -43,9 +41,9 @@ public Speed(Mod[] mods, double hitWindowGreat)
protected override double StrainValueAt(DifficultyHitObject current) protected override double StrainValueAt(DifficultyHitObject current)
{ {
currentStrain *= strainDecay(((OsuDifficultyHitObject)current).StrainTime); currentStrain *= strainDecay(((OsuDifficultyHitObject)current).StrainTime);
currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, greatWindow) * skillMultiplier; currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current) * skillMultiplier;
currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current, greatWindow); currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current);
double totalStrain = currentStrain * currentRhythm; double totalStrain = currentStrain * currentRhythm;