Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,10 @@ 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 = osuLastObj.GetDistance(withSliderTravelDistance);

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 prevVelocity = prevDistance / osuLastObj.AdjustedDeltaTime;

double flowDifficulty = currVelocity;
Expand Down Expand Up @@ -83,11 +75,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with

if (Math.Max(prevVelocity, currVelocity) != 0)
{
if (withSliderTravelDistance)
{
currVelocity = currDistance / 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);

Expand All @@ -104,7 +91,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
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,10 @@ 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;

// 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 currDistance = osuCurrObj.GetDistance(withSliderTravelDistance);
double prevDistance = osuLastObj.GetDistance(withSliderTravelDistance);

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

double wideAngleBonus = 0;
Expand Down Expand Up @@ -119,12 +112,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with

if (Math.Max(prevVelocity, currVelocity) != 0)
{
if (withSliderTravelDistance)
{
// We want to use just the object jump without slider velocity when awarding differences
currVelocity = currDistance / 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);

Expand All @@ -140,11 +127,11 @@ 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.
aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj);
aimStrain *= vectorAngleRepetition(osuCurrObj, osuLastObj, withSliderTravelDistance);

aimStrain += wiggleBonus * wiggle_multiplier;
aimStrain += velocityChangeBonus * velocity_change_multiplier;
Expand All @@ -159,7 +146,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, currDistance);

return aimStrain;
}
Expand All @@ -170,7 +157,7 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
private static double highBpmBonus(double ms, double distance) => 1 / (1 - Math.Pow(0.03, Math.Pow(ms / 1000, 0.65)))
* DifficultyCalculationUtils.Smootherstep(distance, 0, OsuDifficultyHitObject.NORMALISED_RADIUS);

private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuDifficultyHitObject previous)
private static double vectorAngleRepetition(OsuDifficultyHitObject current, OsuDifficultyHitObject previous, bool withSliderTravelDistance)
{
if (current.Angle == null || previous.Angle == null)
return 1;
Expand Down Expand Up @@ -201,7 +188,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.GetDistance(withSliderTravelDistance), 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
11 changes: 6 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.GetDistance(true) / 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.GetDistance(true), 15, distance_influence_threshold);
}

// Value higher note densities exponentially
Expand Down Expand Up @@ -134,7 +134,8 @@ 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)
// Distance without slider is deliberately used since perfectly stacked slider heads should also be buffed
if (currObj.GetDistance(false) == 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 +150,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.GetDistance(true), 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 +246,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.GetDistance(true), 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