From de04eee33c9565e47d38226cfd57af7bd6173057 Mon Sep 17 00:00:00 2001 From: zkldi Date: Fri, 14 May 2021 07:03:38 +0100 Subject: [PATCH] Class refactor - This is really hard --- server/src/common/class.ts | 103 ++++++++++++++++++ .../framework/user-game-stats/classes.ts | 65 +++++------ .../framework/user-game-stats/update-ugs.ts | 22 ++-- .../common/batch-manual/converter.test.ts | 8 +- .../common/batch-manual/parser.ts | 1 + .../file/eamusement-iidx-csv/parser.ts | 1 + .../import-types/ir/barbatos/parser.ts | 1 + .../import-types/ir/fervidex-static/parser.ts | 1 + .../import-types/ir/fervidex/parser.ts | 1 + 9 files changed, 148 insertions(+), 55 deletions(-) create mode 100644 server/src/common/class.ts diff --git a/server/src/common/class.ts b/server/src/common/class.ts new file mode 100644 index 000000000..7664f9ff8 --- /dev/null +++ b/server/src/common/class.ts @@ -0,0 +1,103 @@ +import { Game, integer, Playtypes, UserGameStats } from "kamaitachi-common"; +import { ClassData, gameClassValues } from "kamaitachi-common/js/game-classes"; +import db from "../db/db"; +import CreateLogCtx from "../logger"; + +const logger = CreateLogCtx("class.ts"); + +/** + * Returns the provided class if it is greater than the one in userGameStats + * @returns The provided class if it is greater, NULL if there is nothing + * to compare to, and FALSE if it is worse or equal. + */ +export function ReturnClassIfGreater( + game: Game, + playtype: Playtypes[Game], + setName: string, + newClass: string, + userGameStats?: UserGameStats | null +) { + // @ts-expect-error It's complaining about Game+PT permutations instead of Game->PT permutations. + let gcv: ClassData = gameClassValues[game][playtype][setName]; + + if (gcv === undefined) { + logger.error(`Invalid classKey ${setName}. Cannot process class.`); + throw new Error(`Invalid classKey ${setName}. Cannot process class.`); + } + + let newClassInfo = gcv[newClass]; + + if (!userGameStats) { + return null; + } + + let val = newClassInfo.index; + let pastClass = userGameStats.classes[setName]; + + if (!pastClass) { + return null; + } + + let pastVal = gcv[pastClass].index; + + if (val > pastVal) { + return newClass; + } + + return false; +} + +/** + * Updates a user's class value if it is greater than the one in their + * UserGameStats. + * @returns False if nothing was updated. + * Null if it was updated because there was nothing in UserGameStats to + * compare to. + * True if it was updated because it was better than UserGameStats. + */ +export async function UpdateClassIfGreater( + userID: integer, + game: Game, + playtype: Playtypes[Game], + classKey: string, + newClass: string, + userGameStats?: UserGameStats +) { + let isGreater = ReturnClassIfGreater(game, playtype, classKey, newClass, userGameStats); + + if (isGreater === false) { + return false; + } + + if (userGameStats) { + await db["game-stats"].update( + { userID, game, playtype }, + { $set: { [`classes.${classKey}`]: newClass } } + ); + } else { + // insert new game stats for this user - this is an awkward place + // to call this - maybe we should call it elsewhere. + await db["game-stats"].insert({ + userID, + game, + playtype, + customRatings: {}, + lampRating: 0, + rating: 0, + classes: { + classKey: newClass, + }, + }); + logger.info(`Created new player gamestats for ${userID} ${game} (${playtype})`); + } + + if (isGreater === null) { + // @todo REDIS-IPC new class achieved + + return null; + } else { + // @todo REDIS-IPC class improved + + return true; + } +} diff --git a/server/src/score-import/framework/user-game-stats/classes.ts b/server/src/score-import/framework/user-game-stats/classes.ts index 2ccde911b..a80d7d7a9 100644 --- a/server/src/score-import/framework/user-game-stats/classes.ts +++ b/server/src/score-import/framework/user-game-stats/classes.ts @@ -3,6 +3,7 @@ import { gameClassValues, ClassData } from "kamaitachi-common/js/game-classes"; import deepmerge from "deepmerge"; import { KtLogger } from "../../../types"; import { CalculateGitadoraColour, CalculateJubeatColour } from "./builtin-class-handlers"; +import { ReturnClassIfGreater } from "../../../common/class"; export interface ClassHandler { ( @@ -111,13 +112,12 @@ export async function UpdateUGSClasses( export function CalculateClassDeltas( game: Game, playtype: Playtypes[Game], - userID: integer, classes: Record, userGameStats: UserGameStats | null, logger: KtLogger ): ClassDelta[] { // @ts-expect-error It's complaining about Game+PT permutations instead of Game->PT permutations. - let gcv = gameClassValues[game][playtype] as ClassData; + let gcv = gameClassValues[game]?.[playtype]; if (Object.keys(classes).length !== 0 && !gcv) { logger.severe( @@ -132,52 +132,37 @@ export function CalculateClassDeltas( let deltas = []; - for (const type in classes) { - const gameClass = classes[type]; - let classInfo = gcv[gameClass]; - - if (!classInfo) { - logger.severe( - `Class ${type}:${gameClass} was assigned, but this does not exist for ${game} ${playtype}? Unassigning this and continuing.` - ); - - delete classes[type]; - continue; - } - - if (!userGameStats) { - // @todo REDISIPC-New Class Achieved - deltas.push({ + for (const setName in classes) { + try { + let isGreater = ReturnClassIfGreater( game, playtype, - old: null, - new: gameClass, - }); - } else { - let pastClass = userGameStats.classes[type]; - let pastVal = gcv[pastClass]; + setName, + classes[setName], + userGameStats + ); - let thisIndex = classInfo.index; - - let pastIndex; - if (!pastVal) { - logger.severe( - `UserID ${userID} has an invalid class of ${type} - This does not exist in GCV. Ignoring??` - ); - pastIndex = -1; - } else { - pastIndex = pastVal.index; - } - - if (thisIndex > pastIndex) { - // @todo REDISIPC-Class Improved! + if (isGreater === false) { + continue; + } else if (isGreater === null) { + // @todo REDISIPC-New Class Achieved deltas.push({ game, playtype, - old: userGameStats.classes[pastClass], - new: gameClass, + old: null, + new: classes[setName], }); } + + // @todo REDISIPC-Class Improved! + deltas.push({ + game, + playtype, + old: userGameStats!.classes[setName], + new: classes[setName], + }); + } catch (err) { + logger.error(err); } } diff --git a/server/src/score-import/framework/user-game-stats/update-ugs.ts b/server/src/score-import/framework/user-game-stats/update-ugs.ts index 738160fbc..24f4d1adc 100644 --- a/server/src/score-import/framework/user-game-stats/update-ugs.ts +++ b/server/src/score-import/framework/user-game-stats/update-ugs.ts @@ -41,20 +41,10 @@ export async function UpdateUsersGamePlaytypeStats( logger.debug(`Calculating Class Deltas...`); - let deltas = CalculateClassDeltas(game, playtype, userID, classes, userGameStats, logger); + let deltas = CalculateClassDeltas(game, playtype, classes, userGameStats, logger); logger.debug(`Had ${deltas.length} deltas.`); - let newStats: UserGameStats = { - game, - playtype, - userID, - rating, - lampRating, - customRatings, - classes, - }; - if (userGameStats) { logger.debug(`Updated player gamestats for ${game} (${playtype})`); await db["game-stats"].update( @@ -73,6 +63,16 @@ export async function UpdateUsersGamePlaytypeStats( } ); } else { + let newStats: UserGameStats = { + game, + playtype, + userID, + rating, + lampRating, + customRatings, + classes, + }; + logger.info(`Created new player gamestats for ${game} (${playtype})`); await db["game-stats"].insert(newStats); } diff --git a/server/src/score-import/import-types/common/batch-manual/converter.test.ts b/server/src/score-import/import-types/common/batch-manual/converter.test.ts index a8c617bf9..53ecf05e5 100644 --- a/server/src/score-import/import-types/common/batch-manual/converter.test.ts +++ b/server/src/score-import/import-types/common/batch-manual/converter.test.ts @@ -332,8 +332,8 @@ t.test("#ConverterFn", (t) => { scoreData: { lamp: "HARD CLEAR", score: 500, - grade: "B", - // percent: 63, -- ish, FPA is hard. + grade: "E", + // percent: 31.5, -- ish, FPA is hard. hitData: {}, hitMeta: {}, }, @@ -349,12 +349,12 @@ t.test("#ConverterFn", (t) => { () => ConverterBatchManual( // @ts-expect-error broken deepmerge - deepmerge(baseBatchManualScore, { score: 1000 }), + deepmerge(baseBatchManualScore, { score: 2000 }), { game: "iidx", service: "foo", version: null }, importType, logger ), - { message: /Invalid score of 1000, produced percent of 127/u } as any + { message: /Invalid score of 2000, produced percent of 127/u } as any ); t.end(); diff --git a/server/src/score-import/import-types/common/batch-manual/parser.ts b/server/src/score-import/import-types/common/batch-manual/parser.ts index 9f6eda7f7..a0059869d 100644 --- a/server/src/score-import/import-types/common/batch-manual/parser.ts +++ b/server/src/score-import/import-types/common/batch-manual/parser.ts @@ -172,5 +172,6 @@ export function ParseBatchManualFromObject( }, iterable: batchManual.body, ConverterFunction: ConverterBatchManual, + classHandler: null, }; } diff --git a/server/src/score-import/import-types/file/eamusement-iidx-csv/parser.ts b/server/src/score-import/import-types/file/eamusement-iidx-csv/parser.ts index a327d79da..b2e368a7f 100644 --- a/server/src/score-import/import-types/file/eamusement-iidx-csv/parser.ts +++ b/server/src/score-import/import-types/file/eamusement-iidx-csv/parser.ts @@ -270,6 +270,7 @@ function ParseEamusementCSV( context, ConverterFunction: ConverterFn, game: "iidx", + classHandler: null, }; } diff --git a/server/src/score-import/import-types/ir/barbatos/parser.ts b/server/src/score-import/import-types/ir/barbatos/parser.ts index 5c1fc3083..3618295c6 100644 --- a/server/src/score-import/import-types/ir/barbatos/parser.ts +++ b/server/src/score-import/import-types/ir/barbatos/parser.ts @@ -39,5 +39,6 @@ export function ParseBarbatosSingle( game: "sdvx", iterable: ([body] as unknown) as BarbatosScore[], ConverterFunction: ConverterIRBarbatos, + classHandler: null, }; } diff --git a/server/src/score-import/import-types/ir/fervidex-static/parser.ts b/server/src/score-import/import-types/ir/fervidex-static/parser.ts index 170ff1319..4206a9ed8 100644 --- a/server/src/score-import/import-types/ir/fervidex-static/parser.ts +++ b/server/src/score-import/import-types/ir/fervidex-static/parser.ts @@ -78,5 +78,6 @@ export function ParseFervidexStatic( game: "iidx", iterable: scores, ConverterFunction: ConverterIRFervidexStatic, + classHandler: null, //@todo }; } diff --git a/server/src/score-import/import-types/ir/fervidex/parser.ts b/server/src/score-import/import-types/ir/fervidex/parser.ts index 34fcd05ca..3f6dbe165 100644 --- a/server/src/score-import/import-types/ir/fervidex/parser.ts +++ b/server/src/score-import/import-types/ir/fervidex/parser.ts @@ -95,5 +95,6 @@ export function ParseFervidexSingle( game: "iidx", iterable: ([body] as unknown) as FervidexScore[], ConverterFunction: ConverterIRFervidex, + classHandler: null, }; }