mirror of https://github.com/ppy/osu
Retrieve great hit window from the hit object
This commit is contained in:
parent
604fc0fb97
commit
b5779508d0
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue