mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-03 12:28:13 +03:00
Merge pull request #347 from TeamNewGuys/zkldi/issue-344-Major-Tierlist-Refactor
Massive Tierlist Overhaul
This commit is contained in:
+1
-1
@@ -73,7 +73,7 @@
|
||||
"redis": "3.1.2",
|
||||
"rimraf": "3.0.2",
|
||||
"safe-json-stringify": "1.2.0",
|
||||
"tachi-common": "0.2.10",
|
||||
"tachi-common": "0.2.15",
|
||||
"typescript": "4.3.4",
|
||||
"winston": "3.3.3"
|
||||
},
|
||||
|
||||
Generated
+4
-4
@@ -54,7 +54,7 @@ specifiers:
|
||||
rimraf: 3.0.2
|
||||
safe-json-stringify: 1.2.0
|
||||
supertest: 6.1.3
|
||||
tachi-common: 0.2.10
|
||||
tachi-common: 0.2.15
|
||||
tap: 15.0.9
|
||||
ts-node: 10.0.0
|
||||
tsconfig-paths: 3.10.1
|
||||
@@ -88,7 +88,7 @@ dependencies:
|
||||
redis: 3.1.2
|
||||
rimraf: 3.0.2
|
||||
safe-json-stringify: 1.2.0
|
||||
tachi-common: 0.2.10
|
||||
tachi-common: 0.2.15
|
||||
typescript: 4.3.4
|
||||
winston: 3.3.3
|
||||
|
||||
@@ -3892,8 +3892,8 @@ packages:
|
||||
strip-ansi: 6.0.0
|
||||
dev: true
|
||||
|
||||
/tachi-common/0.2.10:
|
||||
resolution: {integrity: sha512-WNZXqeiyVLg0Ek2c8iv9hgUx8IV7hmvSXhRfzP4oBlpmc0b+aFv1+Fdxtka42EcOzdwDIrCNCFOgWc2wXPTKug==}
|
||||
/tachi-common/0.2.15:
|
||||
resolution: {integrity: sha512-p7nt7pupl2JWNb20K7n18YOBtxUYeoyDsE6YbPVVyPvY1oj74a2YxALpmajGV2pbVAkdywrJS94In2sQUGzJtw==}
|
||||
dependencies:
|
||||
monk: 7.3.4
|
||||
transitivePeerDependencies:
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
import { ChartDocument } from "tachi-common";
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "../../src/common/logger";
|
||||
import MigrateRecords from "../migrate";
|
||||
import { gameOrders } from "tachi-common/js/config";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
@@ -26,10 +25,7 @@ async function ConvertFn(c: any): Promise<ChartDocument<"chunithm:Single">> {
|
||||
playtype: c.playtype,
|
||||
levelNum: c.levelNum,
|
||||
level: c.level.toString(),
|
||||
flags: {
|
||||
"IN BASE GAME": !!c.flags["IN BASE GAME"],
|
||||
OMNIMIX: !!c.flags.OMNIMIX,
|
||||
},
|
||||
tierlistInfo: {},
|
||||
data: {
|
||||
inGameID: c.internals.inGameID,
|
||||
},
|
||||
@@ -37,15 +33,6 @@ async function ConvertFn(c: any): Promise<ChartDocument<"chunithm:Single">> {
|
||||
versions: [], // sentinel
|
||||
};
|
||||
|
||||
const idx = gameOrders.chunithm.indexOf(song.firstVersion!);
|
||||
|
||||
if (idx === -1) {
|
||||
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
|
||||
newChartDoc.versions = [song.firstVersion!];
|
||||
} else {
|
||||
newChartDoc.versions = gameOrders.chunithm.slice(idx);
|
||||
}
|
||||
|
||||
return newChartDoc;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { ChartDocument, SongDocument } from "tachi-common";
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import MigrateRecords from "../migrate";
|
||||
import { gameOrders } from "tachi-common/js/config";
|
||||
import { oldKTDB } from "../old-db";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
@@ -31,27 +30,15 @@ async function ConvertFn(c: any): Promise<ChartDocument<"ddr:SP" | "ddr:DP">> {
|
||||
playtype: c.playtype,
|
||||
levelNum: c.levelNum,
|
||||
level: c.level.toString(),
|
||||
flags: {
|
||||
"IN BASE GAME": true,
|
||||
"N-1": true,
|
||||
},
|
||||
data: {
|
||||
inGameID: c.internals.inGameID,
|
||||
songHash: oldSong.internals.songHash,
|
||||
},
|
||||
tierlistInfo: {},
|
||||
isPrimary: true,
|
||||
versions: [], // sentinel
|
||||
};
|
||||
|
||||
const idx = gameOrders.ddr.indexOf(song.firstVersion!);
|
||||
|
||||
if (idx === -1) {
|
||||
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
|
||||
newChartDoc.versions = [song.firstVersion!];
|
||||
} else {
|
||||
newChartDoc.versions = gameOrders.ddr.slice(idx);
|
||||
}
|
||||
|
||||
return newChartDoc;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ async function ConvertFn(c: any): Promise<ChartDocument<"iidx:SP" | "iidx:DP"> |
|
||||
if (!song) {
|
||||
logger.warn(`Cannot find song with ID ${c.id}?`);
|
||||
return null;
|
||||
throw new Error(`Cannot find song with ID ${c.id}?`);
|
||||
}
|
||||
|
||||
const newChartDoc: ChartDocument<"iidx:SP" | "iidx:DP"> = {
|
||||
@@ -46,6 +45,7 @@ async function ConvertFn(c: any): Promise<ChartDocument<"iidx:SP" | "iidx:DP"> |
|
||||
"2dxtraSet": Get2DXTraSet(c.flags),
|
||||
},
|
||||
isPrimary: true,
|
||||
tierlistInfo: {},
|
||||
versions: [], // handled by scripts/single-use/fix-iidx-versions atm
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ async function ConvertFn(c: any): Promise<ChartDocument<"museca:Single"> | null>
|
||||
// for our kt1 dataset, inGameID *is* song id.
|
||||
data: { inGameID: c.id },
|
||||
isPrimary: true,
|
||||
versions: ["1+1/2"],
|
||||
tierlistInfo: {},
|
||||
versions: ["1.5", "1.5-b"],
|
||||
};
|
||||
|
||||
return newChartDoc;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ChartDocument } from "tachi-common";
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "../../src/common/logger";
|
||||
import MigrateRecords from "./migrate";
|
||||
import { gameOrders } from "tachi-common/js/config";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import MigrateRecords from "../migrate";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
@@ -25,27 +24,15 @@ async function ConvertFn(c: any): Promise<ChartDocument<"sdvx:Single">> {
|
||||
playtype: c.playtype,
|
||||
levelNum: c.levelNum,
|
||||
level: c.level.toString(),
|
||||
flags: {
|
||||
"IN BASE GAME": !!c.flags["IN BASE GAME"],
|
||||
OMNIMIX: !!c.flags.OMNIMIX,
|
||||
"N-1": !!c.flags["N-1"],
|
||||
},
|
||||
data: {
|
||||
inGameID: c.internals.inGameINTID,
|
||||
arcChartID: null,
|
||||
},
|
||||
isPrimary: true,
|
||||
versions: [], // sentinel
|
||||
tierlistInfo: {},
|
||||
versions: ["vivid"],
|
||||
};
|
||||
|
||||
const idx = gameOrders.sdvx.indexOf(song.firstVersion!);
|
||||
|
||||
if (idx === -1) {
|
||||
logger.warn(`Invalid firstAppearance of ${song.firstVersion!}, running anyway.`);
|
||||
newChartDoc.versions = [song.firstVersion!];
|
||||
} else {
|
||||
newChartDoc.versions = gameOrders.sdvx.slice(idx);
|
||||
}
|
||||
|
||||
return newChartDoc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import db from "external/mongo/db";
|
||||
import { TierlistDataDocument } from "tachi-common";
|
||||
import { CalculateTierlistDataID } from "../../../src/common/tierlist";
|
||||
import { oldKTDB } from "../old-db";
|
||||
import CreateLogCtx from "../../../src/common/logger";
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
const TIERLIST_ID = "ed45403c2cd93922d8a45b3c5bc352a962a8f115";
|
||||
|
||||
function ConvertFn(c: any) {
|
||||
const tdd: TierlistDataDocument<"Individual Difference"> = {
|
||||
chartID: c.chartID,
|
||||
type: "score",
|
||||
key: null,
|
||||
tierlistDataID: CalculateTierlistDataID(c.chartID, "score", null, TIERLIST_ID),
|
||||
tierlistID: TIERLIST_ID,
|
||||
data: {
|
||||
flags: {
|
||||
"Individual Difference": c.idvDifference === "FALSE",
|
||||
},
|
||||
value: c.tiers["score-tier"],
|
||||
humanised: `☆${c.tiers["score-tier"]}`,
|
||||
},
|
||||
};
|
||||
|
||||
return tdd;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const exists = await db["tierlist-data"].count({
|
||||
tierlistID: TIERLIST_ID,
|
||||
});
|
||||
|
||||
if (exists > 0) {
|
||||
logger.error(`Cancelling migration request as ${exists} documents already exist.`);
|
||||
return process.exit(1);
|
||||
}
|
||||
|
||||
const docs = await oldKTDB.get("tierlistdata").find({
|
||||
tierlistID: TIERLIST_ID,
|
||||
});
|
||||
|
||||
const newDocs = await Promise.all(docs.map(ConvertFn));
|
||||
|
||||
await db["tierlist-data"].insert(newDocs);
|
||||
})();
|
||||
@@ -1,41 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { TierlistParent, Game } from "tachi-common";
|
||||
import { gameHuman, validPlaytypes } from "tachi-common/js/config";
|
||||
import db from "../../src/external/mongo/db";
|
||||
import MigrateRecords from "./migrate";
|
||||
|
||||
function ConvertFn(c: any): TierlistParent {
|
||||
const tierlistParent: TierlistParent = {
|
||||
createdAt: Date.now(),
|
||||
tierlistID: c.tierlistID,
|
||||
createdBy: 1,
|
||||
description: `The official Kamaitachi Tierlist for ${gameHuman[c.game as Game]}${
|
||||
validPlaytypes[c.game as Game].length > 1 ? ` (${c.playtype})` : ""
|
||||
}.`,
|
||||
game: c.game,
|
||||
playtype: c.playtype,
|
||||
isDefault: true,
|
||||
name: c.title,
|
||||
lastUpdated: Date.now(),
|
||||
permissions: {
|
||||
anyPlayer: {
|
||||
edit: 0,
|
||||
submit: 1,
|
||||
vote: 1,
|
||||
},
|
||||
},
|
||||
config: {
|
||||
autoHumanise: false,
|
||||
flags: ["Individual Difference"],
|
||||
requireState: "clear",
|
||||
},
|
||||
};
|
||||
|
||||
return tierlistParent;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await MigrateRecords(db.tierlists, "tierlist", ConvertFn);
|
||||
|
||||
process.exit(0);
|
||||
})();
|
||||
@@ -1,27 +1,36 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
/* eslint-disable no-case-declarations */
|
||||
/* eslint-disable no-param-reassign */
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import fetch from "node-fetch";
|
||||
import { FindSongOnTitle } from "../../src/common/database-lookup/song";
|
||||
import { FindChartWithPTDF } from "../../src/common/database-lookup/chart";
|
||||
import { Difficulties, TierlistDataDocument } from "tachi-common";
|
||||
|
||||
import { CalculateTierlistDataID } from "../../src/common/tierlist";
|
||||
import CreateLogCtx from "../../src/common/logger";
|
||||
import { Difficulties, integer } from "tachi-common";
|
||||
import { FindChartWithPTDF } from "utils/queries/charts";
|
||||
import { FindSongOnTitle } from "utils/queries/songs";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
const TIERLIST_ID = "ee9b756e50cff8282091102257b01f423ef855f2";
|
||||
interface SP12Data {
|
||||
id: integer;
|
||||
title: string;
|
||||
n_clear: integer;
|
||||
hard: integer;
|
||||
exh: integer;
|
||||
n_clear_string: string;
|
||||
hard_string: string;
|
||||
exh_string: string;
|
||||
version: integer;
|
||||
}
|
||||
|
||||
async function FetchSP12Data() {
|
||||
const rj = await fetch("https://sp12.iidx.app/api/v1/sheets").then((r) => r.json()); // will throw if somethings wrong, anyway
|
||||
const rj: { sheets: SP12Data[] } = await fetch("https://sp12.iidx.app/api/v1/sheets").then(
|
||||
(r) => r.json()
|
||||
); // will throw if somethings wrong, anyway
|
||||
|
||||
if (!rj.sheets) {
|
||||
throw new Error(`No sheets in return from sp12?`);
|
||||
}
|
||||
|
||||
const tdd: TierlistDataDocument<"Individual Difference">[] = [];
|
||||
|
||||
for (const sh of rj.sheets) {
|
||||
let chart;
|
||||
try {
|
||||
@@ -31,14 +40,16 @@ async function FetchSP12Data() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const key of ["NORMAL CLEAR", "HARD CLEAR", "EX HARD CLEAR"]) {
|
||||
let fakeKey;
|
||||
if (!chart) {
|
||||
logger.warn(`Couldn't find chart with title ${sh.title}`);
|
||||
}
|
||||
|
||||
for (const key of ["n_clear", "hard", "exh"] as const) {
|
||||
let val;
|
||||
|
||||
switch (key) {
|
||||
case "NORMAL CLEAR":
|
||||
fakeKey = "n_clear";
|
||||
const v = Math.floor(sh[fakeKey] / 2);
|
||||
case "n_clear":
|
||||
const v = Math.floor(sh[key] / 2);
|
||||
|
||||
if (v === 9) {
|
||||
val = 11.8;
|
||||
@@ -57,9 +68,8 @@ async function FetchSP12Data() {
|
||||
}
|
||||
|
||||
break;
|
||||
case "HARD CLEAR":
|
||||
fakeKey = "hard";
|
||||
const v2 = Math.floor(sh[fakeKey] / 2);
|
||||
case "hard":
|
||||
const v2 = Math.floor(sh[key] / 2);
|
||||
|
||||
if (v2 === 9) {
|
||||
val = 11.9;
|
||||
@@ -78,10 +88,8 @@ async function FetchSP12Data() {
|
||||
}
|
||||
|
||||
break;
|
||||
case "EX HARD CLEAR":
|
||||
fakeKey = "exh";
|
||||
|
||||
const v3 = sh[fakeKey];
|
||||
case "exh":
|
||||
const v3 = sh[key];
|
||||
if (v3 < 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -93,49 +101,47 @@ async function FetchSP12Data() {
|
||||
throw new Error("??");
|
||||
}
|
||||
|
||||
const humanised = sh[`${fakeKey}_string`];
|
||||
const stringVal = sh[`${key}_string` as const];
|
||||
|
||||
if (humanised === "難易度未定") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val < 11.8) {
|
||||
logger.info(`Skipping ${sh.title} ${key}, ${humanised}.`);
|
||||
if (stringVal === "難易度未定") {
|
||||
continue;
|
||||
}
|
||||
|
||||
val = parseFloat(val.toFixed(2));
|
||||
|
||||
tdd.push({
|
||||
chartID: chart.chartID,
|
||||
type: "lamp",
|
||||
tierlistID: TIERLIST_ID,
|
||||
tierlistDataID: CalculateTierlistDataID(chart.chartID, "lamp", key, TIERLIST_ID),
|
||||
key,
|
||||
data: {
|
||||
humanised,
|
||||
value: val,
|
||||
flags: {
|
||||
"Individual Difference": !!humanised.match(/個人差/u),
|
||||
},
|
||||
const ktKey = key === "exh" ? "kt-EXHC" : key === "hard" ? "kt-HC" : "kt-NC";
|
||||
|
||||
// If EXH, just save the string version as 12.xx
|
||||
// Else, use the A/S+ thing that people are used to.
|
||||
const text =
|
||||
ktKey === "kt-EXHC"
|
||||
? val.toFixed(2)
|
||||
: `12${stringVal.replace(/(個人差|地力)/u, "")}`;
|
||||
|
||||
await db.charts.iidx.update(
|
||||
{
|
||||
chartID: chart.chartID,
|
||||
},
|
||||
});
|
||||
{
|
||||
$set: {
|
||||
[`tierlistInfo.${ktKey}`]: {
|
||||
text,
|
||||
value: val,
|
||||
individualDifference: stringVal.includes("個人差"),
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
logger.info(`Saved ${sh.title} value ${key} = ${val} (${text}).`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`Inserting ${tdd.length} documents...`);
|
||||
|
||||
await db["tierlist-data"].insert(tdd);
|
||||
|
||||
logger.info("Done!");
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function isOdd(num: number) {
|
||||
return num % 2 !== 0;
|
||||
}
|
||||
|
||||
async function HumanisedTitleLookup(originalTitle: string) {
|
||||
let difficulty: Difficulties["iidx:SP"] = "ANOTHER";
|
||||
|
||||
@@ -143,7 +149,7 @@ async function HumanisedTitleLookup(originalTitle: string) {
|
||||
|
||||
if (title.match(/(†|†LEGGENDARIA)$/u)) {
|
||||
difficulty = "LEGGENDARIA";
|
||||
title = title.split("†")[0]; // this will break if there is ever a ptp leggendaria
|
||||
title = title.split(/(†|†LEGGENDARIA)$/u)[0];
|
||||
} else if (title.match(/\[H\]$/u)) {
|
||||
difficulty = "HYPER";
|
||||
title = title.split("[")[0];
|
||||
|
||||
@@ -2,4 +2,4 @@ get the data by going to https://iidx.insane.pe.kr/!/sp10/ and typing copy(table
|
||||
|
||||
parsers here handle the rest.
|
||||
|
||||
the sp8h tierlist *sucks*, so, we're ignoring it.
|
||||
the sp8h, 9 and 10 tierlists *suck*, so, we're ignoring them.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,20 @@
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import db from "external/mongo/db";
|
||||
import fs from "fs";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import path from "path";
|
||||
import { CalculateTierlistDataID } from "../../src/common/tierlist";
|
||||
import { FindSongOnTitle } from "../../src/common/database-lookup/song";
|
||||
import CreateLogCtx from "../../src/common/logger";
|
||||
import { FindChartWithPTDF } from "../../src/common/database-lookup/chart";
|
||||
import { Difficulties } from "tachi-common";
|
||||
import { FindChartWithPTDF } from "utils/queries/charts";
|
||||
import { FindSongOnTitle } from "utils/queries/songs";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
const TIERLIST_ID = "ee9b756e50cff8282091102257b01f423ef855f2";
|
||||
|
||||
async function parseKr(
|
||||
dir: string,
|
||||
key: "NORMAL CLEAR" | "HARD CLEAR",
|
||||
catVals: { h: string; v: number }[]
|
||||
file: string,
|
||||
mode: "NC" | "HC",
|
||||
catVals: { text: string; value: number; idv: boolean }[]
|
||||
) {
|
||||
const krdata = JSON.parse(fs.readFileSync(path.join(__dirname, "./iidx-pe-kr", dir), "utf-8"));
|
||||
|
||||
const tdd = [];
|
||||
const krdata = JSON.parse(fs.readFileSync(path.join(__dirname, "./iidx-pe-kr", file), "utf-8"));
|
||||
|
||||
for (let i = 0; i < krdata.categories.length; i++) {
|
||||
const data = krdata.categories[i];
|
||||
@@ -63,102 +59,59 @@ async function parseKr(
|
||||
continue;
|
||||
}
|
||||
|
||||
tdd.push({
|
||||
chartID: chart.chartID,
|
||||
type: "lamp" as const,
|
||||
tierlistID: TIERLIST_ID,
|
||||
tierlistDataID: CalculateTierlistDataID(chart.chartID, "lamp", key, TIERLIST_ID),
|
||||
key,
|
||||
data: {
|
||||
humanised: cv.h,
|
||||
value: cv.v,
|
||||
flags: {
|
||||
"Individual Difference": !!data.category.match(/個人差/u),
|
||||
},
|
||||
// Update this part of the tierlist, we've got everything.
|
||||
|
||||
await db.charts.iidx.update(
|
||||
{
|
||||
chartID: chart.chartID,
|
||||
},
|
||||
});
|
||||
{
|
||||
$set: {
|
||||
[`tierlistInfo.kt-${mode}`]: {
|
||||
text: cv.text,
|
||||
value: cv.value,
|
||||
individualDifference: cv.idv,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
logger.verbose(`Updated ${chart.chartID} to value ${cv.value}.`);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`Inserting ${tdd.length} documents...`);
|
||||
|
||||
const x = await db["tierlist-data"].bulkWrite(
|
||||
tdd.map((e) => ({
|
||||
updateOne: {
|
||||
filter: {
|
||||
tierlistDataID: e.tierlistDataID,
|
||||
},
|
||||
update: {
|
||||
$set: e,
|
||||
},
|
||||
upsert: true,
|
||||
},
|
||||
}))
|
||||
);
|
||||
|
||||
logger.info(x);
|
||||
|
||||
logger.info("done...");
|
||||
logger.info(`Finished parsing ${file}`);
|
||||
}
|
||||
|
||||
function h(h: string, v: number) {
|
||||
return { h, v };
|
||||
function h(text: string, value: number, idv = false) {
|
||||
return { text, value, idv };
|
||||
}
|
||||
|
||||
parseKr("sp9H.json", "HARD CLEAR", [
|
||||
h("S+", 10.2),
|
||||
h("S", 10),
|
||||
h("S 個人差", 10),
|
||||
h("A+", 9.9),
|
||||
h("A+ 個人差", 9.9),
|
||||
h("A", 9.8),
|
||||
h("B+", 9.7),
|
||||
h("B", 9.6),
|
||||
h("C+", 9.5),
|
||||
h("C", 9.4),
|
||||
h("D", 9.2),
|
||||
h("E", 9.0),
|
||||
h("F", 8.8),
|
||||
parseKr("sp11N.json", "NC", [
|
||||
h("11S+", 12.2),
|
||||
h("11S", 12),
|
||||
h("11A+", 11.9),
|
||||
h("11A", 11.8),
|
||||
h("11B", 11.6),
|
||||
h("11C", 11.4),
|
||||
h("11D", 11.2),
|
||||
h("11E", 11.0),
|
||||
h("11F", 10.8),
|
||||
]);
|
||||
|
||||
parseKr("sp10H.json", "HARD CLEAR", [
|
||||
h("S", 11),
|
||||
h("A+", 10.9),
|
||||
h("A", 10.8),
|
||||
h("B+", 10.7),
|
||||
h("B", 10.6),
|
||||
h("C+", 10.5),
|
||||
h("C", 10.4),
|
||||
h("D", 10.2),
|
||||
h("E", 10.0),
|
||||
h("F", 9.8),
|
||||
]);
|
||||
|
||||
parseKr("sp11N.json", "NORMAL CLEAR", [
|
||||
h("S+", 12.2),
|
||||
h("S", 12),
|
||||
h("A+", 11.9),
|
||||
h("A", 11.8),
|
||||
h("B", 11.6),
|
||||
h("C", 11.4),
|
||||
h("D", 11.2),
|
||||
h("E", 11.0),
|
||||
h("F", 10.8),
|
||||
]);
|
||||
|
||||
parseKr("sp11H.json", "HARD CLEAR", [
|
||||
h("S+", 12.2),
|
||||
h("S+ 個人差", 12.2),
|
||||
h("S", 12),
|
||||
h("S 個人差", 12),
|
||||
h("A+", 11.9),
|
||||
h("A+ 個人差", 11.9),
|
||||
h("A", 11.8),
|
||||
h("A 個人差", 11.0),
|
||||
h("B+", 11.7),
|
||||
h("B", 11.6),
|
||||
h("C", 11.4),
|
||||
h("D", 11.2),
|
||||
h("E", 11.0),
|
||||
h("F", 10.8),
|
||||
parseKr("sp11H.json", "HC", [
|
||||
h("11S+", 12.2),
|
||||
h("11S+", 12.2, true), // 個人差
|
||||
h("11S", 12),
|
||||
h("11S", 12, true), // 個人差
|
||||
h("11A+", 11.9),
|
||||
h("11A+", 11.9, true), // 個人差
|
||||
h("11A", 11.8),
|
||||
h("11A", 11.0, true), // 個人差
|
||||
h("11B+", 11.7),
|
||||
h("11B", 11.6),
|
||||
h("11C", 11.4),
|
||||
h("11D", 11.2),
|
||||
h("11E", 11.0),
|
||||
h("11F", 10.8),
|
||||
]);
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import db from "external/mongo/db";
|
||||
|
||||
db.charts.iidx
|
||||
.find({})
|
||||
.each(async (c, { pause, resume }) => {
|
||||
pause();
|
||||
|
||||
await db.charts.iidx.update(
|
||||
{ _id: c._id },
|
||||
{
|
||||
$set: {
|
||||
"flags.2dxtra": false,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
resume();
|
||||
})
|
||||
.then(() => console.log("done"));
|
||||
@@ -1,24 +0,0 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { PRUDENCE_CHART_SCHEMAS } from "../../src/db/schemas";
|
||||
import p from "prudence";
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "../../src/common/logger";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
const data = JSON.parse(fs.readFileSync(path.join(__dirname, "./hcnverdata.json"), "utf-8"));
|
||||
|
||||
for (const d of data) {
|
||||
const r = p(d, PRUDENCE_CHART_SCHEMAS.iidx);
|
||||
if (r) {
|
||||
logger.error(r.userVal);
|
||||
logger.error(r);
|
||||
throw r;
|
||||
}
|
||||
}
|
||||
|
||||
db.charts.iidx.insert(data).then(() => {
|
||||
logger.info("Done.");
|
||||
process.exit(0);
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
import { ServerTypeInfo } from "lib/setup/config";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
if (require.main === module) {
|
||||
(async () => {
|
||||
for (const game of ServerTypeInfo.supportedGames) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const res = await db.charts[game].update(
|
||||
{ tierlistInfo: { $exists: false } },
|
||||
{ $set: { tierlistInfo: {} } },
|
||||
{ multi: true }
|
||||
);
|
||||
|
||||
logger.info(`Added tierlistInfo to ${game}'s charts.`, { res });
|
||||
}
|
||||
})();
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
import bcrypt from "bcrypt";
|
||||
|
||||
console.log(bcrypt.hashSync("password", 12));
|
||||
@@ -1,21 +0,0 @@
|
||||
import db from "external/mongo/db";
|
||||
import { Random20Hex } from "utils/misc";
|
||||
|
||||
(async () => {
|
||||
const docs = await db.charts.iidx.find({ version: "inf" }, { projectID: true });
|
||||
|
||||
for (const doc of docs) {
|
||||
await db.charts.iidx.update(
|
||||
{
|
||||
_id: doc._id,
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
chartID: Random20Hex(),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
console.log("done");
|
||||
})();
|
||||
@@ -1,28 +0,0 @@
|
||||
import db from "external/mongo/db";
|
||||
import { FolderDocument } from "tachi-common";
|
||||
|
||||
(async () => {
|
||||
const folders = (await db.folders.find({})) as any[];
|
||||
|
||||
for (const fl of folders) {
|
||||
const f: FolderDocument = {
|
||||
folderID: fl.folderID,
|
||||
game: fl.game,
|
||||
playtype: fl.playtype,
|
||||
table: fl.table,
|
||||
tableIndex: fl.tableIndex,
|
||||
title: fl.title,
|
||||
type: fl.query.collection === "charts" ? "charts" : "songs",
|
||||
data: fl.query.body,
|
||||
};
|
||||
|
||||
await db.folders.update(
|
||||
{
|
||||
_id: fl._id,
|
||||
},
|
||||
{ $set: f }
|
||||
);
|
||||
}
|
||||
|
||||
console.log("done");
|
||||
})();
|
||||
@@ -1,410 +0,0 @@
|
||||
[
|
||||
{
|
||||
"songID": 919,
|
||||
"rgcID": null,
|
||||
"chartID": "90a2e4664a1a3f8a3a2fd2d8d6a89fd0a47ca659",
|
||||
"level": "11",
|
||||
"length": null,
|
||||
"levelNum": 11,
|
||||
"bpmString": "178",
|
||||
"playtype": "SP",
|
||||
"difficulty": "HYPER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 1146,
|
||||
"inGameID": 17100
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 919,
|
||||
"rgcID": null,
|
||||
"chartID": "360ac8bd65fe8b019d0457bd6603c2bff29d0cd8",
|
||||
"level": "7",
|
||||
"length": null,
|
||||
"levelNum": 7,
|
||||
"bpmString": "178",
|
||||
"playtype": "SP",
|
||||
"difficulty": "NORMAL",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 518,
|
||||
"inGameID": 17100
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 919,
|
||||
"rgcID": null,
|
||||
"chartID": "d7b1c2beb792de3f76a13297a02d8326367f71bc",
|
||||
"level": "12",
|
||||
"length": null,
|
||||
"levelNum": 12,
|
||||
"bpmString": "178",
|
||||
"playtype": "SP",
|
||||
"difficulty": "ANOTHER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 1629,
|
||||
"inGameID": 17100
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 919,
|
||||
"rgcID": null,
|
||||
"chartID": "e36e466c21f208b7489fadf465a257c5ab00f672",
|
||||
"level": "11",
|
||||
"length": null,
|
||||
"levelNum": 11,
|
||||
"bpmString": "178",
|
||||
"playtype": "DP",
|
||||
"difficulty": "HYPER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 1117,
|
||||
"inGameID": 17100
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 919,
|
||||
"rgcID": null,
|
||||
"chartID": "b421a3efeed03f97f5d0ab1901bf539d398755c8",
|
||||
"level": "6",
|
||||
"length": null,
|
||||
"levelNum": 6,
|
||||
"bpmString": "178",
|
||||
"playtype": "DP",
|
||||
"difficulty": "NORMAL",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 506,
|
||||
"inGameID": 17100
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 919,
|
||||
"rgcID": null,
|
||||
"chartID": "7292edfe76c7178f1f608d5e34c0fa09d8cfcc17",
|
||||
"level": "12",
|
||||
"length": null,
|
||||
"levelNum": 12,
|
||||
"bpmString": "178",
|
||||
"playtype": "DP",
|
||||
"difficulty": "ANOTHER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 1764,
|
||||
"inGameID": 17100
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 994,
|
||||
"rgcID": null,
|
||||
"chartID": "125dd4e63a8fced77696313a7a274b4e1c51df4d",
|
||||
"level": "9",
|
||||
"length": null,
|
||||
"levelNum": 9,
|
||||
"bpmString": "146",
|
||||
"playtype": "SP",
|
||||
"difficulty": "HYPER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 708,
|
||||
"inGameID": 18102
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 994,
|
||||
"rgcID": null,
|
||||
"chartID": "7de251ff40cca708de47cce82cbe58d60bc13561",
|
||||
"level": "5",
|
||||
"length": null,
|
||||
"levelNum": 5,
|
||||
"bpmString": "146",
|
||||
"playtype": "SP",
|
||||
"difficulty": "NORMAL",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 268,
|
||||
"inGameID": 18102
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 994,
|
||||
"rgcID": null,
|
||||
"chartID": "20aabe8ae38b5facc6a4f7953f6c73c4c9817840",
|
||||
"level": "11",
|
||||
"length": null,
|
||||
"levelNum": 11,
|
||||
"bpmString": "146",
|
||||
"playtype": "SP",
|
||||
"difficulty": "ANOTHER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 1125,
|
||||
"inGameID": 18102
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 994,
|
||||
"rgcID": null,
|
||||
"chartID": "fa58148d78b33fdb6bc7437065d35285a962d27d",
|
||||
"level": "9",
|
||||
"length": null,
|
||||
"levelNum": 9,
|
||||
"bpmString": "146",
|
||||
"playtype": "DP",
|
||||
"difficulty": "HYPER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 740,
|
||||
"inGameID": 18102
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 994,
|
||||
"rgcID": null,
|
||||
"chartID": "731a4407beeba780e429796ddc6d64444ea64079",
|
||||
"level": "4",
|
||||
"length": null,
|
||||
"levelNum": 4,
|
||||
"bpmString": "146",
|
||||
"playtype": "DP",
|
||||
"difficulty": "NORMAL",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 429,
|
||||
"inGameID": 18102
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
},
|
||||
{
|
||||
"songID": 994,
|
||||
"rgcID": null,
|
||||
"chartID": "1807545aa0e71df21c6ab518a0dccdc12aa3535e",
|
||||
"level": "12",
|
||||
"length": null,
|
||||
"levelNum": 12,
|
||||
"bpmString": "146",
|
||||
"playtype": "DP",
|
||||
"difficulty": "ANOTHER",
|
||||
"flags": {
|
||||
"IN BASE GAME": false,
|
||||
"OMNIMIX": true,
|
||||
"N-1": true
|
||||
},
|
||||
"data": {
|
||||
"notecount": 1120,
|
||||
"inGameID": 18102
|
||||
},
|
||||
"isPrimary": true,
|
||||
"versions": [
|
||||
"18",
|
||||
"19",
|
||||
"20",
|
||||
"21",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,24 +0,0 @@
|
||||
import db from "external/mongo/db";
|
||||
|
||||
(async () => {
|
||||
db.folders
|
||||
.find({})
|
||||
// @ts-expect-error ??? monk
|
||||
.each(async (c, { pause, resume }) => {
|
||||
pause();
|
||||
|
||||
await db.folders.update(
|
||||
{
|
||||
_id: c._id,
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
tableIndex: Number(c.tableIndex),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
resume();
|
||||
})
|
||||
.then(() => console.log("done"));
|
||||
})();
|
||||
@@ -1,21 +0,0 @@
|
||||
import parser from "fast-xml-parser";
|
||||
import CreateLogCtx from "../../src/common/logger";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
let parsedXML;
|
||||
|
||||
const fileData = fs.readFileSync(
|
||||
path.join(__dirname, "../../src/test-utils/test-data/s3/valid.xml"),
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
try {
|
||||
parsedXML = parser.parse(fileData);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, "s3data.json"), JSON.stringify(parsedXML, null, 4));
|
||||
@@ -1,69 +0,0 @@
|
||||
{
|
||||
"s3data": {
|
||||
"userdata": {
|
||||
"id": 3,
|
||||
"login": "zkldi",
|
||||
"djname": "ZKLDI"
|
||||
},
|
||||
"scoredata": {
|
||||
"song": [
|
||||
{
|
||||
"id": 187,
|
||||
"diff": 7,
|
||||
"songname": "GAMBOL",
|
||||
"artist": "SLAKE",
|
||||
"genre": "BIG BEAT",
|
||||
"bpm": 174,
|
||||
"styles": "3rd",
|
||||
"rating": 1,
|
||||
"notes": 137,
|
||||
"exscore": 100,
|
||||
"grade": "AA",
|
||||
"djpoints": 9,
|
||||
"scorebreakdown": {
|
||||
"justgreats": 50,
|
||||
"greats": 50,
|
||||
"good": 0,
|
||||
"bad": 0,
|
||||
"poor": 4
|
||||
},
|
||||
"mods": {
|
||||
"highspeed": 2,
|
||||
"hidsud": "T",
|
||||
"ranmir": "B"
|
||||
},
|
||||
"cleartype": "perfect",
|
||||
"date": "2010-10-19 04:54:22"
|
||||
},
|
||||
{
|
||||
"id": 187,
|
||||
"diff": "L7",
|
||||
"songname": "GAMBOL",
|
||||
"artist": "SLAKE",
|
||||
"genre": "BIG BEAT",
|
||||
"bpm": 174,
|
||||
"styles": "3rd",
|
||||
"rating": 1,
|
||||
"notes": 137,
|
||||
"exscore": 100,
|
||||
"grade": "AA",
|
||||
"djpoints": 9,
|
||||
"scorebreakdown": {
|
||||
"justgreats": 50,
|
||||
"greats": 50,
|
||||
"good": 0,
|
||||
"bad": 0,
|
||||
"poor": 4
|
||||
},
|
||||
"mods": {
|
||||
"highspeed": 2,
|
||||
"hidsud": "T",
|
||||
"ranmir": "B"
|
||||
},
|
||||
"cleartype": "perfect",
|
||||
"date": "2010-10-19 04:54:22"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import fs from "fs";
|
||||
import db from "../../db/db";
|
||||
import path from "path";
|
||||
|
||||
(async () => {
|
||||
const data = await db.scores.find({ game: "iidx", playtype: "SP" }, { limit: 1000 });
|
||||
fs.writeFileSync(path.join(__dirname, "data.json"), JSON.stringify(data));
|
||||
process.exit(0);
|
||||
})();
|
||||
Vendored
-6
@@ -4,10 +4,8 @@ import {
|
||||
GoalDocument,
|
||||
IIDXBPIData,
|
||||
ImportDocument,
|
||||
TierlistParent,
|
||||
InviteCodeDocument,
|
||||
APITokenDocument,
|
||||
TierlistDataDocument,
|
||||
MilestoneDocument,
|
||||
FolderChartLookup,
|
||||
ImportTimingsDocument,
|
||||
@@ -144,8 +142,6 @@ const db = {
|
||||
songs,
|
||||
charts,
|
||||
scores: monkDB.get<ScoreDocument>("scores"),
|
||||
tierlists: monkDB.get<TierlistParent>("tierlists"),
|
||||
"tierlist-data": monkDB.get<TierlistDataDocument<never>>("tierlist-data"),
|
||||
"personal-bests": monkDB.get<PBScoreDocument>("personal-bests"),
|
||||
folders: monkDB.get<FolderDocument>("folders"),
|
||||
"folder-chart-lookup": monkDB.get<FolderChartLookup>("folder-chart-lookup"),
|
||||
@@ -192,8 +188,6 @@ export type StaticDatabases =
|
||||
| "personal-bests"
|
||||
| "imports"
|
||||
| "import-timings"
|
||||
| "tierlist-data"
|
||||
| "tierlists"
|
||||
| "goals"
|
||||
| "user-goals"
|
||||
| "user-milestones"
|
||||
|
||||
Vendored
-10
@@ -38,12 +38,6 @@ const staticIndexes: Partial<Record<Databases, Index[]>> = {
|
||||
"game-stats": [index({ userID: 1, game: 1, playtype: 1 }, UNIQUE)],
|
||||
"game-settings": [index({ userID: 1, game: 1, playtype: 1 }, UNIQUE)],
|
||||
"folder-chart-lookup": [index({ chartID: 1, folderID: 1 }, UNIQUE)],
|
||||
"tierlist-data": [
|
||||
index({ tierlistDataID: 1 }, UNIQUE),
|
||||
index({ chartID: 1, tierlistID: 1 }),
|
||||
index({ chartID: 1, tierlistID: 1, type: 1 }),
|
||||
index({ chartID: 1, tierlistID: 1, type: 1, key: 1 }, UNIQUE),
|
||||
],
|
||||
goals: [index({ goalID: 1 }, UNIQUE)],
|
||||
"user-goals": [index({ goalID: 1, userID: 1 }, UNIQUE), index({ goalID: 1 })],
|
||||
milestones: [index({ milestoneID: 1 }, UNIQUE), index({ group: 1, game: 1, playtype: 1 })],
|
||||
@@ -62,10 +56,6 @@ const staticIndexes: Partial<Record<Databases, Index[]>> = {
|
||||
index({ username: 1 }, UNIQUE),
|
||||
index({ usernameLowercase: 1 }, UNIQUE),
|
||||
],
|
||||
tierlists: [
|
||||
index({ tierlistID: 1 }, UNIQUE),
|
||||
index({ game: 1, playtype: 1, isDefault: 1 }, UNIQUE),
|
||||
],
|
||||
folders: [
|
||||
index({ folderID: 1 }, UNIQUE),
|
||||
index({ game: 1, playtype: 1 }),
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
export enum IIDX_LAMPS {
|
||||
NO_PLAY,
|
||||
FAILED,
|
||||
ASSIST_CLEAR,
|
||||
EASY_CLEAR,
|
||||
CLEAR,
|
||||
HARD_CLEAR,
|
||||
EX_HARD_CLEAR,
|
||||
FULL_COMBO,
|
||||
}
|
||||
|
||||
export enum CHUNITHM_LAMPS {
|
||||
FAILED,
|
||||
CLEAR,
|
||||
FULL_COMBO,
|
||||
ALL_JUSTICE,
|
||||
ALL_JUSTICE_CRITICAL,
|
||||
}
|
||||
|
||||
export enum SDVX_LAMPS {
|
||||
FAILED,
|
||||
CLEAR,
|
||||
EXCESSIVE_CLEAR,
|
||||
ULTIMATE_CHAIN,
|
||||
PERFECT_ULTIMATE_CHAIN,
|
||||
}
|
||||
|
||||
export enum MUSECA_LAMPS {
|
||||
FAILED,
|
||||
CLEAR,
|
||||
CONNECT_ALL,
|
||||
PERFECT_CONNECT_ALL,
|
||||
}
|
||||
|
||||
export enum DDR_LAMPS {
|
||||
FAILED,
|
||||
CLEAR,
|
||||
LIFE4,
|
||||
FULL_COMBO,
|
||||
GREAT_FULL_COMBO,
|
||||
PERFECT_FULL_COMBO,
|
||||
MARVELOUS_FULL_COMBO,
|
||||
}
|
||||
|
||||
export enum MAIMAI_LAMPS {
|
||||
FAILED,
|
||||
CLEAR,
|
||||
FULL_COMBO,
|
||||
ALL_PERFECT,
|
||||
ALL_PERFECT_PLUS,
|
||||
}
|
||||
|
||||
export enum GITADORA_LAMPS {
|
||||
FAILED,
|
||||
CLEAR,
|
||||
FULL_COMBO,
|
||||
EXCELLENT,
|
||||
}
|
||||
|
||||
export enum IIDX_GRADES {
|
||||
F,
|
||||
E,
|
||||
D,
|
||||
C,
|
||||
B,
|
||||
A,
|
||||
AA,
|
||||
AAA,
|
||||
MAX_MINUS,
|
||||
MAX,
|
||||
}
|
||||
|
||||
export enum CHUNITHM_GRADES {
|
||||
D,
|
||||
C,
|
||||
B,
|
||||
BB,
|
||||
BBB,
|
||||
A,
|
||||
AA,
|
||||
AAA,
|
||||
S,
|
||||
SS,
|
||||
SSS,
|
||||
}
|
||||
|
||||
export enum SDVX_GRADES {
|
||||
D,
|
||||
C,
|
||||
B,
|
||||
A,
|
||||
A_PLUS,
|
||||
AA,
|
||||
AA_PLUS,
|
||||
AAA,
|
||||
AAA_PLUS,
|
||||
S,
|
||||
}
|
||||
|
||||
export enum MUSECA_GRADES {
|
||||
没,
|
||||
拙,
|
||||
凡,
|
||||
佳,
|
||||
良,
|
||||
優,
|
||||
秀,
|
||||
傑,
|
||||
傑G,
|
||||
}
|
||||
|
||||
/**
|
||||
* Kxxx refers to the starting point of that grade,
|
||||
* since they dont translate to english well.
|
||||
* K950 means the grade that starts at 950K and goes
|
||||
* to 975K.
|
||||
*/
|
||||
export enum MUSECA_GRADES_ASCII {
|
||||
ZERO,
|
||||
K600,
|
||||
K700,
|
||||
K800,
|
||||
K850,
|
||||
K900,
|
||||
K950,
|
||||
K975,
|
||||
K1000,
|
||||
}
|
||||
|
||||
export enum DDR_GRADES {
|
||||
D,
|
||||
D_PLUS,
|
||||
C_MINUS,
|
||||
C,
|
||||
C_PLUS,
|
||||
B_MINUS,
|
||||
B,
|
||||
B_PLUS,
|
||||
A_MINUS,
|
||||
A,
|
||||
A_PLUS,
|
||||
AA_MINUS,
|
||||
AA,
|
||||
AA_PLUS,
|
||||
AAA,
|
||||
}
|
||||
|
||||
export enum MAIMAI_GRADES {
|
||||
F,
|
||||
E,
|
||||
D,
|
||||
C,
|
||||
B,
|
||||
A,
|
||||
AA,
|
||||
AAA,
|
||||
S,
|
||||
S_PLUS,
|
||||
SS,
|
||||
SS_PLUS,
|
||||
SSS,
|
||||
SSS_PLUS,
|
||||
}
|
||||
|
||||
export enum GITADORA_GRADES {
|
||||
C,
|
||||
B,
|
||||
A,
|
||||
S,
|
||||
SS,
|
||||
MAX,
|
||||
}
|
||||
@@ -58,7 +58,6 @@ t.test("#CreateCalculatedData", async (t) => {
|
||||
* These tests only check that the right properties are assigned.
|
||||
*/
|
||||
t.test("#CalculateDataForGamePT", (t) => {
|
||||
const defaultTierlistID = undefined;
|
||||
t.test("IIDX:SP", async (t) => {
|
||||
const res = await CalculateDataForGamePT(
|
||||
"iidx",
|
||||
@@ -66,7 +65,7 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore,
|
||||
30,
|
||||
defaultTierlistID,
|
||||
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -90,7 +89,7 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an SP score. but we're testing
|
||||
30,
|
||||
defaultTierlistID,
|
||||
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -114,7 +113,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingSDVXSingleDryScore,
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -136,7 +134,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -159,7 +156,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -182,7 +178,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -204,7 +199,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -226,7 +220,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -248,7 +241,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -270,7 +262,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -292,7 +283,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -314,7 +304,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -336,7 +325,6 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
Testing511SPA,
|
||||
TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
null,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -358,7 +346,7 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
// Testing511SPA,
|
||||
// TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
// null,
|
||||
// defaultTierlistID,
|
||||
//
|
||||
// logger
|
||||
// );
|
||||
|
||||
@@ -380,7 +368,7 @@ t.test("#CalculateDataForGamePT", (t) => {
|
||||
// Testing511SPA,
|
||||
// TestingIIDXSPDryScore, // fake! this is an iidx score. but we're testing
|
||||
// null,
|
||||
// defaultTierlistID,
|
||||
//
|
||||
// logger
|
||||
// );
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import db from "external/mongo/db";
|
||||
import { HasOwnProperty } from "utils/misc";
|
||||
|
||||
import { GetDefaultTierlist } from "utils/tierlist";
|
||||
import { KtLogger } from "lib/logger/logger";
|
||||
import { DryScore } from "../common/types";
|
||||
import {
|
||||
@@ -32,16 +31,12 @@ export async function CreateCalculatedData(
|
||||
const game = dryScore.game;
|
||||
const playtype = chart.playtype;
|
||||
|
||||
const defaultTierlist = await GetDefaultTierlist(game, playtype);
|
||||
const defaultTierlistID = defaultTierlist?.tierlistID; // tierlistID | undefined
|
||||
|
||||
const calculatedData = await CalculateDataForGamePT(
|
||||
game,
|
||||
playtype,
|
||||
chart,
|
||||
dryScore,
|
||||
esd,
|
||||
defaultTierlistID,
|
||||
logger
|
||||
);
|
||||
|
||||
@@ -53,7 +48,6 @@ type CalculatedDataFunctions = {
|
||||
[P in Playtypes[G]]: (
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string,
|
||||
logger: KtLogger
|
||||
) => Promise<ScoreDocument["calculatedData"]> | ScoreDocument["calculatedData"];
|
||||
};
|
||||
@@ -109,7 +103,6 @@ export async function CalculateDataForGamePT<G extends Game>(
|
||||
// ESD gets specially passed through because it's not part of the DryScore, but
|
||||
// can be used for statistics anyway.
|
||||
esd: number | null,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<ScoreDocument["calculatedData"]> {
|
||||
const GameRatingFns = CalculatedDataFunctions[game];
|
||||
@@ -122,7 +115,7 @@ export async function CalculateDataForGamePT<G extends Game>(
|
||||
}
|
||||
|
||||
// @ts-expect-error standard game->pt stuff.
|
||||
return GameRatingFns[playtype](dryScore, chart, defaultTierlistID, logger);
|
||||
return GameRatingFns[playtype](dryScore, chart, logger);
|
||||
}
|
||||
|
||||
type CalculatedData<I extends IDStrings> = Required<ScoreDocument<I>["calculatedData"]>;
|
||||
@@ -130,7 +123,6 @@ type CalculatedData<I extends IDStrings> = Required<ScoreDocument<I>["calculated
|
||||
async function CalculateDataIIDXSP(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<CalculatedData<"iidx:SP">> {
|
||||
const BPIData = await db["iidx-bpi-data"].findOne({
|
||||
@@ -155,15 +147,14 @@ async function CalculateDataIIDXSP(
|
||||
|
||||
return {
|
||||
BPI: bpi,
|
||||
ktRating: await CalculateKTRating(dryScore, "iidx", "SP", chart, logger, defaultTierlistID),
|
||||
ktLampRating: await CalculateKTLampRating(dryScore, "iidx", "SP", chart, defaultTierlistID),
|
||||
ktRating: await CalculateKTRating(dryScore, "iidx", "SP", chart, logger),
|
||||
ktLampRating: await CalculateKTLampRating(dryScore, "iidx", "SP", chart),
|
||||
};
|
||||
}
|
||||
|
||||
async function CalculateDataIIDXDP(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<CalculatedData<"iidx:DP">> {
|
||||
const BPIData = await db["iidx-bpi-data"].findOne({
|
||||
@@ -188,15 +179,14 @@ async function CalculateDataIIDXDP(
|
||||
|
||||
return {
|
||||
BPI: bpi,
|
||||
ktRating: await CalculateKTRating(dryScore, "iidx", "DP", chart, logger, defaultTierlistID),
|
||||
ktLampRating: await CalculateKTLampRating(dryScore, "iidx", "DP", chart, defaultTierlistID),
|
||||
ktRating: await CalculateKTRating(dryScore, "iidx", "DP", chart, logger),
|
||||
ktLampRating: await CalculateKTLampRating(dryScore, "iidx", "DP", chart),
|
||||
};
|
||||
}
|
||||
|
||||
function CalculateDataSDVXorUSC(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): CalculatedData<"sdvx:Single" | "usc:Single"> {
|
||||
// for usc, unofficial charts currently have no VF6 value.
|
||||
@@ -220,18 +210,10 @@ function CalculateDataSDVXorUSC(
|
||||
async function CalculateDataMuseca(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<CalculatedData<"museca:Single">> {
|
||||
return {
|
||||
ktRating: await CalculateKTRating(
|
||||
dryScore,
|
||||
"museca",
|
||||
"Single",
|
||||
chart,
|
||||
logger,
|
||||
defaultTierlistID
|
||||
),
|
||||
ktRating: await CalculateKTRating(dryScore, "museca", "Single", chart, logger),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -247,18 +229,10 @@ function CalculateDataCHUNITHM(
|
||||
async function CalculateDataMaimai(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<CalculatedData<"maimai:Single">> {
|
||||
return {
|
||||
ktRating: await CalculateKTRating(
|
||||
dryScore,
|
||||
"maimai",
|
||||
"Single",
|
||||
chart,
|
||||
logger,
|
||||
defaultTierlistID
|
||||
),
|
||||
ktRating: await CalculateKTRating(dryScore, "maimai", "Single", chart, logger),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -274,26 +248,17 @@ function CalculateDataGitadora(
|
||||
async function CalculateDataDDR(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<CalculatedData<"ddr:SP" | "ddr:DP">> {
|
||||
return {
|
||||
MFCP: CalculateMFCP(dryScore, chart, logger),
|
||||
ktRating: await CalculateKTRating(
|
||||
dryScore,
|
||||
"ddr",
|
||||
chart.playtype,
|
||||
chart,
|
||||
logger,
|
||||
defaultTierlistID
|
||||
),
|
||||
ktRating: await CalculateKTRating(dryScore, "ddr", chart.playtype, chart, logger),
|
||||
};
|
||||
}
|
||||
|
||||
export async function CalculateDataBMS14K(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<CalculatedData<"bms:14K">> {
|
||||
return {
|
||||
@@ -304,7 +269,6 @@ export async function CalculateDataBMS14K(
|
||||
export async function CalculateDataBMS7K(
|
||||
dryScore: DryScore,
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID: string | undefined,
|
||||
logger: KtLogger
|
||||
): Promise<CalculatedData<"bms:7K">> {
|
||||
return {
|
||||
@@ -315,7 +279,6 @@ export async function CalculateDataBMS7K(
|
||||
// async function CalculateDataJubeat(
|
||||
// dryScore: DryScore,
|
||||
// chart: ChartDocument,
|
||||
// defaultTierlistID: string | undefined,
|
||||
// logger: KtLogger
|
||||
// ): Promise<CalculatedData<"jubeat:Single">> {
|
||||
// return {
|
||||
|
||||
@@ -348,164 +348,3 @@ t.test("#CalculateRating", (t) => {
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("#CalculateLampRating", (t) => {
|
||||
t.beforeEach(ResetDBState);
|
||||
|
||||
const defaultTierlist = {
|
||||
createdAt: 1620150338858,
|
||||
tierlistID: "ee9b756e50cff8282091102257b01f423ef855f2",
|
||||
createdBy: 1,
|
||||
description: "The official Kamaitachi Tierlist for beatmania IIDX (SP).",
|
||||
game: "iidx",
|
||||
playtype: "SP",
|
||||
isDefault: true,
|
||||
name: "Kamaitachi IIDX SP Official",
|
||||
lastUpdated: 1620150338858,
|
||||
permissions: {
|
||||
anyPlayer: {
|
||||
edit: 0,
|
||||
submit: 1,
|
||||
vote: 1,
|
||||
},
|
||||
},
|
||||
config: {
|
||||
autoHumanise: false,
|
||||
flags: ["Individual Difference"],
|
||||
requireState: "clear",
|
||||
},
|
||||
};
|
||||
|
||||
t.test("TierlistData", async (t) => {
|
||||
const lampRating = await CalculateKTLampRating(
|
||||
TestingIIDXSPDryScore,
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
t.equal(lampRating, 10, "Should equal the levelNum of the chart.");
|
||||
|
||||
const lampRatingFail = await CalculateKTLampRating(
|
||||
deepmerge(TestingIIDXSPDryScore, { scoreData: { lamp: "FAILED" } }),
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
t.equal(lampRatingFail, 0, "Should equal 0, if the score is not a clear.");
|
||||
|
||||
const lampRatingHC = await CalculateKTLampRating(
|
||||
deepmerge(TestingIIDXSPDryScore, { scoreData: { lamp: "HARD CLEAR" } }),
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
t.equal(lampRatingHC, 10.6, "Should equal the tierlist value for HC on this chart.");
|
||||
|
||||
const lampRatingEXHC = await CalculateKTLampRating(
|
||||
deepmerge(TestingIIDXSPDryScore, { scoreData: { lamp: "EX HARD CLEAR" } }),
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
// deliberate - there is no EXHC data here
|
||||
t.equal(lampRatingEXHC, 10.6, "Should equal the tierlist value for HC on this chart.");
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("TierlistData edge cases", async (t) => {
|
||||
await db["tierlist-data"].remove({ chartID: Testing511SPA.chartID, key: "CLEAR" });
|
||||
// mock document that implies 5.1.1. SPA is worth 11.9 to NC and 10.6 to HC.
|
||||
await db["tierlist-data"].insert({
|
||||
chartID: Testing511SPA.chartID,
|
||||
type: "lamp",
|
||||
key: "CLEAR",
|
||||
tierlistDataID: "asdf",
|
||||
tierlistID: defaultTierlist!.tierlistID,
|
||||
data: {
|
||||
flags: {},
|
||||
humanised: "a",
|
||||
value: 11.9,
|
||||
},
|
||||
});
|
||||
|
||||
const lampRating = await CalculateKTLampRating(
|
||||
TestingIIDXSPDryScore,
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
t.equal(lampRating, 11.9, "Should equal the NC value of the chart.");
|
||||
|
||||
const lampRatingFail = await CalculateKTLampRating(
|
||||
deepmerge(TestingIIDXSPDryScore, { scoreData: { lamp: "FAILED" } }),
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
t.equal(lampRatingFail, 0, "Should equal 0, if the score is not a clear.");
|
||||
|
||||
const lampRatingHC = await CalculateKTLampRating(
|
||||
deepmerge(TestingIIDXSPDryScore, { scoreData: { lamp: "HARD CLEAR" } }),
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
t.equal(
|
||||
lampRatingHC,
|
||||
11.9,
|
||||
"Should equal the tierlist value for NC, as it is higher than HC on this chart."
|
||||
);
|
||||
|
||||
const lampRatingEXHC = await CalculateKTLampRating(
|
||||
deepmerge(TestingIIDXSPDryScore, { scoreData: { lamp: "EX HARD CLEAR" } }),
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA,
|
||||
defaultTierlist!.tierlistID
|
||||
);
|
||||
|
||||
t.equal(lampRatingEXHC, 11.9, "Should equal the tierlist value for NC on this chart.");
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("No TierlistData", async (t) => {
|
||||
await db["tierlist-data"].remove({});
|
||||
const lampRating = await CalculateKTLampRating(
|
||||
TestingIIDXSPDryScore,
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA
|
||||
);
|
||||
|
||||
t.equal(lampRating, 10, "Should equal the levelNum of the chart.");
|
||||
|
||||
const lampRatingFail = await CalculateKTLampRating(
|
||||
deepmerge(TestingIIDXSPDryScore, { scoreData: { lamp: "FAILED" } }),
|
||||
"iidx",
|
||||
"SP",
|
||||
Testing511SPA
|
||||
);
|
||||
|
||||
t.equal(lampRatingFail, 0, "Should equal 0, if the score is not a clear.");
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
GetGamePTConfig,
|
||||
IDStrings,
|
||||
} from "tachi-common";
|
||||
import { GetAllTierlistDataOfType, GetOneTierlistData } from "utils/tierlist";
|
||||
import { KtLogger } from "lib/logger/logger";
|
||||
import { DryScore } from "../common/types";
|
||||
|
||||
@@ -302,26 +301,11 @@ export async function CalculateKTRating(
|
||||
game: "iidx" | "bms" | "ddr" | "maimai" | "museca",
|
||||
playtype: Playtypes[Game],
|
||||
chart: ChartDocument,
|
||||
logger: KtLogger,
|
||||
defaultTierlistID?: string
|
||||
logger: KtLogger
|
||||
) {
|
||||
const parameters = ratingParameters[game];
|
||||
|
||||
let levelNum = chart.levelNum;
|
||||
|
||||
if (defaultTierlistID) {
|
||||
const tierlistData = await GetOneTierlistData(
|
||||
game,
|
||||
chart,
|
||||
"score",
|
||||
null,
|
||||
defaultTierlistID
|
||||
);
|
||||
|
||||
if (tierlistData) {
|
||||
levelNum = tierlistData.data.value;
|
||||
}
|
||||
}
|
||||
const levelNum = chart.levelNum;
|
||||
|
||||
return KTRatingCalcV1(dryScore.scoreData.percent, levelNum, parameters, logger);
|
||||
}
|
||||
@@ -330,45 +314,9 @@ export async function CalculateKTLampRating(
|
||||
dryScore: DryScore,
|
||||
game: Game,
|
||||
playtype: Playtypes[Game],
|
||||
chart: ChartDocument,
|
||||
defaultTierlistID?: string
|
||||
chart: ChartDocument
|
||||
) {
|
||||
// if no tierlist data
|
||||
if (!defaultTierlistID) {
|
||||
return LampRatingNoTierlistInfo(dryScore, game, playtype, chart);
|
||||
}
|
||||
|
||||
const lampTierlistInfo = await GetAllTierlistDataOfType(game, chart, "lamp", defaultTierlistID);
|
||||
|
||||
// if no tierlist info
|
||||
if (lampTierlistInfo.length === 0) {
|
||||
return LampRatingNoTierlistInfo(dryScore, game, playtype, chart);
|
||||
}
|
||||
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
const lamps = gptConfig.lamps;
|
||||
|
||||
const userLampIndex = lamps.indexOf(dryScore.scoreData.lamp);
|
||||
|
||||
let lampRating = 0;
|
||||
|
||||
// why is this like this and not a lookup table?
|
||||
// Some charts have higher values for *lower* lamps, such as
|
||||
// one more lovely in IIDX being harder to NC than it is to HC!
|
||||
// this means we have to iterate over all tierlist data, in general.
|
||||
for (const tierlistData of lampTierlistInfo) {
|
||||
if (
|
||||
// this tierlistData has higher value than the current lampRating
|
||||
tierlistData.data.value > lampRating &&
|
||||
// and your clear is better than the lamp its for
|
||||
lamps.indexOf(tierlistData.key as Lamps[IDStrings]) <= userLampIndex
|
||||
) {
|
||||
lampRating = tierlistData.data.value;
|
||||
}
|
||||
}
|
||||
|
||||
return lampRating;
|
||||
return LampRatingNoTierlistInfo(dryScore, game, playtype, chart);
|
||||
}
|
||||
|
||||
function LampRatingNoTierlistInfo(
|
||||
|
||||
@@ -173,6 +173,7 @@ function ConvertBeatorajaChartToTachi(chart: BeatorajaChart) {
|
||||
rgcID: null,
|
||||
songID: 0,
|
||||
versions: [],
|
||||
tierlistInfo: {},
|
||||
data: {
|
||||
hashMD5: chart.md5,
|
||||
hashSHA256: chart.sha256,
|
||||
|
||||
@@ -4,9 +4,9 @@ import { EvaluateShowcaseStat } from "./evaluator";
|
||||
|
||||
import ResetDBState from "test-utils/resets";
|
||||
import { Testing511SPA, TestingIIDXFolderSP10, TestingIIDXSPScorePB } from "test-utils/test-data";
|
||||
import { IIDX_LAMPS } from "lib/constants/game";
|
||||
import { CreateFolderChartLookup } from "utils/folder";
|
||||
import db from "external/mongo/db";
|
||||
import { IIDX_LAMPS } from "tachi-common";
|
||||
|
||||
/* eslint-disable no-return-await */
|
||||
// causes a race condition otherwise due to weird tap interaction
|
||||
|
||||
@@ -3,7 +3,8 @@ import db from "external/mongo/db";
|
||||
|
||||
import ResetDBState from "test-utils/resets";
|
||||
import { TestingIIDXFolderSP10, Testing511SPA, TestingIIDXSPScorePB } from "test-utils/test-data";
|
||||
import { IIDX_LAMPS } from "lib/constants/game";
|
||||
import { IIDX_LAMPS } from "tachi-common";
|
||||
|
||||
import { EvaluateUsersStatsShowcase } from "./get-stats";
|
||||
import deepmerge from "deepmerge";
|
||||
import { CreateFolderChartLookup } from "utils/folder";
|
||||
|
||||
@@ -98,68 +98,3 @@ t.test("GET /api/v1/games/:game/:playtype/charts/:chartID/playcount", (t) => {
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("GET /api/v1/games/:game/:playtype/charts/:chartID/tierlist", (t) => {
|
||||
t.beforeEach(ResetDBState);
|
||||
|
||||
t.test("Should return all tierlist information about the chart.", async (t) => {
|
||||
const res = await mockApi.get(
|
||||
`/api/v1/games/iidx/SP/charts/${Testing511SPA.chartID}/tierlist`
|
||||
);
|
||||
|
||||
t.equal(res.body.body.tierlistData.length, 2);
|
||||
t.hasStrict(res.body.body.tierlist, { isDefault: true, game: "iidx", playtype: "SP" });
|
||||
t.equal(res.body.body.tierlistData[0].chartID, Testing511SPA.chartID);
|
||||
t.equal(res.body.body.tierlistData[1].chartID, Testing511SPA.chartID);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should throw 501 if no default tierlist exists", async (t) => {
|
||||
await db.tierlists.remove({});
|
||||
|
||||
const res = await mockApi.get(
|
||||
`/api/v1/games/iidx/SP/charts/${Testing511SPA.chartID}/tierlist`
|
||||
);
|
||||
|
||||
t.equal(res.statusCode, 501);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should throw 404 if the tierlistID given does not exist.", async (t) => {
|
||||
const res = await mockApi.get(
|
||||
`/api/v1/games/iidx/SP/charts/${Testing511SPA.chartID}/tierlist?tierlistID=foobar`
|
||||
);
|
||||
|
||||
t.equal(res.statusCode, 404);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should support setting your own tierlistID", async (t) => {
|
||||
const tierlist = await db.tierlists.findOne({
|
||||
game: "iidx",
|
||||
playtype: "SP",
|
||||
isDefault: true,
|
||||
});
|
||||
|
||||
if (!tierlist) {
|
||||
t.fail("No tierlists in database?");
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await mockApi.get(
|
||||
`/api/v1/games/iidx/SP/charts/${Testing511SPA.chartID}/tierlist?tierlistID=${tierlist.tierlistID}`
|
||||
);
|
||||
|
||||
t.equal(res.body.body.tierlistData.length, 2);
|
||||
t.equal(res.body.body.tierlist.tierlistID, tierlist.tierlistID);
|
||||
t.equal(res.body.body.tierlistData[0].chartID, Testing511SPA.chartID);
|
||||
t.equal(res.body.body.tierlistData[1].chartID, Testing511SPA.chartID);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@ import { SearchUsersRegExp } from "lib/search/search";
|
||||
import { IsString } from "utils/misc";
|
||||
import { ParseStrPositiveNonZeroInt } from "utils/string-checks";
|
||||
import { GetUsersWithIDs } from "utils/user";
|
||||
import { HandleTierlistIDParam } from "../../folders/middleware";
|
||||
import { ValidateAndGetChart } from "./middleware";
|
||||
import { FormatChart } from "tachi-common";
|
||||
|
||||
@@ -50,33 +49,6 @@ router.get("/", async (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns all tierlist information for this chart.
|
||||
*
|
||||
* @param tierlistID - If specified, retrieve this tierlist instead of the
|
||||
* default. If there is no default for this game, 501 is returned.
|
||||
*
|
||||
* @name GET /api/v1/games/:game/:playtype/charts/:chartID/tierlist
|
||||
*/
|
||||
router.get("/tierlist", HandleTierlistIDParam, async (req, res) => {
|
||||
const tierlist = req[SYMBOL_TachiData]!.tierlistDoc!;
|
||||
const chart = req[SYMBOL_TachiData]!.chartDoc!;
|
||||
|
||||
const tierlistData = await db["tierlist-data"].find({
|
||||
chartID: chart.chartID,
|
||||
tierlistID: tierlist.tierlistID,
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
description: `Returned ${tierlistData.length} tierlist information.`,
|
||||
body: {
|
||||
tierlist,
|
||||
tierlistData,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the total amount of unique players that have played this chart.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,6 @@ import db from "external/mongo/db";
|
||||
import { SYMBOL_TachiData } from "lib/constants/tachi";
|
||||
import { IsString } from "utils/misc";
|
||||
import { AssignToReqTachiData } from "utils/req-tachi-data";
|
||||
import { GetDefaultTierlist } from "utils/tierlist";
|
||||
|
||||
export const GetFolderFromParam: RequestHandler = async (req, res, next) => {
|
||||
const game = req[SYMBOL_TachiData]!.game!;
|
||||
@@ -22,37 +21,3 @@ export const GetFolderFromParam: RequestHandler = async (req, res, next) => {
|
||||
|
||||
return next();
|
||||
};
|
||||
|
||||
export const HandleTierlistIDParam: RequestHandler = async (req, res, next) => {
|
||||
const game = req[SYMBOL_TachiData]!.game!;
|
||||
const playtype = req[SYMBOL_TachiData]!.playtype!;
|
||||
let tierlist;
|
||||
|
||||
if (IsString(req.query.tierlistID)) {
|
||||
tierlist = await db.tierlists.findOne({
|
||||
tierlistID: req.query.tierlistID,
|
||||
game,
|
||||
playtype,
|
||||
});
|
||||
|
||||
if (!tierlist) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
description: `A tierlist with this ID (for this game + playtype) does not exist.`,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
tierlist = await GetDefaultTierlist(game, playtype);
|
||||
|
||||
if (!tierlist) {
|
||||
return res.status(501).json({
|
||||
success: false,
|
||||
description: `This game does not support tierlists, yet.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
AssignToReqTachiData(req, { tierlistDoc: tierlist });
|
||||
|
||||
return next();
|
||||
};
|
||||
|
||||
@@ -77,66 +77,3 @@ t.test("GET /api/v1/games/:game/:playtype/folders/:folderID", (t) => {
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("GET /api/v1/games/:game/:playtype/folders/:folderID/tierlist", (t) => {
|
||||
t.beforeEach(ResetDBState);
|
||||
t.beforeEach(async () => {
|
||||
await db.folders.insert(deepmerge(mockFolder, {}));
|
||||
await CreateFolderChartLookup(mockFolder);
|
||||
});
|
||||
|
||||
t.test("Should return the songs, charts, folder and tierlist information.", async (t) => {
|
||||
const res = await mockApi.get("/api/v1/games/iidx/SP/folders/foo/tierlist?type=lamp");
|
||||
|
||||
t.equal(res.body.body.charts.length, 1);
|
||||
t.equal(res.body.body.songs.length, 1);
|
||||
t.equal(res.body.body.songs[0].id, 1);
|
||||
t.equal(res.body.body.charts[0].chartID, Testing511SPA.chartID);
|
||||
t.equal(res.body.body.folder.folderID, "foo");
|
||||
t.equal(res.body.body.tierlistData.length, 2);
|
||||
t.equal(res.body.body.tierlistData[0].chartID, Testing511SPA.chartID);
|
||||
t.equal(res.body.body.tierlistData[1].chartID, Testing511SPA.chartID);
|
||||
t.equal(res.body.body.tierlistData[0].type, "lamp");
|
||||
t.equal(res.body.body.tierlistData[1].type, "lamp");
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should return 404 if the specified tierlistID does not exist.", async (t) => {
|
||||
const res = await mockApi.get(
|
||||
"/api/v1/games/iidx/SP/folders/foo/tierlist?tierlistID=garbage&type=lamp"
|
||||
);
|
||||
|
||||
t.equal(res.statusCode, 404);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should return 501 if the specified game has no default tierlist.", async (t) => {
|
||||
await db.tierlists.remove({ game: "iidx", playtype: "SP" });
|
||||
|
||||
const res = await mockApi.get("/api/v1/games/iidx/SP/folders/foo/tierlist?type=lamp");
|
||||
|
||||
t.equal(res.statusCode, 501);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should return 400 if no type is given", async (t) => {
|
||||
const res = await mockApi.get("/api/v1/games/iidx/SP/folders/foo/tierlist");
|
||||
|
||||
t.equal(res.statusCode, 400);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test("Should return 400 if an invalid type is given", async (t) => {
|
||||
const res = await mockApi.get("/api/v1/games/iidx/SP/folders/foo/tierlist?type=nonsense");
|
||||
|
||||
t.equal(res.statusCode, 400);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SYMBOL_TachiData } from "lib/constants/tachi";
|
||||
import { SearchCollection } from "lib/search/search";
|
||||
import { GetFolderCharts } from "utils/folder";
|
||||
import { IsString } from "utils/misc";
|
||||
import { GetFolderFromParam, HandleTierlistIDParam } from "./middleware";
|
||||
import { GetFolderFromParam } from "./middleware";
|
||||
|
||||
const router: Router = Router({ mergeParams: true });
|
||||
|
||||
@@ -62,44 +62,4 @@ router.get("/:folderID", GetFolderFromParam, async (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Return all of the tierlist information for the charts inside this folder.
|
||||
*
|
||||
* @param tierlistID - Optionally, specify and alternative tierlistID to use.
|
||||
* If not present, uses the game's default. If the game does not have a
|
||||
* default, 501 is returned.
|
||||
* @param type - The type of tierlist data to return. Can be "lamp" or
|
||||
* "score".
|
||||
*/
|
||||
router.get("/:folderID/tierlist", GetFolderFromParam, HandleTierlistIDParam, async (req, res) => {
|
||||
const folder = req[SYMBOL_TachiData]!.folderDoc!;
|
||||
const tierlist = req[SYMBOL_TachiData]!.tierlistDoc!;
|
||||
|
||||
if (req.query.type !== "lamp" && req.query.type !== "score") {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
description: `Invalid value of type. Expected lamp or score.`,
|
||||
});
|
||||
}
|
||||
|
||||
const { charts, songs } = await GetFolderCharts(folder, {}, true);
|
||||
|
||||
const tierlistData = await db["tierlist-data"].find({
|
||||
chartID: { $in: charts.map((e) => e.chartID) },
|
||||
tierlistID: tierlist!.tierlistID,
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
description: `Returned ${tierlistData.length} tierlist data documents.`,
|
||||
body: {
|
||||
charts,
|
||||
songs,
|
||||
tierlistData,
|
||||
tierlist,
|
||||
folder,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
import { ChartDocument, PublicUserDocument } from "tachi-common";
|
||||
import { ChartDocument, PublicUserDocument, IIDX_LAMPS, IIDX_GRADES } from "tachi-common";
|
||||
import db from "external/mongo/db";
|
||||
import { IIDX_GRADES, IIDX_LAMPS } from "lib/constants/game";
|
||||
import t from "tap";
|
||||
|
||||
import mockApi from "test-utils/mock-api";
|
||||
import ResetDBState from "test-utils/resets";
|
||||
import { TestingIIDXFolderSP10, Testing511SPA, TestingIIDXSPScorePB } from "test-utils/test-data";
|
||||
|
||||
@@ -213,6 +213,7 @@ export function ConvertUSCChart(uscChartDoc: USCClientChart) {
|
||||
rgcID: null,
|
||||
songID: 0,
|
||||
versions: [],
|
||||
tierlistInfo: {},
|
||||
data: {
|
||||
hashSHA1: uscChartDoc.chartHash,
|
||||
isOfficial: false,
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
[
|
||||
{
|
||||
"tierlistDataID": "5216a7fc389a78d456d8aae33ed4c82d27025a1cac9e06789acfd38e726a9773",
|
||||
"chartID": "c2311194e3897ddb5745b1760d2c0141f933e683",
|
||||
"data": {
|
||||
"humanised": "B",
|
||||
"value": 10.6,
|
||||
"flags": {
|
||||
"Individual Difference": false
|
||||
}
|
||||
},
|
||||
"key": "HARD CLEAR",
|
||||
"tierlistID": "ee9b756e50cff8282091102257b01f423ef855f2",
|
||||
"type": "lamp"
|
||||
},
|
||||
{
|
||||
"tierlistDataID": "ce915895169642b143c450efca070947546bfe1d4863c27bd4301b34505f4a68",
|
||||
"chartID": "c2311194e3897ddb5745b1760d2c0141f933e683",
|
||||
"data": {
|
||||
"humanised": "F",
|
||||
"value": 10.0,
|
||||
"flags": {
|
||||
"Individual Difference": false
|
||||
}
|
||||
},
|
||||
"key": "CLEAR",
|
||||
"tierlistID": "ee9b756e50cff8282091102257b01f423ef855f2",
|
||||
"type": "lamp"
|
||||
}
|
||||
]
|
||||
@@ -1,27 +0,0 @@
|
||||
[
|
||||
{
|
||||
"createdAt": 1620150338858,
|
||||
"tierlistID": "ee9b756e50cff8282091102257b01f423ef855f2",
|
||||
"createdBy": 1,
|
||||
"description": "The official Kamaitachi Tierlist for beatmania IIDX (SP).",
|
||||
"game": "iidx",
|
||||
"playtype": "SP",
|
||||
"isDefault": true,
|
||||
"name": "Kamaitachi IIDX SP Official",
|
||||
"lastUpdated": 1620150338858,
|
||||
"permissions": {
|
||||
"anyPlayer": {
|
||||
"edit": 0,
|
||||
"submit": 1,
|
||||
"vote": 1
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"autoHumanise": false,
|
||||
"flags": [
|
||||
"Individual Difference"
|
||||
],
|
||||
"requireState": "clear"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -208,6 +208,7 @@ export const uscChart: ChartDocument<"usc:Single"> = {
|
||||
hashSHA1: "USC_CHART_HASH",
|
||||
isOfficial: false,
|
||||
},
|
||||
tierlistInfo: {},
|
||||
isPrimary: true,
|
||||
versions: [],
|
||||
};
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import crypto from "crypto";
|
||||
import { ChartDocument, Game, Playtypes } from "tachi-common";
|
||||
import db from "external/mongo/db";
|
||||
import CreateLogCtx from "lib/logger/logger";
|
||||
|
||||
const logger = CreateLogCtx(__filename);
|
||||
|
||||
export function CalculateTierlistDataID(
|
||||
chartID: string,
|
||||
type: "score" | "lamp" | "grade",
|
||||
key: string | null,
|
||||
tierlistID: string
|
||||
) {
|
||||
return crypto
|
||||
.createHash("sha256")
|
||||
.update(`${chartID}|${type}|${key}|${tierlistID}`)
|
||||
.digest("hex");
|
||||
}
|
||||
|
||||
export function GetDefaultTierlist(game: Game, playtype: Playtypes[Game]) {
|
||||
return db.tierlists.findOne({
|
||||
game,
|
||||
playtype,
|
||||
isDefault: true,
|
||||
});
|
||||
}
|
||||
|
||||
async function GetDefaultTierlistID(game: Game, playtype: Playtypes[Game]) {
|
||||
const tierlistData = await GetDefaultTierlist(game, playtype);
|
||||
|
||||
if (!tierlistData) {
|
||||
logger.warn(
|
||||
`Attempted to GetTierlistData for ${game} ${playtype}, but no default tierlist is set.`
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return tierlistData.tierlistID;
|
||||
}
|
||||
|
||||
export async function GetOneTierlistData(
|
||||
game: Game,
|
||||
chart: ChartDocument,
|
||||
type: "score" | "lamp" | "grade",
|
||||
key: string | null,
|
||||
tierlistID?: string
|
||||
) {
|
||||
const tlID = tierlistID ?? (await GetDefaultTierlistID(game, chart.playtype));
|
||||
|
||||
const query: Record<string, unknown> = {
|
||||
tierlistID: tlID,
|
||||
chartID: chart.chartID,
|
||||
type,
|
||||
key,
|
||||
};
|
||||
|
||||
return db["tierlist-data"].findOne(query);
|
||||
}
|
||||
|
||||
export async function GetAllTierlistDataOfType(
|
||||
game: Game,
|
||||
chart: ChartDocument,
|
||||
type: "score" | "lamp" | "grade",
|
||||
tierlistID?: string
|
||||
) {
|
||||
const tlID = tierlistID ?? (await GetDefaultTierlistID(game, chart.playtype));
|
||||
|
||||
const query: Record<string, unknown> = {
|
||||
tierlistID: tlID,
|
||||
chartID: chart.chartID,
|
||||
type,
|
||||
};
|
||||
|
||||
return db["tierlist-data"].find(query);
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
UserGameStats,
|
||||
Game,
|
||||
Playtypes,
|
||||
TierlistParent,
|
||||
SongDocument,
|
||||
UserSettings,
|
||||
OAuth2ApplicationDocument,
|
||||
@@ -63,7 +62,6 @@ export interface TachiRequestData {
|
||||
sessionDoc?: SessionDocument;
|
||||
tableDoc?: TableDocument;
|
||||
folderDoc?: FolderDocument;
|
||||
tierlistDoc?: TierlistParent;
|
||||
|
||||
oauth2ClientDoc: Omit<OAuth2ApplicationDocument, "clientSecret">;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user