From 423a8b8088fc8e86e788f20683a8b0270058b9d0 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 5 Jul 2023 01:15:18 +0000 Subject: [PATCH 1/6] feat: added command suffix to commands --- src/commands/debug.ts | 4 +- src/commands/eligible.ts | 4 +- src/commands/evolution.tsx | 6 +- src/commands/help.ts | 4 +- src/commands/inactive.tsx | 4 +- .../{ownedtanks.tsx => ownedTanks.tsx} | 4 +- src/commands/ping.ts | 4 +- ...rachievements.ts => playerAchievements.ts} | 4 +- src/commands/{playerinfo.ts => playerInfo.ts} | 4 +- .../{searchclans.ts => searchClans.ts} | 4 +- .../{searchplayers.ts => searchPlayers.ts} | 4 +- .../{searchtanks.ts => searchTanks.ts} | 4 +- src/commands/stats.tsx | 6 +- src/commands/{statsfull.tsx => statsFull.tsx} | 4 +- src/commands/today.tsx | 4 +- src/commands/verify.ts | 4 +- src/events/interactionCreate/index.ts | 65 +++++++++---------- 17 files changed, 66 insertions(+), 67 deletions(-) rename src/commands/{ownedtanks.tsx => ownedTanks.tsx} (98%) rename src/commands/{playerachievements.ts => playerAchievements.ts} (97%) rename src/commands/{playerinfo.ts => playerInfo.ts} (97%) rename src/commands/{searchclans.ts => searchClans.ts} (97%) rename src/commands/{searchplayers.ts => searchPlayers.ts} (97%) rename src/commands/{searchtanks.ts => searchTanks.ts} (95%) rename src/commands/{statsfull.tsx => statsFull.tsx} (98%) diff --git a/src/commands/debug.ts b/src/commands/debug.ts index 9cfb93357..d3cb7805a 100644 --- a/src/commands/debug.ts +++ b/src/commands/debug.ts @@ -10,7 +10,7 @@ import { CommandRegistry } from '../events/interactionCreate/index.js'; const executionStart = new Date().getTime(); -export default { +export const debugCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -42,4 +42,4 @@ export default { ]), ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 30ec318cf..48312b13f 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -23,7 +23,7 @@ export const SKILLED_CLANS: Record = { SMRI: 'Samurai', }; -export default { +export const eligibleCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: false, @@ -169,4 +169,4 @@ export default { return (isEligible ? embedPositive : embedNegative)(title, body); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 020c60fd5..25e7274dc 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -18,9 +18,9 @@ import evolution from '../renderers/evolution.js'; import { StatType } from '../renderers/statsfull.js'; import { AccountInfo } from '../types/accountInfo.js'; -export default { +export const evolutionCommand: CommandRegistry = { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: addStatTypeSubCommandGroups( @@ -83,4 +83,4 @@ export default { parseInt(url.searchParams.get('tankId')!), ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/help.ts b/src/commands/help.ts index 2ce447da2..408fe78b7 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -8,7 +8,7 @@ import { publicCommands, } from '../events/interactionCreate/index.js'; -export default { +export const helpCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -33,4 +33,4 @@ export default { )}\n\n*I am a new bot; I may make mistakes and go offline unexpectedly from time to time.*`, ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index b5687f3b6..987f6568d 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -16,7 +16,7 @@ import { ClanInfo } from '../types/clanInfo.js'; const DEFAULT_THRESHOLD = 7; -export default { +export const inactiveCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -85,4 +85,4 @@ export default { }, autocomplete: autocompleteClan, -} satisfies CommandRegistry; +}; diff --git a/src/commands/ownedtanks.tsx b/src/commands/ownedTanks.tsx similarity index 98% rename from src/commands/ownedtanks.tsx rename to src/commands/ownedTanks.tsx index a7d9ffd59..66dd7e816 100644 --- a/src/commands/ownedtanks.tsx +++ b/src/commands/ownedTanks.tsx @@ -41,7 +41,7 @@ const COMP_TANKS = [ 6753, // type 71 ]; -export default { +export const ownedTanksCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -121,4 +121,4 @@ export default { }, autocomplete: autocompleteUsername, -} satisfies CommandRegistry; +}; diff --git a/src/commands/ping.ts b/src/commands/ping.ts index bcff65f19..71e2bde94 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -1,7 +1,7 @@ import { SlashCommandBuilder } from 'discord.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; -export default { +export const pingCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -30,4 +30,4 @@ export default { const executionTime = Date.now() - executionStart; interaction.editReply(`Pong 🏓 - ${executionTime}ms`); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/playerachievements.ts b/src/commands/playerAchievements.ts similarity index 97% rename from src/commands/playerachievements.ts rename to src/commands/playerAchievements.ts index 242826988..a0a6d41d9 100644 --- a/src/commands/playerachievements.ts +++ b/src/commands/playerAchievements.ts @@ -16,7 +16,7 @@ import { AccountInfo } from '../types/accountInfo.js'; type SortBy = 'name' | 'count'; -export default { +export const playerAchievementsCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -75,4 +75,4 @@ export default { }, autocomplete: autocompleteUsername, -} satisfies CommandRegistry; +}; diff --git a/src/commands/playerinfo.ts b/src/commands/playerInfo.ts similarity index 97% rename from src/commands/playerinfo.ts rename to src/commands/playerInfo.ts index 7e34552e3..d33e2f06a 100644 --- a/src/commands/playerinfo.ts +++ b/src/commands/playerInfo.ts @@ -10,7 +10,7 @@ import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; -export default { +export const playerInfoCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -57,4 +57,4 @@ export default { }, autocomplete: autocompleteUsername, -} satisfies CommandRegistry; +}; diff --git a/src/commands/searchclans.ts b/src/commands/searchClans.ts similarity index 97% rename from src/commands/searchclans.ts rename to src/commands/searchClans.ts index 56244b025..64980acde 100644 --- a/src/commands/searchclans.ts +++ b/src/commands/searchClans.ts @@ -9,7 +9,7 @@ import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { ClanList } from '../types/clanList.js'; -export default { +export const searchClansCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -44,4 +44,4 @@ export default { .join('\n')}\n\`\`\``, ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/searchplayers.ts b/src/commands/searchPlayers.ts similarity index 97% rename from src/commands/searchplayers.ts rename to src/commands/searchPlayers.ts index fba77980e..4db2f37e4 100644 --- a/src/commands/searchplayers.ts +++ b/src/commands/searchPlayers.ts @@ -10,7 +10,7 @@ import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountList } from '../types/accountList.js'; -export default { +export const searchPlayersCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -52,4 +52,4 @@ export default { }\`\`\``, ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/searchtanks.ts b/src/commands/searchTanks.ts similarity index 95% rename from src/commands/searchtanks.ts rename to src/commands/searchTanks.ts index 76e4157c3..1bb160254 100644 --- a/src/commands/searchtanks.ts +++ b/src/commands/searchTanks.ts @@ -6,7 +6,7 @@ import addTankChoices from '../core/discord/addTankChoices.js'; import embedInfo from '../core/discord/embedInfo.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; -export default { +export const searchTanksCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -37,4 +37,4 @@ export default { : `\`\`\`\n${results.join('\n')}\n\`\`\``, ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 4f29fbda2..e7b4d47a8 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -18,9 +18,9 @@ import stats from '../renderers/stats.js'; import { StatType } from '../renderers/statsfull.js'; import { AccountInfo } from '../types/accountInfo.js'; -export default { +export const statsCommand: CommandRegistry = { inProduction: true, - inDevelopment: true, + inDevelopment: false, inPublic: true, command: addStatTypeSubCommandGroups( @@ -81,4 +81,4 @@ export default { parseInt(url.searchParams.get('tankId')!), ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/statsfull.tsx b/src/commands/statsFull.tsx similarity index 98% rename from src/commands/statsfull.tsx rename to src/commands/statsFull.tsx index 1683abb8d..501e6e511 100644 --- a/src/commands/statsfull.tsx +++ b/src/commands/statsFull.tsx @@ -17,7 +17,7 @@ import { CommandRegistry } from '../events/interactionCreate/index.js'; import statsfull, { StatType } from '../renderers/statsfull.js'; import { AccountInfo } from '../types/accountInfo.js'; -export default { +export const statsFullCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -80,4 +80,4 @@ export default { parseInt(url.searchParams.get('tankId')!), ); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/today.tsx b/src/commands/today.tsx index 950297142..d2a166afd 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -12,7 +12,7 @@ import { CommandRegistry } from '../events/interactionCreate/index.js'; import today from '../renderers/today.js'; import { AccountInfo } from '../types/accountInfo.js'; -export default { +export const todayCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -49,4 +49,4 @@ export default { return await today(player); }, -} satisfies CommandRegistry; +}; diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 5a3e3402c..c3cfb4b59 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -12,7 +12,7 @@ import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; -export default { +export const verifyCommand: CommandRegistry = { inProduction: true, inDevelopment: false, inPublic: true, @@ -80,4 +80,4 @@ export default { }, autocomplete: autocompleteUsername, -} satisfies CommandRegistry; +}; diff --git a/src/events/interactionCreate/index.ts b/src/events/interactionCreate/index.ts index 92e145979..49b3ec1e7 100644 --- a/src/events/interactionCreate/index.ts +++ b/src/events/interactionCreate/index.ts @@ -13,22 +13,22 @@ import { SlashCommandSubcommandsOnlyBuilder, } from 'discord.js'; import discord from '../../../discord.json' assert { type: 'json' }; -import debug from '../../commands/debug.js'; -import eligible from '../../commands/eligible.js'; -import evolution from '../../commands/evolution.js'; -import help from '../../commands/help.js'; -import inactive from '../../commands/inactive.js'; -import ownedtanks from '../../commands/ownedtanks.js'; -import ping from '../../commands/ping.js'; -import playerachievements from '../../commands/playerachievements.js'; -import playerinfo from '../../commands/playerinfo.js'; -import searchclans from '../../commands/searchclans.js'; -import searchplayers from '../../commands/searchplayers.js'; -import searchtanks from '../../commands/searchtanks.js'; -import stats from '../../commands/stats.js'; -import statsfull from '../../commands/statsfull.js'; -import today from '../../commands/today.js'; -import verify from '../../commands/verify.js'; +import { debugCommand } from '../../commands/debug.js'; +import { eligibleCommand } from '../../commands/eligible.js'; +import { evolutionCommand } from '../../commands/evolution.js'; +import { helpCommand } from '../../commands/help.js'; +import { inactiveCommand } from '../../commands/inactive.js'; +import { ownedTanksCommand } from '../../commands/ownedTanks.js'; +import { pingCommand } from '../../commands/ping.js'; +import { playerAchievementsCommand } from '../../commands/playerAchievements.js'; +import { playerInfoCommand } from '../../commands/playerInfo.js'; +import { searchClansCommand } from '../../commands/searchClans.js'; +import { searchPlayersCommand } from '../../commands/searchPlayers.js'; +import { searchTanksCommand } from '../../commands/searchTanks.js'; +import { statsCommand } from '../../commands/stats.js'; +import { statsFullCommand } from '../../commands/statsFull.js'; +import { todayCommand } from '../../commands/today.js'; +import { verifyCommand } from '../../commands/verify.js'; import { DISCORD_TOKEN } from '../../core/node/arguments.js'; import getClientId from '../../core/node/getClientId.js'; import isDev from '../../core/node/isDev.js'; @@ -72,26 +72,25 @@ const rest = new REST().setToken(DISCORD_TOKEN); export const commands: Record = ( [ - debug, - eligible, - help, - inactive, - ownedtanks, - playerachievements, - playerinfo, - searchclans, - searchplayers, - searchtanks, - statsfull, - today, - verify, - ping, - evolution, - stats, + debugCommand, + eligibleCommand, + helpCommand, + inactiveCommand, + ownedTanksCommand, + playerAchievementsCommand, + playerInfoCommand, + searchClansCommand, + searchPlayersCommand, + searchTanksCommand, + statsFullCommand, + todayCommand, + verifyCommand, + pingCommand, + evolutionCommand, + statsCommand, ] as CommandRegistry[] ).reduce((accumulator, registry) => { if (isDev()) registry.command.setDefaultMemberPermissions(0); - return { ...accumulator, [registry.command.name]: registry }; }, {}); From 433ffba1e3c32bde82286bcca4463f5ddeab9834 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 5 Jul 2023 01:16:19 +0000 Subject: [PATCH 2/6] feat: added route suffix to routes --- src/routes/stats.tsx | 4 ++-- src/server.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/stats.tsx b/src/routes/stats.tsx index 3ce638a67..71cd12053 100644 --- a/src/routes/stats.tsx +++ b/src/routes/stats.tsx @@ -3,7 +3,7 @@ import resolvePlayerFromRequest from '../core/express/resolvePlayerFromRequest.j import stats, { StatType } from '../renderers/stats.js'; import { RouteRegistry } from '../server.js'; -export default { +export const statsRoute: RouteRegistry = { route: '/stats/:type/:period', inProduction: true, inDevelopment: false, @@ -21,4 +21,4 @@ export default { true, ); }, -} satisfies RouteRegistry; +}; diff --git a/src/server.ts b/src/server.ts index 660710863..c2ed63b6d 100644 --- a/src/server.ts +++ b/src/server.ts @@ -3,7 +3,7 @@ import normalizeRouteReturnable from './core/express/normalizeRouteReturnable.js import withAutoRefresh from './core/express/withAutoRefresh.js'; import isDev from './core/node/isDev.js'; import { Registry } from './events/interactionCreate/index.js'; -import stats from './routes/stats.js'; +import { statsRoute } from './routes/stats.js'; export type RouteReturnable = JSX.Element | Promise; @@ -20,7 +20,7 @@ export interface RouteRegistry const app = express(); -([stats] as RouteRegistry[]).forEach((registry) => { +([statsRoute] as RouteRegistry[]).forEach((registry) => { if (!(isDev() ? registry.inDevelopment : registry.inProduction)) return; app.get(registry.route, async (req, res) => { From 95b105cb65e36634d2b348ad483d1c8df02fb662 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 5 Jul 2023 01:28:59 +0000 Subject: [PATCH 3/6] fix: stats now handles unowned tanks --- src/commands/evolution.tsx | 2 +- src/commands/stats.tsx | 2 +- src/renderers/stats.tsx | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 25e7274dc..2e467e769 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export const evolutionCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index e7b4d47a8..45702853b 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -20,7 +20,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export const statsCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index bbcfb9629..b11137e8d 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -52,7 +52,7 @@ export default async function stats( } const tankStats = await getTankStatsDiffed(server, id, start, end); - let stats: AllStats; + let stats: AllStats | undefined; let supplementaryStats: SupplementaryStats; let tierWeights: TierWeightsRecord; @@ -117,7 +117,9 @@ export default async function stats( stats = tankStats[tankId!]; supplementaryStats = { - WN8: calculateWN8(tankAverages[tankId!].all, tankStats[tankId!]), + WN8: stats + ? calculateWN8(tankAverages[tankId!].all, tankStats[tankId!]) + : undefined, tier: tankopedia[tankId!].tier, }; } @@ -154,8 +156,8 @@ export default async function stats( }`} /> - {stats.battles === 0 && } - {stats.battles > 0 && overview} + {!stats?.battles && } + {stats?.battles > 0 && overview} From 00b721f34f77483e0742d5cd46b3e873eb1c0a93 Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 5 Jul 2023 02:09:36 +0000 Subject: [PATCH 4/6] feat: moved tankopedia and tankaverages into a runtime cache --- scripts/build.js | 25 +----- src/commands/debug.ts | 8 +- src/commands/eligible.ts | 74 +++++++++++------- src/commands/evolution.tsx | 2 +- src/commands/help.ts | 2 +- src/commands/inactive.tsx | 2 +- src/commands/ownedTanks.tsx | 10 ++- src/commands/ping.ts | 2 +- src/commands/playerAchievements.ts | 2 +- src/commands/playerInfo.ts | 2 +- src/commands/searchClans.ts | 2 +- src/commands/searchPlayers.ts | 2 +- src/commands/searchTanks.ts | 2 +- src/commands/stats.tsx | 3 +- src/commands/statsFull.tsx | 5 +- src/commands/today.tsx | 2 +- src/commands/verify.ts | 2 +- src/core/blitz/resolveTankId.ts | 4 +- src/core/blitz/resolveTankName.ts | 4 +- src/core/blitz/tankopedia.ts | 15 ++-- src/core/blitzstars/playerAverage.ts | 2 +- src/core/blitzstars/tankAverages.ts | 24 ++++-- src/core/discord/autocompleteTanks.ts | 18 +++-- src/renderers/evolution.tsx | 4 +- src/renderers/stats.tsx | 88 +++++++++++---------- src/renderers/statsfull.tsx | 88 +++++++++++---------- src/renderers/today.tsx | 106 +++++++++++++------------- src/routes/stats.tsx | 2 +- src/types/possiblyPromise.ts | 1 + 29 files changed, 268 insertions(+), 235 deletions(-) create mode 100644 src/types/possiblyPromise.ts diff --git a/scripts/build.js b/scripts/build.js index 49774e78b..a49c88c09 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,5 +1,5 @@ import { build } from 'esbuild'; -import { copyFile, mkdir, rm, writeFile } from 'fs/promises'; +import { copyFile, mkdir, rm } from 'fs/promises'; import { argv } from 'process'; const isProd = !argv.includes('--dev'); @@ -17,29 +17,6 @@ if (isProd) { await mkdir('dist'); console.log('✅ Dist created'); - console.log('🟡 Caching tankopedia...'); - fetch('https://www.blitzstars.com/bs-tankopedia.json') - .then((response) => response.text()) - .then((tankopedia) => writeFile('./dist/tankopedia.json', tankopedia)) - .then(() => console.log('✅ Tankopedia cached')); - - console.log('🟡 Caching tank averages...'); - fetch('https://www.blitzstars.com/api/tankaverages.json') - .then((response) => response.json()) - .then((individualTankAverages) => { - const tankAverages = {}; - - individualTankAverages.forEach((individualTankAverage) => { - tankAverages[individualTankAverage.tank_id] = individualTankAverage; - }); - - return writeFile( - './dist/tankaverages.json', - JSON.stringify(tankAverages), - ); - }) - .then(() => console.log('✅ Tank averages cached')); - console.log('🟡 Copying package.json...'); copyFile('package.dist.json', 'dist/package.json').then(() => console.log('✅ package.json copied'), diff --git a/src/commands/debug.ts b/src/commands/debug.ts index d3cb7805a..77af7954d 100644 --- a/src/commands/debug.ts +++ b/src/commands/debug.ts @@ -12,14 +12,14 @@ const executionStart = new Date().getTime(); export const debugCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() .setName('debug') .setDescription('Debug information about the bot'), - handler(interaction) { + async handler(interaction) { const currentTime = new Date().getTime(); const uptime = currentTime - executionStart; @@ -37,8 +37,8 @@ export const debugCommand: CommandRegistry = { (uptime / 1000) % 60, )}s ${Math.floor(uptime % 1000)}ms`, ], - ['Tankopedia cached', `${tankopedia !== undefined}`], - ['Tank averages cached', `${tankAverages !== undefined}`], + ['Tankopedia cached', `${(await tankopedia) !== undefined}`], + ['Tank averages cached', `${(await tankAverages) !== undefined}`], ]), ); }, diff --git a/src/commands/eligible.ts b/src/commands/eligible.ts index 48312b13f..52e0a4177 100644 --- a/src/commands/eligible.ts +++ b/src/commands/eligible.ts @@ -15,6 +15,7 @@ import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand.j import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { CommandRegistry } from '../events/interactionCreate/index.js'; import { AccountInfo } from '../types/accountInfo.js'; +import { PossiblyPromise } from '../types/possiblyPromise.js'; export type SkilledClan = 'SKLLD' | 'SMRI'; @@ -25,7 +26,7 @@ export const SKILLED_CLANS: Record = { export const eligibleCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: false, command: new SlashCommandBuilder() @@ -67,41 +68,56 @@ export const eligibleCommand: CommandRegistry = { const entries = Object.entries(tankStatsOverTime); const stats = sumStats(entries.map(([, stats]) => stats)); const averageTier = - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankTier = tankopedia[tankId].tier; + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankTier = (await tankopedia)[tankId].tier; - return accumulator + tankTier * stats.battles; - }, 0) / stats.battles; + return (await accumulator) + tankTier * stats.battles; + }, + 0, + )) / stats.battles; const WN8 = - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); - // edge case where new tanks don't have averages - if (tankAverages[tankId]) { - const tankWN8 = calculateWN8(tankAverages[tankId].all, stats); + // edge case where new tanks don't have averages + if ((await tankAverages)[tankId]) { + const tankWN8 = calculateWN8( + (await tankAverages)[tankId].all, + stats, + ); - if (isNaN(tankWN8)) return accumulator; - return accumulator + tankWN8 * stats.battles; - } else return accumulator; - }, 0) / stats.battles; + if (isNaN(tankWN8)) return accumulator; + return (await accumulator) + tankWN8 * stats.battles; + } else return accumulator; + }, + 0, + )) / stats.battles; const tier10Damage = - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); - if (tankopedia[tankId]?.tier === 10) { - const tankStats = tankStatsOverTime[tankId]; - return accumulator + tankStats.damage_dealt; - } else return accumulator; - }, 0) / - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); + if ((await tankopedia)[tankId]?.tier === 10) { + const tankStats = tankStatsOverTime[tankId]; + return (await accumulator) + tankStats.damage_dealt; + } else return accumulator; + }, + 0, + )) / + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); - if (tankopedia[tankId]?.tier === 10) { - const tankStats = tankStatsOverTime[tankId]; - return accumulator + tankStats.battles; - } else return accumulator; - }, 0); + if ((await tankopedia)[tankId]?.tier === 10) { + const tankStats = tankStatsOverTime[tankId]; + return (await accumulator) + tankStats.battles; + } else return accumulator; + }, + 0, + )); if (stats.battles < 126) { problems.push(['Battles', `${stats.battles} (${stats.battles - 126})`]); diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 2e467e769..3187aab66 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -36,7 +36,7 @@ export const evolutionCommand: CommandRegistry = { const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; - const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null; + const tankId = commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; const start = interaction.options.getInteger('start'); const end = interaction.options.getInteger('end'); const { nickname } = ( diff --git a/src/commands/help.ts b/src/commands/help.ts index 408fe78b7..164acd3df 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -10,7 +10,7 @@ import { export const helpCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/inactive.tsx b/src/commands/inactive.tsx index 987f6568d..0dc891f13 100644 --- a/src/commands/inactive.tsx +++ b/src/commands/inactive.tsx @@ -18,7 +18,7 @@ const DEFAULT_THRESHOLD = 7; export const inactiveCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/ownedTanks.tsx b/src/commands/ownedTanks.tsx index 66dd7e816..2d63ca6bd 100644 --- a/src/commands/ownedTanks.tsx +++ b/src/commands/ownedTanks.tsx @@ -43,7 +43,7 @@ const COMP_TANKS = [ export const ownedTanksCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() @@ -77,9 +77,11 @@ export const ownedTanksCommand: CommandRegistry = { `https://api.wotblitz.${server}/wotb/account/info/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); const tankStats = await getTankStats(server, id); - const tanks = tankStats - .map((tankData) => tankopedia[tankData.tank_id]) - .filter((tank) => tank?.tier === tier); + const tanks = ( + await Promise.all( + tankStats.map(async (tankData) => (await tankopedia)[tankData.tank_id]), + ) + ).filter((tank) => tank?.tier === tier); const clanData = await getWargamingResponse( `https://api.wotblitz.${server}/wotb/clans/accountinfo/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}&extra=clan`, ); diff --git a/src/commands/ping.ts b/src/commands/ping.ts index 71e2bde94..bcaa52371 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -3,7 +3,7 @@ import { CommandRegistry } from '../events/interactionCreate/index.js'; export const pingCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, handlesInteraction: true, diff --git a/src/commands/playerAchievements.ts b/src/commands/playerAchievements.ts index a0a6d41d9..fcd9c9a75 100644 --- a/src/commands/playerAchievements.ts +++ b/src/commands/playerAchievements.ts @@ -18,7 +18,7 @@ type SortBy = 'name' | 'count'; export const playerAchievementsCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/playerInfo.ts b/src/commands/playerInfo.ts index d33e2f06a..67ddcf1fa 100644 --- a/src/commands/playerInfo.ts +++ b/src/commands/playerInfo.ts @@ -12,7 +12,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export const playerInfoCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/searchClans.ts b/src/commands/searchClans.ts index 64980acde..18bdc8f00 100644 --- a/src/commands/searchClans.ts +++ b/src/commands/searchClans.ts @@ -11,7 +11,7 @@ import { ClanList } from '../types/clanList.js'; export const searchClansCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/searchPlayers.ts b/src/commands/searchPlayers.ts index 4db2f37e4..870342c7a 100644 --- a/src/commands/searchPlayers.ts +++ b/src/commands/searchPlayers.ts @@ -12,7 +12,7 @@ import { AccountList } from '../types/accountList.js'; export const searchPlayersCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/searchTanks.ts b/src/commands/searchTanks.ts index 1bb160254..144d2f54a 100644 --- a/src/commands/searchTanks.ts +++ b/src/commands/searchTanks.ts @@ -8,7 +8,7 @@ import { CommandRegistry } from '../events/interactionCreate/index.js'; export const searchTanksCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 45702853b..9a8e4e59f 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -36,7 +36,8 @@ export const statsCommand: CommandRegistry = { const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; - const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null; + const tankId = + commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; const start = interaction.options.getInteger('start'); const end = interaction.options.getInteger('end'); const path = interactionToURL(interaction, { diff --git a/src/commands/statsFull.tsx b/src/commands/statsFull.tsx index 501e6e511..180cc59f6 100644 --- a/src/commands/statsFull.tsx +++ b/src/commands/statsFull.tsx @@ -19,7 +19,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export const statsFullCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: addStatTypeSubCommandGroups( @@ -35,7 +35,8 @@ export const statsFullCommand: CommandRegistry = { const player = await resolvePlayerFromCommand(interaction); const period = resolvePeriodFromCommand(interaction); const tankIdRaw = interaction.options.getString('tank')!; - const tankId = commandGroup === 'tank' ? resolveTankId(tankIdRaw) : null; + const tankId = + commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; const start = interaction.options.getInteger('start'); const end = interaction.options.getInteger('end'); const path = interactionToURL(interaction, { diff --git a/src/commands/today.tsx b/src/commands/today.tsx index d2a166afd..613014928 100644 --- a/src/commands/today.tsx +++ b/src/commands/today.tsx @@ -14,7 +14,7 @@ import { AccountInfo } from '../types/accountInfo.js'; export const todayCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/commands/verify.ts b/src/commands/verify.ts index c3cfb4b59..0dc4aa4a5 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -14,7 +14,7 @@ import { PlayerClanData } from '../types/playerClanData.js'; export const verifyCommand: CommandRegistry = { inProduction: true, - inDevelopment: false, + inDevelopment: true, inPublic: true, command: new SlashCommandBuilder() diff --git a/src/core/blitz/resolveTankId.ts b/src/core/blitz/resolveTankId.ts index 89da65c1d..ddbe33b66 100644 --- a/src/core/blitz/resolveTankId.ts +++ b/src/core/blitz/resolveTankId.ts @@ -2,7 +2,7 @@ import { go } from 'fuzzysort'; import throwError from '../node/throwError.js'; import { TANKS, tankopedia } from './tankopedia.js'; -export default function resolveTankId(tank: string) { +export default async function resolveTankId(tank: string) { const number = parseInt(tank); if (Number.isNaN(number)) { @@ -17,7 +17,7 @@ export default function resolveTankId(tank: string) { return searchResult[0].obj.tank_id; } } else { - if (tankopedia[number]) { + if ((await tankopedia)[number]) { return number; } else { throw throwError( diff --git a/src/core/blitz/resolveTankName.ts b/src/core/blitz/resolveTankName.ts index 2f97fdb7f..51ca38cea 100644 --- a/src/core/blitz/resolveTankName.ts +++ b/src/core/blitz/resolveTankName.ts @@ -1,6 +1,6 @@ import { tankopedia } from './tankopedia.js'; -export default function resolveTankName(tankId: number) { - const tankopediaName = tankopedia[tankId].name; +export default async function resolveTankName(tankId: number) { + const tankopediaName = (await tankopedia)[tankId].name; return tankopediaName ? tankopediaName : `Unknown Tank ${tankId}`; } diff --git a/src/core/blitz/tankopedia.ts b/src/core/blitz/tankopedia.ts index 6e0b2678e..981a59002 100644 --- a/src/core/blitz/tankopedia.ts +++ b/src/core/blitz/tankopedia.ts @@ -1,6 +1,3 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; - export type TankType = 'AT-SPG' | 'lightTank' | 'mediumTank' | 'heavyTank'; export interface TankopediaEntry { @@ -19,11 +16,13 @@ export interface Tankopedia { [id: number]: TankopediaEntry; } -export const tankopedia = ( - JSON.parse( - readFileSync(join(__dirname, 'tankopedia.json')) as unknown as string, - ) as { data: Tankopedia } -).data; +console.log('Caching tankopedia...'); +export const tankopedia = fetch('https://www.blitzstars.com/bs-tankopedia.json') + .then((response) => response.json()) + .then((wrapperTankopedia) => { + console.log('Tankopedia cached'); + return (wrapperTankopedia as { data: Tankopedia }).data; + }); const entries = Object.entries(tankopedia); export const TANK_IDS = entries.map(([, { tank_id }]) => tank_id as number); export const TANKS = entries.map(([, entry]) => entry as TankopediaEntry); diff --git a/src/core/blitzstars/playerAverage.ts b/src/core/blitzstars/playerAverage.ts index a2315adb1..f2206d83c 100644 --- a/src/core/blitzstars/playerAverage.ts +++ b/src/core/blitzstars/playerAverage.ts @@ -3,7 +3,7 @@ import { emptyAllStats } from './getTankStatsDiffed.js'; import { tankAverages } from './tankAverages.js'; console.log('Calculating player average...'); -export const playerAverage = Object.entries(tankAverages).reduce( +export const playerAverage = Object.entries(await tankAverages).reduce( (accumulator, [, tankAverage]) => { return sumStats([accumulator, tankAverage.all]); }, diff --git a/src/core/blitzstars/tankAverages.ts b/src/core/blitzstars/tankAverages.ts index b5858a13b..84733e336 100644 --- a/src/core/blitzstars/tankAverages.ts +++ b/src/core/blitzstars/tankAverages.ts @@ -1,5 +1,3 @@ -import { readFileSync } from 'fs'; -import { join } from 'path'; import { AllStats } from '../../types/accountInfo.js'; export interface SpecialStats { @@ -82,6 +80,22 @@ export interface IndividualTankAverage { export type TankAverages = Record; -export const tankAverages = JSON.parse( - readFileSync(join(__dirname, 'tankaverages.json')) as unknown as string, -) as TankAverages; +console.log('Caching tank averages...'); +export const tankAverages = fetch( + 'https://www.blitzstars.com/api/tankaverages.json', +) + .then((response) => response.json()) + .then((individualTankAverages) => { + const partialTankAverages: TankAverages = {}; + + (individualTankAverages as IndividualTankAverage[]).forEach( + (individualTankAverage) => { + partialTankAverages[individualTankAverage.tank_id] = + individualTankAverage; + }, + ); + + console.log('Tank averages cached'); + + return partialTankAverages; + }); diff --git a/src/core/discord/autocompleteTanks.ts b/src/core/discord/autocompleteTanks.ts index 8b45d8022..46fa638bc 100644 --- a/src/core/discord/autocompleteTanks.ts +++ b/src/core/discord/autocompleteTanks.ts @@ -15,14 +15,16 @@ export default async function autocompleteTanks( await interaction.respond( focusedOption.value - ? go(focusedOption.value, TANKS, { keys: ['name'], limit: 10 }).map( - (item) => - ({ - name: item.obj.name - ? item.obj.name - : resolveTankName(item.obj.tank_id), - value: `${item.obj.tank_id}`, - } satisfies ApplicationCommandOptionChoiceData), + ? await Promise.all( + go(focusedOption.value, TANKS, { keys: ['name'], limit: 10 }).map( + async (item) => + ({ + name: item.obj.name + ? item.obj.name + : await resolveTankName(item.obj.tank_id), + value: `${item.obj.tank_id}`, + } satisfies ApplicationCommandOptionChoiceData), + ), ) : [], ); diff --git a/src/renderers/evolution.tsx b/src/renderers/evolution.tsx index 0ccac742f..153d1a60b 100644 --- a/src/renderers/evolution.tsx +++ b/src/renderers/evolution.tsx @@ -38,8 +38,8 @@ export default async function evolution( ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` : undefined; } else { - nameDiscriminator = `(${resolveTankName(tankId!)})`; - image = tankopedia[tankId!].images.normal; + nameDiscriminator = `(${await resolveTankName(tankId!)})`; + image = (await tankopedia)[tankId!].images.normal; } let histories: Histories; diff --git a/src/renderers/stats.tsx b/src/renderers/stats.tsx index b11137e8d..03e0ef12f 100644 --- a/src/renderers/stats.tsx +++ b/src/renderers/stats.tsx @@ -22,6 +22,7 @@ import { SupplementaryStats, } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; +import { PossiblyPromise } from '../types/possiblyPromise.js'; export type StatType = 'player' | 'tank'; @@ -47,8 +48,8 @@ export default async function stats( ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` : undefined; } else if (type === 'tank') { - nameDiscriminator = `(${resolveTankName(tankId!)})`; - image = tankopedia[tankId!].images.normal; + nameDiscriminator = `(${await resolveTankName(tankId!)})`; + image = (await tankopedia)[tankId!].images.normal; } const tankStats = await getTankStatsDiffed(server, id, start, end); @@ -59,54 +60,61 @@ export default async function stats( if (type === 'player') { const entries = Object.entries(tankStats); stats = sumStats(entries.map(([, stats]) => stats)); - const battlesOfTanksWithAverages = entries.reduce( - (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankAverage = tankAverages[tankId]; + const battlesOfTanksWithAverages = await entries.reduce< + PossiblyPromise + >(async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankAverage = (await tankAverages)[tankId]; - return tankAverage ? accumulator + stats.battles : accumulator; - }, - 0, - ); - const battlesOfTanksWithTankopediaEntry = entries.reduce( - (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankopediaEntry = tankopedia[tankId]; + return tankAverage ? (await accumulator) + stats.battles : accumulator; + }, 0); + const battlesOfTanksWithTankopediaEntry = await entries.reduce< + PossiblyPromise + >(async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankopediaEntry = (await tankopedia)[tankId]; - return tankopediaEntry ? accumulator + stats.battles : accumulator; - }, - 0, - ); + return tankopediaEntry + ? (await accumulator) + stats.battles + : accumulator; + }, 0); supplementaryStats = { WN8: - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankAverage = tankAverages[tankId]; + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankAverage = (await tankAverages)[tankId]; - return tankAverage - ? accumulator + calculateWN8(tankAverage.all, stats) * stats.battles - : accumulator; - }, 0) / battlesOfTanksWithAverages, + return tankAverage + ? (await accumulator) + + calculateWN8(tankAverage.all, stats) * stats.battles + : accumulator; + }, + 0, + )) / battlesOfTanksWithAverages, tier: - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankopediaEntry = tankopedia[tankId]; + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankopediaEntry = (await tankopedia)[tankId]; - return tankopediaEntry - ? accumulator + tankopediaEntry.tier * stats.battles - : accumulator; - }, 0) / battlesOfTanksWithTankopediaEntry, + return tankopediaEntry + ? (await accumulator) + tankopediaEntry.tier * stats.battles + : accumulator; + }, + 0, + )) / battlesOfTanksWithTankopediaEntry, }; - tierWeights = entries.reduce( - (accumulator, [tankIdString, stats]) => { + tierWeights = await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { const tankId = parseInt(tankIdString); - const tier = tankopedia[tankId].tier as Tier; + const tier = (await tankopedia)[tankId].tier as Tier; - if (accumulator[tier]) { - accumulator[tier]! += stats.battles; + if ((await accumulator)[tier]) { + (await accumulator)[tier]! += stats.battles; } else { - accumulator[tier] = stats.battles; + (await accumulator)[tier] = stats.battles; } return accumulator; @@ -118,9 +126,9 @@ export default async function stats( supplementaryStats = { WN8: stats - ? calculateWN8(tankAverages[tankId!].all, tankStats[tankId!]) + ? calculateWN8((await tankAverages)[tankId!].all, tankStats[tankId!]) : undefined, - tier: tankopedia[tankId!].tier, + tier: (await tankopedia)[tankId!].tier, }; } diff --git a/src/renderers/statsfull.tsx b/src/renderers/statsfull.tsx index a5617a208..1c867f9f9 100644 --- a/src/renderers/statsfull.tsx +++ b/src/renderers/statsfull.tsx @@ -21,6 +21,7 @@ import { SupplementaryStats, } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; +import { PossiblyPromise } from '../types/possiblyPromise.js'; export type StatType = 'player' | 'tank'; @@ -45,8 +46,8 @@ export default async function statsfull( ? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png` : undefined; } else if (type === 'tank') { - nameDiscriminator = `(${resolveTankName(tankId!)})`; - image = tankopedia[tankId!].images.normal; + nameDiscriminator = `(${await resolveTankName(tankId!)})`; + image = (await tankopedia)[tankId!].images.normal; } const tankStats = await getTankStatsDiffed(server, id, start, end); @@ -57,54 +58,61 @@ export default async function statsfull( if (type === 'player') { const entries = Object.entries(tankStats); stats = sumStats(entries.map(([, stats]) => stats)); - const battlesOfTanksWithAverages = entries.reduce( - (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankAverage = tankAverages[tankId]; + const battlesOfTanksWithAverages = await entries.reduce< + PossiblyPromise + >(async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankAverage = (await tankAverages)[tankId]; - return tankAverage ? accumulator + stats.battles : accumulator; - }, - 0, - ); - const battlesOfTanksWithTankopediaEntry = entries.reduce( - (accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankopediaEntry = tankopedia[tankId]; + return tankAverage ? (await accumulator) + stats.battles : accumulator; + }, 0); + const battlesOfTanksWithTankopediaEntry = await entries.reduce< + PossiblyPromise + >(async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankopediaEntry = (await tankopedia)[tankId]; - return tankopediaEntry ? accumulator + stats.battles : accumulator; - }, - 0, - ); + return tankopediaEntry + ? (await accumulator) + stats.battles + : accumulator; + }, 0); supplementaryStats = { WN8: - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankAverage = tankAverages[tankId]; + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankAverage = (await tankAverages)[tankId]; - return tankAverage - ? accumulator + calculateWN8(tankAverage.all, stats) * stats.battles - : accumulator; - }, 0) / battlesOfTanksWithAverages, + return tankAverage + ? (await accumulator) + + calculateWN8(tankAverage.all, stats) * stats.battles + : accumulator; + }, + 0, + )) / battlesOfTanksWithAverages, tier: - entries.reduce((accumulator, [tankIdString, stats]) => { - const tankId = parseInt(tankIdString); - const tankopediaEntry = tankopedia[tankId]; + (await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { + const tankId = parseInt(tankIdString); + const tankopediaEntry = (await tankopedia)[tankId]; - return tankopediaEntry - ? accumulator + tankopediaEntry.tier * stats.battles - : accumulator; - }, 0) / battlesOfTanksWithTankopediaEntry, + return tankopediaEntry + ? (await accumulator) + tankopediaEntry.tier * stats.battles + : accumulator; + }, + 0, + )) / battlesOfTanksWithTankopediaEntry, }; - tierWeights = entries.reduce( - (accumulator, [tankIdString, stats]) => { + tierWeights = await entries.reduce>( + async (accumulator, [tankIdString, stats]) => { const tankId = parseInt(tankIdString); - const tier = tankopedia[tankId].tier as Tier; + const tier = (await tankopedia)[tankId].tier as Tier; - if (accumulator[tier]) { - accumulator[tier]! += stats.battles; + if ((await accumulator)[tier]) { + (await accumulator)[tier]! += stats.battles; } else { - accumulator[tier] = stats.battles; + (await accumulator)[tier] = stats.battles; } return accumulator; @@ -115,8 +123,8 @@ export default async function statsfull( stats = tankStats[tankId!]; supplementaryStats = { - WN8: calculateWN8(tankAverages[tankId!].all, tankStats[tankId!]), - tier: tankopedia[tankId!].tier, + WN8: calculateWN8((await tankAverages)[tankId!].all, tankStats[tankId!]), + tier: (await tankopedia)[tankId!].tier, }; } diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index 021274e04..cd7f99a04 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -18,6 +18,7 @@ import { ResolvedPlayer } from '../core/discord/resolvePlayerFromCommand.js'; import { WARGAMING_APPLICATION_ID } from '../core/node/arguments.js'; import { AccountInfo, AllStats } from '../types/accountInfo.js'; import { PlayerClanData } from '../types/playerClanData.js'; +import { PossiblyPromise } from '../types/possiblyPromise.js'; export default async function today({ server, id }: ResolvedPlayer) { const tankStatsOverTime = await getTankStatsDiffed( @@ -52,33 +53,31 @@ export default async function today({ server, id }: ResolvedPlayer) { } const tankStatsOverTimeEntries = Object.entries(tankStatsOverTime); - const todayWN8s = tankStatsOverTimeEntries.reduce>( - (accumulator, [tankIdString, tankStats]) => { - const tankId = Number(tankIdString); + const todayWN8s = await tankStatsOverTimeEntries.reduce< + PossiblyPromise> + >(async (accumulator, [tankIdString, tankStats]) => { + const tankId = Number(tankIdString); - return tankId === 0 || tankAverages[tankId] === undefined - ? accumulator - : { - ...accumulator, - [tankId]: calculateWN8(tankAverages[tankId].all, tankStats), - }; - }, - {}, - ); - const careerWN8s = careerTankStatsRaw.reduce>( - (accumulator, { tank_id }) => { - return tank_id === 0 || tankAverages[tank_id] === undefined - ? accumulator - : { - ...accumulator, - [tank_id]: calculateWN8( - tankAverages[tank_id].all, - careerStats[tank_id], - ), - }; - }, - {}, - ); + return tankId === 0 || (await tankAverages)[tankId] === undefined + ? accumulator + : { + ...accumulator, + [tankId]: calculateWN8((await tankAverages)[tankId].all, tankStats), + }; + }, {}); + const careerWN8s = await careerTankStatsRaw.reduce< + PossiblyPromise> + >(async (accumulator, { tank_id }) => { + return tank_id === 0 || (await tankAverages)[tank_id] === undefined + ? accumulator + : { + ...accumulator, + [tank_id]: calculateWN8( + (await tankAverages)[tank_id].all, + careerStats[tank_id], + ), + }; + }, {}); const todayWN8sEntries = Object.entries(todayWN8s); const careerWN8sEntries = Object.entries(careerWN8s); @@ -109,32 +108,37 @@ export default async function today({ server, id }: ResolvedPlayer) { 0, ); - const rows = tankStatsOverTimeEntries.map(([tankIdString, tankStats]) => { - const tankId = Number(tankIdString); - const career = careerStats[tankId]; + const rows = await Promise.all( + tankStatsOverTimeEntries.map(async ([tankIdString, tankStats]) => { + const tankId = Number(tankIdString); + const career = careerStats[tankId]; - return ( - - ); - }); + return ( + + ); + }), + ); return ( diff --git a/src/routes/stats.tsx b/src/routes/stats.tsx index 71cd12053..43216240d 100644 --- a/src/routes/stats.tsx +++ b/src/routes/stats.tsx @@ -6,7 +6,7 @@ import { RouteRegistry } from '../server.js'; export const statsRoute: RouteRegistry = { route: '/stats/:type/:period', inProduction: true, - inDevelopment: false, + inDevelopment: true, async handler(req) { const type = req.params.type as StatType; diff --git a/src/types/possiblyPromise.ts b/src/types/possiblyPromise.ts new file mode 100644 index 000000000..005f03fa7 --- /dev/null +++ b/src/types/possiblyPromise.ts @@ -0,0 +1 @@ +export type PossiblyPromise = Promise | Type; \ No newline at end of file From 604e356736d19baf0bd568d5abf5f2e81f09259f Mon Sep 17 00:00:00 2001 From: tresabhi Date: Wed, 5 Jul 2023 02:15:28 +0000 Subject: [PATCH 5/6] feat: changelogs --- docs/changelogs/1.9.3.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/changelogs/1.9.3.md diff --git a/docs/changelogs/1.9.3.md b/docs/changelogs/1.9.3.md new file mode 100644 index 000000000..3a6468658 --- /dev/null +++ b/docs/changelogs/1.9.3.md @@ -0,0 +1,14 @@ +# Blitzkrieg 1.9.3 + +A few fixes before we tackle the next major release. + +## Fixes + +- `/stats`, `/evolution`, and `/statsfull` now properly handle unowned or unplayed tanks + +## Technical Changes + +- Added a `Command` suffix after all command exports +- Added a `Route` suffix after all route exports +- Moved `tankopedia` and `tankaverages` into a runtime cache + - But, this time, it's a promise so we get the best of both worlds From cf291c89a27158c70453f7f384d514128da0cb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 4 Jul 2023 21:17:21 -0500 Subject: [PATCH 6/6] feat: version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e462a2cca..e41d802c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkrieg", - "version": "1.9.0", + "version": "1.9.3", "description": "", "main": "src/server.ts", "type": "module",