From aa6011b18d1955d2ca0fc1a9d245362df73f44ae Mon Sep 17 00:00:00 2001 From: tresabhi Date: Sat, 15 Jul 2023 18:44:20 +0000 Subject: [PATCH] feat: added basic infrastructure for ratings command --- scripts/build.ts | 2 - src/commands/eligible.ts | 2 +- src/commands/evolution.tsx | 6 +- src/commands/fullStats.tsx | 6 +- src/commands/inactive.tsx | 4 +- src/commands/ownedTanks.tsx | 6 +- src/commands/playerAchievements.ts | 2 +- src/commands/playerInfo.ts | 2 +- src/commands/ratings.ts | 115 ++++++++++++++++++ src/commands/searchClans.ts | 8 +- src/commands/searchPlayers.ts | 8 +- src/commands/stats.tsx | 8 +- src/commands/today.tsx | 4 +- src/commands/verify.ts | 2 +- src/constants/regions.ts | 4 +- src/core/blitz/getBlitzClan.ts | 4 +- src/core/blitz/getTankStats.ts | 6 +- src/core/blitz/listClans.ts | 8 +- src/core/blitz/listPlayers.ts | 8 +- src/core/blitz/regionToRegionSubdomain.ts | 7 ++ src/core/blitzstars/getDiffedTankStats.ts | 4 +- src/core/blitzstars/getPeriodStart.ts | 4 +- src/core/blitzstars/getPlayerHistories.ts | 6 +- src/core/blitzstars/getTankHistories.ts | 4 +- src/core/blitzstars/getTimeDaysAgo.ts | 6 +- src/core/discord/addServerChoices.ts | 8 +- src/core/discord/autocompleteClan.ts | 4 +- src/core/discord/autocompleteUsername.ts | 6 +- src/core/discord/resolvePeriodFromButton.ts | 4 +- src/core/discord/resolvePeriodFromCommand.ts | 4 +- src/core/discord/resolvePlayerFromCommand.ts | 8 +- src/core/express/resolvePeriodFromRequest.ts | 4 +- src/core/express/resolvePeriodFromURL.ts | 4 +- src/core/express/resolvePlayerFromURL.ts | 4 +- .../handlers/chatInputCommand.ts | 14 +++ src/events/interactionCreate/index.ts | 3 + src/renderers/evolution.tsx | 6 +- src/renderers/fullStats.tsx | 6 +- src/renderers/stats.tsx | 6 +- src/renderers/today.tsx | 6 +- 40 files changed, 227 insertions(+), 96 deletions(-) create mode 100644 src/commands/ratings.ts create mode 100644 src/core/blitz/regionToRegionSubdomain.ts diff --git a/scripts/build.ts b/scripts/build.ts index 18c450987..522841e3f 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -7,8 +7,6 @@ const buildAll = argv.includes('--build=all'); const buildBot = argv.includes('--build=bot') || buildAll; const buildServer = argv.includes('--build=server') || buildAll; -console.log(buildAll, buildBot, buildServer); - if (isProd) { // only remove in production to ensure no time is wasted in dev console.log('Removing dist...'); diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 43c6991d6..2ded85c56 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -49,7 +49,7 @@ export const eligibleCommand: CommandRegistry = { async handler(interaction) { const clan = interaction.options.getString('clan') as SkilledClan; - const { id, server } = await resolvePlayerFromCommand(interaction); + const { id, region: server } = await resolvePlayerFromCommand(interaction); const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index e3b62fbe4..4754f635a 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -34,7 +34,7 @@ export const evolutionCommand: CommandRegistry = { true, ) as StatType; const player = await resolvePlayerFromCommand(interaction); - const period = resolvePeriodFromCommand(player.server, interaction); + const period = resolvePeriodFromCommand(player.region, interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; @@ -42,7 +42,7 @@ export const evolutionCommand: CommandRegistry = { const end = interaction.options.getInteger('end'); const { nickname } = ( await getWargamingResponse( - `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + `https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, ) )[player.id]; const path = interactionToURL(interaction, { @@ -57,7 +57,7 @@ export const evolutionCommand: CommandRegistry = { primaryButton(path, 'Refresh'), // linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( - `https://www.blitzstars.com/player/${player.server}/${nickname}${ + `https://www.blitzstars.com/player/${player.region}/${nickname}${ commandGroup === 'tank' ? `/tank/${tankId!}` : '' }`, 'BlitzStars', diff --git a/src/commands/fullStats.tsx b/src/commands/fullStats.tsx index adbd15159..d5c9a7e67 100644 --- a/src/commands/fullStats.tsx +++ b/src/commands/fullStats.tsx @@ -33,7 +33,7 @@ export const fullStatsCommand: CommandRegistry = { true, ) as StatType; const player = await resolvePlayerFromCommand(interaction); - const period = resolvePeriodFromCommand(player.server, interaction); + const period = resolvePeriodFromCommand(player.region, interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; @@ -47,7 +47,7 @@ export const fullStatsCommand: CommandRegistry = { }); const { nickname } = ( await getWargamingResponse( - `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + `https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, ) )[player.id]; @@ -56,7 +56,7 @@ export const fullStatsCommand: CommandRegistry = { primaryButton(path, 'Refresh'), // linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( - `https://www.blitzstars.com/player/${player.server}/${nickname}`, + `https://www.blitzstars.com/player/${player.region}/${nickname}`, 'BlitzStars', ), ]; diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index 33a6ef8b6..e059125fe 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -4,7 +4,7 @@ import NoData, { NoDataType } from '../components/NoData'; import PoweredBy, { PoweredByType } from '../components/PoweredBy'; import TitleBar from '../components/TitleBar'; import Wrapper from '../components/Wrapper'; -import { REGION_DOMAIN_NAMES } from '../constants/regions'; +import { REGION_NAMES } from '../constants/regions'; import getBlitzClan from '../core/blitz/getBlitzClan'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; import addClanChoices from '../core/discord/addClanChoices'; @@ -72,7 +72,7 @@ export const inactiveCommand: CommandRegistry = { nameDiscriminator="(Inactivity)" image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanData.emblem_set_id}.png`} description={`${threshold}+ Days • ${new Date().toDateString()} • ${ - REGION_DOMAIN_NAMES[server] + REGION_NAMES[server] }`} /> diff --git a/src/commands/ownedTanks.tsx b/src/commands/ownedTanks.tsx index 0a4cbcfde..637739d6b 100644 --- a/src/commands/ownedTanks.tsx +++ b/src/commands/ownedTanks.tsx @@ -4,7 +4,7 @@ import PoweredBy, { PoweredByType } from '../components/PoweredBy'; import * as Tanks from '../components/Tanks'; import TitleBar from '../components/TitleBar'; import Wrapper from '../components/Wrapper'; -import { REGION_DOMAIN_NAMES } from '../constants/regions'; +import { REGION_NAMES } from '../constants/regions'; import getTankStats from '../core/blitz/getTankStats'; import getTreeType from '../core/blitz/getTreeType'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; @@ -74,7 +74,7 @@ export const ownedTanksCommand: CommandRegistry = { async handler(interaction) { const tier = Number(interaction.options.getString('tier')); const account = await resolvePlayerFromCommand(interaction); - const { id, server } = account; + const { id, region: server } = account; const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); @@ -105,7 +105,7 @@ export const ownedTanksCommand: CommandRegistry = { : undefined } description={`Owned tanks • ${new Date().toDateString()} • ${ - REGION_DOMAIN_NAMES[server] + REGION_NAMES[server] }`} /> diff --git a/src/commands/playerAchievements.ts b/src/commands/playerAchievements.ts index 3301e5542..505cf18de 100644 --- a/src/commands/playerAchievements.ts +++ b/src/commands/playerAchievements.ts @@ -36,7 +36,7 @@ export const playerAchievementsCommand: CommandRegistry = { async handler(interaction) { const sortBy = (interaction.options.getString('sort') ?? 'name') as SortBy; const account = await resolvePlayerFromCommand(interaction); - const { id, server } = account; + const { id, region: server } = account; const accounts = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); diff --git a/src/commands/playerInfo.ts b/src/commands/playerInfo.ts index d6661373f..ad7876c66 100644 --- a/src/commands/playerInfo.ts +++ b/src/commands/playerInfo.ts @@ -22,7 +22,7 @@ export const playerInfoCommand: CommandRegistry = { async handler(interaction) { const account = await resolvePlayerFromCommand(interaction); - const { id, server } = account; + const { id, region: server } = account; const accounts = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); diff --git a/src/commands/ratings.ts b/src/commands/ratings.ts new file mode 100644 index 000000000..de0702faa --- /dev/null +++ b/src/commands/ratings.ts @@ -0,0 +1,115 @@ +import { SlashCommandBuilder, SlashCommandSubcommandBuilder } from 'discord.js'; +import regionToRegionSubdomain from '../core/blitz/regionToRegionSubdomain'; +import addUsernameChoices from '../core/discord/addUsernameChoices'; +import autocompleteUsername from '../core/discord/autocompleteUsername'; +import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand'; +import { CommandRegistry } from '../events/interactionCreate'; + +export interface LeaguePlayer { + spa_id: number; + mmr: number; + season_number: number; + calibrationBattlesLeft: number; + number: number; + percentile: number; + skip: boolean; + updated_at: string; + score: number; + nickname: string; + clan_tag: string; +} + +export interface LeagueTop { + result: LeaguePlayer[]; +} + +const LEAGUE_INDEXES = ['diamond', 'platinum', 'gold', 'silver', 'bronze']; + +function optionalParameters(option: SlashCommandSubcommandBuilder) { + return option + .addIntegerOption((option) => + option + .setName('limit') + .setDescription('How many rows to display (default: 16)') + .setRequired(true) + .setMinValue(5) + .setMaxValue(30), + ) + .addStringOption(addUsernameChoices); +} + +export const ratingsCommand: CommandRegistry = { + inProduction: true, + inDevelopment: true, + inPublic: true, + inPreview: true, + + command: new SlashCommandBuilder() + .setName('ratings') + .setDescription('Ratings battles statistics') + .addSubcommandGroup((option) => + option + .setName('league') + .setDescription('Top league players') + .addSubcommand((option) => + optionalParameters( + option + .setName('diamond') + .setDescription('Top Diamond League players'), + ), + ) + .addSubcommand((option) => + optionalParameters( + option + .setName('platinum') + .setDescription('Top Platinum League players'), + ), + ) + .addSubcommand((option) => + optionalParameters( + option.setName('gold').setDescription('Top Gold League players'), + ), + ) + .addSubcommand((option) => + optionalParameters( + option + .setName('silver') + .setDescription('Top Silver League players'), + ), + ) + .addSubcommand((option) => + optionalParameters( + option + .setName('bronze') + .setDescription('Top Bronze League players'), + ), + ), + ), + + async handler(interaction) { + const subcommandGroup = interaction.options.getSubcommandGroup(true); + + if (subcommandGroup === 'league') { + const limit = interaction.options.getInteger('limit') ?? 16; + const subcommand = interaction.options.getSubcommand(true); + const leagueIndex = LEAGUE_INDEXES.indexOf(subcommand); + const player = await resolvePlayerFromCommand(interaction); + const regionSubdomain = regionToRegionSubdomain(player.region); + const { result } = await fetch( + `https://${regionSubdomain}.wotblitz.com/en/api/rating-leaderboards/league/${leagueIndex}/top/`, + ).then((response) => response.json() as Promise); + + return `\`\`\`${result + .slice(0, limit) + .map( + (player) => + `${player.number}: ${player.nickname} [${player.clan_tag}]`, + ) + .join('\n')}\`\`\``; + } + + return []; + }, + + autocomplete: autocompleteUsername, +}; diff --git a/src/commands/searchClans.ts b/src/commands/searchClans.ts index f89ea8f78..a483d4510 100644 --- a/src/commands/searchClans.ts +++ b/src/commands/searchClans.ts @@ -1,6 +1,6 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; -import { REGION_DOMAIN_NAMES, RegionDomain } from '../constants/regions'; +import { REGION_NAMES, Region } from '../constants/regions'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; import addClanChoices from '../core/discord/addClanChoices'; import addServerChoices from '../core/discord/addServerChoices'; @@ -28,7 +28,7 @@ export const searchClansCommand: CommandRegistry = { ), async handler(interaction) { - const server = interaction.options.getString('server') as RegionDomain; + const server = interaction.options.getString('server') as Region; const clan = interaction.options.getString('clan')!; const limit = interaction.options.getInteger('limit') ?? 25; const clanList = await getWargamingResponse( @@ -36,9 +36,7 @@ export const searchClansCommand: CommandRegistry = { ); return embedInfo( - `Clan search for "${markdownEscape(clan)}" in ${ - REGION_DOMAIN_NAMES[server] - }`, + `Clan search for "${markdownEscape(clan)}" in ${REGION_NAMES[server]}`, clanList.length === 0 ? 'No clans found.' : `\`\`\`\n${clanList diff --git a/src/commands/searchPlayers.ts b/src/commands/searchPlayers.ts index 4b430aea4..7de26bc69 100644 --- a/src/commands/searchPlayers.ts +++ b/src/commands/searchPlayers.ts @@ -1,6 +1,6 @@ import { SlashCommandBuilder } from 'discord.js'; import markdownEscape from 'markdown-escape'; -import { REGION_DOMAIN_NAMES, RegionDomain } from '../constants/regions'; +import { REGION_NAMES, Region } from '../constants/regions'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; import { usernamePattern } from '../core/blitz/listPlayers'; import addServerChoices from '../core/discord/addServerChoices'; @@ -31,7 +31,7 @@ export const searchPlayersCommand: CommandRegistry = { ), async handler(interaction) { - const server = interaction.options.getString('server') as RegionDomain; + const server = interaction.options.getString('server') as Region; const name = interaction.options.getString('username')!; const limit = interaction.options.getInteger('limit') ?? 25; const trimmedSearch = name.trim(); @@ -44,9 +44,7 @@ export const searchPlayersCommand: CommandRegistry = { : []; return embedInfo( - `Player search for "${markdownEscape(name)}" in ${ - REGION_DOMAIN_NAMES[server] - }`, + `Player search for "${markdownEscape(name)}" in ${REGION_NAMES[server]}`, `\`\`\`${ players.length === 0 ? 'No players found.' diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 4f5f5721f..2b392fb7f 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -26,7 +26,7 @@ export const statsCommand: CommandRegistry = { command: addStatTypeSubCommandGroups( new SlashCommandBuilder() .setName('stats') - .setDescription('In-game statistics'), + .setDescription('Regular battles statistics'), ), async handler(interaction) { @@ -34,7 +34,7 @@ export const statsCommand: CommandRegistry = { true, ) as StatType; const player = await resolvePlayerFromCommand(interaction); - const period = resolvePeriodFromCommand(player.server, interaction); + const period = resolvePeriodFromCommand(player.region, interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; @@ -48,7 +48,7 @@ export const statsCommand: CommandRegistry = { }); const { nickname } = ( await getWargamingResponse( - `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + `https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, ) )[player.id]; @@ -57,7 +57,7 @@ export const statsCommand: CommandRegistry = { primaryButton(path, 'Refresh'), linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( - `https://www.blitzstars.com/player/${player.server}/${nickname}`, + `https://www.blitzstars.com/player/${player.region}/${nickname}`, 'BlitzStars', ), ]; diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 7026723fd..48c01c68c 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -37,7 +37,7 @@ export const todayCommand: CommandRegistry = { const limit = interaction.options.getInteger('limit') ?? Infinity; const { nickname } = ( await getWargamingResponse( - `https://api.wotblitz.${player.server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, + `https://api.wotblitz.${player.region}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${player.id}`, ) )[player.id]; const path = interactionToURL(interaction, player); @@ -47,7 +47,7 @@ export const todayCommand: CommandRegistry = { primaryButton(path, 'Refresh'), linkButton(`${CYCLIC_API}/${path}`, 'Embed'), linkButton( - `https://www.blitzstars.com/player/${player.server}/${nickname}`, + `https://www.blitzstars.com/player/${player.region}/${nickname}`, 'BlitzStars', ), ]; diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 66c78d35e..de53dc2a7 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -24,7 +24,7 @@ export const verifyCommand: CommandRegistry = { async handler(interaction) { const blitzAccount = await resolvePlayerFromCommand(interaction); - const { id, server } = blitzAccount; + const { id, region: server } = blitzAccount; const accountInfo = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); diff --git a/src/constants/regions.ts b/src/constants/regions.ts index 59602911c..43118a767 100644 --- a/src/constants/regions.ts +++ b/src/constants/regions.ts @@ -1,7 +1,7 @@ -export type RegionDomain = 'com' | 'eu' | 'asia'; +export type Region = 'com' | 'eu' | 'asia'; export type RegionSubdomain = 'na' | 'eu' | 'asia'; -export const REGION_DOMAIN_NAMES: Record = { +export const REGION_NAMES: Record = { com: 'North America', eu: 'Europe', asia: 'Asia', diff --git a/src/core/blitz/getBlitzClan.ts b/src/core/blitz/getBlitzClan.ts index be7281baa..68f32222b 100644 --- a/src/core/blitz/getBlitzClan.ts +++ b/src/core/blitz/getBlitzClan.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { serverAndIdPattern } from '../discord/resolvePlayerFromCommand'; import throwError from '../node/throwError'; import listClans from './listClans'; @@ -6,7 +6,7 @@ import listClans from './listClans'; export default async function getBlitzClan(clan: string) { if (serverAndIdPattern.test(clan)) { const [server, accountId] = clan.split('/'); - return { server: server as RegionDomain, id: Number(accountId) }; + return { server: server as Region, id: Number(accountId) }; } else { const accounts = await listClans(clan); diff --git a/src/core/blitz/getTankStats.ts b/src/core/blitz/getTankStats.ts index 09b2b58c4..d12be6448 100644 --- a/src/core/blitz/getTankStats.ts +++ b/src/core/blitz/getTankStats.ts @@ -1,10 +1,10 @@ -import { REGION_DOMAIN_NAMES, RegionDomain } from '../../constants/regions'; +import { REGION_NAMES, Region } from '../../constants/regions'; import { TanksStats } from '../../types/tanksStats'; import { WARGAMING_APPLICATION_ID } from '../node/arguments'; import throwError from '../node/throwError'; import getWargamingResponse from './getWargamingResponse'; -export default async function getTankStats(server: RegionDomain, id: number) { +export default async function getTankStats(server: Region, id: number) { const tankStats = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); @@ -12,7 +12,7 @@ export default async function getTankStats(server: RegionDomain, id: number) { if (tankStats[id] === null) { throw throwError( 'No tank stats available', - `Wargaming says there is no tank stats for this account. This account may not have any battles/tanks or exist in the ${REGION_DOMAIN_NAMES[server]} server.`, + `Wargaming says there is no tank stats for this account. This account may not have any battles/tanks or exist in the ${REGION_NAMES[server]} server.`, ); } diff --git a/src/core/blitz/listClans.ts b/src/core/blitz/listClans.ts index 5ae7c3f25..69e84ec29 100644 --- a/src/core/blitz/listClans.ts +++ b/src/core/blitz/listClans.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { Clan, ClanList } from '../../types/clanList'; import { WARGAMING_APPLICATION_ID } from '../node/arguments'; import getWargamingResponse from './getWargamingResponse'; @@ -21,7 +21,7 @@ export default async function listClans(search: string, limit = 9) { value && value.map((account) => ({ ...account, - server: 'com' as RegionDomain, + server: 'com' as Region, })), ), getWargamingResponse( @@ -31,7 +31,7 @@ export default async function listClans(search: string, limit = 9) { value && value.map((account) => ({ ...account, - server: 'eu' as RegionDomain, + server: 'eu' as Region, })), ), getWargamingResponse( @@ -41,7 +41,7 @@ export default async function listClans(search: string, limit = 9) { value && value.map((account) => ({ ...account, - server: 'asia' as RegionDomain, + server: 'asia' as Region, })), ), ]) diff --git a/src/core/blitz/listPlayers.ts b/src/core/blitz/listPlayers.ts index 2571c7f14..6ecc9a3fb 100644 --- a/src/core/blitz/listPlayers.ts +++ b/src/core/blitz/listPlayers.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { Account, AccountList } from '../../types/accountList'; import { WARGAMING_APPLICATION_ID } from '../node/arguments'; import getWargamingResponse from './getWargamingResponse'; @@ -25,7 +25,7 @@ export default async function listPlayers(search: string, limit = 9) { value && value.map((account) => ({ ...account, - server: 'com' as RegionDomain, + server: 'com' as Region, })), ), getWargamingResponse( @@ -35,7 +35,7 @@ export default async function listPlayers(search: string, limit = 9) { value && value.map((account) => ({ ...account, - server: 'eu' as RegionDomain, + server: 'eu' as Region, })), ), getWargamingResponse( @@ -45,7 +45,7 @@ export default async function listPlayers(search: string, limit = 9) { value && value.map((account) => ({ ...account, - server: 'asia' as RegionDomain, + server: 'asia' as Region, })), ), ]) diff --git a/src/core/blitz/regionToRegionSubdomain.ts b/src/core/blitz/regionToRegionSubdomain.ts new file mode 100644 index 000000000..fe44d9dcd --- /dev/null +++ b/src/core/blitz/regionToRegionSubdomain.ts @@ -0,0 +1,7 @@ +import { Region, RegionSubdomain } from '../../constants/regions'; + +export default function regionToRegionSubdomain( + regionDomain: Region, +): RegionSubdomain { + return regionDomain === 'com' ? 'na' : regionDomain; +} diff --git a/src/core/blitzstars/getDiffedTankStats.ts b/src/core/blitzstars/getDiffedTankStats.ts index 2b1e3f269..68bb54618 100644 --- a/src/core/blitzstars/getDiffedTankStats.ts +++ b/src/core/blitzstars/getDiffedTankStats.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { AllStats } from '../../types/accountInfo'; import getTankHistories, { TankHistories, @@ -35,7 +35,7 @@ export const emptyTankHistoryNode: TankHistoryRaw = { }; export default async function getDiffedTankStats( - server: RegionDomain, + server: Region, id: number, start: number, end: number, diff --git a/src/core/blitzstars/getPeriodStart.ts b/src/core/blitzstars/getPeriodStart.ts index 0faae2fba..1ad1ff478 100644 --- a/src/core/blitzstars/getPeriodStart.ts +++ b/src/core/blitzstars/getPeriodStart.ts @@ -1,9 +1,9 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { Period } from '../discord/addPeriodSubCommands'; import getTimeDaysAgo from './getTimeDaysAgo'; export default function getPeriodStart( - server: RegionDomain, + server: Region, period: Exclude, ) { if (period === 'career') { diff --git a/src/core/blitzstars/getPlayerHistories.ts b/src/core/blitzstars/getPlayerHistories.ts index 895ba7edf..ad9cf6e46 100644 --- a/src/core/blitzstars/getPlayerHistories.ts +++ b/src/core/blitzstars/getPlayerHistories.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { AccountInfo, AllStats } from '../../types/accountInfo'; import { GetHistoriesOptions, @@ -25,13 +25,13 @@ export interface PlayerHistoryRaw { account_id: number; [key: string]: number; }; - region: RegionDomain; + region: Region; } export type PlayerHistoriesRaw = PlayerHistoryRaw[]; export default async function getPlayerHistories( - server: RegionDomain, + server: Region, id: number, options?: Partial, ) { diff --git a/src/core/blitzstars/getTankHistories.ts b/src/core/blitzstars/getTankHistories.ts index 96f9b8e03..3b5ed9d14 100644 --- a/src/core/blitzstars/getTankHistories.ts +++ b/src/core/blitzstars/getTankHistories.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { GetHistoriesOptions, Histories, @@ -32,7 +32,7 @@ export const getTankHistoriesDefaultOptions: GetTankHistoriesOptions = { }; export default async function getTankHistories( - server: RegionDomain, + server: Region, id: number, options?: Partial, ) { diff --git a/src/core/blitzstars/getTimeDaysAgo.ts b/src/core/blitzstars/getTimeDaysAgo.ts index 421fec09f..652b28fea 100644 --- a/src/core/blitzstars/getTimeDaysAgo.ts +++ b/src/core/blitzstars/getTimeDaysAgo.ts @@ -1,12 +1,12 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; -export const TIME_ZONE_MAPPINGS: Record = { +export const TIME_ZONE_MAPPINGS: Record = { com: -5, // Central North American Time eu: +1, // Central European Time asia: +7, // Central Asia Standard Time }; -export default function getTimeDaysAgo(server: RegionDomain, daysAgo: number) { +export default function getTimeDaysAgo(server: Region, daysAgo: number) { const now = new Date(); if (daysAgo === 0) now.getTime() / 1000; diff --git a/src/core/discord/addServerChoices.ts b/src/core/discord/addServerChoices.ts index e702c85d7..83e35c4f7 100644 --- a/src/core/discord/addServerChoices.ts +++ b/src/core/discord/addServerChoices.ts @@ -1,14 +1,14 @@ import { SlashCommandStringOption } from 'discord.js'; -import { REGION_DOMAIN_NAMES } from '../../constants/regions'; +import { REGION_NAMES } from '../../constants/regions'; export default function addServerChoices(option: SlashCommandStringOption) { return option .setName('server') .setDescription('The Blitz server you are in') .addChoices( - { name: REGION_DOMAIN_NAMES.com, value: 'com' }, - { name: REGION_DOMAIN_NAMES.eu, value: 'eu' }, - { name: REGION_DOMAIN_NAMES.asia, value: 'asia' }, + { name: REGION_NAMES.com, value: 'com' }, + { name: REGION_NAMES.eu, value: 'eu' }, + { name: REGION_NAMES.asia, value: 'asia' }, ) .setRequired(true); } diff --git a/src/core/discord/autocompleteClan.ts b/src/core/discord/autocompleteClan.ts index a06497e6a..6f0efb31e 100644 --- a/src/core/discord/autocompleteClan.ts +++ b/src/core/discord/autocompleteClan.ts @@ -3,7 +3,7 @@ import { AutocompleteInteraction, CacheType, } from 'discord.js'; -import { REGION_DOMAIN_NAMES } from '../../constants/regions'; +import { REGION_NAMES } from '../../constants/regions'; import listClans from '../blitz/listClans'; export default async function autocompleteClan( @@ -18,7 +18,7 @@ export default async function autocompleteClan( ? players.map( (player) => ({ - name: `${player.name} (${REGION_DOMAIN_NAMES[player.server]})`, + name: `${player.name} (${REGION_NAMES[player.server]})`, value: `${player.server}/${player.clan_id}`, }) satisfies ApplicationCommandOptionChoiceData, ) diff --git a/src/core/discord/autocompleteUsername.ts b/src/core/discord/autocompleteUsername.ts index 4664baf10..f52557095 100644 --- a/src/core/discord/autocompleteUsername.ts +++ b/src/core/discord/autocompleteUsername.ts @@ -3,7 +3,7 @@ import { AutocompleteInteraction, CacheType, } from 'discord.js'; -import { REGION_DOMAIN_NAMES } from '../../constants/regions'; +import { REGION_NAMES } from '../../constants/regions'; import listPlayers from '../blitz/listPlayers'; export default async function autocompleteUsername( @@ -19,9 +19,7 @@ export default async function autocompleteUsername( ? players.map( (player) => ({ - name: `${player.nickname} (${ - REGION_DOMAIN_NAMES[player.server] - })`, + name: `${player.nickname} (${REGION_NAMES[player.server]})`, value: `${player.server}/${player.account_id}`, }) satisfies ApplicationCommandOptionChoiceData, ) diff --git a/src/core/discord/resolvePeriodFromButton.ts b/src/core/discord/resolvePeriodFromButton.ts index 1e7236857..3bdd6d103 100644 --- a/src/core/discord/resolvePeriodFromButton.ts +++ b/src/core/discord/resolvePeriodFromButton.ts @@ -1,10 +1,10 @@ import { ButtonInteraction, CacheType } from 'discord.js'; import { CYCLIC_API } from '../../constants/cyclic'; -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import resolvePeriodFromURL from '../express/resolvePeriodFromURL'; export default function resolvePeriodFromButton( - server: RegionDomain, + server: Region, interaction: ButtonInteraction, ) { return resolvePeriodFromURL(server, `${CYCLIC_API}/${interaction.customId}`); diff --git a/src/core/discord/resolvePeriodFromCommand.ts b/src/core/discord/resolvePeriodFromCommand.ts index c5fe1259c..95210715d 100644 --- a/src/core/discord/resolvePeriodFromCommand.ts +++ b/src/core/discord/resolvePeriodFromCommand.ts @@ -1,5 +1,5 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js'; -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import getPeriodNow from '../blitzstars/getPeriodNow'; import getPeriodStart from '../blitzstars/getPeriodStart'; import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo'; @@ -31,7 +31,7 @@ export interface ResolvedPeriod { } export default function resolvePeriodFromCommand( - server: RegionDomain, + server: Region, interaction: ChatInputCommandInteraction, ) { let statsName: string; diff --git a/src/core/discord/resolvePlayerFromCommand.ts b/src/core/discord/resolvePlayerFromCommand.ts index e9762d01a..1452e6bc8 100644 --- a/src/core/discord/resolvePlayerFromCommand.ts +++ b/src/core/discord/resolvePlayerFromCommand.ts @@ -1,5 +1,5 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js'; -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import listPlayers, { usernamePatternWithoutPosition, } from '../blitz/listPlayers'; @@ -8,7 +8,7 @@ import throwError from '../node/throwError'; export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; export interface ResolvedPlayer { - server: RegionDomain; + region: Region; id: number; } @@ -31,7 +31,7 @@ export default async function resolvePlayerFromCommand( if (serverAndIdPattern.test(username)) { const [server, accountId] = username.split('/'); return { - server: server as RegionDomain, + region: server as Region, id: Number(accountId), } satisfies ResolvedPlayer; } else { @@ -39,7 +39,7 @@ export default async function resolvePlayerFromCommand( if (accounts[0]) { return { - server: accounts[0].server, + region: accounts[0].server, id: accounts[0].account_id, } satisfies ResolvedPlayer; } else { diff --git a/src/core/express/resolvePeriodFromRequest.ts b/src/core/express/resolvePeriodFromRequest.ts index 7ff160402..bf88d3ea7 100644 --- a/src/core/express/resolvePeriodFromRequest.ts +++ b/src/core/express/resolvePeriodFromRequest.ts @@ -1,10 +1,10 @@ import { Request } from 'express'; import { CYCLIC_API } from '../../constants/cyclic'; -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import resolvePeriodFromURL from './resolvePeriodFromURL'; export default function resolvePeriodFromRequest( - server: RegionDomain, + server: Region, request: Request, ) { return resolvePeriodFromURL(server, `${CYCLIC_API}${request.path}`); diff --git a/src/core/express/resolvePeriodFromURL.ts b/src/core/express/resolvePeriodFromURL.ts index 464e1c904..035f68916 100644 --- a/src/core/express/resolvePeriodFromURL.ts +++ b/src/core/express/resolvePeriodFromURL.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import getPeriodNow from '../blitzstars/getPeriodNow'; import getPeriodStart from '../blitzstars/getPeriodStart'; import getTimeDaysAgo from '../blitzstars/getTimeDaysAgo'; @@ -10,7 +10,7 @@ import { } from '../discord/resolvePeriodFromCommand'; export default function resolvePeriodFromURL( - server: RegionDomain, + server: Region, urlString: string, ) { let statsName: string; diff --git a/src/core/express/resolvePlayerFromURL.ts b/src/core/express/resolvePlayerFromURL.ts index 112e2abb5..421b05cdc 100644 --- a/src/core/express/resolvePlayerFromURL.ts +++ b/src/core/express/resolvePlayerFromURL.ts @@ -1,4 +1,4 @@ -import { RegionDomain } from '../../constants/regions'; +import { Region } from '../../constants/regions'; import { ResolvedPlayer } from '../discord/resolvePlayerFromCommand'; export default function resolvePlayerFromURL(urlString: string) { @@ -6,6 +6,6 @@ export default function resolvePlayerFromURL(urlString: string) { return { id: parseInt(url.searchParams.get('id')!), - server: url.searchParams.get('server') as RegionDomain, + region: url.searchParams.get('server') as Region, } satisfies ResolvedPlayer; } diff --git a/src/events/interactionCreate/handlers/chatInputCommand.ts b/src/events/interactionCreate/handlers/chatInputCommand.ts index f7b1a855d..18b81dcb6 100644 --- a/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -6,6 +6,7 @@ import { ChatInputCommandInteraction, } from 'discord.js'; import { commands } from '..'; +import discord from '../../../../discord.json' assert { type: 'json' }; import embedNegative from '../../../core/discord/embedNegative'; import embedWarning from '../../../core/discord/embedWarning'; import normalizeInteractionReturnable from '../../../core/discord/normalizeInteractionReturnable'; @@ -21,6 +22,19 @@ export default async function handleChatInputCommand( await interaction.deferReply(); try { + if (registry.inPreview && interaction.guildId !== discord.tres_guild_id) { + interaction.editReply({ + embeds: [ + embedWarning( + `\`/${registry.command.name}\` is in Public Preview`, + '[Join the official Discord server](https://discord.gg/nDt7AjGJQH) to gain early access to this command before it is released to the public.', + ), + ], + }); + + return; + } + const returnable = await registry.handler(interaction); if (registry.handlesInteraction) return; diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index af2ba8d27..ef951d1d9 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -23,6 +23,7 @@ import { ownedTanksCommand } from '../../commands/ownedTanks'; import { pingCommand } from '../../commands/ping'; import { playerAchievementsCommand } from '../../commands/playerAchievements'; import { playerInfoCommand } from '../../commands/playerInfo'; +import { ratingsCommand } from '../../commands/ratings'; import { searchClansCommand } from '../../commands/searchClans'; import { searchPlayersCommand } from '../../commands/searchPlayers'; import { searchTanksCommand } from '../../commands/searchTanks'; @@ -56,6 +57,7 @@ export interface Registry { export interface CommandRegistry extends Registry { inPublic: boolean; + inPreview?: boolean; handlesInteraction?: HandlesInteraction; command: | SlashCommandBuilder @@ -88,6 +90,7 @@ export const COMMANDS_RAW: CommandRegistry[] = [ pingCommand, evolutionCommand, statsCommand, + ratingsCommand, ]; export const commands: Record = COMMANDS_RAW.reduce( (accumulator, registry) => { diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index 5300a2619..c6996cbcb 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -3,7 +3,7 @@ import NoData, { NoDataType } from '../components/NoData'; import PoweredBy, { PoweredByType } from '../components/PoweredBy'; import TitleBar from '../components/TitleBar'; import Wrapper from '../components/Wrapper'; -import { REGION_DOMAIN_NAMES } from '../constants/regions'; +import { REGION_NAMES } from '../constants/regions'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; import resolveTankName from '../core/blitz/resolveTankName'; import { tankopedia } from '../core/blitz/tankopedia'; @@ -20,7 +20,7 @@ import { StatType } from './fullStats'; export default async function evolution( type: Type, { start, end, evolutionName }: ResolvedPeriod, - { server, id }: ResolvedPlayer, + { region: server, id }: ResolvedPlayer, tankId: Type extends 'tank' ? number : null, ) { let nameDiscriminator: string | undefined; @@ -89,7 +89,7 @@ export default async function evolution( nameDiscriminator={nameDiscriminator} image={image} description={`${evolutionName} • ${new Date().toDateString()} • ${ - REGION_DOMAIN_NAMES[server] + REGION_NAMES[server] }`} /> diff --git a/src/renderers/fullStats.tsx b/src/renderers/fullStats.tsx index 16957b2bd..21e798190 100644 --- a/src/renderers/fullStats.tsx +++ b/src/renderers/fullStats.tsx @@ -4,7 +4,7 @@ import PoweredBy, { PoweredByType } from '../components/PoweredBy'; import TierWeights, { TierWeightsRecord } from '../components/TierWeights'; import TitleBar from '../components/TitleBar'; import Wrapper from '../components/Wrapper'; -import { REGION_DOMAIN_NAMES } from '../constants/regions'; +import { REGION_NAMES } from '../constants/regions'; import calculateWN8 from '../core/blitz/calculateWN8'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; import resolveTankName from '../core/blitz/resolveTankName'; @@ -28,7 +28,7 @@ export type StatType = 'player' | 'tank'; export default async function fullStats( type: Type, { start, end, statsName }: ResolvedPeriod, - { server, id }: ResolvedPlayer, + { region: server, id }: ResolvedPlayer, tankId: Type extends 'tank' ? number : null, ) { let nameDiscriminator: string | undefined; @@ -143,7 +143,7 @@ export default async function fullStats( nameDiscriminator={nameDiscriminator} image={image} description={`${statsName} • ${new Date().toDateString()} • ${ - REGION_DOMAIN_NAMES[server] + REGION_NAMES[server] }`} /> diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index ed8755d0d..b95db2528 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -4,7 +4,7 @@ import PoweredBy, { PoweredByType } from '../components/PoweredBy'; import { TierWeightsRecord } from '../components/TierWeights'; import TitleBar from '../components/TitleBar'; import Wrapper from '../components/Wrapper'; -import { REGION_DOMAIN_NAMES } from '../constants/regions'; +import { REGION_NAMES } from '../constants/regions'; import calculateWN8 from '../core/blitz/calculateWN8'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; import resolveTankName from '../core/blitz/resolveTankName'; @@ -29,7 +29,7 @@ export type StatType = 'player' | 'tank'; export default async function stats( type: Type, { start, end, statsName }: ResolvedPeriod, - { server, id }: ResolvedPlayer, + { region: server, id }: ResolvedPlayer, tankId: Type extends 'tank' ? number : null, naked = false, ) { @@ -164,7 +164,7 @@ export default async function stats( nameDiscriminator={nameDiscriminator} image={image} description={`${statsName} • ${new Date().toDateString()} • ${ - REGION_DOMAIN_NAMES[server] + REGION_NAMES[server] }`} /> diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index 9928062c3..dd0716979 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -3,7 +3,7 @@ import NoData, { NoDataType } from '../components/NoData'; import PoweredBy, { PoweredByType } from '../components/PoweredBy'; import TitleBar from '../components/TitleBar'; import Wrapper from '../components/Wrapper'; -import { REGION_DOMAIN_NAMES } from '../constants/regions'; +import { REGION_NAMES } from '../constants/regions'; import calculateWN8 from '../core/blitz/calculateWN8'; import getTankStats from '../core/blitz/getTankStats'; import getWargamingResponse from '../core/blitz/getWargamingResponse'; @@ -21,7 +21,7 @@ import { PlayerClanData } from '../types/playerClanData'; import { PossiblyPromise } from '../types/possiblyPromise'; export default async function today( - { server, id }: ResolvedPlayer, + { region: server, id }: ResolvedPlayer, limit = Infinity, naked?: boolean, ) { @@ -162,7 +162,7 @@ export default async function today( : undefined } description={`Today's breakdown • ${new Date().toDateString()} • ${ - REGION_DOMAIN_NAMES[server] + REGION_NAMES[server] }`} />