Updated BL curve
Some checks are pending
continuous-integration/drone/push Build is running

This commit is contained in:
Lee 2023-03-26 20:39:55 +01:00
parent 4c32f504a4
commit 024f553586
No known key found for this signature in database
GPG Key ID: BAF8F4DB8E7F38EF
4 changed files with 154 additions and 40 deletions

View File

@ -1,53 +1,121 @@
import Utils from "../utils/utils";
/**
* I'm not even sure what this shit does, ask BL
* @see https://github.com/BeatLeader/beatleader-server/blob/16123a792b1a837faf6287e5bcd58e2e06e6a6f0/Utils/ReplayUtils.cs for more info
* The pp curve of this leaderboard
*/
const ppCurve = [
[1.0, 7.424],
[0.999, 6.241],
[0.9975, 5.158],
[0.995, 4.01],
[0.9925, 3.241],
[0.99, 2.7],
[0.9875, 2.303],
[0.985, 2.007],
[0.9825, 1.786],
[0.98, 1.618],
[0.9775, 1.49],
[0.975, 1.392],
[0.9725, 1.315],
[0.97, 1.256],
[0.965, 1.167],
[0.96, 1.101],
[0.955, 1.047],
[0.95, 1.0],
[0.94, 0.919],
[0.93, 0.847],
[0.92, 0.786],
[0.91, 0.734],
[0.9, 0.692],
[0.875, 0.606],
[0.85, 0.537],
[0.825, 0.48],
[0.8, 0.429],
[0.75, 0.345],
[0.7, 0.286],
[0.65, 0.246],
[0.6, 0.217],
[0.0, 0.0],
];
/**
* https://github.com/BeatLeader/beatleader-server/blob/master/Utils/ReplayUtils.cs#L45
* funky shit from ^
*
* @param {Number} acc the accuracy of the score
* @param {Number} stars the ranked star count
* @param {Number} accuracy the accuracy of the score
* @param {Number} accRating the acc rating of the difficulty
* @param {Number} passRating the pass rating of the difficulty
* @param {Number} techRating the tech rating of the difficulty
* @returns
*/
function curve(acc, stars) {
var l = 1 - (0.03 * (stars - 3.0)) / 11.0;
var a = 0.96 * l;
var f = 1.2 - (0.6 * stars) / 14.0;
return Math.pow(Math.log10(l / (l - acc)) / Math.log10(l / (l - a)), f);
export function getBeatLeaderPP(accuracy, accRating, passRating, techRating) {
const modifierBonus = Utils.calculateModifierBonus();
const ppValues = getPP(
accuracy,
accRating,
passRating * modifierBonus,
techRating * modifierBonus
);
const pp = inflate(ppValues.passPP + ppValues.accPP + ppValues.techPP);
return isNaN(pp) ? 1024 : pp;
}
/**
* Gets the raw pp from the given score
* https://github.com/BeatLeader/beatleader-server/blob/master/Utils/ReplayUtils.cs#L45
* funky shit from ^
*
* @param {Number} acc the accuracy of the score
* @param {Number} stars the ranked star count
* @param {Number} accuracy the accuracy of the score
* @param {Number} accRating the acc rating of the difficulty
* @param {Number} passRating the pass rating of the difficulty
* @param {Number} techRating the tech rating of the difficulty
* @returns
*/
export function getBeatLeaderPP(acc, stars) {
if (stars === undefined || acc === undefined) {
return undefined;
function getPP(accuracy, accRating, passRating, techRating) {
let passPP = 15.2 * Math.exp(Math.pow(passRating, 1 / 2.62)) - 30;
if (isNaN(passPP) || passPP == Infinity) {
passPP = 0;
}
const modifierBonus = Utils.calculateModifierBonus();
let rawPP = curve(acc, stars - 0.5) * (stars + 0.5) * 42;
let fullPP =
curve(acc, stars * modifierBonus - 0.5) *
(stars * modifierBonus + 0.5) *
42;
let accPP = curve(accuracy) * accRating * 34;
let techPP = Math.exp(1.9 * accuracy) * techRating;
const isNegativeAcc = acc < 0;
if (isNegativeAcc) {
acc *= -1;
}
if (isNaN(rawPP) || rawPP == Infinity) {
return 1024;
}
if (isNaN(fullPP) || fullPP == Infinity) {
return 1024;
}
if (isNegativeAcc) {
fullPP *= -1;
}
return fullPP;
return {
passPP: passPP,
accPP: accPP,
techPP: techPP,
};
}
/**
* https://github.com/BeatLeader/beatleader-server/blob/master/Utils/ReplayUtils.cs#L45
* funky shit from ^
*
* @param {Number} acc the accuracy of the score
* @returns something
*/
function curve(acc) {
let i = 0;
for (; i < ppCurve.length; i++) {
if (ppCurve[i][0] <= acc) {
break;
}
}
if (i == 0) {
i = 1;
}
const middle_dis =
(acc - ppCurve[i - 1][0]) / (ppCurve[i][0] - ppCurve[i - 1][0]);
return ppCurve[i - 1][1] + middle_dis * (ppCurve[i][1] - ppCurve[i - 1][1]);
}
/**
* https://github.com/BeatLeader/beatleader-server/blob/master/Utils/ReplayUtils.cs#L77
* funky shit from ^
*
* @param {Number} peepee
* @returns funny number, idk
*/
function inflate(peepee) {
return (650 * Math.pow(peepee, 1.3)) / Math.pow(650, 1.3);
}

View File

@ -33,6 +33,9 @@ export default async function handler(req, res) {
difficulty: difficulty,
stars: json.stars,
modifiers: json.modifiers,
passRating: json.passRating,
accRating: json.accRating,
techRating: json.techRating,
});
}
@ -54,6 +57,10 @@ export default async function handler(req, res) {
const json = reesponse.data;
let starCount = undefined;
let modifiers = undefined;
let passRating = undefined;
let accRating = undefined;
let techRating = undefined;
for (const diff of json.difficulties) {
if (
diff.difficultyName === difficulty &&
@ -61,6 +68,9 @@ export default async function handler(req, res) {
) {
starCount = diff.stars;
modifiers = diff.modifierValues;
passRating = diff.passRating;
accRating = diff.accRating;
techRating = diff.techRating;
}
}
if (starCount === undefined) {
@ -74,6 +84,9 @@ export default async function handler(req, res) {
JSON.stringify({
stars: starCount,
modifiers: modifiers,
passRating: passRating,
accRating: accRating,
techRating: techRating,
})
);
console.log(
@ -87,5 +100,8 @@ export default async function handler(req, res) {
difficulty: difficulty,
stars: starCount,
modifiers: modifiers,
passRating: passRating,
accRating: accRating,
techRating: techRating,
});
}

View File

@ -20,6 +20,9 @@ interface SongDataState {
beatleader: {
stars: Number | undefined;
modifiers: Object;
passRating: number | undefined;
accRating: number | undefined;
techRating: number | undefined;
};
};
mapArt: string;
@ -82,6 +85,9 @@ export const useSongDataStore = create<SongDataState>()((set) => ({
beatleader: {
stars: 0,
modifiers: {},
passRating: undefined,
accRating: undefined,
techRating: undefined,
},
},
mapArt: "",
@ -134,6 +140,16 @@ export const useSongDataStore = create<SongDataState>()((set) => ({
}
const { bsr, mapArt } = mapDataresponse.data.data;
console.log({
beatleader: {
stars: beatLeaderLeaderboardData.stars,
modifiers: beatLeaderLeaderboardData.modifiers,
passRating: beatLeaderLeaderboardData.passRating,
accRating: beatLeaderLeaderboardData.accRating,
techRating: beatLeaderLeaderboardData.techRating,
},
});
set({
isLoading: false,
hasError: hasError,
@ -141,6 +157,9 @@ export const useSongDataStore = create<SongDataState>()((set) => ({
beatleader: {
stars: beatLeaderLeaderboardData.stars,
modifiers: beatLeaderLeaderboardData.modifiers,
passRating: beatLeaderLeaderboardData.passRating,
accRating: beatLeaderLeaderboardData.accRating,
techRating: beatLeaderLeaderboardData.techRating,
},
scoresaber: {
stars: scoreSaberLeaderboardData.stars,
@ -244,6 +263,9 @@ export const useSongDataStore = create<SongDataState>()((set) => ({
beatleader: {
stars: undefined,
modifiers: {},
passRating: undefined,
accRating: undefined,
techRating: undefined,
},
},
mapArt: "",

View File

@ -37,7 +37,15 @@ export default class Utils {
return undefined;
}
if (type === "BeatLeader") {
return getBeatLeaderPP(acc, stars);
const leaderboardData =
useSongDataStore.getState().mapLeaderboardData.beatleader;
return getBeatLeaderPP(
acc,
leaderboardData.accRating,
leaderboardData.passRating,
leaderboardData.techRating
);
}
if (type === "ScoreSaber") {
return getScoreSaberPP(acc, stars);
@ -48,7 +56,7 @@ export default class Utils {
static calculateModifierBonus() {
const songMods = useSongDataStore.getState().songModifiers;
const modifierMulipliers =
useSongDataStore.getState().mapLeaderboardData.modifiers;
useSongDataStore.getState().mapLeaderboardData.beatleader.modifiers;
let bonus = 1;
// No Fail