This repository has been archived on 2023-10-27. You can view files and clone it, but cannot push or open issues or pull requests.
Files
scoresaber-reloaded/src/services/scoresaber/pp.js
2023-10-17 23:41:42 +01:00

122 lines
3.1 KiB
JavaScript

import createScoresService from "./scores";
import makePendingPromisePool from "../../utils/pending-promises";
import { getTotalPpFromSortedPps } from "../../utils/scoresaber/pp";
let service = null;
let serviceCreationCount = 0;
export default () => {
serviceCreationCount++;
if (service) return service;
const scoresService = createScoresService();
const resolvePromiseOrWaitForPending = makePendingPromisePool();
const getTotalPp = (scores) =>
scores && Array.isArray(scores)
? getTotalPpFromSortedPps(
scores
.filter((s) => s.pp > 0)
.map((s) => s.pp)
.sort((a, b) => b - a)
)
: null;
const getTotalPlayerPp = async (playerId, modifiedScores = {}) =>
getTotalPp(
Object.values({
...(await resolvePromiseOrWaitForPending(`scores/${playerId}`, () =>
scoresService.getPlayerScoresAsObject(playerId)
)),
...modifiedScores,
})
);
async function getWhatIfScore(playerId, leaderboardId, pp = 0) {
const currentTotalPp = await getTotalPlayerPp(playerId);
if (!currentTotalPp) return null;
const newTotalPp = await getTotalPlayerPp(playerId, {
[leaderboardId]: { pp },
});
return {
currentTotalPp,
newTotalPp,
diff: newTotalPp - currentTotalPp,
};
}
// written by BaliBalo: https://github.com/BaliBalo/ScoreSaber/blob/master/pages/peepee.js
const PP_PER_STAR = 42.114296;
const ppCurve = [
{ at: 0, value: 0 },
{ at: 45, value: 0.015 },
{ at: 50, value: 0.03 },
{ at: 55, value: 0.06 },
{ at: 60, value: 0.105 },
{ at: 65, value: 0.16 },
{ at: 68, value: 0.24 },
{ at: 70, value: 0.285 },
{ at: 80, value: 0.563 },
{ at: 84, value: 0.695 },
{ at: 88, value: 0.826 },
{ at: 94.5, value: 1.015 },
{ at: 95, value: 1.046 },
{ at: 100, value: 1.12 },
{ at: 110, value: 1.18 },
{ at: 114, value: 1.25 },
];
function ppFactorFromAcc(acc) {
if (!acc || acc <= 0) {
return 0;
}
let index = ppCurve.findIndex((o) => o.at >= acc);
if (index === -1) {
return ppCurve[ppCurve.length - 1].value;
}
if (!index) {
return ppCurve[0].value;
}
let from = ppCurve[index - 1];
let to = ppCurve[index];
let progress = (acc - from.at) / (to.at - from.at);
return from.value + (to.value - from.value) * progress;
}
function accFromPpFactor(ppFactor) {
if (!ppFactor || ppFactor <= 0) return 0;
const idx = ppCurve.findIndex((o) => o.value >= ppFactor);
if (idx < 0) return ppCurve[ppCurve.length - 1].at;
const from = ppCurve[idx - 1];
const to = ppCurve[idx];
const progress = (ppFactor - from.value) / (to.value - from.value);
return from.at + (to.at - from.at) * progress;
}
const destroyService = () => {
serviceCreationCount--;
if (serviceCreationCount === 0) {
scoresService.destroyService();
service = null;
}
};
service = {
getWhatIfScore,
getTotalPlayerPp,
getTotalPp,
ppFactorFromAcc,
accFromPpFactor,
PP_PER_STAR,
destroyService,
};
return service;
};