1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-17 04:32:35 +08:00

Make sliderless aim in fact sliderless (#29993)

Part of this PR - https://github.com/ppy/osu/pull/27303

Current aim calculation have a flaw of sliderless aim still accounting
for sliders. This happens because of usage of `LazyJumpDistance` as a
main distance metric.

This PR is fixing this by adding `JumpDistance` as true sliderless
metric, using it instead of `LazyJumpDistance`.
This can introduce very rare cases where sliderless aim is worth more
than normal aim (because of velocity change bonus).

The effect of this is minimal on most of the maps. It can be seen the
best on this map - https://osu.ppy.sh/beatmapsets/594751#osu/1257904
Before:

![image](https://github.com/user-attachments/assets/e96773e6-3274-4ed6-8293-ed9bdfa213d0)

After:

![image](https://github.com/user-attachments/assets/126e861b-c28d-4ed4-a0db-f5305225a749)

---------

Co-authored-by: James Wilson <tsunyoku@gmail.com>
Co-authored-by: StanR <8269193+stanriders@users.noreply.github.com>
This commit is contained in:
Givy120
2026-01-27 22:23:22 +02:00
committed by GitHub
Unverified
parent ea87e82a91
commit aefe31d315
2 changed files with 23 additions and 12 deletions
@@ -40,7 +40,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER;
// Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle.
double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.AdjustedDeltaTime;
double currDistance = withSliderTravelDistance ? osuCurrObj.LazyJumpDistance : osuCurrObj.JumpDistance;
double currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime;
// But if the last object is a slider, then we extend the travel velocity through the slider into the current object.
if (osuLastObj.BaseObject is Slider && withSliderTravelDistance)
@@ -52,7 +53,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
}
// As above, do the same for the previous hitobject.
double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.AdjustedDeltaTime;
double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance;
double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime;
if (osuLastLastObj.BaseObject is Slider && withSliderTravelDistance)
{
@@ -88,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
// Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter
acuteAngleBonus *= angleBonus *
DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) *
DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2);
DifficultyCalculationUtils.Smootherstep(currDistance, diameter, diameter * 2);
}
wideAngleBonus = calcWideAngleBonus(currAngle);
@@ -97,16 +99,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3));
// Apply full wide angle bonus for distance more than one diameter
wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter);
wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(currDistance, 0, diameter);
// Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle
// https://www.desmos.com/calculator/dp0v0nvowc
wiggleBonus = angleBonus
* DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter)
* Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuCurrObj.LazyJumpDistance, diameter * 3, diameter), 1.8)
* DifficultyCalculationUtils.Smootherstep(currDistance, radius, diameter)
* Math.Pow(DifficultyCalculationUtils.ReverseLerp(currDistance, diameter * 3, diameter), 1.8)
* DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60))
* DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter)
* Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 3, diameter), 1.8)
* DifficultyCalculationUtils.Smootherstep(prevDistance, radius, diameter)
* Math.Pow(DifficultyCalculationUtils.ReverseLerp(prevDistance, diameter * 3, diameter), 1.8)
* DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60));
if (osuLast2Obj != null)
@@ -127,9 +129,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
if (Math.Max(prevVelocity, currVelocity) != 0)
{
// We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities.
prevVelocity = (osuLastObj.LazyJumpDistance + osuLastLastObj.TravelDistance) / osuLastObj.AdjustedDeltaTime;
currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.AdjustedDeltaTime;
if (withSliderTravelDistance)
{
// We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities.
prevVelocity = (osuLastObj.LazyJumpDistance + osuLastLastObj.TravelDistance) / osuLastObj.AdjustedDeltaTime;
currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.AdjustedDeltaTime;
}
// Scale with ratio of difference compared to 0.5 * max dist.
double distRatio = DifficultyCalculationUtils.Smoothstep(Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity), 0, 1);
@@ -46,6 +46,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
/// </summary>
public readonly double ClockRate;
/// <summary>
/// Normalised distance from the start position of the previous <see cref="OsuDifficultyHitObject"/> to the start position of this <see cref="OsuDifficultyHitObject"/>.
/// </summary>
public double JumpDistance { get; private set; }
/// <summary>
/// Normalised distance from the "lazy" end position of the previous <see cref="OsuDifficultyHitObject"/> to the start position of this <see cref="OsuDifficultyHitObject"/>.
/// <para>
@@ -232,7 +237,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
Vector2 lastCursorPosition = lastDifficultyObject != null ? getEndCursorPosition(lastDifficultyObject) : LastObject.StackedPosition;
LazyJumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length;
JumpDistance = (LastObject.StackedPosition - BaseObject.StackedPosition).Length * scalingFactor;
LazyJumpDistance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor;
MinimumJumpTime = AdjustedDeltaTime;
MinimumJumpDistance = LazyJumpDistance;