1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 18:37:52 +08:00

Pass OK hit window as a separate difficulty attribute, fix erfc approximation

This commit is contained in:
Natelytle 2023-03-20 22:00:33 -04:00
parent adf16187b1
commit 858afcd0b3
3 changed files with 16 additions and 12 deletions

View File

@ -43,6 +43,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
[JsonProperty("great_hit_window")] [JsonProperty("great_hit_window")]
public double GreatHitWindow { get; set; } public double GreatHitWindow { get; set; }
/// <summary>
/// The perceived hit window for an OK hit inclusive of rate-adjusting mods (DT/HT/etc).
/// </summary>
/// <remarks>
/// Rate-adjusting mods don't directly affect the hit window, but have a perceived effect as a result of adjusting audio timing.
/// </remarks>
[JsonProperty("ok_hit_window")]
public double OkHitWindow { get; set; }
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes() public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
{ {
foreach (var v in base.ToDatabaseAttributes()) foreach (var v in base.ToDatabaseAttributes())

View File

@ -95,6 +95,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
ColourDifficulty = colourRating, ColourDifficulty = colourRating,
PeakDifficulty = combinedRating, PeakDifficulty = combinedRating,
GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate, GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate,
OkHitWindow = hitWindows.WindowFor(HitResult.Ok) / clockRate,
MaxCombo = beatmap.HitObjects.Count(h => h is Hit), MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
}; };
} }

View File

@ -12,8 +12,6 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Scoring; using osu.Game.Scoring;
using MathNet.Numerics; using MathNet.Numerics;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions;
namespace osu.Game.Rulesets.Taiko.Difficulty namespace osu.Game.Rulesets.Taiko.Difficulty
{ {
@ -125,17 +123,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
/// </summary> /// </summary>
private double? computeEstimatedUr(ScoreInfo score, TaikoDifficultyAttributes attributes) private double? computeEstimatedUr(ScoreInfo score, TaikoDifficultyAttributes attributes)
{ {
if (totalSuccessfulHits == 0 || attributes.GreatHitWindow == 0) if (totalSuccessfulHits == 0 || attributes.GreatHitWindow <= 0)
return null; return null;
// Create a new track to properly calculate the hit window of 100s.
var track = new TrackVirtual(10000);
score.Mods.OfType<IApplicableToTrack>().ForEach(m => m.ApplyToTrack(track));
double clockRate = track.Rate;
double overallDifficulty = (50 - attributes.GreatHitWindow * clockRate) / 3;
double h300 = attributes.GreatHitWindow; double h300 = attributes.GreatHitWindow;
double h100 = overallDifficulty <= 5 ? (120 - 8 * overallDifficulty) / clockRate : (80 - 6 * (overallDifficulty - 5)) / clockRate; double h100 = attributes.OkHitWindow;
// Returns the likelihood of a deviation resulting in the score's hit judgements. The peak of the curve is the most likely deviation. // Returns the likelihood of a deviation resulting in the score's hit judgements. The peak of the curve is the most likely deviation.
double likelihoodGradient(double d) double likelihoodGradient(double d)
@ -167,8 +159,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
private double logPcHit(double x, double deviation) => logErfcApprox(x / (deviation * Math.Sqrt(2))); private double logPcHit(double x, double deviation) => logErfcApprox(x / (deviation * Math.Sqrt(2)));
// There is a numerical approximation to increase how far you can calculate Erfc(x). // There's a numerical approximation to increase how far you can calculate ln(erfc(x)).
private double logErfcApprox(double x) => x <= 5 ? Math.Log(SpecialFunctions.Erfc(x)) : -Math.Pow(x, 2) - Math.Log(x) - Math.Log(Math.Sqrt(Math.PI)); private double logErfcApprox(double x) => x <= 5
? Math.Log(SpecialFunctions.Erfc(x))
: -Math.Pow(x, 2) - Math.Log(x * Math.Sqrt(Math.PI)); // https://www.desmos.com/calculator/kdbxwxgf01
// Log rules make subtraction of the non-log value non-trivial, this method simply subtracts the base value of 2 logs. // Log rules make subtraction of the non-log value non-trivial, this method simply subtracts the base value of 2 logs.
private double logDiff(double firstLog, double secondLog) private double logDiff(double firstLog, double secondLog)