Skip to content

Commit

Permalink
came back to v1
Browse files Browse the repository at this point in the history
  • Loading branch information
Givikap120 committed Oct 10, 2024
1 parent 8a890fa commit 556b90d
Show file tree
Hide file tree
Showing 8 changed files with 16 additions and 208 deletions.
36 changes: 1 addition & 35 deletions osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;

namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
{
Expand All @@ -17,9 +15,6 @@ public static class AimEvaluator
private const double slider_multiplier = 1.35;
private const double velocity_change_multiplier = 0.75;

private const double slider_shape_reading_multiplier = 4;
private const double slider_end_distance_multiplier = 0.3;

/// <summary>
/// Evaluates the difficulty of aiming the current object, based on:
/// <list type="bullet">
Expand Down Expand Up @@ -117,11 +112,10 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2);
}

if (withSliderTravelDistance && osuLastObj.BaseObject is Slider slider)
if (withSliderTravelDistance && osuLastObj.BaseObject is Slider)
{
// Reward sliders based on velocity.
sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime;
sliderBonus *= calculateCurvature(slider);
}

// Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger.
Expand All @@ -134,34 +128,6 @@ public static double EvaluateDifficultyOf(DifficultyHitObject current, bool with
return aimStrain;
}

private static double calculateCurvature(Slider slider)
{
if (slider.SpanDuration == 0) return 1;

//double minFollowRadius = slider.Radius;
//double maxFollowRadius = slider.Radius * 2.4;
//double deltaFollowRadius = maxFollowRadius - minFollowRadius;

//OsuHitObject head;
//if (slider.RepeatCount == 0)
// head = (OsuHitObject)slider.NestedHitObjects[0];
//else
// head = (OsuHitObject)slider.NestedHitObjects.Where(o => o is SliderRepeat).Last();

//var tail = (OsuHitObject)slider.NestedHitObjects[^1];

//double numberOfUpdates = Math.Ceiling(2 * slider.Path.Distance / slider.Radius);
//double deltaT = slider.SpanDuration / numberOfUpdates;

//double middleTime = (head.StartTime + tail.StartTime) / 2 - head.StartTime;
//var middlePos = positionWithRepeats(middleTime, slider);

//double curvedLengthBonus = (Vector2.Distance(head.Position, middlePos) + Vector2.Distance(middlePos, tail.Position))
// / Vector2.Distance(head.Position, tail.Position) - 1;
//curveBonus += curvedLengthBonus;
return 1;
}

private static double calcWideAngleBonus(double angle) => Math.Pow(Math.Sin(3.0 / 4 * (Math.Min(5.0 / 6 * Math.PI, Math.Max(Math.PI / 6, angle)) - Math.PI / 6)), 2);

