From 587cf09d2a1e91fb51339730404f85d86c861bdd Mon Sep 17 00:00:00 2001 From: Xexxar Date: Sat, 25 Sep 2021 03:02:33 +0000 Subject: [PATCH] base change of aim refactor, isolated --- .../Preprocessing/OsuDifficultyHitObject.cs | 22 +++-- .../Difficulty/Skills/Aim.cs | 96 ++++++++++++++----- .../Difficulty/Skills/Speed.cs | 4 +- 3 files changed, 89 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 8e8f9bc06e..52f18539c4 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -12,20 +12,20 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { public class OsuDifficultyHitObject : DifficultyHitObject { - private const int normalized_radius = 52; + private const int normalized_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths. protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject; - /// - /// Milliseconds elapsed since the start time of the previous , with a minimum of 25ms to account for simultaneous s. - /// - public double StrainTime { get; private set; } - /// /// Normalized distance from the end position of the previous to the start position of this . /// public double JumpDistance { get; private set; } + /// + /// Normalized Vector from the end position of the previous to the start position of this . + /// + public Vector2 JumpVector { get; private set; } + /// /// Normalized distance between the start and end position of the previous . /// @@ -37,6 +37,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double? Angle { get; private set; } + /// + /// Milliseconds elapsed since the start time of the previous , with a minimum of 50ms. + /// + public readonly double StrainTime; + private readonly OsuHitObject lastLastObject; private readonly OsuHitObject lastObject; @@ -73,7 +78,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // Don't need to jump to reach spinners if (!(BaseObject is Spinner)) - JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; + { + JumpVector = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor); + JumpDistance = JumpVector.Length; + } if (lastLastObject != null) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 16a18cbcb9..677d3c06aa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -6,6 +6,8 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; +using osu.Framework.Utils; +using osuTK; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { @@ -14,51 +16,97 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Aim : OsuStrainSkill { - private const double angle_bonus_begin = Math.PI / 3; - private const double timing_threshold = 107; - public Aim(Mod[] mods) : base(mods) { } - protected override double SkillMultiplier => 26.25; + protected override int HistoryLength => 2; + + protected override double SkillMultiplier => 24.75; protected override double StrainDecayBase => 0.15; + private const double wide_angle_multiplier = 1.0; + private const double acute_angle_multiplier = 1.0; + private const double rhythm_variance_multiplier = 1.0; + protected override double StrainValueOf(DifficultyHitObject current) { - if (current.BaseObject is Spinner) + if (current.BaseObject is Spinner || Previous.Count <= 1) return 0; - var osuCurrent = (OsuDifficultyHitObject)current; + var osuCurrObj = (OsuDifficultyHitObject)current; + var osuPrevObj = (OsuDifficultyHitObject)Previous[0]; + var osuLastObj = (OsuDifficultyHitObject)Previous[1]; - double result = 0; + var currVector = Vector2.Divide(osuCurrObj.JumpVector, (float)osuCurrObj.StrainTime); + var prevVector = Vector2.Divide(osuPrevObj.JumpVector, (float)osuPrevObj.StrainTime); - if (Previous.Count > 0) + // Start with regular velocity. + double aimStrain = currVector.Length; + + if (Precision.AlmostEquals(osuCurrObj.StrainTime, osuPrevObj.StrainTime, 10)) // Rhythms are the same. { - var osuPrevious = (OsuDifficultyHitObject)Previous[0]; - - if (osuCurrent.Angle != null && osuCurrent.Angle.Value > angle_bonus_begin) + if (osuCurrObj.Angle != null) { - const double scale = 90; + double angle = osuCurrObj.Angle.Value; - var angleBonus = Math.Sqrt( - Math.Max(osuPrevious.JumpDistance - scale, 0) - * Math.Pow(Math.Sin(osuCurrent.Angle.Value - angle_bonus_begin), 2) - * Math.Max(osuCurrent.JumpDistance - scale, 0)); - result = 1.4 * applyDiminishingExp(Math.Max(0, angleBonus)) / Math.Max(timing_threshold, osuPrevious.StrainTime); + // Rewarding angles, take the smaller velocity as base. + double angleBonus = Math.Min(currVector.Length, prevVector.Length); + + double wideAngleBonus = calcWideAngleBonus(angle); + double acuteAngleBonus = calcAcuteAngleBonus(angle); + + if (osuCurrObj.StrainTime > 100) + acuteAngleBonus = 0; + else + { + acuteAngleBonus *= Math.Min(2, Math.Pow((100 - osuCurrObj.StrainTime) / 15, 1.5)); + wideAngleBonus *= Math.Pow(osuCurrObj.StrainTime / 100, 6); + } + + if (acuteAngleBonus > wideAngleBonus) + angleBonus = Math.Min(angleBonus, 150 / osuCurrObj.StrainTime) * Math.Min(1, Math.Pow(Math.Min(osuCurrObj.JumpDistance, osuPrevObj.JumpDistance) / 150, 2)); + + angleBonus *= Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); + + // add in angle velocity. + aimStrain += angleBonus; } } + else // There is a rhythm change + { + // Rewarding rhythm, take the smaller velocity as base. + double rhythmBonus = Math.Min(currVector.Length, prevVector.Length); - double jumpDistanceExp = applyDiminishingExp(osuCurrent.JumpDistance); - double travelDistanceExp = applyDiminishingExp(osuCurrent.TravelDistance); + if (osuCurrObj.StrainTime + 10 < osuPrevObj.StrainTime && osuPrevObj.StrainTime > osuLastObj.StrainTime + 10) + // Don't want to reward for a rhythm change back to back (unless its a double, which is why this only checks for fast -> slow -> fast). + rhythmBonus = 0; - return Math.Max( - result + (jumpDistanceExp + travelDistanceExp + Math.Sqrt(travelDistanceExp * jumpDistanceExp)) / Math.Max(osuCurrent.StrainTime, timing_threshold), - (Math.Sqrt(travelDistanceExp * jumpDistanceExp) + jumpDistanceExp + travelDistanceExp) / osuCurrent.StrainTime - ); + aimStrain += rhythmBonus * rhythm_variance_multiplier; // add in rhythm velocity. + } + + return aimStrain; } - private double applyDiminishingExp(double val) => Math.Pow(val, 0.99); + private double calcWideAngleBonus(double angle) + { + if (angle < Math.PI / 3) + return 0; + if (angle < 2 * Math.PI / 3) + return Math.Pow(Math.Sin(1.5 * (angle - Math.PI / 3)), 2); + + return 0.25 + 0.75 * Math.Pow(Math.Sin(1.5 * (Math.PI - angle)), 2); + } + + private double calcAcuteAngleBonus(double angle) + { + if (angle < Math.PI / 3) + return 0.5 + 0.5 * Math.Pow(Math.Sin(1.5 * angle), 2); + if (angle < 2 * Math.PI / 3) + return Math.Pow(Math.Sin(1.5 * (2 * Math.PI / 3 - angle)), 2); + + return 0; + } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 9364b11048..434074da17 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : OsuStrainSkill { - private const double single_spacing_threshold = 125; + private const double single_spacing_threshold = 135; private const double angle_bonus_begin = 5 * Math.PI / 6; private const double pi_over_4 = Math.PI / 4; @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return (1 + (speedBonus - 1) * 0.75) * angleBonus - * (0.95 + speedBonus * Math.Pow(distance / single_spacing_threshold, 3.5)) + * (0.95 + speedBonus * Math.Pow(distance / single_spacing_threshold, 3.0)) / strainTime; } }