diff --git a/bot/src/webhookHandlers/classUpdate.ts b/bot/src/webhookHandlers/classUpdate.ts index c5bc97813..97f1be508 100644 --- a/bot/src/webhookHandlers/classUpdate.ts +++ b/bot/src/webhookHandlers/classUpdate.ts @@ -5,7 +5,7 @@ import { CreateEmbed } from "../utils/embeds"; import { PrependTachiUrl } from "../utils/fetchTachi"; import logger from "../utils/logger"; import { FormatClass, GetGameChannel } from "../utils/misc"; -import { FormatGame } from "tachi-common"; +import { FormatGame, GetGamePTConfig } from "tachi-common"; import type { Classes, GPTString, @@ -32,15 +32,14 @@ export async function HandleClassUpdateV1( } if (!ShouldRenderUpdate(game, playtype, event.set, event.new)) { + logger.info( + `Not rendering class update ${event.set}: ${event.old} -> ${event.new} (not relevant).` + ); return 204; } const userDoc = await GetUserInfo(event.userID); - // We don't want to render classes if the user is blitzing through them - // because they haven't played enough charts to "average out". - // For example, a new player playing their first 50 charts will blitz through - // atleast 10 of the volforce ranks, which will just result in channel spam. const minimumNecessaryScores = GetMinimumScores(game, playtype, event.set); if (minimumNecessaryScores !== null) { @@ -48,7 +47,9 @@ export async function HandleClassUpdateV1( // Do not render if the user hasn't hit the score cap. if (totalScores < minimumNecessaryScores) { - logger.info(`Not rendering class update ${event.set}: ${event.old} -> ${event.new}.`); + logger.info( + `Not rendering class update ${event.set}: ${event.old} -> ${event.new} (not enough scores).` + ); return 204; } } @@ -82,16 +83,34 @@ function ShouldRenderUpdate( classSet: Classes[GPTString], classValue: string ) { - if (game === "sdvx" && classSet === "vfClass") { - return ["IMPERIAL_I", "IMPERIAL_II", "IMPERIAL_III", "IMPERIAL_IV"].includes(classValue); - } else if (game === "popn" && classSet === "class") { - return [ - // All of the other classes in pop'n can be trivially blitzed through. - "GOD", - ].includes(classValue); + const config = GetGamePTConfig(game, playtype); + const classSpec = config.classes[classSet]; + + if (classSpec === undefined) { + logger.error(`Invalid class ${classSet} for ${game} ${playtype}`); + return false; } - return true; + if (classSpec.minimumRelevantValue === undefined) { + return true; + } + + const ids = classSpec.values.map((c) => c.id); + + const currentId = ids.indexOf(classValue); + const minimumId = ids.indexOf(classSpec.minimumRelevantValue); + + if (currentId < 0) { + logger.error(`Invalid classValue ${classValue} for ${game} ${playtype}`); + return false; + } + + if (minimumId < 0) { + logger.error(`Invalid minimum classValue ${classValue} for ${game} ${playtype}`); + return false; + } + + return currentId >= minimumId; } function GetMinimumScores( @@ -99,29 +118,13 @@ function GetMinimumScores( playtype: Playtype, classSet: Classes[GPTString] ): integer | null { - if (game === "chunithm" && classSet === "colour") { - return 50; - } else if (game === "sdvx" && classSet === "vfClass") { - return 50; - } else if (game === "gitadora") { - return 50; - } else if (game === "jubeat") { - return 60; - } else if (game === "wacca") { - return 50; - } else if (game === "bms") { - return 20; - } else if (game === "iidx") { - return 20; - } else if (game === "pms") { - return 20; - } else if (game === "ddr") { - return 90; - } else if (game === "maimai" && classSet === "colour") { - return 30; - } else if (game === "maimaidx" && classSet === "colour") { - return 50; + const config = GetGamePTConfig(game, playtype); + const classSpec = config.classes[classSet]; + + if (classSpec === undefined) { + logger.error(`Invalid class ${classSet} for ${game} ${playtype}`); + return null; } - return null; + return classSpec.minimumScores ?? null; } diff --git a/common/src/config/game-support/chunithm.ts b/common/src/config/game-support/chunithm.ts index de8cd8362..570484b92 100644 --- a/common/src/config/game-support/chunithm.ts +++ b/common/src/config/game-support/chunithm.ts @@ -151,6 +151,7 @@ export const CHUNITHM_SINGLE_CONF = { colour: { type: "DERIVED", values: CHUNITHMColours, + minimumScores: 50, }, dan: { diff --git a/common/src/config/game-support/ddr.ts b/common/src/config/game-support/ddr.ts index 959b0b7d9..e5518aab8 100644 --- a/common/src/config/game-support/ddr.ts +++ b/common/src/config/game-support/ddr.ts @@ -186,6 +186,7 @@ export const DDR_SP_CONF = { flare: { type: "DERIVED", values: DDRFlare, + minimumRelevantValue: "URANUS", }, }, diff --git a/common/src/config/game-support/gitadora.ts b/common/src/config/game-support/gitadora.ts index 7cbd079a7..92cec4651 100644 --- a/common/src/config/game-support/gitadora.ts +++ b/common/src/config/game-support/gitadora.ts @@ -106,7 +106,7 @@ export const GITADORA_GITA_CONF = { }, classes: { - colour: { type: "DERIVED", values: GitadoraColours }, + colour: { type: "DERIVED", values: GitadoraColours, minimumScores: 50 }, }, orderedJudgements: ["perfect", "great", "good", "ok", "miss"], diff --git a/common/src/config/game-support/jubeat.ts b/common/src/config/game-support/jubeat.ts index a961dd18c..b77f6efc5 100644 --- a/common/src/config/game-support/jubeat.ts +++ b/common/src/config/game-support/jubeat.ts @@ -107,7 +107,7 @@ export const JUBEAT_SINGLE_CONF = { }, classes: { - colour: { type: "DERIVED", values: JubeatColours }, + colour: { type: "DERIVED", values: JubeatColours, minimumScores: 60 }, }, orderedJudgements: ["perfect", "great", "good", "poor", "miss"], diff --git a/common/src/config/game-support/maimai-dx.ts b/common/src/config/game-support/maimai-dx.ts index b7145f87c..a55f844a5 100644 --- a/common/src/config/game-support/maimai-dx.ts +++ b/common/src/config/game-support/maimai-dx.ts @@ -204,6 +204,7 @@ export const MAIMAI_DX_SINGLE_CONF = { colour: { type: "DERIVED", values: MaimaiDXColours, + minimumRelevantValue: "BRONZE", }, dan: { type: "PROVIDED", diff --git a/common/src/config/game-support/maimai.ts b/common/src/config/game-support/maimai.ts index edd93e47a..68c9bad1b 100644 --- a/common/src/config/game-support/maimai.ts +++ b/common/src/config/game-support/maimai.ts @@ -143,6 +143,7 @@ export const MAIMAI_SINGLE_CONF = { colour: { type: "DERIVED", values: MaimaiColours, + minimumScores: 30, }, dan: { type: "PROVIDED", diff --git a/common/src/config/game-support/ongeki.ts b/common/src/config/game-support/ongeki.ts index 4c9cebd31..e0a536b08 100644 --- a/common/src/config/game-support/ongeki.ts +++ b/common/src/config/game-support/ongeki.ts @@ -195,6 +195,7 @@ export const ONGEKI_SINGLE_CONF = { colour: { type: "DERIVED", values: OngekiColours, + minimumRelevantValue: "RAINBOW", }, }, diff --git a/common/src/config/game-support/popn.ts b/common/src/config/game-support/popn.ts index d3d479b3f..928789108 100644 --- a/common/src/config/game-support/popn.ts +++ b/common/src/config/game-support/popn.ts @@ -129,6 +129,7 @@ export const POPN_9B_CONF = { class: { type: "DERIVED", values: PopnClasses, + minimumRelevantValue: "GOD", }, }, diff --git a/common/src/config/game-support/sdvx.ts b/common/src/config/game-support/sdvx.ts index 9ed6a8360..930d50a77 100644 --- a/common/src/config/game-support/sdvx.ts +++ b/common/src/config/game-support/sdvx.ts @@ -168,6 +168,7 @@ export const SDVX_SINGLE_CONF = { vfClass: { type: "DERIVED", values: SDVXVFClasses, + minimumRelevantValue: "IMPERIAL_I", }, }, diff --git a/common/src/config/game-support/usc.ts b/common/src/config/game-support/usc.ts index 8683a55a8..6a663d530 100644 --- a/common/src/config/game-support/usc.ts +++ b/common/src/config/game-support/usc.ts @@ -93,6 +93,7 @@ export const USC_CONTROLLER_CONF = { vfClass: { type: "DERIVED", values: SDVXVFClasses, + minimumRelevantValue: "IMPERIAL_I", }, }, diff --git a/common/src/config/game-support/wacca.ts b/common/src/config/game-support/wacca.ts index 49e7a7f38..c929bd278 100644 --- a/common/src/config/game-support/wacca.ts +++ b/common/src/config/game-support/wacca.ts @@ -128,6 +128,7 @@ export const WACCA_SINGLE_CONF = { colour: { type: "DERIVED", values: WaccaColours, + minimumRelevantValue: "RAINBOW", }, }, diff --git a/common/src/types/game-config-utils.ts b/common/src/types/game-config-utils.ts index b733559e3..a7eaa9a4e 100644 --- a/common/src/types/game-config-utils.ts +++ b/common/src/types/game-config-utils.ts @@ -33,9 +33,24 @@ interface BaseClassConfig { /** * What are the possible values for this class field? * - * @note This should be in ascending order. + * @note This must be in ascending order. */ values: Array>; + + /** + * The ID of the lowest class value that should trigger a discord message. + * Lower values will be ignored to reduce channel spam. + */ + minimumRelevantValue?: V; + + /** + * What number of scores is needed to "fill" this class? + * If the number of scores is lower, new class values will not + * trigger discord messages (useful if minimumRelevantValue is undesired) + * For example, a new SDVX player playing their first 50 charts will blitz through + * at least 10 of the volforce ranks, which would just result in channel spam. + */ + minimumScores?: number; } /**