private static double calcAcuteAngleBonus(double angle) => 1 - calcWideAngleBonus(angle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,92 +2,31 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;

using osu.Game.Rulesets.Osu.Objects;
using osuTK;

namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
{
public static class SliderReadingEvaluator
{
private const double slider_velocity_change_multiplier = 0.5;
private const double slider_shape_reading_multiplier = 4;
private const double slider_end_distance_multiplier = 0.3;

/// <summary>
/// Evaluates the difficulty of tapping the current object, based on:
/// </summary>
public static double EvaluateDifficultyOf(DifficultyHitObject current, List<OsuDifficultyHitObject> previousSliders)
public static double EvaluateDifficultyOf(Slider slider)
{
if (current.BaseObject is not Slider)
return 0;

// Assign prev as curr by default so it will get 0 bonuses
var osuCurrObj = (OsuDifficultyHitObject)current;
OsuDifficultyHitObject osuPrevObj = osuCurrObj;

Slider currSlider = (Slider)current.BaseObject;
Slider prevSlider = currSlider;

double aimCurr = osuCurrObj.TravelDistance / osuCurrObj.TravelTime;
double aimPrev = osuPrevObj.TravelDistance / osuPrevObj.TravelTime;

double weightedPrevVelocity = currSlider.Velocity;
if (previousSliders.Count > 0)
{
osuPrevObj = previousSliders[^1];
prevSlider = (Slider)osuPrevObj.BaseObject;

weightedPrevVelocity = 0;
int maxCount = Math.Min(5, previousSliders.Count);

for (int i = 1; i <= maxCount; i++)
{
Slider loopSlider = (Slider)previousSliders[^i].BaseObject;
weightedPrevVelocity += loopSlider.Velocity / Math.Pow(2, i);
}
// Adjusting accounting for gemoetric sum (1 - 0.5^n) / (1 - 0.5)
weightedPrevVelocity /= (1 - Math.Pow(0.5, maxCount)) * 2;
}

double complexityBonus = calculateSliderShapeComplexity(currSlider);

// Get velocity change bonus
double velocityChangeBonus = slider_velocity_change_multiplier * differenceCurve(currSlider.Velocity, weightedPrevVelocity, 0.5, 0.85);

// Punish velocity change if rhythms was different
velocityChangeBonus *= 1 - 0.7 * differenceCurve(currSlider.SpanDuration, prevSlider.SpanDuration, 0.5, 0.75);

double pointUnpredictability = calculateSliderPointUnpredictability(currSlider);

//complexityBonus *= 1 + velocityChangeBonus;
double complexityBonus = calculateSliderShapeComplexity(slider);
double pointUnpredictability = calculateSliderPointUnpredictability(slider);

double difficulty = 0;
difficulty += aimCurr * complexityBonus * (1 + pointUnpredictability);
double difficulty = complexityBonus * (1 + pointUnpredictability);

return difficulty;
}

/// <summary>
/// Returns curve that goes from 0 to 1 as difference increase, starting to increase on point 1 and getting max on point2
/// </summary>
/// <param name="value1"></param>
/// <param name="value2"></param>
/// <param name="point1"></param>
/// <param name="point2"></param>
/// <returns></returns>
private static double differenceCurve(double value1, double value2, double point1, double point2)
{
double similarity = Math.Min(value1, value2) / Math.Max(value1, value2);
if (Math.Max(value1, value2) <= 0) similarity = 0;
return 1 - sinusCurve(similarity, point1, point2);
}

/// <summary>
/// Increase from 0 on point1 to 1 on point2
/// </summary>
Expand Down Expand Up @@ -228,25 +167,14 @@ private static double calculateSliderShapeComplexity(Slider slider)
lineBonus *= slider_shape_reading_multiplier / slider.SpanDuration;
curveBonus *= slider_shape_reading_multiplier / slider.SpanDuration;

// Curve path takes more aim
double curvedLengthBonus = (Vector2.Distance(head.Position, middlePos) + Vector2.Distance(middlePos, tail.Position))
/ Vector2.Distance(head.Position, tail.Position) - 1;
curveBonus += curvedLengthBonus;

return Math.Min(lineBonus, curveBonus);
}

private static double calculateSliderEndDistanceDifficulty(Slider slider)
{
if (slider.LazyEndPosition is null) return 0;
if (slider.LazyTravelDistance == 0) return 0;
// But start to buff only from 0.2 and more
curveBonus += Math.Max(curvedLengthBonus - 0.2, 0);

float visualDistance = Vector2.Distance(slider.StackedEndPosition, (Vector2)slider.LazyEndPosition);

var preLastObj = (OsuHitObject)slider.NestedHitObjects[^2];

double minimalMovement = Vector2.Distance((Vector2)slider.LazyEndPosition, preLastObj.Position) - slider.Radius * 4.8;
visualDistance *= (float)Math.Clamp(minimalMovement / slider.Radius, 0, 1); // buff only very long sliders
return (visualDistance / slider.LazyTravelDistance) * slider_end_distance_multiplier;
return Math.Min(lineBonus, curveBonus);
}

private static double calculateSliderPointUnpredictability(Slider slider)
Expand All @@ -267,7 +195,7 @@ private static double calculateSliderPointUnpredictability(Slider slider)
OsuHitObject currObj = (OsuHitObject)obj;
Vector2 currObjPos = currObj.StackedPosition;

if (prevObj0 == null)
if (prevObj0 == null || prevObjPos0 == null)
{
prevObj0 = currObj;
prevObjPos0 = currObjPos;
Expand Down
3 changes: 0 additions & 3 deletions osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ public class OsuDifficultyAttributes : DifficultyAttributes
[JsonProperty("speed_note_count")]
public double SpeedNoteCount { get; set; }

[JsonProperty("slider_reading")]
public double SliderReadingDifficulty { get; set; }

/// <summary>
/// The difficulty corresponding to the flashlight skill.
/// </summary>
Expand Down
7 changes: 1 addition & 6 deletions osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
double speedNotes = ((Speed)skills[2]).RelevantNoteCount();
double sliderReadingRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier;

double flashlightRating = 0.0;

Expand All @@ -64,7 +63,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat

double baseAimPerformance = Math.Pow(5 * Math.Max(1, aimRating / 0.0675) - 4, 3) / 100000;
double baseSpeedPerformance = Math.Pow(5 * Math.Max(1, speedRating / 0.0675) - 4, 3) / 100000;
double baseSliderReadingPerformance = SliderReading.DifficultyToPerformance(sliderReadingRating, aimRating);
double baseFlashlightPerformance = 0.0;

if (mods.Any(h => h is OsuModFlashlight))
Expand All @@ -74,7 +72,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
Math.Pow(
Math.Pow(baseAimPerformance, 1.1) +
Math.Pow(baseSpeedPerformance, 1.1) +
Math.Pow(baseSliderReadingPerformance, 1.1) +
Math.Pow(baseFlashlightPerformance, 1.1), 1.0 / 1.1
);

Expand Down Expand Up @@ -104,7 +101,6 @@ protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beat
SpeedNoteCount = speedNotes,
FlashlightDifficulty = flashlightRating,
SliderFactor = sliderFactor,
SliderReadingDifficulty = sliderReadingRating,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
DrainRate = drainRate,
Expand Down Expand Up @@ -138,8 +134,7 @@ protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clo
{
new Aim(mods, true),
new Aim(mods, false),
new Speed(mods),
new SliderReading(mods)
new Speed(mods)
};

if (mods.Any(h => h is OsuModFlashlight))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class OsuPerformanceAttributes : PerformanceAttributes

[JsonProperty("flashlight")]
public double Flashlight { get; set; }
public double SliderReading { get; set; }

[JsonProperty("effective_miss_count")]
public double EffectiveMissCount { get; set; }
Expand Down
26 changes: 0 additions & 26 deletions osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,13 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s

double aimValue = computeAimValue(score, osuAttributes);
double speedValue = computeSpeedValue(score, osuAttributes);
double sliderReadingValue = computeSliderReadingValue(score, osuAttributes);
double accuracyValue = computeAccuracyValue(score, osuAttributes);
double flashlightValue = computeFlashlightValue(score, osuAttributes);

double totalValue =
Math.Pow(
Math.Pow(aimValue, 1.1) +
Math.Pow(speedValue, 1.1) +
Math.Pow(sliderReadingValue, 1.1) +
Math.Pow(accuracyValue, 1.1) +
Math.Pow(flashlightValue, 1.1), 1.0 / 1.1
) * multiplier;
Expand All @@ -81,7 +79,6 @@ protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo s
{
Aim = aimValue,
Speed = speedValue,
SliderReading = sliderReadingValue,
Accuracy = accuracyValue,
Flashlight = flashlightValue,
EffectiveMissCount = effectiveMissCount,
Expand Down Expand Up @@ -189,29 +186,6 @@ private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attrib
return speedValue;
}

private double computeSliderReadingValue(ScoreInfo score, OsuDifficultyAttributes attributes)
{
double sliderReadingValue = SliderReading.DifficultyToPerformance(attributes.SliderReadingDifficulty, attributes.AimDifficulty);

double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) +
(totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0);
sliderReadingValue *= lengthBonus;

sliderReadingValue *= getComboScalingFactor(attributes);

if (score.Mods.Any(m => m is OsuModBlinds))
sliderReadingValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate);

// We assume 15% of sliders in a map are difficult since there's no way to tell from the performance calculator.
double estimateDifficultSliders = Math.Max(1, attributes.SliderCount * 0.15);

double estimateSliderEndsDropped = Math.Clamp(Math.Min(countOk + countMeh + countMiss, attributes.MaxCombo - scoreMaxCombo), 0, estimateDifficultSliders);
double sliderNerfFactor = 1 - estimateSliderEndsDropped / estimateDifficultSliders;
sliderReadingValue *= sliderNerfFactor;

return sliderReadingValue;
}

private double computeAccuracyValue(ScoreInfo score, OsuDifficultyAttributes attributes)
{
if (score.Mods.Any(h => h is OsuModRelax))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Linq;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Difficulty.Evaluators;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
Expand Down Expand Up @@ -144,6 +145,9 @@ private void setDistances(double clockRate)
// Bonus for repeat sliders until a better per nested object strain system can be achieved.
TravelDistance = currentSlider.LazyTravelDistance * (float)Math.Pow(1 + currentSlider.RepeatCount / 2.5, 1.0 / 2.5);
TravelTime = Math.Max(currentSlider.LazyTravelTime / clockRate, min_delta_time);

// Buff curvy sliders
TravelDistance *= 1 + SliderReadingEvaluator.EvaluateDifficultyOf(currentSlider);
}

// We don't need to calculate either angle or distance when one of the last->curr objects is a spinner
Expand Down
55 changes: 0 additions & 55 deletions osu.Game.Rulesets.Osu/Difficulty/Skills/SliderReading.cs

This file was deleted.

0 comments on commit 556b90d

Please sign in to comment.