diff --git a/bot/src/data/data.ts b/bot/src/data/data.ts index b6a94c840..f26e0cdf1 100644 --- a/bot/src/data/data.ts +++ b/bot/src/data/data.ts @@ -15,25 +15,3 @@ export enum LoggerLayers { databaseQuery = "databaseQuery", apiRequests = "apiRequests", } - -export const METALLIC_MIND_SPLASHES = [ - "because 352 people are in this server and they can see that i was looking at chokers and thigh highs", - "No similar commands found, either.", - "**You may be a victim of software counterfeiting.**\n\nTo use all Microsoft Windows® features, such as all updates\nfrom Windows Update; get all the latest updates; and receive\nproduct support, your copy of Microsoft Windows® must be\nvalidated as genuine.\n\n__Go online and resolve now__", - "'DROP TABLE scores;--", - "Ceci n'est pas un splash text", - "Swish swoosh pew pew", - "What is this, a crossover episode?", - "npm install humor", - "Unban me from Quaver", - "You are simply neglecting the law of large numbers.", - "I'm using tilt controls!", - "IT AIN'T NO EASY GRAB THEY GOT T", - "turn on RANDOM!", - "It's all about the CEO grindset.", - "you could be playing mario galaxy right now", - "Play ULTRAKILL.", - "zkldi once said: i piss my bed twice a month and that really annoys me", - "A point in the horizon, a melting scene from your childhood. Your mortality is showing a frantic drift towards nothing, biology doomed to an infinite recursive loop. Teeth with teeth with teeth. Take a bite. Serene scene of a coastal town, warmth of the sun. Bitter tears. Lust for power. This is where you abandoned your dreams. You are a high net worth individual, an expanding vortex of pathetic trauma. Finally a beautiful fucking nerve ape. A pure soul is born, its neurotransactions stutter into being. 30583750937509353 operations per nanosecond. Beauty eludes your porous mind.\n\nThe value of Life is negative. The balance of being is rotated by 38 degrees. The surface is full of cracks, a turgid light shines through. Fleshy primordial bodies sluggishly roll down the slope. Only you slide upwards, with a celestial step. You become beautified, a saintly figure. Your pristine idiocy reveals a safe path through the impenetrable fog of life. Your dull sword cuts through the weak tendons and membranes of the garden of corruption. Sit on the throne of contentment and ferment. Inspect the eternal blue skies of your kingdom. You come to a realization. You pick up and onion and begin peeling.\n\nOnion layer one. Onion layer two. Onion layer three ... Onion layer n^n. Aeons have passed and the onion is fully peeled. Nothing remains. It's perfect. You get lost in the point that remains where the onion used to be. Synaptic cascade, neurological catastrophe. The point becomes infinitely dense, the universe condenses into a unicellular being. It screams sin. It craves happiness. It's done with this world. It tries to commit suicide but it fails. Sad pathetic mess. You feel pity and disgust but in a way only a being of pure grace can. In your violent mercy you terminate the worldlife.", - "Please do not reply to or quote my posts in the future.", -]; diff --git a/bot/src/database/documents.ts b/bot/src/database/documents.ts index 7c7374301..f479c3610 100644 --- a/bot/src/database/documents.ts +++ b/bot/src/database/documents.ts @@ -6,11 +6,3 @@ export interface DiscordUserMapDocument { discordID: Snowflake; tachiApiToken: string; } - -export interface QuoteDocument { - quoteID: string; - text: string; - quotedAt: integer; - quotedBy: integer; - hits: integer; -} diff --git a/bot/src/database/mongo.ts b/bot/src/database/mongo.ts index f2f876f8e..514c04fcd 100644 --- a/bot/src/database/mongo.ts +++ b/bot/src/database/mongo.ts @@ -2,7 +2,7 @@ import { ProcessEnv } from "../config"; import { LoggerLayers } from "../data/data"; import { CreateLayeredLogger } from "../utils/logger"; import monk from "monk"; -import type { DiscordUserMapDocument, QuoteDocument } from "./documents"; +import type { DiscordUserMapDocument } from "./documents"; const logger = CreateLayeredLogger(LoggerLayers.database); @@ -21,7 +21,6 @@ monkDB const db = { discordUserMap: monkDB.get("discord-user-map"), - quotes: monkDB.get("quotes"), }; export async function SetIndexes(hardReset = false) { @@ -30,11 +29,9 @@ export async function SetIndexes(hardReset = false) { if (hardReset) { logger.warn(`Hard resetting indexes!`); await db.discordUserMap.dropIndexes(); - await db.quotes.dropIndexes(); } await db.discordUserMap.createIndex({ discordID: 1 }, { unique: true }); - await db.quotes.createIndex({ quoteID: 1 }, { unique: true }); logger.info(`Indexes have been set.`); } diff --git a/bot/src/database/queries.ts b/bot/src/database/queries.ts index e89cb2957..4e31dd406 100644 --- a/bot/src/database/queries.ts +++ b/bot/src/database/queries.ts @@ -1,7 +1,7 @@ import db from "./mongo"; import { LoggerLayers } from "../data/data"; import { CreateLayeredLogger } from "../utils/logger"; -import type { DiscordUserMapDocument, QuoteDocument } from "./documents"; +import type { DiscordUserMapDocument } from "./documents"; import type { integer } from "tachi-common"; const logger = CreateLayeredLogger(LoggerLayers.databaseQuery); @@ -25,9 +25,3 @@ export async function GetUserIDForDiscordID(discordID: string): Promise { - logger.verbose(`Fetching quote with quoteID: ${quoteID}.`); - - return db.quotes.findOne({ quoteID }); -} diff --git a/bot/src/interactionHandlers/handleIsSelectMenu.ts b/bot/src/interactionHandlers/handleIsSelectMenu.ts index 8e3c23b7a..f404e58ba 100644 --- a/bot/src/interactionHandlers/handleIsSelectMenu.ts +++ b/bot/src/interactionHandlers/handleIsSelectMenu.ts @@ -1,10 +1,6 @@ import { LoggerLayers } from "../data/data"; import { GetUserInfo } from "../utils/apiRequests"; -import { - CreateChartScoresEmbed, - CreateFolderStatsEmbed, - CreateFolderTimelineEmbed, -} from "../utils/embeds"; +import { CreateChartScoresEmbed } from "../utils/embeds"; import { CreateLayeredLogger } from "../utils/logger"; import type { DiscordUserMapDocument } from "../database/documents"; import type { SelectMenuInteraction } from "discord.js"; @@ -48,40 +44,6 @@ export async function handleIsSelectMenu( null ); - await interaction.update({ embeds: [embed] }); - } else if (interaction.customId.startsWith("folder!")) { - const [, game, playtype, username] = /!(.*):(.*):(.*)$/u.exec( - interaction.customId - ) as unknown as [string, Game, Playtype, string]; - - const embed = await CreateFolderStatsEmbed( - game, - playtype, - username, - interaction.values[0]! - ); - - await interaction.update({ embeds: [embed] }); - } else if (interaction.customId.startsWith("ftl!")) { - const [, game, playtype, username, formatMethod, rawTarget] = - /!(.*):(.*):(.*):(.*):(.*)$/u.exec(interaction.customId) as unknown as [ - string, - Game, - Playtype, - string, - "first" | "recent", - string - ]; - - const embed = await CreateFolderTimelineEmbed( - game, - playtype, - username, - interaction.values[0]!, - formatMethod, - rawTarget - ); - await interaction.update({ embeds: [embed] }); } else { logger.warn(`Unknown selector triggered: ${interaction.customId}.`); diff --git a/bot/src/main.ts b/bot/src/main.ts index 206850111..4a89d673a 100644 --- a/bot/src/main.ts +++ b/bot/src/main.ts @@ -1,14 +1,11 @@ import { BotConfig, ProcessEnv, ServerConfig } from "./config"; -import { LoggerLayers, METALLIC_MIND_SPLASHES } from "./data/data"; +import { LoggerLayers } from "./data/data"; import { GetUserAndTokenForDiscordID } from "./database/queries"; import { handleIsCommand } from "./interactionHandlers/handleIsCommand"; import { handleIsSelectMenu } from "./interactionHandlers/handleIsSelectMenu"; - -// import { handleIsSelectMenu } from "./interactionHandlers/handleIsSelectMenu"; import { app } from "./server/server"; import { RegisterSlashCommands } from "./slashCommands/register"; import { CreateLayeredLogger } from "./utils/logger"; -import { RFA, TruncateString } from "./utils/misc"; import { VERSION_PRETTY } from "./version"; import { Client, Intents } from "discord.js"; import type { CommandInteraction, SelectMenuInteraction } from "discord.js"; @@ -19,15 +16,6 @@ export const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.GUILD_MESSAGES], }); -client.on("messageCreate", async (message) => { - // KT1 Easter Egg. - if (message.content === "!!") { - await message.channel.send( - `Invalid Command. (${TruncateString(RFA(METALLIC_MIND_SPLASHES), 500)})` - ); - } -}); - client.on("interactionCreate", async (interaction) => { try { if (!interaction.isSelectMenu() && !interaction.isCommand()) { @@ -68,7 +56,7 @@ We've sent you a DM with instructions on how to link your account.`, }); } -(async () => { +void (async () => { try { logger.info(`Booting Tachi Bot ${VERSION_PRETTY}.`); diff --git a/bot/src/scripts/set-indexes.ts b/bot/src/scripts/set-indexes.ts index 3af1f8dcb..8088d1ad8 100644 --- a/bot/src/scripts/set-indexes.ts +++ b/bot/src/scripts/set-indexes.ts @@ -1,7 +1,7 @@ import { SetIndexes } from "../database/mongo"; if (require.main === module) { - (async () => { + void (async () => { await SetIndexes(true); process.exit(0); })(); diff --git a/bot/src/server/server.ts b/bot/src/server/server.ts index 64ff17cf2..e824f6bdd 100644 --- a/bot/src/server/server.ts +++ b/bot/src/server/server.ts @@ -213,6 +213,7 @@ const MainExpressErrorHandler: express.ErrorRequestHandler = (err, req, res, _ne } logger.error(err, req.route); + return res.status(500).json({ success: false, description: "A fatal internal server error has occured.", diff --git a/bot/src/slashCommands/commands.ts b/bot/src/slashCommands/commands.ts index d387bb726..c4644cb3a 100644 --- a/bot/src/slashCommands/commands.ts +++ b/bot/src/slashCommands/commands.ts @@ -1,12 +1,7 @@ import chart from "./commands/chart"; import faq from "./commands/faq"; -import folder from "./commands/folder"; import invite from "./commands/invite"; -import last_score from "./commands/last_score"; -import last_session from "./commands/last_session"; import ping from "./commands/ping"; -import profile from "./commands/profile"; -import quote from "./commands/quote"; import sync from "./commands/sync"; import whois from "./commands/whois"; import { ServerConfig } from "../config"; @@ -15,14 +10,9 @@ import type { SlashCommand } from "./types"; export const SLASH_COMMANDS: Map = new Map( Object.entries({ ping, - quote, faq, whois, - profile, chart, - folder, - last_score, - last_session, }) ); @@ -34,6 +24,4 @@ if (ServerConfig.type !== "btchi") { // btchi or omni specific commands if (ServerConfig.type !== "ktchi") { SLASH_COMMANDS.set("invite", invite); - - // None. Yet! } diff --git a/bot/src/slashCommands/commands/folder.ts b/bot/src/slashCommands/commands/folder.ts deleted file mode 100644 index 6184dadff..000000000 --- a/bot/src/slashCommands/commands/folder.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { FindFolders } from "../../utils/apiRequests"; -import { GetGPTAndUser } from "../../utils/argParsers"; -import { CreateFolderStatsEmbed, CreateFolderTimelineEmbed } from "../../utils/embeds"; -import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options"; -import { SlashCommandBuilder } from "@discordjs/builders"; -import { MessageActionRow, MessageSelectMenu, Util } from "discord.js"; -import type { SlashCommand } from "../types"; -import type { SlashCommandSubcommandBuilder } from "@discordjs/builders"; - -function ApplyCommonOptions(sub: SlashCommandSubcommandBuilder) { - return sub - .addStringOption(MakeRequired(GPTOptions)) - .addStringOption((str) => - str - .setName("folder_name") - .setDescription("The name of the folder to fetch info on.") - .setRequired(true) - ); -} - -const command: SlashCommand = { - info: new SlashCommandBuilder() - .setName("folder") - .setDescription("Interact with folders.") - .addSubcommand((sub) => - ApplyCommonOptions(sub) - .setName("stats") - .setDescription("Retrieve a user's stats on a folder.") - .addStringOption(OtherUserOption) - ) - .addSubcommand((sub) => - ApplyCommonOptions(sub) - .setName("timeline") - .setDescription( - "Retrieve information about a user's scores in a folder related to a lamp or grade target." - ) - .addStringOption((str) => - str - .setName("target") - .setDescription("A lamp or grade to use as a target inside this folder.") - .setRequired(true) - ) - .addStringOption((str) => - str - .setName("method") - .setDescription("What to display about this user's target in this folder.") - .addChoices([ - ["Most Recent", "recent"], - ["First Achieved", "first"], - ]) - .setRequired(true) - ) - .addStringOption(OtherUserOption) - ) - - .toJSON(), - exec: async (interaction, requestingUser) => { - const gptUserInfo = await GetGPTAndUser(interaction, requestingUser); - - if (gptUserInfo.error !== null) { - return gptUserInfo.error; - } - - const { userDoc, game, playtype } = gptUserInfo.content; - - const folderName = interaction.options.getString("folder_name", true); - - let folders; - - try { - folders = await FindFolders(game, playtype, folderName); - } catch (err) { - return (err as Error).message; - } - - if (folders.length === 0) { - return `Couldn't find any folders with name '${Util.escapeMarkdown(folderName)}'.`; - } - - // discord caps options at 25. - if (folders.length > 25) { - folders = folders.slice(0, 25); - } - - // pick an initial folder - const folder = folders[0]!; // length is asserted as non-zero - - // with all of the common info, we now need to chalk up what to actually do. - - const subCommand = interaction.options.getSubcommand() as "stats" | "timeline"; - - if (subCommand === "stats") { - const select = new MessageActionRow().addComponents( - new MessageSelectMenu() - .setCustomId(`folder!${game}:${playtype}:${userDoc.username}`) - .setPlaceholder("Select a different folder.") - .addOptions( - folders.map((folder) => ({ - label: folder.title, - value: folder.folderID, - })) - ) - ); - - const embed = await CreateFolderStatsEmbed( - game, - playtype, - userDoc.username, - folder.folderID - ); - - if (folders.length === 1) { - return { embeds: [embed] }; - } - - return { embeds: [embed], components: [select] }; - } - - const rawTarget = interaction.options.getString("target", true); - - const formatMethod = interaction.options.getString("method", true) as "first" | "recent"; - - const select = new MessageActionRow().addComponents( - new MessageSelectMenu() - .setCustomId( - `ftl!${game}:${playtype}:${ - userDoc.username - }:${formatMethod}:${rawTarget.replace(/:/gu, "_")}` - ) - .setPlaceholder("Select a different folder.") - .addOptions( - folders.map((folder) => ({ - label: folder.title, - value: folder.folderID, - })) - ) - ); - - const embed = await CreateFolderTimelineEmbed( - game, - playtype, - userDoc.username, - folder.folderID, - formatMethod, - rawTarget - ); - - if (folders.length === 1) { - return { embeds: [embed] }; - } - - return { embeds: [embed], components: [select] }; - }, -}; - -export default command; diff --git a/bot/src/slashCommands/commands/last_score.ts b/bot/src/slashCommands/commands/last_score.ts deleted file mode 100644 index 45ea56839..000000000 --- a/bot/src/slashCommands/commands/last_score.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { GetUGPTStats } from "../../utils/apiRequests"; -import { GetGPTAndUser } from "../../utils/argParsers"; -import { CreateChartScoresEmbed } from "../../utils/embeds"; -import logger from "../../utils/logger"; -import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options"; -import { SlashCommandBuilder } from "@discordjs/builders"; -import { FormatGame } from "tachi-common"; -import type { SlashCommand } from "../types"; - -const command: SlashCommand = { - info: new SlashCommandBuilder() - .setName("last_score") - .setDescription("Retrieve your most recent score.") - .addStringOption(MakeRequired(GPTOptions)) - .addStringOption(OtherUserOption) - .toJSON(), - exec: async (interaction, requestingUser) => { - const gptUserInfo = await GetGPTAndUser(interaction, requestingUser); - - if (gptUserInfo.error !== null) { - return gptUserInfo.error; - } - - const { userDoc, game, playtype } = gptUserInfo.content; - - let mostRecentScore; - - try { - ({ mostRecentScore } = await GetUGPTStats(userDoc.id, game, playtype)); - } catch (err) { - logger.info(err); - return `You haven't played ${FormatGame(game, playtype)}.`; - } - - return CreateChartScoresEmbed( - userDoc, - game, - playtype, - mostRecentScore.chartID, - mostRecentScore - ); - }, -}; - -export default command; diff --git a/bot/src/slashCommands/commands/last_session.ts b/bot/src/slashCommands/commands/last_session.ts deleted file mode 100644 index 6691e661b..000000000 --- a/bot/src/slashCommands/commands/last_session.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { GetMostRecentSession } from "../../utils/apiRequests"; -import { GetGPTAndUser } from "../../utils/argParsers"; -import { CreateSessionEmbed } from "../../utils/embeds"; -import logger from "../../utils/logger"; -import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options"; -import { SlashCommandBuilder } from "@discordjs/builders"; -import { FormatGame } from "tachi-common"; -import type { SlashCommand } from "../types"; - -const command: SlashCommand = { - info: new SlashCommandBuilder() - .setName("last_session") - .setDescription("Retrieve your most recent session (even if ongoing).") - .addStringOption(MakeRequired(GPTOptions)) - .addStringOption(OtherUserOption) - .toJSON(), - exec: async (interaction, requestingUser) => { - const gptUserInfo = await GetGPTAndUser(interaction, requestingUser); - - if (gptUserInfo.error !== null) { - return gptUserInfo.error; - } - - const { userDoc, game, playtype } = gptUserInfo.content; - - let session; - - try { - session = await GetMostRecentSession(userDoc.id, game, playtype); - } catch (err) { - logger.info(err); - return `You haven't got any sessions for ${FormatGame(game, playtype)}.`; - } - - return CreateSessionEmbed(session); - }, -}; - -export default command; diff --git a/bot/src/slashCommands/commands/profile.ts b/bot/src/slashCommands/commands/profile.ts deleted file mode 100644 index f11ae25b2..000000000 --- a/bot/src/slashCommands/commands/profile.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { GetUGPTStats } from "../../utils/apiRequests"; -import { GetGPTAndUser } from "../../utils/argParsers"; -import { CreateGameProfileEmbed } from "../../utils/embeds"; -import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options"; -import { SlashCommandBuilder } from "@discordjs/builders"; -import { FormatGame } from "tachi-common"; -import type { SlashCommand } from "../types"; - -const command: SlashCommand = { - info: new SlashCommandBuilder() - .setName("profile") - .setDescription("Retrieve information about a user on a game.") - .addStringOption(MakeRequired(GPTOptions)) - .addStringOption(OtherUserOption) - .toJSON(), - exec: async (interaction, requestingUser) => { - const gptUserInfo = await GetGPTAndUser(interaction, requestingUser); - - if (gptUserInfo.error !== null) { - return gptUserInfo.error; - } - - const { userDoc, game, playtype } = gptUserInfo.content; - - let ugptStats; - - try { - ugptStats = await GetUGPTStats(userDoc.id, game, playtype); - } catch (err) { - return `This user has not played ${FormatGame(game, playtype)}.`; - } - - return CreateGameProfileEmbed(userDoc, ugptStats); - }, -}; - -export default command; diff --git a/bot/src/slashCommands/commands/quote.ts b/bot/src/slashCommands/commands/quote.ts deleted file mode 100644 index 59b9e189c..000000000 --- a/bot/src/slashCommands/commands/quote.ts +++ /dev/null @@ -1,186 +0,0 @@ -import db from "../../database/mongo"; -import { GetQuoteWithID } from "../../database/queries"; -import { GetUserInfo } from "../../utils/apiRequests"; -import { CreateEmbed } from "../../utils/embeds"; -import { FormatDate, IsAdmin, Pluralise, TruncateString } from "../../utils/misc"; -import { SlashCommandBuilder } from "@discordjs/builders"; -import { Util } from "discord.js"; -import { escapeRegExp } from "lodash"; -import type { SlashCommand } from "../types"; - -const command: SlashCommand = { - info: new SlashCommandBuilder() - .setName("quote") - .setDescription("Interact with the quote database.") - .addSubcommand((sub) => - sub - .setName("read") - .setDescription("Read a quote.") - .addStringOption((str) => - str.setName("name").setDescription("The quote to retrieve.").setRequired(true) - ) - ) - .addSubcommand((sub) => - sub - .setName("write") - .setDescription("Write a quote.") - .addStringOption((str) => - str.setName("name").setDescription("The name for this quote.").setRequired(true) - ) - .addStringOption((str) => - str - .setName("text") - .setDescription("The content for this quote.") - .setRequired(true) - ) - ) - .addSubcommand((sub) => - sub - .setName("delete") - .setDescription("Delete a quote (Admin only).") - .addStringOption((str) => - str.setName("name").setDescription("The quote to delete.").setRequired(true) - ) - ) - .addSubcommand((sub) => - sub - .setName("search_text") - .setDescription("Search for quotes by their text.") - .addStringOption((str) => - str.setName("query").setDescription("What to search for.").setRequired(true) - ) - ) - .addSubcommand((sub) => - sub - .setName("search_id") - .setDescription("Search for quotes by their id.") - .addStringOption((str) => - str.setName("query").setDescription("What to search for.").setRequired(true) - ) - ) - .toJSON(), - exec: async (interaction, requestingUser) => { - const subCommand = interaction.options.getSubcommand() as - | "delete" - | "read" - | "search_id" - | "search_text" - | "write"; - - if (subCommand === "search_id" || subCommand === "search_text") { - const query = interaction.options.getString("query", true).trim(); - - if (!/^[a-z0-9]{3,20}$/u.test(query)) { - return `This query is invalid. It must be all lowercase characters (or numbers), and between 3 and 20 characters.`; - } - - let quotes; - - if (subCommand === "search_id") { - quotes = await db.quotes.find( - { - quoteID: new RegExp(escapeRegExp(query), "iu"), - }, - { - sort: { hits: -1 }, - limit: 10, - } - ); - } else { - quotes = await db.quotes.find( - { - text: new RegExp(escapeRegExp(query), "iu"), - }, - { - sort: { hits: -1 }, - limit: 10, - } - ); - } - - if (quotes.length === 0) { - return `Couldn't find any quotes that matched this query.`; - } - - return CreateEmbed() - .setTitle(`Searched quotes for '${query}'`) - .setDescription(`Found ${quotes.length} ${Pluralise(quotes.length, "quote")}.`) - .addFields( - quotes.map((q) => ({ - name: q.quoteID, - value: TruncateString(q.text, 140), - })) - ); - } - - const quoteID = interaction.options.getString("name", true).trim(); - - if (!/^[a-z0-9]{3,20}$/u.test(quoteID)) { - return `This quote name is invalid. It must be all lowercase characters (or numbers), and between 3 and 20 characters.`; - } - - const quote = await GetQuoteWithID(quoteID); - - switch (subCommand) { - case "read": { - if (!quote) { - return `No quote exists for '${Util.escapeMarkdown(quoteID)}'.`; - } - - await db.quotes.update({ quoteID }, { $inc: { hits: 1 } }); - - const authorInfo = await GetUserInfo(quote.quotedBy); - - return CreateEmbed() - .setTitle(`Quote: ${quoteID}`) - .setDescription(`\`\`\`${Util.escapeMarkdown(quote.text)}\`\`\``) - .setFooter({ - text: `Quoted by ${authorInfo.username} on ${FormatDate( - quote.quotedAt - )}. This quote has been read ${quote.hits + 1} times.`, - }); - } - - case "write": { - const text = interaction.options.getString("text", true); - - if (quote) { - return `A quote exists for '${Util.escapeMarkdown(quoteID)}' already.`; - } - - if (text.length > 480) { - return `Quotes are capped at 480 characters. Not quoting this.`; - } - - await db.quotes.insert({ - quoteID, - text, - hits: 0, - quotedAt: Date.now(), - quotedBy: requestingUser.userID, - }); - - return `Quote '${Util.escapeMarkdown(quoteID)}' has been saved.`; - } - - case "delete": { - if (!IsAdmin(requestingUser.discordID)) { - return `You are not authorised to delete quotes.`; - } - - if (!quote) { - return `No quote exists for '${Util.escapeMarkdown(quoteID)}'.`; - } - - await db.quotes.remove({ quoteID: quote.quoteID }); - - return `Quote '${Util.escapeMarkdown(quoteID)}' has been deleted.`; - } - - default: - throw new Error(`Unknown subcommand '${subCommand}'. How did this happen?`); - } - }, -}; - -export default command; diff --git a/bot/src/slashCommands/register.ts b/bot/src/slashCommands/register.ts index 771531638..f9e507b74 100644 --- a/bot/src/slashCommands/register.ts +++ b/bot/src/slashCommands/register.ts @@ -55,7 +55,7 @@ export async function RegisterSlashCommands(client: Client): Promise { /** * Unregister all the commmands we have. */ -export async function UnregisterAllCommands(client: Client): Promise { +async function UnregisterAllCommands(client: Client): Promise { try { logger.info("Tidying old guild slash commands."); const guilds = client.guilds.cache; diff --git a/bot/src/slashCommands/types.ts b/bot/src/slashCommands/types.ts index 452d27efb..379c2397c 100644 --- a/bot/src/slashCommands/types.ts +++ b/bot/src/slashCommands/types.ts @@ -9,7 +9,7 @@ import type { export type Emittable = InteractionReplyOptions | MessageEmbed | MessagePayload | string; -export type Command = ( +type Command = ( interaction: CommandInteraction, requestingUser: DiscordUserMapDocument ) => Emittable | Promise; diff --git a/bot/src/utils/apiRequests.ts b/bot/src/utils/apiRequests.ts index 2eb9f9c91..4f4f58949 100644 --- a/bot/src/utils/apiRequests.ts +++ b/bot/src/utils/apiRequests.ts @@ -2,21 +2,18 @@ import { RequestTypes, TachiServerV1Get, TachiServerV1Request } from "./fetchTac import { CreateLayeredLogger } from "./logger"; import { Sleep } from "./misc"; import { LoggerLayers } from "../data/data"; -import { ScoreDocument } from "tachi-common"; -import type { ImportDeferred, ImportPollStatus, SessionInfo, UGPTStats } from "./returnTypes"; +import type { ImportDeferred, ImportPollStatus, UGPTStats } from "./returnTypes"; import type { CommandInteraction } from "discord.js"; import type { ChartDocument, - FolderDocument, Game, GoalDocument, ImportDocument, integer, PBScoreDocument, Playtype, - UserDocument, - SessionDocument, SongDocument, + UserDocument, } from "tachi-common"; const logger = CreateLayeredLogger(LoggerLayers.apiRequests); @@ -150,55 +147,3 @@ export async function PerformScoreImport( throw new Error(`Unexpected status code ${initRes.statusCode} returned from ${url}.`); } - -export async function FindFolders(game: Game, playtype: Playtype, folderName: string) { - const res = await TachiServerV1Get>( - `/games/${game}/${playtype}/folders`, - null, - { - search: folderName, - } - ); - - if (!res.success) { - throw new Error(res.description); - } - - return res.body; -} - -export async function GetChartInfo(game: Game, playtype: Playtype, chartID: string) { - const res = await TachiServerV1Get<{ chart: ChartDocument; song: SongDocument }>( - `/games/${game}/${playtype}/charts/${chartID}`, - null - ); - - if (!res.success) { - throw new Error(res.description); - } - - return res.body; -} - -export async function GetMostRecentSession(userID: integer, game: Game, playtype: Playtype) { - const res = await TachiServerV1Get( - `/users/${userID}/games/${game}/${playtype}/sessions/last`, - null - ); - - if (!res.success) { - throw new Error(res.description); - } - - return res.body; -} - -export async function GetSessionInfo(sessionID: string) { - const res = await TachiServerV1Get(`/sessions/${sessionID}`, null); - - if (!res.success) { - throw new Error(res.description); - } - - return res.body; -} diff --git a/bot/src/utils/argParsers.ts b/bot/src/utils/argParsers.ts index 3cea0a142..b4997747d 100644 --- a/bot/src/utils/argParsers.ts +++ b/bot/src/utils/argParsers.ts @@ -27,7 +27,7 @@ export async function GetGPTAndUser( try { userDoc = await GetUserInfo(userID); - } catch (err) { + } catch { return { error: `This user does not exist.` }; } @@ -67,26 +67,3 @@ export function ParseDifficulty( throw new Error(`The difficulty '${input}' was invalid for this game.`); } - -/** - * Converts arbitrary user input into a lamp or grade for this GPT. - */ -export function ParseTimelineTarget(game: Game, playtype: Playtype, input: string) { - const gptConfig = GetGamePTConfig(game, playtype); - - const regex = ConvertInputIntoGenerousRegex(input); - - for (const [index, grade] of Object.entries(gptConfig.grades)) { - if (grade.match(regex)) { - return { type: "grade", value: Number(index) }; - } - } - - for (const [index, lamp] of Object.entries(gptConfig.lamps)) { - if (lamp.match(regex)) { - return { type: "lamp", value: Number(index) }; - } - } - - throw new Error(`The target '${input}' was invalid for this game.`); -} diff --git a/bot/src/utils/constants.ts b/bot/src/utils/constants.ts deleted file mode 100644 index e6c11d297..000000000 --- a/bot/src/utils/constants.ts +++ /dev/null @@ -1,53 +0,0 @@ -export enum SDVX_VF_CLASSES { - SIENNA_I, - SIENNA_II, - SIENNA_III, - SIENNA_IV, - COBALT_I, - COBALT_II, - COBALT_III, - COBALT_IV, - DANDELION_I, - DANDELION_II, - DANDELION_III, - DANDELION_IV, - CYAN_I, - CYAN_II, - CYAN_III, - CYAN_IV, - SCARLET_I, - SCARLET_II, - SCARLET_III, - SCARLET_IV, - CORAL_I, - CORAL_II, - CORAL_III, - CORAL_IV, - ARGENTO_I, - ARGENTO_II, - ARGENTO_III, - ARGENTO_IV, - ELDORA_I, - ELDORA_II, - ELDORA_III, - ELDORA_IV, - CRIMSON_I, - CRIMSON_II, - CRIMSON_III, - CRIMSON_IV, - IMPERIAL_I, - IMPERIAL_II, - IMPERIAL_III, - IMPERIAL_IV, -} - -export enum POPN_CLASSES { - KITTY, - GRADE_SCHOOL, - DELINQUENT, - DETECTIVE, - IDOL, - GENERAL, - HERMIT, - GOD, -} diff --git a/bot/src/utils/embeds.ts b/bot/src/utils/embeds.ts index c10567fa5..cca0f46a8 100644 --- a/bot/src/utils/embeds.ts +++ b/bot/src/utils/embeds.ts @@ -1,41 +1,27 @@ -import { GetChartInfoForUser, GetSessionInfo } from "./apiRequests"; -import { ParseTimelineTarget } from "./argParsers"; -import { PrependTachiUrl, TachiServerV1Get } from "./fetchTachi"; +import { GetChartInfoForUser } from "./apiRequests"; +import { PrependTachiUrl } from "./fetchTachi"; import { CreateChartLink, - CreateChartMap, - CreateSongMap, Entries, FormatChartTierlistInfo, FormatDate, - FormatProfileRating, FormatScoreData, FormatScoreRating, GetChartPertinentInfo, MillisToSince, - NumericSOV, - ONE_HOUR, Pluralise, - UniqueOnKey, UppercaseFirst, } from "./misc"; import { BotConfig, ServerConfig } from "../config"; -import { MessageEmbed, Util } from "discord.js"; -import { FormatChart, FormatGame, GetGamePTConfig } from "tachi-common"; -import type { UGPTFolderStat, UGPTFolderTimeline, UGPTStats } from "./returnTypes"; -import type { EmbedFieldData } from "discord.js"; +import { MessageEmbed } from "discord.js"; +import { FormatChart } from "tachi-common"; import type { - ChartDocument, - FolderDocument, Game, ImportDocument, - integer, PBScoreDocument, Playtype, - UserDocument, ScoreDocument, - SessionDocument, - SongDocument, + UserDocument, } from "tachi-common"; export function CreateEmbed() { @@ -69,62 +55,6 @@ export function CreateUserEmbed(userDoc: UserDocument) { .setURL(`${BotConfig.TACHI_SERVER_LOCATION}/dashboard/users/${userDoc.username}`); } -export function CreateGameProfileEmbed(userDoc: UserDocument, ugptStats: UGPTStats) { - const { game, playtype } = ugptStats.gameStats; - - const gptConfig = GetGamePTConfig(game, playtype); - - return CreateEmbed() - .setTitle(`${userDoc.username} (${FormatGame(game, playtype)})`) - .setThumbnail(PrependTachiUrl(`/users/${userDoc.id}/pfp`)) - .setDescription(userDoc.status ?? "No status...") - .addField( - "Rankings", - Entries(ugptStats.rankingData) - .map( - ([k, v]) => - `**${UppercaseFirst(k)}**: #${v.ranking}/${v.outOf} (${FormatProfileRating( - game, - playtype, - k, - ugptStats.gameStats.ratings[k] - )})` - ) - .join("\n") || "No Rankings", - true - ) - .addField( - "Classes", - Entries(ugptStats.gameStats.classes) - .map( - ([k, v]) => - `**${UppercaseFirst(k)}**: ${gptConfig.classHumanisedFormat[k][v]?.display}` - ) - .join("\n") || "No Classes", - true - ) - .addField("Playcount", ugptStats.totalScores.toString()) - .addField( - "First Play", - ugptStats.firstScore.timeAchieved !== null - ? `${FormatDate(ugptStats.firstScore.timeAchieved)} -(${MillisToSince(ugptStats.firstScore.timeAchieved)})` - : "N/A", - true - ) - .addField( - "Last Played", - ugptStats.mostRecentScore.timeAchieved !== null - ? `${FormatDate(ugptStats.mostRecentScore.timeAchieved)} -(${MillisToSince(ugptStats.mostRecentScore.timeAchieved)})` - : "N/A", - true - ) - .setURL( - `${BotConfig.TACHI_SERVER_LOCATION}/dashboard/users/${userDoc.username}/games/${game}/${playtype}` - ); -} - export async function CreateChartScoresEmbed( userDoc: UserDocument, game: Game, @@ -207,192 +137,3 @@ export async function CreateChartScoresEmbed( return embed; } - -export async function CreateFolderStatsEmbed( - game: Game, - playtype: Playtype, - username: string, - folderID: string -) { - const statsRes = await TachiServerV1Get<{ folder: FolderDocument; stats: UGPTFolderStat }>( - `/users/${username}/games/${game}/${playtype}/folders/${folderID}/stats`, - null - ); - - if (!statsRes.success) { - throw new Error(`Failed to fetch stats on ${folderID} for ${username}.`); - } - - const { folder, stats } = statsRes.body; - - const gptConfig = GetGamePTConfig(game, playtype); - - return CreateEmbed() - .setTitle(`${username}: ${folder.title}`) - .setURL( - `${BotConfig.TACHI_SERVER_LOCATION}/dashboard/users/${username}/games/${game}/${playtype}/folders/${folderID}` - ) - .addField( - "Lamp Distribution", - gptConfig.lamps - .slice() - .reverse() - .map((l) => `${l}: ${stats.lamps[l] ?? 0}`) - .join("\n"), - true - ) - .addField( - "Grade Distribution", - gptConfig.grades - .slice() - .reverse() - .map((g) => `${g}: ${stats.grades[g] ?? 0}`) - .join("\n"), - true - ) - - .addField("Total Charts", stats.chartCount.toString()); -} - -export async function CreateFolderTimelineEmbed( - game: Game, - playtype: Playtype, - username: string, - folderID: string, - formatMethod: "first" | "recent", - rawTarget: string -) { - const gptConfig = GetGamePTConfig(game, playtype); - - const { type, value } = ParseTimelineTarget(game, playtype, rawTarget); - - const prettyValue = gptConfig[type === "grade" ? "grades" : "lamps"][value]; - - const timelineRes = await TachiServerV1Get( - `/users/${username}/games/${game}/${playtype}/folders/${folderID}/timeline`, - null, - { - criteriaType: type, - criteriaValue: value.toString(), - } - ); - - if (!timelineRes.success) { - throw new Error( - `Failed to retrieve timeline info for ${username} on folderID: ${folderID}.` - ); - } - - const { folder, songs, charts, scores } = timelineRes.body; - - const songMap = CreateSongMap(songs); - const chartMap = CreateChartMap(charts); - - let fields: Array = []; - - fields = scores - .filter((e) => e.timeAchieved !== null) - .sort((a, b) => { - if (formatMethod === "first") { - return a.timeAchieved! - b.timeAchieved!; - } - - return b.timeAchieved! - a.timeAchieved!; - }) - .slice(0, 5) - .map((sc) => ScoreToEmbed(sc, songMap, chartMap)); - - const embed = CreateEmbed() - .setTitle( - `${username}: ${folder.title} (${ - formatMethod === "first" ? "First" : "Most Recent" - } ${prettyValue}s)` - ) - .setURL( - `${BotConfig.TACHI_SERVER_LOCATION}/dashboard/users/${username}/games/${game}/${playtype}/folders/${folderID}` - ); - - if (fields.length === 0) { - return embed.addField("N/A", "This user has never achieved this target in this folder."); - } - - return embed.addFields(fields); -} - -export async function CreateSessionEmbed(session: SessionDocument) { - const { game, playtype } = session; - - const { charts, scores, songs, user } = await GetSessionInfo(session.sessionID); - - const embed = CreateEmbed() - .setTitle( - `${user.username}: ${session.name}${ - session.timeEnded < ONE_HOUR * 2 ? " (Ongoing!)" : "" - }` - ) - .setDescription(session.desc ?? "This session has no description") - .setURL( - `${BotConfig.TACHI_SERVER_LOCATION}/dashboard/users/${user.username}/games/${game}/${playtype}/sessions/${session.sessionID}` - ); - - const songMap = CreateSongMap(songs); - const chartMap = CreateChartMap(charts); - - embed - .addField( - "Total Lamp Raises", - session.scoreInfo.filter((e) => !e.isNewScore && e.lampDelta > 0).length.toString(), - true - ) - .addField( - "Total Grade Raises", - session.scoreInfo.filter((e) => !e.isNewScore && e.gradeDelta > 0).length.toString(), - true - ); - - const gptConfig = GetGamePTConfig(game, playtype); - - embed.addFields( - scores - - // don't mutate original array - .slice(0) - - // sort on default rating alg - // @todo Honour the user's preferred rating alg? - .sort( - NumericSOV( - (k) => k.calculatedData[gptConfig.defaultScoreRatingAlg] ?? -Infinity, - true - ) - ) - .filter(UniqueOnKey("chartID")) - - // pick best 5 - .slice(0, 5) - .map((sc) => ScoreToEmbed(sc, songMap, chartMap)) - ); - - embed.setFooter({ - text: "Note: Discord doesn't give me enough room to express everything about the session properly. Click the blue link to go to the session and see it properly.", - }); - - return embed; -} - -function ScoreToEmbed( - sc: ScoreDocument, - songMap: Map, - chartMap: Map -): EmbedFieldData { - const { scoreStr, lampStr } = FormatScoreData(sc); - - return { - name: Util.escapeMarkdown( - FormatChart(sc.game, songMap.get(sc.songID)!, chartMap.get(sc.chartID)!) - ), - value: `${scoreStr} -${lampStr} -${FormatDate(sc.timeAchieved!)} (${MillisToSince(sc.timeAchieved!)})`, - }; -} diff --git a/bot/src/utils/misc.ts b/bot/src/utils/misc.ts index 57aa29732..56ef9c098 100644 --- a/bot/src/utils/misc.ts +++ b/bot/src/utils/misc.ts @@ -1,5 +1,4 @@ import { BotConfig } from "../config"; -import humaniseDuration from "humanize-duration"; import _ from "lodash"; import { DateTime } from "luxon"; import { GenericFormatGradeDelta, GetGameConfig, GetGamePTConfig } from "tachi-common"; @@ -7,45 +6,19 @@ import type { Client } from "discord.js"; import type { ChartDocument, Game, - GoalDocument, Grades, IDStrings, integer, PBScoreDocument, Playtype, Playtypes, - UserDocument, ScoreCalculatedDataLookup, ScoreDocument, SongDocument, - UGSRatingsLookup, GameConfig, } from "tachi-common"; import type { GameClassSets } from "tachi-common/game-classes"; -/** - * Random From Array - Selects a random value from an array. - */ -export function RFA(arr: Array): T { - return arr[Math.floor(Math.random() * arr.length)] as T; -} - -export function TruncateString(string: string, len = 30) { - if (string.length < len) { - return string; - } - - return `${string.substring(0, len - 3)}...`; -} - -/** - * Checks whether a discord user has admin permissions or not. This lets them do - * slightly more destructive things. - */ -export function IsAdmin(discordID: string) { - return BotConfig.DISCORD.ADMIN_USERS.includes(discordID); -} - export function Sleep(ms: number) { return new Promise((resolve) => { setTimeout(() => { @@ -62,25 +35,6 @@ export function Pluralise(int: integer, str: string) { return `${str}s`; } -export function FormatProfileRating( - game: Game, - playtype: Playtype, - rating: UGSRatingsLookup[IDStrings], - value: number | null | undefined -) { - if (value === null || value === undefined) { - return "No Data."; - } - - const formatter = GetGamePTConfig(game, playtype).profileRatingAlgFormatters[rating]; - - if (!formatter) { - return value.toFixed(2); - } - - return formatter(value); -} - export function FormatScoreRating( game: Game, playtype: Playtype, @@ -135,25 +89,10 @@ export function MillisToSince(ms: number) { return DateTime.fromMillis(ms).toRelative(); } -export function FormatTime(ms: number) { - return DateTime.fromMillis(ms).toLocaleString(DateTime.DATETIME_MED); -} - export function FormatDate(ms: number) { return DateTime.fromMillis(ms).toLocaleString(DateTime.DATE_HUGE); } -export function FormatDuration(ms: number) { - return humaniseDuration(ms, { - units: ["d", "h", "m"], - maxDecimalPoints: 0, - }); -} - -export function FormatTimeSmall(ms: number) { - return DateTime.fromMillis(ms).toLocaleString(DateTime.DATE_SHORT); -} - export function FormatClass( game: Game, playtype: Playtype, @@ -251,7 +190,7 @@ export function FormatScoreData(score: ScOrPBDo /** * Util for getting a games' grade for a given percent. */ -export function GetGradeFromPercent( +function GetGradeFromPercent( game: Game, playtype: Playtype, percent: number @@ -276,11 +215,7 @@ export function GetGradeFromPercent( throw new Error(`Couldn't find grade for ${game}:${playtype} (${percent}%)`); } -export function FormatIIDXEXScore( - exscore: integer, - notecount: integer, - playtype: Playtypes["iidx"] -) { +function FormatIIDXEXScore(exscore: integer, notecount: integer, playtype: Playtypes["iidx"]) { const percent = (exscore * 100) / (notecount * 2); const { closer, upper, lower } = GenericFormatGradeDelta( @@ -346,7 +281,7 @@ export function FormatChartTierlistInfo(game: Game, chart: ChartDocument) { export function ConvertInputIntoGenerousRegex(input: string) { const inputSafeRegex = _.escapeRegExp(input); - // for any non-ascii input, replace them with a ".?", representing maybe. This + // for any a-zA-Z input, replace them with a ".?", representing maybe. This // is so users can say things like "Re Master" or "Remaster" for "Re:Master". // It also generally gives lenience. // We match based on what the string starts with case-insensitively. @@ -355,103 +290,3 @@ export function ConvertInputIntoGenerousRegex(input: string) { return regex; } - -export function CreateSongMap(songs: Array>) { - const songMap = new Map>(); - - for (const song of songs) { - songMap.set(song.id, song); - } - - return songMap; -} - -export function CreateUserMap(users: Array) { - const userMap = new Map(); - - for (const user of users) { - userMap.set(user.id, user); - } - - return userMap; -} - -export function CreateGoalMap(goals: Array) { - const goalMap = new Map(); - - for (const goal of goals) { - goalMap.set(goal.goalID, goal); - } - - return goalMap; -} - -export function CreateChartIDMap(arr: Array): Map { - const map = new Map(); - - for (const t of arr) { - map.set(t.chartID, t); - } - - return map; -} - -export function CreateChartMap(charts: Array>) { - const chartMap = new Map>(); - - for (const chart of charts) { - chartMap.set(chart.chartID, chart); - } - - return chartMap; -} - -export function CreateScoreIDMap(scores: Array>) { - const scoreMap = new Map>(); - - for (const score of scores) { - scoreMap.set(score.scoreID, score); - } - - return scoreMap; -} - -/** - * Sorts On Value numerically. - * @returns A sorting function - */ -export function NumericSOV(getValueFn: (data: T) => number, reverse = false) { - if (reverse) { - return (a: T, b: T) => getValueFn(b) - getValueFn(a); - } - - return (a: T, b: T) => getValueFn(a) - getValueFn(b); -} - -/** - * Sorts On Value using locale compare. - * @returns A sorting function - */ -export function StrSOV(getValueFn: (data: T) => string) { - return (a: T, b: T) => getValueFn(a).localeCompare(getValueFn(b)); -} - -export function UniqueOnKey(prop: keyof T) { - const seenBefore = new Set(); - - return (item: T) => { - if (seenBefore.has(item[prop])) { - return false; - } - - seenBefore.add(item[prop]); - - return true; - }; -} - -export const ONE_SECOND = 1000; -export const ONE_MINUTE = ONE_SECOND * 60; -export const ONE_HOUR = ONE_MINUTE * 60; -export const ONE_DAY = ONE_HOUR * 24; -export const ONE_WEEK = ONE_DAY * 7; diff --git a/bot/src/utils/returnTypes.ts b/bot/src/utils/returnTypes.ts index e830d29b3..90f1a6ba6 100644 --- a/bot/src/utils/returnTypes.ts +++ b/bot/src/utils/returnTypes.ts @@ -1,18 +1,12 @@ import type { APIPermissions, ChartDocument, - FolderDocument, Game, - Grades, IDStrings, - IDStringToGame, ImportDocument, ImportTypes, integer, - Lamps, - UserDocument, ScoreDocument, - SessionDocument, SongDocument, UGSRatingsLookup, UserGameStats, @@ -63,25 +57,3 @@ export interface ChartQueryReturns { charts: Array; songs: Array; } - -export interface UGPTFolderStat { - folderID: string; - grades: Partial>; - lamps: Partial>; - chartCount: integer; -} - -export interface UGPTFolderTimeline { - songs: Array>; - charts: Array>; - scores: Array>; - folder: FolderDocument; -} - -export interface SessionInfo { - session: SessionDocument; - songs: Array; - charts: Array; - scores: Array; - user: UserDocument; -} diff --git a/bot/src/webhookHandlers/classUpdate.ts b/bot/src/webhookHandlers/classUpdate.ts index 6332de2f1..06e65cf4c 100644 --- a/bot/src/webhookHandlers/classUpdate.ts +++ b/bot/src/webhookHandlers/classUpdate.ts @@ -1,12 +1,11 @@ import { BotConfig } from "../config"; import { client } from "../main"; import { GetUGPTStats, GetUserInfo } from "../utils/apiRequests"; -import { POPN_CLASSES, SDVX_VF_CLASSES } from "../utils/constants"; 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, POPN_CLASSES, SDVX_VF_CLASSES } from "tachi-common"; import type { Game, integer, Playtype, WebhookEventClassUpdateV1 } from "tachi-common"; import type { AllClassSets } from "tachi-common/game-classes"; @@ -79,17 +78,6 @@ function ShouldRenderUpdate( ) { if (game === "sdvx" && classSet === "vfClass") { return [ - // Notifying about these vfClasses is pointless, since they're - // very easy to just blister through. - // SDVXVFClasses.SIENNA_I, - // SDVXVFClasses.COBALT_I, - // SDVXVFClasses.DANDELION_I, - // SDVXVFClasses.CYAN_I, - // SDVXVFClasses.SCARLET_I, - // SDVX_VF_CLASSES.CORAL_I, - // SDVX_VF_CLASSES.ARGENTO_I, - // SDVX_VF_CLASSES.ELDORA_I, - // SDVX_VF_CLASSES.CRIMSON_I, SDVX_VF_CLASSES.IMPERIAL_I, SDVX_VF_CLASSES.IMPERIAL_II, SDVX_VF_CLASSES.IMPERIAL_III, diff --git a/common/src/constants/game.ts b/common/src/constants/game.ts index 9a058f42b..15116178f 100644 --- a/common/src/constants/game.ts +++ b/common/src/constants/game.ts @@ -170,3 +170,247 @@ export enum GITADORA_GRADES { SS = 4, MAX = 5, } + +export enum IIDX_DANS { + KYU_7 = 0, + KYU_6 = 1, + KYU_5 = 2, + KYU_4 = 3, + KYU_3 = 4, + KYU_2 = 5, + KYU_1 = 6, + + DAN_1 = 7, + DAN_2 = 8, + DAN_3 = 9, + DAN_4 = 10, + DAN_5 = 11, + DAN_6 = 12, + DAN_7 = 13, + DAN_8 = 14, + DAN_9 = 15, + DAN_10 = 16, + + CHUUDEN = 17, + KAIDEN = 18, +} + +export enum GITADORA_COLOURS { + WHITE = 0, + + ORANGE = 1, + ORANGE_GRADIENT = 2, + YELLOW = 3, + YELLOW_GRADIENT = 4, + GREEN = 5, + GREEN_GRADIENT = 6, + BLUE = 7, + BLUE_GRADIENT = 8, + PURPLE = 9, + PURPLE_GRADIENT = 10, + RED = 11, + RED_GRADIENT = 12, + + BRONZE = 13, + SILVER = 14, + GOLD = 15, + RAINBOW = 16, +} + +export enum BMS_GENOCIDE_DANS { + NORMAL_1 = 0, + NORMAL_2 = 1, + NORMAL_3 = 2, + NORMAL_4 = 3, + NORMAL_5 = 4, + NORMAL_6 = 5, + NORMAL_7 = 6, + NORMAL_8 = 7, + NORMAL_9 = 8, + NORMAL_10 = 9, + + INSANE_1 = 10, + INSANE_2 = 11, + INSANE_3 = 12, + INSANE_4 = 13, + INSANE_5 = 14, + INSANE_6 = 15, + INSANE_7 = 16, + INSANE_8 = 17, + INSANE_9 = 18, + INSANE_10 = 19, + INSANE_KAIDEN = 20, + + OVERJOY = 21, +} + +export enum BMS_STSL_DANS { + SL_0 = 0, + SL_1 = 1, + SL_2 = 2, + SL_3 = 3, + SL_4 = 4, + SL_5 = 5, + SL_6 = 6, + SL_7 = 7, + SL_8 = 8, + SL_9 = 9, + SL_10 = 10, + SL_11 = 11, + SL_12 = 12, + + ST_0 = 13, + ST_1 = 14, + ST_2 = 15, + ST_3 = 16, + ST_4 = 17, + ST_5 = 18, + ST_6 = 19, + ST_7 = 20, + ST_8 = 21, + ST_9 = 22, + ST_10 = 23, + ST_11 = 24, + ST_12 = 25, +} + +export enum PMS_INSANE_DANS { + DAN_1 = 0, + DAN_2 = 1, + DAN_3 = 2, + DAN_4 = 3, + DAN_5 = 4, + DAN_6 = 5, + DAN_7 = 6, + DAN_8 = 7, + DAN_9 = 8, + DAN_10 = 9, + KAIDEN = 10, + OVERJOY = 11, + UNDEFINED = 12, +} + +export enum SDVX_DANS { + DAN_1 = 0, + DAN_2 = 1, + DAN_3 = 2, + DAN_4 = 3, + DAN_5 = 4, + DAN_6 = 5, + DAN_7 = 6, + DAN_8 = 7, + DAN_9 = 8, + DAN_10 = 9, + DAN_11 = 10, + INF = 11, +} + +// ewww +export enum SDVX_VF_CLASSES { + SIENNA_I = 0, + SIENNA_II = 1, + SIENNA_III = 2, + SIENNA_IV = 3, + COBALT_I = 4, + COBALT_II = 5, + COBALT_III = 6, + COBALT_IV = 7, + DANDELION_I = 8, + DANDELION_II = 9, + DANDELION_III = 10, + DANDELION_IV = 11, + CYAN_I = 12, + CYAN_II = 13, + CYAN_III = 14, + CYAN_IV = 15, + SCARLET_I = 16, + SCARLET_II = 17, + SCARLET_III = 18, + SCARLET_IV = 19, + CORAL_I = 20, + CORAL_II = 21, + CORAL_III = 22, + CORAL_IV = 23, + ARGENTO_I = 24, + ARGENTO_II = 25, + ARGENTO_III = 26, + ARGENTO_IV = 27, + ELDORA_I = 28, + ELDORA_II = 29, + ELDORA_III = 30, + ELDORA_IV = 31, + CRIMSON_I = 32, + CRIMSON_II = 33, + CRIMSON_III = 34, + CRIMSON_IV = 35, + IMPERIAL_I = 36, + IMPERIAL_II = 37, + IMPERIAL_III = 38, + IMPERIAL_IV = 39, +} + +export enum CHUNITHM_COLOURS { + BLUE = 0, + GREEN = 1, + ORANGE = 2, + RED = 3, + PURPLE = 4, + BRONZE = 5, + SILVER = 6, + GOLD = 7, + PLATINUM = 8, + RAINBOW = 9, +} + +export enum WACCA_STAGEUPS { + I = 0, + II = 1, + III = 2, + IV = 3, + V = 4, + VI = 5, + VII = 6, + VIII = 7, + IX = 8, + X = 9, + XI = 10, + XII = 11, + XIII = 12, + XIV = 13, +} + +export enum WACCA_COLOURS { + ASH = 0, + NAVY = 1, + YELLOW = 2, + RED = 3, + PURPLE = 4, + BLUE = 5, + SILVER = 6, + GOLD = 7, + RAINBOW = 8, +} + +export enum POPN_CLASSES { + KITTY = 0, + GRADE_SCHOOL = 1, + DELINQUENT = 2, + DETECTIVE = 3, + IDOL = 4, + GENERAL = 5, + HERMIT = 6, + GOD = 7, +} + +export enum JUBEAT_COLOURS { + BLACK = 0, + YELLOW_GREEN = 1, + GREEN = 2, + LIGHT_BLUE = 3, + BLUE = 4, + VIOLET = 5, + PURPLE = 6, + PINK = 7, + ORANGE = 8, + GOLD = 9, +} diff --git a/docs/docs/tachi-server/import/ugs.md b/docs/docs/tachi-server/import/ugs.md index a2c7d27eb..663d37cad 100644 --- a/docs/docs/tachi-server/import/ugs.md +++ b/docs/docs/tachi-server/import/ugs.md @@ -41,7 +41,7 @@ A User Game Stats object looks like this: // Note that instead of remembering each number // for each class, they are defined as constants - // in src/lib/constants/classes.ts + // in common/src/constants/game.ts } } ``` diff --git a/server/src/lib/constants/classes.ts b/server/src/lib/constants/classes.ts deleted file mode 100644 index 6a71a3018..000000000 --- a/server/src/lib/constants/classes.ts +++ /dev/null @@ -1,243 +0,0 @@ -export enum IIDXDans { - KYU_7 = 0, - KYU_6 = 1, - KYU_5 = 2, - KYU_4 = 3, - KYU_3 = 4, - KYU_2 = 5, - KYU_1 = 6, - - DAN_1 = 7, - DAN_2 = 8, - DAN_3 = 9, - DAN_4 = 10, - DAN_5 = 11, - DAN_6 = 12, - DAN_7 = 13, - DAN_8 = 14, - DAN_9 = 15, - DAN_10 = 16, - - CHUUDEN = 17, - KAIDEN = 18, -} - -export enum GitadoraColours { - WHITE = 0, - - ORANGE = 1, - ORANGE_GRADIENT = 2, - YELLOW = 3, - YELLOW_GRADIENT = 4, - GREEN = 5, - GREEN_GRADIENT = 6, - BLUE = 7, - BLUE_GRADIENT = 8, - PURPLE = 9, - PURPLE_GRADIENT = 10, - RED = 11, - RED_GRADIENT = 12, - - BRONZE = 13, - SILVER = 14, - GOLD = 15, - RAINBOW = 16, -} - -export enum BMSGenocideDans { - NORMAL_1 = 0, - NORMAL_2 = 1, - NORMAL_3 = 2, - NORMAL_4 = 3, - NORMAL_5 = 4, - NORMAL_6 = 5, - NORMAL_7 = 6, - NORMAL_8 = 7, - NORMAL_9 = 8, - NORMAL_10 = 9, - - INSANE_1 = 10, - INSANE_2 = 11, - INSANE_3 = 12, - INSANE_4 = 13, - INSANE_5 = 14, - INSANE_6 = 15, - INSANE_7 = 16, - INSANE_8 = 17, - INSANE_9 = 18, - INSANE_10 = 19, - INSANE_KAIDEN = 20, - - OVERJOY = 21, -} - -export enum BMSStSlDans { - SL_0 = 0, - SL_1 = 1, - SL_2 = 2, - SL_3 = 3, - SL_4 = 4, - SL_5 = 5, - SL_6 = 6, - SL_7 = 7, - SL_8 = 8, - SL_9 = 9, - SL_10 = 10, - SL_11 = 11, - SL_12 = 12, - - ST_0 = 13, - ST_1 = 14, - ST_2 = 15, - ST_3 = 16, - ST_4 = 17, - ST_5 = 18, - ST_6 = 19, - ST_7 = 20, - ST_8 = 21, - ST_9 = 22, - ST_10 = 23, - ST_11 = 24, - ST_12 = 25, -} - -export enum PMSInsaneDans { - DAN_1 = 0, - DAN_2 = 1, - DAN_3 = 2, - DAN_4 = 3, - DAN_5 = 4, - DAN_6 = 5, - DAN_7 = 6, - DAN_8 = 7, - DAN_9 = 8, - DAN_10 = 9, - KAIDEN = 10, - OVERJOY = 11, - UNDEFINED = 12, -} - -export enum SDVXDans { - DAN_1 = 0, - DAN_2 = 1, - DAN_3 = 2, - DAN_4 = 3, - DAN_5 = 4, - DAN_6 = 5, - DAN_7 = 6, - DAN_8 = 7, - DAN_9 = 8, - DAN_10 = 9, - DAN_11 = 10, - INF = 11, -} - -// ewww -export enum SDVXVFClasses { - SIENNA_I = 0, - SIENNA_II = 1, - SIENNA_III = 2, - SIENNA_IV = 3, - COBALT_I = 4, - COBALT_II = 5, - COBALT_III = 6, - COBALT_IV = 7, - DANDELION_I = 8, - DANDELION_II = 9, - DANDELION_III = 10, - DANDELION_IV = 11, - CYAN_I = 12, - CYAN_II = 13, - CYAN_III = 14, - CYAN_IV = 15, - SCARLET_I = 16, - SCARLET_II = 17, - SCARLET_III = 18, - SCARLET_IV = 19, - CORAL_I = 20, - CORAL_II = 21, - CORAL_III = 22, - CORAL_IV = 23, - ARGENTO_I = 24, - ARGENTO_II = 25, - ARGENTO_III = 26, - ARGENTO_IV = 27, - ELDORA_I = 28, - ELDORA_II = 29, - ELDORA_III = 30, - ELDORA_IV = 31, - CRIMSON_I = 32, - CRIMSON_II = 33, - CRIMSON_III = 34, - CRIMSON_IV = 35, - IMPERIAL_I = 36, - IMPERIAL_II = 37, - IMPERIAL_III = 38, - IMPERIAL_IV = 39, -} - -export enum CHUNITHM_COLOURS { - BLUE = 0, - GREEN = 1, - ORANGE = 2, - RED = 3, - PURPLE = 4, - BRONZE = 5, - SILVER = 6, - GOLD = 7, - PLATINUM = 8, - RAINBOW = 9, -} - -export enum WACCA_STAGEUPS { - I = 0, - II = 1, - III = 2, - IV = 3, - V = 4, - VI = 5, - VII = 6, - VIII = 7, - IX = 8, - X = 9, - XI = 10, - XII = 11, - XIII = 12, - XIV = 13, -} - -export enum WACCA_COLOURS { - ASH = 0, - NAVY = 1, - YELLOW = 2, - RED = 3, - PURPLE = 4, - BLUE = 5, - SILVER = 6, - GOLD = 7, - RAINBOW = 8, -} - -export enum POPN_CLASSES { - KITTY = 0, - GRADE_SCHOOL = 1, - DELINQUENT = 2, - DETECTIVE = 3, - IDOL = 4, - GENERAL = 5, - HERMIT = 6, - GOD = 7, -} - -export enum JUBEAT_COLOURS { - BLACK = 0, - YELLOW_GREEN = 1, - GREEN = 2, - LIGHT_BLUE = 3, - BLUE = 4, - VIOLET = 5, - PURPLE = 6, - PINK = 7, - ORANGE = 8, - GOLD = 9, -} diff --git a/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.test.ts b/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.test.ts index 02492b806..6488084d7 100644 --- a/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.test.ts +++ b/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.test.ts @@ -4,8 +4,8 @@ import { CalculateSDVXClass, SDVXVF6ToClass, } from "./builtin-class-handlers"; -import { GitadoraColours, SDVXVFClasses } from "lib/constants/classes"; import CreateLogCtx from "lib/logger/logger"; +import { GITADORA_COLOURS, SDVX_VF_CLASSES } from "tachi-common"; import t from "tap"; const logger = CreateLogCtx(__filename); @@ -14,7 +14,7 @@ t.test("#CalculateGitadoraColour", (t) => { t.strictSame( CalculateGitadoraColour("gitadora", "Gita", 1, { skill: 1500 }), { - colour: GitadoraColours.ORANGE_GRADIENT, + colour: GITADORA_COLOURS.ORANGE_GRADIENT, }, "Should wrap the skill colour." ); @@ -23,31 +23,31 @@ t.test("#CalculateGitadoraColour", (t) => { }); t.test("#GitadoraSkillToColour", (t) => { - t.equal(GitadoraSkillToColour(0), GitadoraColours.WHITE); - t.equal(GitadoraSkillToColour(999), GitadoraColours.WHITE); - t.equal(GitadoraSkillToColour(1000), GitadoraColours.ORANGE); - t.equal(GitadoraSkillToColour(1500), GitadoraColours.ORANGE_GRADIENT); - t.equal(GitadoraSkillToColour(2000), GitadoraColours.YELLOW); - t.equal(GitadoraSkillToColour(2500), GitadoraColours.YELLOW_GRADIENT); - t.equal(GitadoraSkillToColour(3000), GitadoraColours.GREEN); - t.equal(GitadoraSkillToColour(3500), GitadoraColours.GREEN_GRADIENT); - t.equal(GitadoraSkillToColour(4000), GitadoraColours.BLUE); - t.equal(GitadoraSkillToColour(4500), GitadoraColours.BLUE_GRADIENT); - t.equal(GitadoraSkillToColour(5000), GitadoraColours.PURPLE); - t.equal(GitadoraSkillToColour(5500), GitadoraColours.PURPLE_GRADIENT); - t.equal(GitadoraSkillToColour(6000), GitadoraColours.RED); - t.equal(GitadoraSkillToColour(6500), GitadoraColours.RED_GRADIENT); - t.equal(GitadoraSkillToColour(7000), GitadoraColours.BRONZE); - t.equal(GitadoraSkillToColour(7500), GitadoraColours.SILVER); - t.equal(GitadoraSkillToColour(8000), GitadoraColours.GOLD); - t.equal(GitadoraSkillToColour(8500), GitadoraColours.RAINBOW); + t.equal(GitadoraSkillToColour(0), GITADORA_COLOURS.WHITE); + t.equal(GitadoraSkillToColour(999), GITADORA_COLOURS.WHITE); + t.equal(GitadoraSkillToColour(1000), GITADORA_COLOURS.ORANGE); + t.equal(GitadoraSkillToColour(1500), GITADORA_COLOURS.ORANGE_GRADIENT); + t.equal(GitadoraSkillToColour(2000), GITADORA_COLOURS.YELLOW); + t.equal(GitadoraSkillToColour(2500), GITADORA_COLOURS.YELLOW_GRADIENT); + t.equal(GitadoraSkillToColour(3000), GITADORA_COLOURS.GREEN); + t.equal(GitadoraSkillToColour(3500), GITADORA_COLOURS.GREEN_GRADIENT); + t.equal(GitadoraSkillToColour(4000), GITADORA_COLOURS.BLUE); + t.equal(GitadoraSkillToColour(4500), GITADORA_COLOURS.BLUE_GRADIENT); + t.equal(GitadoraSkillToColour(5000), GITADORA_COLOURS.PURPLE); + t.equal(GitadoraSkillToColour(5500), GITADORA_COLOURS.PURPLE_GRADIENT); + t.equal(GitadoraSkillToColour(6000), GITADORA_COLOURS.RED); + t.equal(GitadoraSkillToColour(6500), GITADORA_COLOURS.RED_GRADIENT); + t.equal(GitadoraSkillToColour(7000), GITADORA_COLOURS.BRONZE); + t.equal(GitadoraSkillToColour(7500), GITADORA_COLOURS.SILVER); + t.equal(GitadoraSkillToColour(8000), GITADORA_COLOURS.GOLD); + t.equal(GitadoraSkillToColour(8500), GITADORA_COLOURS.RAINBOW); t.end(); }); t.test("#CalculateSDVXClass", (t) => { t.strictSame(CalculateSDVXClass("sdvx", "Single", 1, { VF6: 10 }, logger), { - vfClass: SDVXVFClasses.COBALT_I, + vfClass: SDVX_VF_CLASSES.COBALT_I, }); t.end(); @@ -58,50 +58,50 @@ t.test("#SDVXVF6ToClass", (t) => { return SDVXVF6ToClass(vf, logger); } - t.equal(f(0), SDVXVFClasses.SIENNA_I); - t.equal(f(2.5), SDVXVFClasses.SIENNA_II); - t.equal(f(5), SDVXVFClasses.SIENNA_III); - t.equal(f(7.5), SDVXVFClasses.SIENNA_IV); - t.equal(f(10), SDVXVFClasses.COBALT_I); - t.equal(f(10.5), SDVXVFClasses.COBALT_II); - t.equal(f(11), SDVXVFClasses.COBALT_III); - t.equal(f(11.5), SDVXVFClasses.COBALT_IV); - t.equal(f(12), SDVXVFClasses.DANDELION_I); - t.equal(f(12.5), SDVXVFClasses.DANDELION_II); - t.equal(f(13), SDVXVFClasses.DANDELION_III); - t.equal(f(13.5), SDVXVFClasses.DANDELION_IV); + t.equal(f(0), SDVX_VF_CLASSES.SIENNA_I); + t.equal(f(2.5), SDVX_VF_CLASSES.SIENNA_II); + t.equal(f(5), SDVX_VF_CLASSES.SIENNA_III); + t.equal(f(7.5), SDVX_VF_CLASSES.SIENNA_IV); + t.equal(f(10), SDVX_VF_CLASSES.COBALT_I); + t.equal(f(10.5), SDVX_VF_CLASSES.COBALT_II); + t.equal(f(11), SDVX_VF_CLASSES.COBALT_III); + t.equal(f(11.5), SDVX_VF_CLASSES.COBALT_IV); + t.equal(f(12), SDVX_VF_CLASSES.DANDELION_I); + t.equal(f(12.5), SDVX_VF_CLASSES.DANDELION_II); + t.equal(f(13), SDVX_VF_CLASSES.DANDELION_III); + t.equal(f(13.5), SDVX_VF_CLASSES.DANDELION_IV); - t.equal(f(14), SDVXVFClasses.CYAN_I); - t.equal(f(14.25), SDVXVFClasses.CYAN_II); - t.equal(f(14.5), SDVXVFClasses.CYAN_III); - t.equal(f(14.75), SDVXVFClasses.CYAN_IV); - t.equal(f(15), SDVXVFClasses.SCARLET_I); - t.equal(f(15.25), SDVXVFClasses.SCARLET_II); - t.equal(f(15.5), SDVXVFClasses.SCARLET_III); - t.equal(f(15.75), SDVXVFClasses.SCARLET_IV); - t.equal(f(16), SDVXVFClasses.CORAL_I); - t.equal(f(16.25), SDVXVFClasses.CORAL_II); - t.equal(f(16.5), SDVXVFClasses.CORAL_III); - t.equal(f(16.75), SDVXVFClasses.CORAL_IV); - t.equal(f(17), SDVXVFClasses.ARGENTO_I); - t.equal(f(17.25), SDVXVFClasses.ARGENTO_II); - t.equal(f(17.5), SDVXVFClasses.ARGENTO_III); - t.equal(f(17.75), SDVXVFClasses.ARGENTO_IV); - t.equal(f(18), SDVXVFClasses.ELDORA_I); - t.equal(f(18.25), SDVXVFClasses.ELDORA_II); - t.equal(f(18.5), SDVXVFClasses.ELDORA_III); - t.equal(f(18.75), SDVXVFClasses.ELDORA_IV); - t.equal(f(19), SDVXVFClasses.CRIMSON_I); - t.equal(f(19.25), SDVXVFClasses.CRIMSON_II); - t.equal(f(19.5), SDVXVFClasses.CRIMSON_III); - t.equal(f(19.75), SDVXVFClasses.CRIMSON_IV); + t.equal(f(14), SDVX_VF_CLASSES.CYAN_I); + t.equal(f(14.25), SDVX_VF_CLASSES.CYAN_II); + t.equal(f(14.5), SDVX_VF_CLASSES.CYAN_III); + t.equal(f(14.75), SDVX_VF_CLASSES.CYAN_IV); + t.equal(f(15), SDVX_VF_CLASSES.SCARLET_I); + t.equal(f(15.25), SDVX_VF_CLASSES.SCARLET_II); + t.equal(f(15.5), SDVX_VF_CLASSES.SCARLET_III); + t.equal(f(15.75), SDVX_VF_CLASSES.SCARLET_IV); + t.equal(f(16), SDVX_VF_CLASSES.CORAL_I); + t.equal(f(16.25), SDVX_VF_CLASSES.CORAL_II); + t.equal(f(16.5), SDVX_VF_CLASSES.CORAL_III); + t.equal(f(16.75), SDVX_VF_CLASSES.CORAL_IV); + t.equal(f(17), SDVX_VF_CLASSES.ARGENTO_I); + t.equal(f(17.25), SDVX_VF_CLASSES.ARGENTO_II); + t.equal(f(17.5), SDVX_VF_CLASSES.ARGENTO_III); + t.equal(f(17.75), SDVX_VF_CLASSES.ARGENTO_IV); + t.equal(f(18), SDVX_VF_CLASSES.ELDORA_I); + t.equal(f(18.25), SDVX_VF_CLASSES.ELDORA_II); + t.equal(f(18.5), SDVX_VF_CLASSES.ELDORA_III); + t.equal(f(18.75), SDVX_VF_CLASSES.ELDORA_IV); + t.equal(f(19), SDVX_VF_CLASSES.CRIMSON_I); + t.equal(f(19.25), SDVX_VF_CLASSES.CRIMSON_II); + t.equal(f(19.5), SDVX_VF_CLASSES.CRIMSON_III); + t.equal(f(19.75), SDVX_VF_CLASSES.CRIMSON_IV); - t.equal(f(20), SDVXVFClasses.IMPERIAL_I); - t.equal(f(21), SDVXVFClasses.IMPERIAL_II); - t.equal(f(22), SDVXVFClasses.IMPERIAL_III); - t.equal(f(23), SDVXVFClasses.IMPERIAL_IV); - t.equal(f(24), SDVXVFClasses.IMPERIAL_IV); - t.equal(f(1000), SDVXVFClasses.IMPERIAL_IV); + t.equal(f(20), SDVX_VF_CLASSES.IMPERIAL_I); + t.equal(f(21), SDVX_VF_CLASSES.IMPERIAL_II); + t.equal(f(22), SDVX_VF_CLASSES.IMPERIAL_III); + t.equal(f(23), SDVX_VF_CLASSES.IMPERIAL_IV); + t.equal(f(24), SDVX_VF_CLASSES.IMPERIAL_IV); + t.equal(f(1000), SDVX_VF_CLASSES.IMPERIAL_IV); t.end(); }); diff --git a/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.ts b/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.ts index 6e987d466..06ad47585 100644 --- a/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.ts +++ b/server/src/lib/score-import/framework/user-game-stats/builtin-class-handlers.ts @@ -1,11 +1,11 @@ import { CHUNITHM_COLOURS, - GitadoraColours, + GITADORA_COLOURS, JUBEAT_COLOURS, POPN_CLASSES, - SDVXVFClasses, + SDVX_VF_CLASSES, WACCA_COLOURS, -} from "lib/constants/classes"; +} from "tachi-common"; import { IsNullish } from "utils/misc"; import type { KtLogger } from "lib/logger/logger"; import type { Game, integer, Playtype, ScoreCalculatedDataLookup } from "tachi-common"; @@ -35,16 +35,16 @@ export function SDVXVF6ToClass(vf: number, logger: KtLogger) { // This is impossible, but a failsafe regardless if (vf >= 24) { logger.warn(`User has excessive VF6 of ${vf}. Defaulting to Imperial IV.`); - return SDVXVFClasses.IMPERIAL_IV; + return SDVX_VF_CLASSES.IMPERIAL_IV; } else if (vf >= 20) { // imperial i -> iv has gaps of 1 - return SDVXVFClasses.IMPERIAL_I + Math.floor(vf - 20); + return SDVX_VF_CLASSES.IMPERIAL_I + Math.floor(vf - 20); } else if (vf >= 14) { // cyan i -> crimson iv has gaps of 0.25 - return SDVXVFClasses.CYAN_I + Math.floor(4 * (vf - 14)); + return SDVX_VF_CLASSES.CYAN_I + Math.floor(4 * (vf - 14)); } else if (vf >= 10) { // cobalt i -> dandelion iv have gaps of 0.5 - return SDVXVFClasses.COBALT_I + Math.floor(2 * (vf - 10)); + return SDVX_VF_CLASSES.COBALT_I + Math.floor(2 * (vf - 10)); } return Math.floor(vf / 2.5); @@ -69,40 +69,40 @@ export function CalculateGitadoraColour( export function GitadoraSkillToColour(sk: number) { if (sk >= 8500) { - return GitadoraColours.RAINBOW; + return GITADORA_COLOURS.RAINBOW; } else if (sk >= 8000) { - return GitadoraColours.GOLD; + return GITADORA_COLOURS.GOLD; } else if (sk >= 7500) { - return GitadoraColours.SILVER; + return GITADORA_COLOURS.SILVER; } else if (sk >= 7000) { - return GitadoraColours.BRONZE; + return GITADORA_COLOURS.BRONZE; } else if (sk >= 6500) { - return GitadoraColours.RED_GRADIENT; + return GITADORA_COLOURS.RED_GRADIENT; } else if (sk >= 6000) { - return GitadoraColours.RED; + return GITADORA_COLOURS.RED; } else if (sk >= 5500) { - return GitadoraColours.PURPLE_GRADIENT; + return GITADORA_COLOURS.PURPLE_GRADIENT; } else if (sk >= 5000) { - return GitadoraColours.PURPLE; + return GITADORA_COLOURS.PURPLE; } else if (sk >= 4500) { - return GitadoraColours.BLUE_GRADIENT; + return GITADORA_COLOURS.BLUE_GRADIENT; } else if (sk >= 4000) { - return GitadoraColours.BLUE; + return GITADORA_COLOURS.BLUE; } else if (sk >= 3500) { - return GitadoraColours.GREEN_GRADIENT; + return GITADORA_COLOURS.GREEN_GRADIENT; } else if (sk >= 3000) { - return GitadoraColours.GREEN; + return GITADORA_COLOURS.GREEN; } else if (sk >= 2500) { - return GitadoraColours.YELLOW_GRADIENT; + return GITADORA_COLOURS.YELLOW_GRADIENT; } else if (sk >= 2000) { - return GitadoraColours.YELLOW; + return GITADORA_COLOURS.YELLOW; } else if (sk >= 1500) { - return GitadoraColours.ORANGE_GRADIENT; + return GITADORA_COLOURS.ORANGE_GRADIENT; } else if (sk >= 1000) { - return GitadoraColours.ORANGE; + return GITADORA_COLOURS.ORANGE; } - return GitadoraColours.WHITE; + return GITADORA_COLOURS.WHITE; } export function CalculateWACCAColour( diff --git a/server/src/lib/score-import/framework/user-game-stats/classes.test.ts b/server/src/lib/score-import/framework/user-game-stats/classes.test.ts index c2e4c96c0..027892e1e 100644 --- a/server/src/lib/score-import/framework/user-game-stats/classes.test.ts +++ b/server/src/lib/score-import/framework/user-game-stats/classes.test.ts @@ -1,6 +1,6 @@ import { ProcessClassDeltas, UpdateUGSClasses } from "./classes"; -import { GitadoraColours } from "lib/constants/classes"; import CreateLogCtx from "lib/logger/logger"; +import { GITADORA_COLOURS } from "tachi-common"; import t from "tap"; import ResetDBState from "test-utils/resets"; import type { UserGameStats } from "tachi-common"; @@ -36,7 +36,7 @@ t.test("#UpdateUGSClasses", (t) => { logger ); - t.strictSame(res, { colour: GitadoraColours.RAINBOW }); + t.strictSame(res, { colour: GITADORA_COLOURS.RAINBOW }); t.end(); }); diff --git a/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.test.ts b/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.test.ts index 14350654d..eb3faba02 100644 --- a/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.test.ts +++ b/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.test.ts @@ -1,6 +1,6 @@ import { CreateArcIIDXClassHandler } from "./class-handler"; -import { IIDXDans } from "lib/constants/classes"; import CreateLogCtx from "lib/logger/logger"; +import { IIDX_DANS } from "tachi-common"; import t from "tap"; import { MockJSONFetch } from "test-utils/mock-fetch"; import ResetDBState from "test-utils/resets"; @@ -33,11 +33,11 @@ t.test("#CreateArcIIDXClassHandler", (t) => { // its not async but typescript complains const res = await fn("iidx", "SP", 1, {}, logger); - t.equal(res!.dan, IIDXDans.CHUUDEN); + t.equal(res!.dan, IIDX_DANS.CHUUDEN); const res2 = await fn("iidx", "DP", 1, {}, logger); - t.equal(res2!.dan, IIDXDans.DAN_2); + t.equal(res2!.dan, IIDX_DANS.DAN_2); t.end(); }); diff --git a/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.ts b/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.ts index caf2a8e33..997bf9fdf 100644 --- a/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.ts +++ b/server/src/lib/score-import/import-types/api/arc-iidx/class-handler.ts @@ -1,5 +1,5 @@ -import { IIDXDans } from "lib/constants/classes"; import { ServerConfig } from "lib/setup/config"; +import { IIDX_DANS } from "tachi-common"; import nodeFetch from "utils/fetch"; import { HasOwnProperty, IsRecord } from "utils/misc"; import { CreateURLWithParams } from "utils/url"; @@ -82,29 +82,29 @@ export async function CreateArcIIDXClassHandler( } const ARCClasses = { - 皆伝: IIDXDans.KAIDEN, - 中伝: IIDXDans.CHUUDEN, - 十段: IIDXDans.DAN_10, - 九段: IIDXDans.DAN_9, - 八段: IIDXDans.DAN_8, - 七段: IIDXDans.DAN_7, - 六段: IIDXDans.DAN_6, - 五段: IIDXDans.DAN_5, - 四段: IIDXDans.DAN_4, - 三段: IIDXDans.DAN_3, + 皆伝: IIDX_DANS.KAIDEN, + 中伝: IIDX_DANS.CHUUDEN, + 十段: IIDX_DANS.DAN_10, + 九段: IIDX_DANS.DAN_9, + 八段: IIDX_DANS.DAN_8, + 七段: IIDX_DANS.DAN_7, + 六段: IIDX_DANS.DAN_6, + 五段: IIDX_DANS.DAN_5, + 四段: IIDX_DANS.DAN_4, + 三段: IIDX_DANS.DAN_3, // These two look very similar but they aren't // and ARC uses both, from what I can tell. // How nice of them. - 二段: IIDXDans.DAN_2, - ニ段: IIDXDans.DAN_2, + 二段: IIDX_DANS.DAN_2, + ニ段: IIDX_DANS.DAN_2, - 初段: IIDXDans.DAN_1, - 一級: IIDXDans.KYU_1, - 二級: IIDXDans.KYU_2, - 三級: IIDXDans.KYU_3, - 四級: IIDXDans.KYU_4, - 五級: IIDXDans.KYU_5, - 六級: IIDXDans.KYU_6, - 七級: IIDXDans.KYU_7, + 初段: IIDX_DANS.DAN_1, + 一級: IIDX_DANS.KYU_1, + 二級: IIDX_DANS.KYU_2, + 三級: IIDX_DANS.KYU_3, + 四級: IIDX_DANS.KYU_4, + 五級: IIDX_DANS.KYU_5, + 六級: IIDX_DANS.KYU_6, + 七級: IIDX_DANS.KYU_7, }; diff --git a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts index bcf18a83b..ba9468b67 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.test.ts @@ -1,7 +1,7 @@ import { CreateKaiIIDXClassHandler } from "./class-handler"; import { KaiTypeToBaseURL } from "../utils"; -import { IIDXDans } from "lib/constants/classes"; import CreateLogCtx from "lib/logger/logger"; +import { IIDX_DANS } from "tachi-common"; import t from "tap"; import { MockBasicFetch, MockJSONFetch } from "test-utils/mock-fetch"; import ResetDBState from "test-utils/resets"; @@ -86,7 +86,7 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { _links: {}, iidx_id: 12345678, dj_name: "SOMEONE", - sp: IIDXDans.KAIDEN + 1, + sp: IIDX_DANS.KAIDEN + 1, dp: 4, access_time: "2021-08-08T18:50:40Z", register_time: "2019-01-19T12:53:50Z", @@ -114,7 +114,7 @@ t.test("#CreateKaiIIDXClassHandler", async (t) => { _links: {}, iidx_id: 12345678, dj_name: "SOMEONE", - sp: IIDXDans.KYU_7 - 1, + sp: IIDX_DANS.KYU_7 - 1, dp: 4, access_time: "2021-08-08T18:50:40Z", register_time: "2019-01-19T12:53:50Z", diff --git a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts index eb0b3a2f7..fd6929170 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/iidx/class-handler.ts @@ -1,5 +1,5 @@ import { KaiTypeToBaseURL } from "../utils"; -import { IIDXDans } from "lib/constants/classes"; +import { IIDX_DANS } from "tachi-common"; import nodeFetch from "utils/fetch"; import { IsRecord } from "utils/misc"; import type { KaiAPIReauthFunction } from "../traverse-api"; @@ -88,16 +88,16 @@ export async function CreateKaiIIDXClassHandler( return {}; } - if (iidxDan > IIDXDans.KAIDEN) { + if (iidxDan > IIDX_DANS.KAIDEN) { logger.warn( - `${baseUrl} returned a dan of ${iidxDan}, which was greater than KAIDEN (${IIDXDans.KAIDEN}.)` + `${baseUrl} returned a dan of ${iidxDan}, which was greater than KAIDEN (${IIDX_DANS.KAIDEN}.)` ); return {}; } - if (iidxDan < IIDXDans.KYU_7) { + if (iidxDan < IIDX_DANS.KYU_7) { logger.warn( - `${baseUrl} returned a dan of ${iidxDan}, which was less than KYU_7 (${IIDXDans.KYU_7}.)` + `${baseUrl} returned a dan of ${iidxDan}, which was less than KYU_7 (${IIDX_DANS.KYU_7}.)` ); return {}; } diff --git a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts index 57027b703..dfa62fbb4 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.test.ts @@ -1,7 +1,7 @@ import { CreateKaiSDVXClassHandler } from "./class-handler"; import { KaiTypeToBaseURL } from "../utils"; -import { SDVXDans } from "lib/constants/classes"; import CreateLogCtx from "lib/logger/logger"; +import { SDVX_DANS } from "tachi-common"; import t from "tap"; import { MockBasicFetch, MockJSONFetch } from "test-utils/mock-fetch"; import ResetDBState from "test-utils/resets"; @@ -84,7 +84,7 @@ t.test("#CreateKaiSDVXClassHandler", async (t) => { _links: {}, sdvx_id: 12345678, name: "SOMEONE", - skill_level: SDVXDans.INF + 2, + skill_level: SDVX_DANS.INF + 2, access_time: "2019-08-26T18:22:36Z", register_time: "2019-08-26T18:22:36Z", }, diff --git a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts index d41daae01..554025b97 100644 --- a/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts +++ b/server/src/lib/score-import/import-types/common/api-kai/sdvx/class-handler.ts @@ -1,5 +1,5 @@ import { KaiTypeToBaseURL } from "../utils"; -import { SDVXDans } from "lib/constants/classes"; +import { SDVX_DANS } from "tachi-common"; import nodeFetch from "utils/fetch"; import { IsRecord } from "utils/misc"; import type { KaiAPIReauthFunction } from "../traverse-api"; @@ -75,9 +75,9 @@ export async function CreateKaiSDVXClassHandler( return {}; } - if (sdvxDan > SDVXDans.INF) { + if (sdvxDan > SDVX_DANS.INF) { logger.warn( - `${baseUrl} returned a dan of ${sdvxDan}, which was greater than INF (${SDVXDans.INF}.)` + `${baseUrl} returned a dan of ${sdvxDan}, which was greater than INF (${SDVX_DANS.INF}.)` ); return {}; } @@ -88,9 +88,9 @@ export async function CreateKaiSDVXClassHandler( return {}; } - if (sdvxDan < SDVXDans.DAN_1) { + if (sdvxDan < SDVX_DANS.DAN_1) { logger.warn( - `${baseUrl} returned a dan of ${sdvxDan}, which was less than DAN_1 (${SDVXDans.DAN_1}.)` + `${baseUrl} returned a dan of ${sdvxDan}, which was less than DAN_1 (${SDVX_DANS.DAN_1}.)` ); return {}; } diff --git a/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts b/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts index dc1194184..fffb02e06 100644 --- a/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts +++ b/server/src/lib/score-import/import-types/common/batch-manual/parser.test.ts @@ -1,8 +1,8 @@ import { ParseBatchManualFromObject as ParserFn } from "./parser"; import ScoreImportFatalError from "../../../framework/score-importing/score-import-error"; import deepmerge from "deepmerge"; -import { IIDXDans } from "lib/constants/classes"; import CreateLogCtx from "lib/logger/logger"; +import { IIDX_DANS } from "tachi-common"; import t from "tap"; import { EscapeStringRegexp } from "utils/misc"; import type { BatchManual } from "tachi-common"; @@ -338,7 +338,7 @@ t.test("#ParserFn", (t) => { t.not(res.classHandler, null); - t.strictSame(res.classHandler!("iidx", "SP", 1, {}, logger), { dan: IIDXDans.KAIDEN }); + t.strictSame(res.classHandler!("iidx", "SP", 1, {}, logger), { dan: IIDX_DANS.KAIDEN }); t.end(); }); diff --git a/server/src/lib/score-mutation/delete-scores.test.ts b/server/src/lib/score-mutation/delete-scores.test.ts index 2c29bf87d..f5d0088de 100644 --- a/server/src/lib/score-mutation/delete-scores.test.ts +++ b/server/src/lib/score-mutation/delete-scores.test.ts @@ -1,8 +1,8 @@ import { DeleteScore } from "./delete-scores"; import deepmerge from "deepmerge"; import db from "external/mongo/db"; -import { SDVXVFClasses } from "lib/constants/classes"; import CreateLogCtx from "lib/logger/logger"; +import { SDVX_VF_CLASSES } from "tachi-common"; import t from "tap"; import { mkFakeSDVXChart, mkFakeSDVXPB } from "test-utils/misc"; import ResetDBState from "test-utils/resets"; @@ -225,7 +225,7 @@ t.test("#DeleteScore", (t) => { game: "sdvx", playtype: "Single", classes: { - vfClass: SDVXVFClasses.CYAN_I, + vfClass: SDVX_VF_CLASSES.CYAN_I, }, ratings: { VF6: 14, @@ -242,7 +242,7 @@ t.test("#DeleteScore", (t) => { t.hasStrict(res, { classes: { - vfClass: SDVXVFClasses.SIENNA_II, + vfClass: SDVX_VF_CLASSES.SIENNA_II, }, ratings: { VF6: 4,