From bf5828c5f2463c0a86ee42597921bc1e5bb1d029 Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Thu, 25 Aug 2022 23:39:17 +0100 Subject: [PATCH 1/2] feat: barbatos sdvx6 support --- .../score-import/import-types/common/types.ts | 4 +- .../ir/barbatos/converter.test.ts | 92 +++++++++++++++++-- .../import-types/ir/barbatos/converter.ts | 70 ++++++++++---- .../import-types/ir/barbatos/parser.ts | 46 ++++++++-- .../import-types/ir/barbatos/types.ts | 37 +++++++- server/src/test-utils/test-data.ts | 41 ++++++++- 6 files changed, 257 insertions(+), 33 deletions(-) diff --git a/server/src/lib/score-import/import-types/common/types.ts b/server/src/lib/score-import/import-types/common/types.ts index 9de5f1ec6..d1ee92051 100644 --- a/server/src/lib/score-import/import-types/common/types.ts +++ b/server/src/lib/score-import/import-types/common/types.ts @@ -4,7 +4,7 @@ import type { ClassHandler } from "../../framework/user-game-stats/types"; import type { SDVXEamusementCSVData } from "../file/eamusement-sdvx-csv/types"; import type { MerScore } from "../file/mer-iidx/types"; import type { S3Score } from "../file/solid-state-squad/types"; -import type { BarbatosContext, BarbatosScore } from "../ir/barbatos/types"; +import type { BarbatosContext, BarbatosScore, BarbatosSDVX6Score } from "../ir/barbatos/types"; import type { BeatorajaContext, BeatorajaScore } from "../ir/beatoraja/types"; import type { FervidexStaticContext, FervidexStaticScore } from "../ir/fervidex-static/types"; import type { FervidexContext, FervidexScore } from "../ir/fervidex/types"; @@ -36,7 +36,7 @@ export interface ImportTypeDataMap { "file/pli-iidx-csv": IIDXEamusementCSVData; "ir/direct-manual": BatchManualScore; - "ir/barbatos": BarbatosScore; + "ir/barbatos": BarbatosScore | BarbatosSDVX6Score; "ir/fervidex": FervidexScore; "ir/fervidex-static": FervidexStaticScore; "ir/beatoraja": BeatorajaScore; diff --git a/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts b/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts index ab8f2e3a0..307e69a65 100644 --- a/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts +++ b/server/src/lib/score-import/import-types/ir/barbatos/converter.test.ts @@ -4,7 +4,7 @@ import db from "external/mongo/db"; import CreateLogCtx from "lib/logger/logger"; import t from "tap"; import ResetDBState from "test-utils/resets"; -import { MockBarbatosScore } from "test-utils/test-data"; +import { MockBarbatosScore, MockBarbatosSDVX6Score } from "test-utils/test-data"; import type { BarbatosScore } from "./types"; const logger = CreateLogCtx(__filename); @@ -36,13 +36,13 @@ t.test("#ConverterIRBarbatos", (t) => { inGameID: 1, }, isPrimary: true, - versions: ["booth", "inf", "gw", "heaven", "vivid"], + versions: ["booth", "inf", "gw", "heaven", "vivid", "exceed"], }; t.test("Should convert a BarbatosScore into a Dry Score", async (t) => { const res = await ConverterIRBarbatos( MockBarbatosScore, - { timeReceived: 10 }, + { timeReceived: 10, version: "vivid" }, "ir/barbatos", logger ); @@ -52,7 +52,7 @@ t.test("#ConverterIRBarbatos", (t) => { chart: albidaChart, dryScore: { game: "sdvx", - service: "Barbatos", + service: "Barbatos (vivid)", comment: null, importType: "ir/barbatos", @@ -72,6 +72,7 @@ t.test("#ConverterIRBarbatos", (t) => { slow: 10, gauge: 90, maxCombo: 100, + exScore: null, }, }, scoreMeta: { @@ -83,12 +84,57 @@ t.test("#ConverterIRBarbatos", (t) => { t.end(); }); + t.test("Should convert a BarbatosSDVX6Score into a Dry Score", async (t) => { + const res = await ConverterIRBarbatos( + MockBarbatosSDVX6Score, + { timeReceived: 10, version: "exceed" }, + "ir/barbatos", + logger + ); + + t.hasStrict(res, { + song: albidaSong, + chart: albidaChart, + dryScore: { + game: "sdvx", + service: "Barbatos (exceed)", + comment: null, + importType: "ir/barbatos", + + // timeAchieved: , its Date.now() give or take lol + scoreData: { + score: 9000000, + percent: 90, + grade: "A+", + lamp: "CLEAR", + judgements: { + critical: 26, + near: 2, + miss: 17, + }, + hitMeta: { + fast: 6, + slow: 9, + gauge: 90, + maxCombo: 100, + exScore: 1234, + }, + }, + scoreMeta: { + inSkillAnalyser: null, + }, + }, + }); + + t.end(); + }); + t.test("Should throw KTDataNotFound if chart not found.", (t) => { t.rejects( () => ConverterIRBarbatos( deepmerge(MockBarbatosScore, { song_id: 1000 }) as BarbatosScore, - { timeReceived: 10 }, + { timeReceived: 10, version: "vivid" }, "ir/barbatos", logger ), @@ -100,13 +146,47 @@ t.test("#ConverterIRBarbatos", (t) => { t.end(); }); + t.test("Should honor provided context.version, and match accordingly.", async (t) => { + // remove vividwave from the set of charts that this chart appears in. + await db.charts.sdvx.update( + { + "data.inGameID": 1, + }, + { + $pull: { + versions: "vivid", + }, + } + ); + + t.rejects( + () => + ConverterIRBarbatos( + MockBarbatosScore, + { timeReceived: 10, version: "vivid" }, + "ir/barbatos", + logger + ), + { + message: /Could not find chart with songID 1/u, + } + ); + + t.end(); + }); + t.test("Should throw InternalFailure if song-chart desync.", async (t) => { // force a song-chart desync await db.songs.sdvx.remove({ id: 1 }); t.rejects( () => - ConverterIRBarbatos(MockBarbatosScore, { timeReceived: 10 }, "ir/barbatos", logger), + ConverterIRBarbatos( + MockBarbatosScore, + { timeReceived: 10, version: "vivid" }, + "ir/barbatos", + logger + ), { message: /Song 1 \(sdvx\) has no parent song/u, } diff --git a/server/src/lib/score-import/import-types/ir/barbatos/converter.ts b/server/src/lib/score-import/import-types/ir/barbatos/converter.ts index 39346b33d..3d42ed01b 100644 --- a/server/src/lib/score-import/import-types/ir/barbatos/converter.ts +++ b/server/src/lib/score-import/import-types/ir/barbatos/converter.ts @@ -3,11 +3,11 @@ import { KTDataNotFoundFailure, } from "../../../framework/common/converter-failures"; import { GenericGetGradeAndPercent } from "../../../framework/common/score-utils"; -import { FindSDVXChartOnInGameID } from "utils/queries/charts"; +import { FindSDVXChartOnInGameIDVersion } from "utils/queries/charts"; import { FindSongOnID } from "utils/queries/songs"; import type { DryScore } from "../../../framework/common/types"; import type { ConverterFunction } from "../../common/types"; -import type { BarbatosContext, BarbatosScore } from "./types"; +import type { BarbatosContext, BarbatosScore, BarbatosSDVX6Score } from "./types"; import type { Lamps } from "tachi-common"; const LAMP_LOOKUP = { @@ -28,12 +28,10 @@ const DIFFICULTY_LOOKUP = { 4: "MXM", }; -export const ConverterIRBarbatos: ConverterFunction = async ( - data, - context, - importType, - logger -) => { +export const ConverterIRBarbatos: ConverterFunction< + BarbatosScore | BarbatosSDVX6Score, + BarbatosContext +> = async (data, context, importType, logger) => { const difficulty = DIFFICULTY_LOOKUP[data.difficulty] as | "ADV" | "ANY_INF" @@ -41,7 +39,7 @@ export const ConverterIRBarbatos: ConverterFunction = { game: "sdvx", - service: "Barbatos", + service: `Barbatos (${context.version})`, comment: null, importType: "ir/barbatos", timeAchieved: context.timeReceived, @@ -73,21 +74,58 @@ export const ConverterIRBarbatos: ConverterFunction, _logger: KtLogger -): ParserFunctionReturns { - const err = p(body, PR_BARBATOS); +): ParserFunctionReturns { + // this is an extremely sketchy way of sniffing out whether it's sdvx6 or not. + // We could ask barbatos to send a header, but what difference does it make? + const schema = "ex_score" in body ? PR_BARBATOS_SDVX6 : PR_BARBATOS; + + const err = p(body, schema); if (err) { throw new ScoreImportFatalError(400, FormatPrError(err, "Invalid Barbatos Request")); } - // asserted using prudence. return { - context: { timeReceived: Date.now() }, + context: { timeReceived: Date.now(), version: "ex_score" in body ? "exceed" : "vivid" }, game: "sdvx", - iterable: [body] as unknown as Array, + iterable: [body] as unknown as Array, classHandler: null, }; } diff --git a/server/src/lib/score-import/import-types/ir/barbatos/types.ts b/server/src/lib/score-import/import-types/ir/barbatos/types.ts index 487d42d71..3c1aa64c3 100644 --- a/server/src/lib/score-import/import-types/ir/barbatos/types.ts +++ b/server/src/lib/score-import/import-types/ir/barbatos/types.ts @@ -1,4 +1,4 @@ -import type { integer } from "tachi-common"; +import type { GPTSupportedVersions, integer } from "tachi-common"; export interface BarbatosScore { difficulty: 0 | 1 | 2 | 3 | 4; @@ -14,10 +14,43 @@ export interface BarbatosScore { percent: number; did_fail: boolean; clear_type: 1 | 2 | 3 | 4 | 5; - gauge_type: 1 | 2; + gauge_type: 0 | 1 | 2 | 3; is_skill_analyzer: boolean; } +export interface BarbatosSDVX6Score { + difficulty: 0 | 1 | 2 | 3 | 4; + level: integer; + score: integer; + ex_score: integer; + clear_type: 1 | 2 | 3 | 4 | 5; + song_id: integer; + + grade: unknown; // don't care, we calculate this + + percent: number; // "health" + + max_chain: integer; + early_error: integer; + early_near: integer; + early_crit: integer; + s_crit: integer; + late_crit: integer; + late_near: integer; + late_error: integer; + chip_s_crit: integer; + chip_crit: integer; + chip_near: integer; + chip_error: integer; + long_crit: integer; + long_error: integer; + vol_crit: integer; + vol_error: integer; + + gauge_type: 0 | 1 | 2 | 3; +} + export interface BarbatosContext { timeReceived: number; + version: GPTSupportedVersions["sdvx:Single"]; } diff --git a/server/src/test-utils/test-data.ts b/server/src/test-utils/test-data.ts index 43cf925aa..96e8b50b9 100644 --- a/server/src/test-utils/test-data.ts +++ b/server/src/test-utils/test-data.ts @@ -12,7 +12,10 @@ import fs from "fs"; import path from "path"; import type { DryScore } from "lib/score-import/framework/common/types"; import type { S3Score } from "lib/score-import/import-types/file/solid-state-squad/types"; -import type { BarbatosScore } from "lib/score-import/import-types/ir/barbatos/types"; +import type { + BarbatosScore, + BarbatosSDVX6Score, +} from "lib/score-import/import-types/ir/barbatos/types"; import type { FervidexScore } from "lib/score-import/import-types/ir/fervidex/types"; import type { KsHookSV6CScore } from "lib/score-import/import-types/ir/kshook-sv6c/types"; import type { LR2HookScore } from "lib/score-import/import-types/ir/lr2hook/types"; @@ -615,6 +618,42 @@ export const MockBarbatosScore: BarbatosScore = { song_id: 1, }; +export const MockBarbatosSDVX6Score: BarbatosSDVX6Score = { + clear_type: 2, + difficulty: 1, + level: 10, + max_chain: 100, + percent: 90, + score: 9_000_000, + song_id: 1, + + chip_s_crit: 4, + chip_crit: 3, + chip_near: 2, + chip_error: 1, + + early_crit: 5, + early_near: 6, + early_error: 7, + + ex_score: 1234, + + gauge_type: 1, + + grade: "whocares", + + late_crit: 8, + late_near: 9, + late_error: 10, + + long_crit: 11, + long_error: 12, + + s_crit: 13, + vol_crit: 14, + vol_error: 15, +}; + export const uscChart: ChartDocument<"usc:Controller" | "usc:Keyboard"> = { rgcID: null, chartID: "USC_CHART_ID", From bc1918454ef26a38b8db49b6ec06df85b52a8261 Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Thu, 25 Aug 2022 23:48:56 +0100 Subject: [PATCH 2/2] test: update how POST /ir/barbatos checks scores --- server/src/server/router/ir/barbatos/router.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/server/router/ir/barbatos/router.test.ts b/server/src/server/router/ir/barbatos/router.test.ts index 489e2d126..2b3f19b28 100644 --- a/server/src/server/router/ir/barbatos/router.test.ts +++ b/server/src/server/router/ir/barbatos/router.test.ts @@ -20,7 +20,7 @@ t.test("POST /ir/barbatos/score/submit", (t) => { t.equal(res.body.body.errors.length, 0, "Should have 0 failed scores."); const scores = await db.scores.count({ - service: "Barbatos", + service: "Barbatos (vivid)", }); t.equal(scores, 1, "Should import 1 score.");