Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current)
return 0;

var osuCurrObj = (OsuDifficultyHitObject)current;
var osuPrevObj = current.Index > 0 ? (OsuDifficultyHitObject)current.Previous(0) : null;

double travelDistance = osuPrevObj?.LazyTravelDistance ?? 0;
double distance = travelDistance + osuCurrObj.LazyJumpDistance;
double distance = osuCurrObj.GetDistance(true);

double distanceScaled = Math.Min(distance, distance_cap) / distance_cap;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
var osuLastObj = (OsuDifficultyHitObject)current.Previous(0);
var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1);

double currDistance = withSliderTravelDistance ? osuCurrObj.LazyJumpDistance : osuCurrObj.JumpDistance;
double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance;
double currDistance = osuCurrObj.GetDistance(withSliderTravelDistance);
double prevDistance = withSliderTravelDistance ? osuLastObj.TailJumpDistance : osuLastObj.GetDistance(false);

double currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime;

if (osuLastObj.BaseObject is Slider && withSliderTravelDistance)
{
// If the last object is a slider, then we extend the travel velocity through the slider into the current object.
double sliderDistance = osuLastObj.LazyTravelDistance + osuCurrObj.LazyJumpDistance;
currVelocity = Math.Max(currVelocity, sliderDistance / osuCurrObj.AdjustedDeltaTime);
}
double currFakeDistance = withSliderTravelDistance ? osuCurrObj.TailJumpDistance : osuCurrObj.GetDistance(false); // Keeping to preserve values

double currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime;
double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime;

double flowDifficulty = currVelocity;
Expand Down Expand Up @@ -85,7 +79,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
{
if (withSliderTravelDistance)
{
currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime;
currVelocity = currFakeDistance / osuCurrObj.AdjustedDeltaTime;
}

// Scale with ratio of difference compared to 0.5 * max dist.
Expand All @@ -104,7 +98,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
if (osuCurrObj.BaseObject is Slider && withSliderTravelDistance)
{
// Include slider velocity to make velocity more consistent with snap
flowDifficulty += osuCurrObj.TravelDistance / osuCurrObj.TravelTime;
flowDifficulty += osuCurrObj.SliderBonusDistance / osuCurrObj.SliderTravelTime;
}

// Final velocity is being raised to a power because flow difficulty scales harder with both high distance and time, and we want to account for that
Expand Down
26 changes: 11 additions & 15 deletions osu.Game.Rulesets.Osu/Difficulty/Evaluators/Aim/SnapAimEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,12 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
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 currDistance = withSliderTravelDistance ? osuCurrObj.LazyJumpDistance : osuCurrObj.JumpDistance;
double currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime;
double currDistance = osuCurrObj.GetDistance(withSliderTravelDistance);
double prevDistance = withSliderTravelDistance ? osuLastObj.TailJumpDistance : osuLastObj.GetDistance(false);

// 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)
{
double sliderDistance = osuLastObj.LazyTravelDistance + osuCurrObj.LazyJumpDistance;
currVelocity = Math.Max(currVelocity, sliderDistance / osuCurrObj.AdjustedDeltaTime);
}
double currFakeDistance = withSliderTravelDistance ? osuCurrObj.TailJumpDistance : osuCurrObj.GetDistance(false); // Keeping to preserve values

double prevDistance = withSliderTravelDistance ? osuLastObj.LazyJumpDistance : osuLastObj.JumpDistance;
double currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime;
double prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime;

double wideAngleBonus = 0;
Expand Down Expand Up @@ -94,8 +89,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
// 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(currDistance, radius, diameter)
* Math.Pow(DifficultyCalculationUtils.ReverseLerp(currDistance, diameter * 3, diameter), 1.8)
* DifficultyCalculationUtils.Smootherstep(currFakeDistance, radius, diameter)
* Math.Pow(DifficultyCalculationUtils.ReverseLerp(currFakeDistance, diameter * 3, diameter), 1.8)
* DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60))
* DifficultyCalculationUtils.Smootherstep(prevDistance, radius, diameter)
* Math.Pow(DifficultyCalculationUtils.ReverseLerp(prevDistance, diameter * 3, diameter), 1.8)
Expand All @@ -122,7 +117,8 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
if (withSliderTravelDistance)
{
// We want to use just the object jump without slider velocity when awarding differences
currVelocity = currDistance / osuCurrObj.AdjustedDeltaTime;
// This is objectively incorrect in some cases, but kept for now to preserve values
currVelocity = currFakeDistance / osuCurrObj.AdjustedDeltaTime;
}

// Scale with ratio of difference compared to 0.5 * max dist.
Expand All @@ -140,7 +136,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
if (osuCurrObj.BaseObject is Slider)
{
// Reward sliders based on velocity.
sliderBonus = osuCurrObj.TravelDistance / osuCurrObj.TravelTime;
sliderBonus = osuCurrObj.SliderBonusDistance / osuCurrObj.SliderTravelTime;
}

// Penalize angle repetition.
Expand All @@ -159,7 +155,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
// Apply high circle size bonus
aimStrain *= osuCurrObj.SmallCircleBonus;

aimStrain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime, osuCurrObj.LazyJumpDistance);
aimStrain *= highBpmBonus(osuCurrObj.AdjustedDeltaTime, osuCurrObj.TailJumpDistance);

return aimStrain;
}
Expand Down Expand Up @@ -201,7 +197,7 @@ private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuD

double vectorRepetition = Math.Pow(Math.Min(0.5 / constantAngleCount, 1), 2);

double stackFactor = DifficultyCalculationUtils.Smootherstep(current.LazyJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_DIAMETER);
double stackFactor = DifficultyCalculationUtils.Smootherstep(current.TailJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_DIAMETER);

