1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-14 05:47:20 +08:00

fixed high AR (i hope)

This commit is contained in:
Givikap120 2024-03-25 01:02:38 +02:00
parent 4051413c92
commit 98873e2401
5 changed files with 44 additions and 148 deletions

View File

@ -211,9 +211,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
public static double EvaluateInpredictabilityOf(DifficultyHitObject current)
{
// make the sum equal to 1
const double velocity_change_part = 0.25;
const double angle_change_part = 0.45;
const double rhythm_change_part = 0.3;
const double velocity_change_part = 0.8;
const double angle_change_part = 0.1;
const double rhythm_change_part = 0.1;
if (current.BaseObject is Spinner || current.Index == 0 || current.Previous(0).BaseObject is Spinner)
return 0;
@ -349,4 +349,38 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
}
private static double logistic(double x) => 1 / (1 + Math.Exp(-x));
}
public static class ReadingHighAREvaluator
{
public static double EvaluateDifficultyOf(DifficultyHitObject current, bool applyAdjust = false)
{
var currObj = (OsuDifficultyHitObject)current;
double result = GetDifficulty(currObj.Preempt);
if (applyAdjust)
{
double inpredictability = ReadingEvaluator.EvaluateInpredictabilityOf(current);
// follow lines make high AR easier, so apply nerf if object isn't new combo
inpredictability *= 1 + 0.1 * (800 - currObj.FollowLineTime) / 800;
result *= 0.98 + 0.6 * inpredictability;
}
return result;
}
// High AR curve
// https://www.desmos.com/calculator/srzbeumngi
public static double GetDifficulty(double preempt)
{
// Get preempt in seconds
preempt /= 1000;
if (preempt < 0.375) // We have stop in the point of AR10.5, the value here = 0.396875, derivative = -10.5833,
return 0.63 * Math.Pow(8 - 20 * preempt, 2.0 / 3); // This function is matching live high AR bonus
else
return Math.Exp(9.07583 - 80.0 * preempt / 3);
}
}
}

View File

@ -1,135 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
{
// Main class with some util functions
public static class ReadingHighAREvaluator
{
public static double EvaluateDifficultyOf(DifficultyHitObject current, bool applyAdjust = false)
{
var currObj = (OsuDifficultyHitObject)current;
double result = GetDifficulty(currObj.Preempt);
if (applyAdjust)
{
double inpredictability = ReadingEvaluator.EvaluateInpredictabilityOf(current);
// follow lines make high AR easier, so apply nerf if object isn't new combo
inpredictability *= 1 + 0.1 * (800 - currObj.FollowLineTime) / 800;
result *= 0.9 + 1 * inpredictability;
result *= 1.05 - 0.4 * EvaluateFieryAnglePunishmentOf(current);
}
return result;
}
// Explicitely nerfs edgecased fiery-type jumps for high AR. The difference from Inpredictability is that this is not used in HD calc
public static double EvaluateFieryAnglePunishmentOf(DifficultyHitObject current)
{
if (current.Index <= 2)
return 0;
var currObj = (OsuDifficultyHitObject)current;
var lastObj0 = (OsuDifficultyHitObject)current.Previous(0);
var lastObj1 = (OsuDifficultyHitObject)current.Previous(1);
var lastObj2 = (OsuDifficultyHitObject)current.Previous(2);
if (currObj.Angle.IsNull() || lastObj0.Angle.IsNull() || lastObj1.Angle.IsNull() || lastObj2.Angle.IsNull())
return 0;
// Punishment will be reduced if velocity is changing
double velocityChangeFactor = getVelocityChangeFactor(currObj, lastObj0);
velocityChangeFactor = 1 - Math.Pow(velocityChangeFactor, 2);
double a1 = currObj.Angle.Value / Math.PI;
double a2 = lastObj0.Angle.Value / Math.PI;
double a3 = lastObj1.Angle.Value / Math.PI;
double a4 = lastObj2.Angle.Value / Math.PI;
// - 4 same sharp angles in a row: (0.3 0.3 0.3 0.3) -> max punishment
// Normalized difference
double angleDifference1 = Math.Abs(a1 - a2);
double angleDifference2 = Math.Abs(a1 - a3);
double angleDifference3 = Math.Abs(a1 - a4);
// Will be close to 1 if angleDifference1 and angleDifference2 was both close to 0
double sameAnglePunishment = Math.Pow((1 - angleDifference1) * (1 - angleDifference2) * (1 - angleDifference3), 3);
// Starting from 60 degrees - reduce same angle punishment
double angleSharpnessFactor = Math.Max(0, a1 - 1.0 / 3);
angleSharpnessFactor = 1 - angleSharpnessFactor;
sameAnglePunishment *= angleSharpnessFactor;
sameAnglePunishment *= velocityChangeFactor;
sameAnglePunishment *= 0.75;
// - Alternating angles with 0: (0.3 0 0.3 0) or (0 0.3 0 0.3) -> max punishment, (0.3 0 0.1 0) -> some punishment
double alternateWithZeroAnglePunishment = Math.Max(
getAlternateWithZeroAnglePunishment(a1, a2, a3, a4),
getAlternateWithZeroAnglePunishment(a2, a1, a4, a3));
alternateWithZeroAnglePunishment *= velocityChangeFactor;
return Math.Min(1, sameAnglePunishment + alternateWithZeroAnglePunishment);
}
private static double getVelocityChangeFactor(OsuDifficultyHitObject osuCurrObj, OsuDifficultyHitObject osuLastObj)
{
double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime;
double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.StrainTime;
double velocityChangeFactor = 0;
// https://www.desmos.com/calculator/kqxmqc8pkg
if (currVelocity > 0 || prevVelocity > 0)
{
double velocityChange = Math.Max(0,
Math.Min(
Math.Abs(prevVelocity - currVelocity) - 0.5 * Math.Min(currVelocity, prevVelocity),
Math.Max(((OsuHitObject)osuCurrObj.BaseObject).Radius / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Min(currVelocity, prevVelocity))
)); // Stealed from xexxar
velocityChangeFactor = velocityChange / Math.Max(currVelocity, prevVelocity); // maxiumum is 0.4
velocityChangeFactor /= 0.4;
}
return velocityChangeFactor;
}
private static double getAlternateWithZeroAnglePunishment(double a1, double a2, double a3, double a4)
{
// We assume that a1 and a3 are 0
double zeroFactor = Math.Pow((1 - a1) * (1 - a3), 8);
zeroFactor *= Math.Pow(1 - Math.Abs(a1 - a3), 2);
double angleSimilarityFactor = 1 - Math.Abs(a2 - a4);
double angleSharpnessFactor = Math.Min(1 - Math.Max(0, a2 - 1.0 / 3), 1 - Math.Max(0, a4 - 1.0 / 3));
return zeroFactor * angleSimilarityFactor * angleSharpnessFactor;
}
// High AR curve
// https://www.desmos.com/calculator/hbj7swzlth
public static double GetDifficulty(double preempt)
{
double value = Math.Pow(4, 3 - 0.01 * preempt); // 1 for 300ms, 0.25 for 400ms, 0.0625 for 500ms
value = softmin(value, 2, 1.7); // use softmin to achieve full-memory cap, 2 times more than AR11 (300ms)
return value;
}
// We are using mutiply and divide instead of add and subtract, so values won't be negative
// https://www.desmos.com/calculator/fv5xerwpd2
private static double softmin(double a, double b, double power = Math.E) => a * b / Math.Log(Math.Pow(power, a) + Math.Pow(power, b), power);
}
}

