From 188457257d85325a8b80cac070fb83b2a036b9cf Mon Sep 17 00:00:00 2001 From: nairobi <61069237+nyairobi@users.noreply.github.com> Date: Mon, 13 May 2024 16:33:32 +0200 Subject: [PATCH] chore,fix: upgrade ongeki seeds (#1070) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore,fix: upgrade ongeki seeds The dataset is up to date up until March 27th, 2024. A single chart is missing: https://wikiwiki.jp/gameongeki/怒槌~光吉猛修一部謎~ Added maxPlatScore and inGameID. Added alt (romaji) song titles. Removed the wikiwiki scraper because it's no longer relevant. Restored the score column that relied on maxPlatScore. Fixed the client crashing when you click Lamps Only in a geki session. Removed Act 2. * fix: missing fields in the test chart * chore: get rid of isUnranked * fix: clarify the track ID range --- .../sessions/SessionRaiseBreakdown.tsx | 5 +- .../tables/cells/OngekiPlatinumCell.tsx | 34 + client/src/lib/game-implementations.tsx | 29 +- common/src/config/game-support/ongeki.ts | 11 +- database-seeds/collections/charts-ongeki.json | 23836 ++++++++-------- database-seeds/collections/folders.json | 1732 +- database-seeds/collections/songs-ongeki.json | 4444 ++- database-seeds/collections/tables.json | 220 +- .../scripts/rerunners/ongeki/.gitkeep | 1 + .../scripts/rerunners/ongeki/fetch-ongeki.ts | 173 - docs/docs/game-support/games/ongeki-Single.md | 1 - .../src/game-implementations/games/ongeki.ts | 15 +- server/src/test-utils/test-data.ts | 2 + 13 files changed, 15709 insertions(+), 14794 deletions(-) create mode 100644 client/src/components/tables/cells/OngekiPlatinumCell.tsx create mode 100644 database-seeds/scripts/rerunners/ongeki/.gitkeep delete mode 100644 database-seeds/scripts/rerunners/ongeki/fetch-ongeki.ts diff --git a/client/src/components/sessions/SessionRaiseBreakdown.tsx b/client/src/components/sessions/SessionRaiseBreakdown.tsx index d011ae54e..2825e1fab 100644 --- a/client/src/components/sessions/SessionRaiseBreakdown.tsx +++ b/client/src/components/sessions/SessionRaiseBreakdown.tsx @@ -49,6 +49,7 @@ export default function SessionRaiseBreakdown({ }) { const game = sessionData.session.game; const playtype = sessionData.session.playtype; + const lampName = game === "ongeki" ? "noteLamp" : "lamp"; const { user } = useContext(UserContext); @@ -82,14 +83,12 @@ export default function SessionRaiseBreakdown({
- + Lamps Only - All - Grades Only diff --git a/client/src/components/tables/cells/OngekiPlatinumCell.tsx b/client/src/components/tables/cells/OngekiPlatinumCell.tsx new file mode 100644 index 000000000..9c833cabb --- /dev/null +++ b/client/src/components/tables/cells/OngekiPlatinumCell.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import { Difficulties, integer } from "tachi-common"; + +export default function OngekiPlatinumCell({ + platScore: platScore, + maxPlatScore: maxPlatScore, + difficulty, +}: { + platScore: integer | null | undefined; + maxPlatScore: integer; + difficulty: Difficulties["ongeki:Single"]; +}) { + if (difficulty !== "MASTER" && difficulty !== "LUNATIC") { + return N/A; + } + + if (platScore === null || platScore === undefined) { + return Unknown; + } + + return ( + + MAX-{maxPlatScore - platScore} + {platScore !== undefined && ( + <> +
+ + [{platScore}/{maxPlatScore}] + + + )} + + ); +} diff --git a/client/src/lib/game-implementations.tsx b/client/src/lib/game-implementations.tsx index aaa0e08f0..1b76d8076 100644 --- a/client/src/lib/game-implementations.tsx +++ b/client/src/lib/game-implementations.tsx @@ -20,6 +20,7 @@ import WaccaJudgementCell from "components/tables/cells/WACCAJudgementCell"; import OngekiJudgementCell from "components/tables/cells/OngekiJudgementCell"; import React from "react"; import OngekiLampCell from "components/tables/cells/OngekiLampCell"; +import OngekiPlatinumCell from "components/tables/cells/OngekiPlatinumCell"; import { CreateRatingSys, bgc } from "./games/_util"; import { BMS_14K_IMPL, BMS_7K_IMPL, PMS_IMPL } from "./games/bms-pms"; import { IIDX_DP_IMPL, IIDX_SP_IMPL } from "./games/iidx"; @@ -786,6 +787,8 @@ export const GPT_CLIENT_IMPLEMENTATIONS: GPTClientImplementations = { (x) => x.scoreData.score * 10000 + (x.scoreData.optional.platScore ?? 0) ), ], + // TODO: this should be sorted by % + ["Platinum Score", "Score", NumericSOV((x) => x.scoreData.optional.platScore ?? 0)], ["Judgements", "Hits", NumericSOV((x) => x.scoreData.score)], [ "Lamp", @@ -798,22 +801,16 @@ export const GPT_CLIENT_IMPLEMENTATIONS: GPTClientImplementations = { ], scoreCoreCells: ({ sc, chart }) => ( <> - - {sc.scoreData.grade} -
- {FormatMillions(sc.scoreData.score)} - {typeof sc.scoreData.optional.platScore === "number" && - (chart.difficulty === "MASTER" || chart.difficulty === "LUNATIC") && ( - <> -
- [Plat: {sc.scoreData.optional.platScore}] - - )} - + + ; -type OngekiSong = SongDocument<"ongeki">; - -interface SxgaEntry { - date: string; - title: string; - artist: string; - category: string; - lunatic: "" | "1"; -} - -// Wikiwiki really sucks -const unnormalizeTitle = (title: string): string => - title - .replace("...", "…") - .replace(/:/gu, ":") - .replace(/\(/gu, "(") - .replace(/\)/gu, ")") - .replace(/!/gu, "!") - .replace(/\?/gu, "?") - .replace(/~/gu, "~"); - -const scrapeWikiwiki = async ( - charts: OngekiChart[], - songID: number, - title: string, - lunatic: boolean, - unnormalized = false -) => { - const res = await fetch(`https://wikiwiki.jp/gameongeki/${title.replace(/ /gu, "%20")}`); - const $ = cheerio.load(await res.text()); - const tables = $("#content tbody").toArray(); - if (tables.length < 2) { - if (unnormalized) { - throw new Error(`${title}: Invalid wikipage: expected 2 tables, got ${tables.length}`); - } else { - return scrapeWikiwiki(charts, songID, unnormalizeTitle(title), lunatic, true); - } - } - const diffTable = tables![1]; - const diffRows = $(diffTable).find("tr").toArray(); - - const diffsToParse: Difficulties["ongeki:Single"][] = lunatic - ? ["LUNATIC"] - : ["BASIC", "ADVANCED", "EXPERT", "MASTER"]; - for (const diff of diffsToParse) { - const row = diffRows.find((row) => $(row.firstChild!).html() === diff); - - const level = $(row?.children[1]).html(); - const noteCountRaw = $(row?.children[2]).html(); - const bellCountRaw = $(row?.children[3]).html(); - const internalLevelRaw = $(row?.children[4]).html(); - - let noteCount: number | undefined; - let bellCount: number | undefined; - let internalLevel: number; - - if (!level) { - throw new Error(`${title} ${diff}: Invalid wikipage: ${diff} has no level`); - } - - if (!noteCountRaw) { - if (diff === "MASTER" || diff === "LUNATIC") { - // This value is necessary for platinum delta calculation - throw new Error(`${title} ${diff}: unknown note count`); - } else { - console.log(`warn: ${title} ${diff}: unknown note count`); - } - } else { - noteCount = parseInt(noteCountRaw, 10); - } - if (!bellCountRaw) { - console.log(`warn: ${title} ${diff}: unknown bell count`); - } else { - bellCount = parseInt(bellCountRaw, 10); - } - if (!internalLevelRaw) { - console.log(`warn: ${title} ${diff}: unknown internal level (will be deduced)`); - internalLevel = parseInt(level, 10); - if (level.endsWith("+")) { - internalLevel += 0.7; - } - } else { - internalLevel = parseFloat(internalLevelRaw); - } - - const newChart: OngekiChart = { - difficulty: diff, - chartID: CreateChartID(), - songID, - level, - levelNum: internalLevel, - isPrimary: true, - playtype: "Single", - data: { - displayVersion: CURRENT_VERSION_PRETTY, - }, - versions: [CURRENT_VERSION, `${CURRENT_VERSION}Omni`], - }; - - charts.push(newChart); - } -}; - -const main = async ({ date }) => { - const charts: OngekiChart[] = ReadCollection("charts-ongeki.json"); - const songs: OngekiSong[] = ReadCollection("songs-ongeki.json"); - - const sxgaEntriesRaw = await fetch(SXGA_DATA_URL); - const sxgaEntries: SxgaEntry[] = (await sxgaEntriesRaw.json()).filter( - (o: SxgaEntry) => o.date >= date - ); - for (const entry of sxgaEntries) { - const queriedDiff = entry.lunatic ? "LUNATIC" : "MASTER"; - const song = songs.find((song) => song.title === entry.title); - - console.log(`${entry.title} ${queriedDiff}`); - - if (song) { - const chart = charts.find( - (chart) => chart.songID === song.id && chart.difficulty === queriedDiff - ); - if (chart) { - console.log(`\tskipping`); - } else { - console.log(`\t\x1b[34mnew chart\x1b[0m`); - - scrapeWikiwiki(charts, song.id, entry.title, entry.lunatic ? true : false); - } - } else { - console.log(`\t\x1b[31mnew song\x1b[0m`); - - songs.push({ - title: entry.title, - artist: entry.artist, - id: songs[songs.length - 1]!.id + 1, - searchTerms: [], - altTitles: [], - data: { - genre: entry.category, - }, - }); - - scrapeWikiwiki( - charts, - songs[songs.length - 1]!.id, - entry.title, - entry.lunatic ? true : false - ); - } - - console.log(""); - } - - WriteCollection("songs-ongeki.json", songs); - WriteCollection("charts-ongeki.json", charts); -}; - -new Command() - .name("Fetch Ongeki") - .description("Fetch new Ongeki charts.") - .requiredOption("--date ", "Start date as YYYYMMDD, e.g. 20231228") - .action(main) - .parse(); diff --git a/docs/docs/game-support/games/ongeki-Single.md b/docs/docs/game-support/games/ongeki-Single.md index 4311de3a6..4c5faff46 100644 --- a/docs/docs/game-support/games/ongeki-Single.md +++ b/docs/docs/game-support/games/ongeki-Single.md @@ -85,7 +85,6 @@ Note: since bright MEMORY Act.3, "crazy" charts and "Re:MASTER" charts are in se | ID | Pretty Name | | :: | :: | -| `brightMemory2` | bright MEMORY Act.2 | | `brightMemory3` | bright MEMORY Act.3 | ## Supported Match Types diff --git a/server/src/game-implementations/games/ongeki.ts b/server/src/game-implementations/games/ongeki.ts index 256861971..3f14fe5d1 100644 --- a/server/src/game-implementations/games/ongeki.ts +++ b/server/src/game-implementations/games/ongeki.ts @@ -7,23 +7,20 @@ import { ONGEKIRating } from "rg-stats"; import { ONGEKI_GBOUNDARIES, FmtNum, GetGrade } from "tachi-common"; import { IsNullish } from "utils/misc"; import type { GPTServerImplementation } from "game-implementations/types"; -import type { Difficulties } from "tachi-common"; -export const OngekiPlatDiff = (diff: Difficulties["ongeki:Single"]) => - diff === "MASTER" || diff === "LUNATIC"; +const isBonusTrack = (inGameID: number) => inGameID >= 7000 && inGameID < 8000; export const ONGEKI_IMPL: GPTServerImplementation<"ongeki:Single"> = { chartSpecificValidators: { platScore: (platScore, chart) => { - if (!OngekiPlatDiff(chart.difficulty)) { - // We don't care about other difficulties - return true; - } - if (platScore < 0) { return `Platinum Score must be non-negative. Got ${platScore}`; } + if (platScore > chart.data.maxPlatScore) { + return `Platinum Score is too large: ${platScore}>${chart.data.maxPlatScore}`; + } + return true; }, bellCount: (bellCount) => { @@ -53,7 +50,7 @@ export const ONGEKI_IMPL: GPTServerImplementation<"ongeki:Single"> = { }, scoreCalcs: { rating: (scoreData, chart) => - chart.data.isUnranked || chart.levelNum === 0.0 + isBonusTrack(chart.data.inGameID) || chart.levelNum === 0.0 ? 0 : ONGEKIRating.calculate(scoreData.score, chart.levelNum), }, diff --git a/server/src/test-utils/test-data.ts b/server/src/test-utils/test-data.ts index 6326b8938..e8e269de6 100644 --- a/server/src/test-utils/test-data.ts +++ b/server/src/test-utils/test-data.ts @@ -1269,6 +1269,8 @@ export const TestingOngekiChart: ChartDocument<"ongeki:Single"> = { chartID: "213796bdb6150f80ba6412ce69df1249e16c0cb0", data: { displayVersion: "bright MEMORY Act.3", + inGameID: 2137, + maxPlatScore: 1000, }, difficulty: "MASTER", isPrimary: true,