double currAngle = current.Angle.Value;
double lastAngle = previous.Angle.Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, IReadOnly
smallDistNerf = Math.Min(1.0, jumpDistance / 75.0);

// We also want to nerf stacks so that only the first object of the stack is accounted for.
double stackNerf = Math.Min(1.0, (currentObj.LazyJumpDistance / scalingFactor) / 25.0);
double stackNerf = Math.Min(1.0, (currentObj.TailJumpDistance / scalingFactor) / 25.0);

// Bonus based on how visible the object is.
double opacityBonus = 1.0 + max_opacity_bonus * (1.0 - osuCurrent.OpacityAt(currentHitObject.StartTime, mods.OfType<OsuModHidden>().Any(m => !m.OnlyFadeApproachCircles.Value)));
Expand Down Expand Up @@ -99,10 +99,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, IReadOnly
if (osuCurrent.BaseObject is Slider osuSlider)
{
// Invert the scaling factor to determine the true travel distance independent of circle size.
double pixelTravelDistance = osuCurrent.LazyTravelDistance / scalingFactor;
double pixelTravelDistance = osuCurrent.SliderBodyDistance / scalingFactor;

// Reward sliders based on velocity.
sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.TravelTime - min_velocity), 0.5);
sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.SliderTravelTime - min_velocity), 0.5);

// Longer sliders require more memorisation.
sliderBonus *= pixelTravelDistance;
Expand Down
10 changes: 5 additions & 5 deletions osu.Game.Rulesets.Osu/Difficulty/Evaluators/ReadingEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool hidd
var currObj = (OsuDifficultyHitObject)current;
var nextObj = (OsuDifficultyHitObject)current.Next(0);

double velocity = Math.Max(1, currObj.LazyJumpDistance / currObj.AdjustedDeltaTime); // Only allow velocity to buff
double velocity = Math.Max(1, currObj.TailJumpDistance / currObj.AdjustedDeltaTime); // Only allow velocity to buff

double currentVisibleObjectDensity = retrieveCurrentVisibleObjectDensity(currObj);
double pastObjectDifficultyInfluence = getPastObjectDifficultyInfluence(currObj);
Expand Down Expand Up @@ -72,7 +72,7 @@ private static double calculateDensityDifficulty(OsuDifficultyHitObject? nextObj
if (nextObj != null)
{
// Reduce difficulty if movement to next object is small
futureObjectDifficultyInfluence *= DifficultyCalculationUtils.Smootherstep(nextObj.LazyJumpDistance, 15, distance_influence_threshold);
futureObjectDifficultyInfluence *= DifficultyCalculationUtils.Smootherstep(nextObj.TailJumpDistance, 15, distance_influence_threshold);
}

// Value higher note densities exponentially
Expand Down Expand Up @@ -134,7 +134,7 @@ private static double calculateHiddenDifficulty(OsuDifficultyHitObject currObj,
var previousObj = (OsuDifficultyHitObject)currObj.Previous(0);

// Buff perfect stacks only if current note is completely invisible at the time you click the previous note.
if (currObj.LazyJumpDistance == 0 && currObj.OpacityAt(previousObj.BaseObject.StartTime, true) == 0 && previousObj.StartTime > currObj.StartTime - currObj.Preempt)
if (currObj.TailJumpDistance == 0 && currObj.OpacityAt(previousObj.BaseObject.StartTime, true) == 0 && previousObj.StartTime > currObj.StartTime - currObj.Preempt)
hiddenDifficulty += hidden_multiplier * 2500 / Math.Pow(currObj.AdjustedDeltaTime, 1.5); // Perfect stacks are harder the less time between notes

return hiddenDifficulty;
Expand All @@ -149,7 +149,7 @@ private static double getPastObjectDifficultyInfluence(OsuDifficultyHitObject cu
double loopDifficulty = currObj.OpacityAt(loopObj.BaseObject.StartTime, false);

// When aiming an object small distances mean previous objects may be cheesed, so it doesn't matter whether they were arranged confusingly.
loopDifficulty *= DifficultyCalculationUtils.Smootherstep(loopObj.LazyJumpDistance, 15, distance_influence_threshold);
loopDifficulty *= DifficultyCalculationUtils.Smootherstep(loopObj.TailJumpDistance, 15, distance_influence_threshold);

// Account less for objects close to the max reading window
double timeBetweenCurrAndLoopObj = currObj.StartTime - loopObj.StartTime;
Expand Down Expand Up @@ -245,7 +245,7 @@ private static double getConstantAngleNerfFactor(OsuDifficultyHitObject current)
angleDifferenceAlternating = double.Lerp(Math.PI, 0.1 * angleDifferenceAlternating, weight);
}

double stackFactor = DifficultyCalculationUtils.Smootherstep(loopObj.LazyJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS);
double stackFactor = DifficultyCalculationUtils.Smootherstep(loopObj.TailJumpDistance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS);

constantAngleCount += Math.Cos(3 * Math.Min(double.DegreesToRadians(30), Math.Min(angleDifference, angleDifferenceAlternating) * stackFactor)) * longIntervalFactor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current)
// for example a slider-circle-circle pattern should be evaluated as a regular triple and not as a single->double
if (prevObj.BaseObject is Slider)
{
double sliderLazyEndDelta = currObj.MinimumJumpTime;
double sliderLazyEndDelta = currObj.TailDeltaTime;
double sliderLazyDeltaDifference = Math.Max(sliderLazyEndDelta, currDelta) / Math.Min(sliderLazyEndDelta, currDelta);

double sliderRealEndDelta = currObj.LastObjectEndDeltaTime;
Expand Down
Loading
Loading