View File

@ -83,7 +83,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double lowARValue = computeReadingLowARValue(score, osuAttributes);
double readingHDValue = computeReadingHiddenValue(score, osuAttributes);
double readingSlidersValue = 0;
double highARValue = computeReadingHighARValue(score, osuAttributes);
@ -95,8 +94,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double flPower = OsuDifficultyCalculator.FL_SUM_POWER;
double flashlightARValue = Math.Pow(Math.Pow(flashlightValue, flPower) + Math.Pow(readingARValue, flPower), 1.0 / flPower);
double readingNonARValue = readingHDValue + readingSlidersValue;
double cognitionValue = Math.Pow(Math.Pow(flashlightARValue, power) + Math.Pow(readingNonARValue, power), 1.0 / power);
double cognitionValue = flashlightARValue + readingHDValue;
cognitionValue = AdjustCognitionPerformance(cognitionValue, mechanicalValue, potentialHiddenFlashlightValue);
double accuracyValue = computeAccuracyValue(score, osuAttributes);
@ -104,9 +102,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double totalValue =
Math.Pow(
Math.Pow(mechanicalValue, power) +
Math.Pow(cognitionValue, power) +
Math.Pow(accuracyValue, power), 1.0 / power
) * multiplier;
totalValue += cognitionValue * multiplier;
return new OsuPerformanceAttributes
{

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
public class ReadingLowAR : GraphSkill
{
private readonly List<double> difficulties = new List<double>();
private double skillMultiplier => 1.08;
private double skillMultiplier => 1.04;
private double aimComponentMultiplier => 0.7;
public ReadingLowAR(Mod[] mods)
@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
}
private double currentStrain;
private double skillMultiplier => 4.9;
private double skillMultiplier => 4.8;
protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * StrainDecay(time - current.Previous(0).StartTime);

View File

@ -73,8 +73,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
double adjustedDifficulty = OsuStrainSkill.PerformanceToDifficulty(totalPerformance);
double difficultyValue = Math.Pow(adjustedDifficulty / OsuDifficultyCalculator.DIFFICULTY_MULTIPLIER, 2.0);
// have the same value as difficultyValue at 500pp point
return 75 * Math.Sqrt(difficultyValue);
return 54 * Math.Sqrt(difficultyValue);
}
}
@ -89,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
private bool adjustHighAR;
private double currentStrain;
private double skillMultiplier => 17;
private double skillMultiplier => 6.85;
private double defaultValueMultiplier => 25;
protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => currentStrain * StrainDecay(time - current.Previous(0).StartTime);
@ -109,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
public class HighARSpeedComponent : OsuStrainSkill
{
private double skillMultiplier => 670;
private double skillMultiplier => 400;
protected override double StrainDecayBase => 0.3;
private double currentStrain;