From 2e06ac16ace30959a7344bb2e4af1d70012fa382 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 11 Dec 2022 09:42:24 +0000 Subject: [PATCH] Add BeatLeader score modifier support --- README.md | 1 - next.config.js | 6 +-- src/consts/LeaderboardType.js | 12 ++--- src/curve/BeatLeaderCurve.js | 1 - src/helpers/websocketClient.ts | 11 ++--- .../api/beatleader/{stars.js => data.js} | 26 +++++++---- .../api/scoresaber/{stars.js => data.js} | 13 +++--- src/store/songDataStore.ts | 36 ++++++++++----- src/utils/utils.js | 44 ++++++++++++++++++- 9 files changed, 103 insertions(+), 47 deletions(-) rename src/pages/api/beatleader/{stars.js => data.js} (78%) rename src/pages/api/scoresaber/{stars.js => data.js} (87%) diff --git a/README.md b/README.md index 2c3ab21..2ec8515 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ Need help? Feel free to message me at: Fascinated#4719 ## Todo -- Make BeatLeader pp count check for modifiers - Add toggle for showing pp - Change the song time to a circular style in the song art diff --git a/next.config.js b/next.config.js index fae69a9..dd3ab77 100644 --- a/next.config.js +++ b/next.config.js @@ -12,9 +12,9 @@ const nextConfig = { "avatars.akamai.steamstatic.com", ], }, - experimental: { - optimizeCss: true, - }, + // experimental: { + // optimizeCss: true, + // }, }; module.exports = nextConfig; diff --git a/src/consts/LeaderboardType.js b/src/consts/LeaderboardType.js index 4cd8d03..0a7a794 100644 --- a/src/consts/LeaderboardType.js +++ b/src/consts/LeaderboardType.js @@ -9,12 +9,12 @@ const LeaderboardType = { MapData: "https://scoresaber.com/api/leaderboard/by-hash/%h/info?difficulty=%d", }, - async getMapStarCount(mapHash, mapDiff, characteristic) { + async getMapLeaderboardData(mapHash, mapDiff, characteristic) { const data = await fetch( - `/api/scoresaber/stars?hash=${mapHash}&difficulty=${mapDiff}&characteristic=${characteristic}` + `/api/scoresaber/data?hash=${mapHash}&difficulty=${mapDiff}&characteristic=${characteristic}` ); const json = await data.json(); - return json.stars || undefined; + return json || undefined; }, }, BeatLeader: { @@ -23,12 +23,12 @@ const LeaderboardType = { env(VARS.HTTP_PROXY) + "/https://api.beatleader.xyz/player/%s", MapData: "https://api.beatleader.xyz/map/hash/%h", }, - async getMapStarCount(mapHash, mapDiff, characteristic) { + async getMapLeaderboardData(mapHash, mapDiff, characteristic) { const data = await fetch( - `/api/beatleader/stars?hash=${mapHash}&difficulty=${mapDiff}&characteristic=${characteristic}` + `/api/beatleader/data?hash=${mapHash}&difficulty=${mapDiff}&characteristic=${characteristic}` ); const json = await data.json(); - return json.stars || undefined; + return json || undefined; }, }, }; diff --git a/src/curve/BeatLeaderCurve.js b/src/curve/BeatLeaderCurve.js index b6177a9..ec7b176 100644 --- a/src/curve/BeatLeaderCurve.js +++ b/src/curve/BeatLeaderCurve.js @@ -2,7 +2,6 @@ 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); } diff --git a/src/helpers/websocketClient.ts b/src/helpers/websocketClient.ts index 7868c42..f4d9941 100644 --- a/src/helpers/websocketClient.ts +++ b/src/helpers/websocketClient.ts @@ -77,6 +77,7 @@ const handlers: any = { resetCutState(); state.setInSong(true); state.setCombo(data.status.performance.combo); + state.setModifiers(data.status.mod); useDataStore.setState({ loadedDuringSong: true }); const { score, relativeScore } = data.status.performance; @@ -114,15 +115,9 @@ const handlers: any = { } = data.status.beatmap; state.reset(); - cutData.saberA = { - count: [0, 0, 0], - totalScore: [0, 0, 0], - }; - cutData.saberB = { - count: [0, 0, 0], - totalScore: [0, 0, 0], - }; + resetCutState(); state.setInSong(true); + state.setModifiers(data.status.mod); state.updateMapData( getMapHashFromLevelId(levelId), difficultyEnum, diff --git a/src/pages/api/beatleader/stars.js b/src/pages/api/beatleader/data.js similarity index 78% rename from src/pages/api/beatleader/stars.js rename to src/pages/api/beatleader/data.js index 15943f5..d1f00cc 100644 --- a/src/pages/api/beatleader/stars.js +++ b/src/pages/api/beatleader/data.js @@ -1,12 +1,8 @@ import fetch from "node-fetch"; -import WebsiteTypes from "../../../../src/consts/LeaderboardType"; -import { - getValue, - setValue, - valueExists, -} from "../../../../src/utils/redisUtils"; +import WebsiteTypes from "../../../consts/LeaderboardType"; +import { getValue, setValue, valueExists } from "../../../utils/redisUtils"; -const KEY = "BL_MAP_STAR_"; +const KEY = "BL_MAP_DATA_"; /** * @@ -29,12 +25,14 @@ export default async function handler(req, res) { const exists = await valueExists(key); if (exists) { const data = await getValue(key); + const json = JSON.parse(data); res.setHeader("Cache-Status", "hit"); return res.status(200).json({ status: "OK", - stars: Number.parseFloat(data), difficulty: difficulty, + stars: json.stars, + modifiers: json.modifiers, }); } @@ -55,12 +53,14 @@ export default async function handler(req, res) { } const json = await data.json(); let starCount = undefined; + let modifiers = undefined; for (const diff of json.difficulties) { if ( diff.difficultyName === difficulty && diff.modeName === characteristic ) { starCount = diff.stars; + modifiers = diff.modifierValues; } } if (starCount === undefined) { @@ -69,7 +69,13 @@ export default async function handler(req, res) { message: "Unknown Map Hash", }); } - await setValue(key, starCount); + await setValue( + key, + JSON.stringify({ + stars: starCount, + modifiers: modifiers, + }) + ); console.log( `[Cache]: Cached BL Star Count for hash ${mapHash} in ${ Date.now() - before @@ -78,6 +84,8 @@ export default async function handler(req, res) { res.setHeader("Cache-Status", "miss"); return res.status(200).json({ status: "OK", + difficulty: difficulty, stars: starCount, + modifiers: modifiers, }); } diff --git a/src/pages/api/scoresaber/stars.js b/src/pages/api/scoresaber/data.js similarity index 87% rename from src/pages/api/scoresaber/stars.js rename to src/pages/api/scoresaber/data.js index 4a8e261..6c9c966 100644 --- a/src/pages/api/scoresaber/stars.js +++ b/src/pages/api/scoresaber/data.js @@ -1,11 +1,7 @@ import fetch from "node-fetch"; -import WebsiteTypes from "../../../../src/consts/LeaderboardType"; -import { - getValue, - setValue, - valueExists, -} from "../../../../src/utils/redisUtils"; -import { diffToScoreSaberDiff } from "../../../../src/utils/scoreSaberUtils"; +import WebsiteTypes from "../../../consts/LeaderboardType"; +import { getValue, setValue, valueExists } from "../../../utils/redisUtils"; +import { diffToScoreSaberDiff } from "../../../utils/scoreSaberUtils"; const KEY = "SS_MAP_STAR_"; @@ -34,8 +30,8 @@ export default async function handler(req, res) { return res.status(200).json({ status: "OK", - stars: Number.parseFloat(data), difficulty: difficulty, + stars: Number.parseFloat(data), }); } @@ -74,6 +70,7 @@ export default async function handler(req, res) { res.setHeader("Cache-Status", "miss"); return res.status(200).json({ status: "OK", + difficulty: difficulty, stars: starCount, }); } diff --git a/src/store/songDataStore.ts b/src/store/songDataStore.ts index b492155..4503c50 100644 --- a/src/store/songDataStore.ts +++ b/src/store/songDataStore.ts @@ -12,7 +12,11 @@ interface SongDataState { songSubTitle: string; songLength: number; songDifficulty: string; - mapStarCount: number; + songModifiers: Object; + mapLeaderboardData: { + stars: Number; + modifiers: Object; + }; mapArt: string; bsr: string; @@ -50,6 +54,7 @@ interface SongDataState { setPp: (percent: number) => void; setInSong: (isInSong: boolean) => void; setSaberData: (saberType: string, cutData: any) => void; + setModifiers: (modifiers: Map) => void; } export const useSongDataStore = create()((set) => ({ @@ -60,7 +65,11 @@ export const useSongDataStore = create()((set) => ({ songSubTitle: "", songLength: 0, songDifficulty: "", - mapStarCount: 0, + songModifiers: {}, + mapLeaderboardData: { + stars: 0, + modifiers: {}, + }, mapArt: "", bsr: "", @@ -93,11 +102,10 @@ export const useSongDataStore = create()((set) => ({ let hasError = false; const leaderboardType = useSettingsStore.getState().leaderboardType; - const mapStars = await Utils.getWebsiteApi(leaderboardType).getMapStarCount( - mapHash, - mapDiff, - characteristic - ); + const mapLeaderboardData = await Utils.getWebsiteApi( + leaderboardType + ).getMapLeaderboardData(mapHash, mapDiff, characteristic); + console.log(mapLeaderboardData); const mapData = await axios.get( `${env("SITE_URL")}/api/beatsaver/map?hash=${mapHash}` @@ -110,7 +118,7 @@ export const useSongDataStore = create()((set) => ({ set({ isLoading: false, hasError: hasError, - mapStarCount: mapStars, + mapLeaderboardData: mapLeaderboardData, bsr: bsr, mapArt: mapArt, songDifficulty: mapDiff, @@ -150,7 +158,7 @@ export const useSongDataStore = create()((set) => ({ setPp: (percent: number) => { const leaderboardType = useSettingsStore.getState().leaderboardType; - const mapStarCount = useSongDataStore.getState().mapStarCount; + const mapStarCount = useSongDataStore.getState().mapLeaderboardData.stars; let pp = Utils.calculatePP(mapStarCount, percent, leaderboardType); if (pp === undefined) { @@ -163,6 +171,10 @@ export const useSongDataStore = create()((set) => ({ set({ inSong: isInSong }); }, + setModifiers(modifiers: Map) { + set({ songModifiers: modifiers }); + }, + reset: () => set({ isLoading: true, @@ -170,7 +182,11 @@ export const useSongDataStore = create()((set) => ({ songTitle: "", songSubTitle: "", songDifficulty: "", - mapStarCount: 0, + songModifiers: {}, + mapLeaderboardData: { + stars: 0, + modifiers: {}, + }, mapArt: "", bsr: "", diff --git a/src/utils/utils.js b/src/utils/utils.js index 2b63649..4dd558a 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,6 +1,7 @@ import { default as LeaderboardType } from "../consts/LeaderboardType"; import { getBeatLeaderPP } from "../curve/BeatLeaderCurve"; import { getScoreSaberPP } from "../curve/ScoreSaberCurve"; +import { useSongDataStore } from "../store/songDataStore"; export default class Utils { /** @@ -35,7 +36,7 @@ export default class Utils { return undefined; } if (type === "BeatLeader") { - return getBeatLeaderPP(acc, stars); + return getBeatLeaderPP(acc, stars) * (1 + this.calculateModifierBonus()); } if (type === "ScoreSaber") { return getScoreSaberPP(acc, stars); @@ -43,6 +44,47 @@ export default class Utils { return undefined; } + static calculateModifierBonus() { + const songMods = useSongDataStore.getState().songModifiers; + const modifierMulipliers = + useSongDataStore.getState().mapLeaderboardData.modifiers; + let bonus = 0; + + if ( + songMods.noFail == true && + modifierMulipliers.nf < 0 && + useSongDataStore.getState().failed + ) { + bonus -= modifierMulipliers.nf; + } + + if (songMods.songSpeed != "Normal") { + if (songMods.songSpeed == "FasterSong" && modifierMulipliers.fs > 0) { + bonus += modifierMulipliers.fs; + } + if (songMods.songSpeed == "SuperFast" && modifierMulipliers.sf > 0) { + bonus += modifierMulipliers.sf; + } + } + + if (songMods.disappearingArrows == true && modifierMulipliers.da > 0) { + bonus += modifierMulipliers.da; + } + + if (songMods.ghostNotes == true && modifierMulipliers.gn > 0) { + toAdd += modifierMulipliers.gn; + } + + if (songMods.noArrows == true && modifierMulipliers.na < 0) { + bonus -= modifierMulipliers.na; + } + + if (songMods.noBombs == true && modifierMulipliers.nb < 0) { + bonus -= modifierMulipliers.nb; + } + return bonus; + } + static base64ToArrayBuffer(base64) { return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)); }