diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index 250cd6706..3b7757240 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -2,7 +2,6 @@ name: CD Build Assets on: push: - branches: [dev, main] workflow_dispatch: schedule: - cron: '0 0 * * *' @@ -18,6 +17,9 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + submodules: recursive + token: ${{ secrets.GH_TOKEN }} - name: Use node uses: actions/setup-node@v4 @@ -46,6 +48,14 @@ jobs: - name: Run DepotDownloader run: ./temp/depotDownloader/DepotDownloader.exe -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" + - name: Apply patches + run: | + $env:GH_TOKEN = "${{ secrets.GH_TOKEN }}" + $env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}" + $env:DISCORD_BLITZ_DB = "${{ secrets.DISCORD_BLITZ_DB }}" + $env:WOTB_DLC_CDN = "${{ secrets.WOTB_DLC_CDN }}" + yarn setup:patches --depot + - name: Build assets run: | $env:GH_TOKEN = "${{ secrets.GH_TOKEN }}" diff --git a/.github/workflows/cd-host.yml b/.github/workflows/cd-host.yml index 435540fb6..b75d31c4a 100644 --- a/.github/workflows/cd-host.yml +++ b/.github/workflows/cd-host.yml @@ -6,6 +6,8 @@ on: schedule: - cron: '0 */5 * * *' workflow_dispatch: + release: + types: [created, published, released, edited] concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.gitignore b/.gitignore index 3464b9cc4..7dc3942e0 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ tsconfig.tsbuildinfo temp/ /.yarn /.VSCodeCounter -/.yarn \ No newline at end of file +/.yarn +depots \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index b72b99f10..8c41337cf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,6 +7,7 @@ "alphatest", "APAC", "apcr", + "applypatches", "artefacts", "atgm", "AYUV", @@ -21,6 +22,7 @@ "CDON", "classname", "cleandist", + "closedkrieg", "cockroackdb", "Coef", "cooldown", diff --git a/docs/changelogs/1.16.4.md b/docs/changelogs/1.16.4.md new file mode 100644 index 000000000..ec81946b8 --- /dev/null +++ b/docs/changelogs/1.16.4.md @@ -0,0 +1,19 @@ +# Blitzkrieg 1.16.4 + +A few issues here and there addressed for good measure. + +## Changes + +- Armor layer penetration indices are now much more compact. + +## Fixes + +- Reverted splash mechanics changes from `1.16.1` as it made them less accurate. +- Auto-reloaders now report their DPM stats correctly with crew training. + +## Technical Changes + +- All files in the project were reviewed and constant exports were isolated. +- The downloaded game in the workflow now also includes the latest patches. +- Asset building now uses sharp under the hood which should in theory be faster. +- Fetching CDON LZ4 files now uses `no-store` instead of `no-cache` diff --git a/package.json b/package.json index b4f9ff3f3..3546cc0e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkrieg", - "version": "1.16.2", + "version": "1.16.4", "description": "🎉 Tools for everything World of Tanks Blitz", "main": "src/server.ts", "type": "module", @@ -19,6 +19,7 @@ "start:website": "next start", "host:docs": "vitepress preview docs", "publish:ratingsleaderboard": "vite-node --script scripts/buildRatingsLeaderboard --publish", + "setup:patches": "vite-node --script scripts/applyPatches", "lint": "npx tsc", "lint:website": "next lint", "format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"", diff --git a/scripts/applyPatches.ts b/scripts/applyPatches.ts new file mode 100644 index 000000000..7c2b51fe1 --- /dev/null +++ b/scripts/applyPatches.ts @@ -0,0 +1,48 @@ +import { mkdir, writeFile } from 'fs/promises'; +import { parse as parsePath } from 'path'; +import { parse as parseYaml } from 'yaml'; +import { readStringDVPL } from '../src/core/blitz/readStringDVPL'; +import { writeDVPL } from '../src/core/blitz/writeDVPL'; +import { secrets } from '../src/core/blitzkrieg/secrets'; +import { dvp } from '../submodules/closedkrieg/src/dvp'; +import { DATA } from './buildAssets/constants'; + +const versionTextFile = await readStringDVPL(`${DATA}/version.txt.dvpl`); +const currentVersion = versionTextFile + .split(' ')[0] + .split('.') + .slice(0, 3) + .join('.'); + +console.log(`Installing patches for ${currentVersion}...`); + +let patchIndex = 1; +while (true) { + const response = await fetch( + `${secrets.WOTB_DLC_CDN}/dlc/s${currentVersion}_${patchIndex}.yaml`, + ); + + if (response.status === 200) { + console.log(`Applying patch ${patchIndex}...`); + + const data = parseYaml(await response.text()); + const dvpm = await fetch(`${secrets.WOTB_DLC_CDN}/dlc/${data.dx11}`).then( + (response) => response.arrayBuffer(), + ); + const dvpd = await fetch( + `${secrets.WOTB_DLC_CDN}/dlc/${data.dx11.replace('.dvpm', '.dvpd')}`, + ).then((response) => response.arrayBuffer()); + const files = await dvp(dvpm, dvpd); + + await Promise.all( + files.map(async ({ path, data }) => { + const { dir } = parsePath(path); + + await mkdir(`${DATA}/${dir}`, { recursive: true }); + await writeFile(`${DATA}/${path}.dvpl`, writeDVPL(Buffer.from(data))); + }), + ); + + patchIndex++; + } else break; +} diff --git a/scripts/buildAssets/constants.ts b/scripts/buildAssets/constants.ts index 75907fa3a..d7649d279 100644 --- a/scripts/buildAssets/constants.ts +++ b/scripts/buildAssets/constants.ts @@ -24,7 +24,7 @@ export const POI = { collisionMeshes: '3d/Tanks/CollisionMeshes', optionalDevices: 'XML/item_defs/vehicles/common/optional_devices.xml', optionalDeviceSlots: - 'XML/item_defs/vehicles/common/optional_device_slots.xml', + 'XML/item_defs/vehicles/common/optional_device_slots.xml', optionalDeviceImageMappings: 'UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml', optionalDevicesImage: diff --git a/scripts/buildAssets/tankModels.ts b/scripts/buildAssets/tankModels.ts index edf276fe9..f639dac88 100644 --- a/scripts/buildAssets/tankModels.ts +++ b/scripts/buildAssets/tankModels.ts @@ -1,21 +1,15 @@ import { NodeIO } from '@gltf-transform/core'; import { readdir } from 'fs/promises'; -import { Vector3Tuple } from 'three'; import { extractModel } from '../../src/core/blitz/extractModel'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; -// import { AssetCommit } from '../../src/core/github/assetCommit'; import { commitAssets } from '../../src/core/blitzkrieg/commitAssets'; import { FileChange } from '../../src/core/blitzkrieg/commitMultipleFiles'; import { DATA, POI } from './constants'; import { VehicleDefinitionList } from './definitions'; import { TankParameters } from './tankIcons'; -interface VehicleCustomization { - armorColor: string; -} - export async function tankModels(production: boolean) { console.log('Building tank models...'); @@ -27,18 +21,9 @@ export async function tankModels(production: boolean) { for (const nationIndex in nations) { const nation = nations[nationIndex]; const changes: FileChange[] = []; - // const assetCommit = new AssetCommit(`tank models ${nation}`, production); const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>( `${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`, ); - const customization = await readXMLDVPL<{ root: VehicleCustomization }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/customization.xml.dvpl`, - ); - const baseColor = customization.root.armorColor - .split(' ') - .slice(0, 3) - .map(Number) - .map((channel) => channel / 255) as Vector3Tuple; console.log(`Building models for ${nation}`); @@ -56,11 +41,8 @@ export async function tankModels(production: boolean) { const model = await extractModel( DATA, parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ''), - baseColor, ); - // writeFile(`test.${tankKey}.glb`, await nodeIO.writeBinary(model)); - changes.push({ path: `3d/tanks/models/${id}.glb`, content: Buffer.from(await nodeIO.writeBinary(model)).toString( @@ -71,7 +53,6 @@ export async function tankModels(production: boolean) { }), ); - // assetCommit.push(); await commitAssets(`tank models ${nation}`, changes, production); } } diff --git a/src/app/embeds/session/page.tsx b/src/app/embeds/session/page.tsx index 85b766b22..0d724f360 100644 --- a/src/app/embeds/session/page.tsx +++ b/src/app/embeds/session/page.tsx @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react'; import * as Breakdown from '../../../components/Breakdown'; import { WARGAMING_APPLICATION_ID } from '../../../constants/wargamingApplicationID'; import fetchBlitz from '../../../core/blitz/fetchBlitz'; +import { resetSession } from '../../../core/blitzkrieg/resetSession'; import { TankDefinition, tankDefinitions, @@ -13,10 +14,7 @@ import { tankAverages } from '../../../core/blitzstars/tankAverages'; import calculateWN8 from '../../../core/statistics/calculateWN8'; import { deltaTankStats } from '../../../core/statistics/deltaTankStats'; import getWN8Percentile from '../../../core/statistics/getWN8Percentile'; -import mutateSession, { - resetSession, - useSession, -} from '../../../stores/session'; +import mutateSession, { useSession } from '../../../stores/session'; import { IndividualTankStats, TanksStats } from '../../../types/tanksStats'; import { CustomColumnDisplay } from '../../tools/session/components/CustomColumn'; import { Menu } from '../../tools/session/components/Menu'; diff --git a/src/app/tools/session/page.tsx b/src/app/tools/session/page.tsx index a092b4f8a..10123cb34 100644 --- a/src/app/tools/session/page.tsx +++ b/src/app/tools/session/page.tsx @@ -22,7 +22,9 @@ import { UNLOCALIZED_REGION_NAMES } from '../../../constants/regions'; import searchPlayersAcrossRegions, { AccountListWithServer, } from '../../../core/blitz/searchPlayersAcrossRegions'; -import { resetSession, setSession, useSession } from '../../../stores/session'; +import { resetSession } from '../../../core/blitzkrieg/resetSession'; +import { setSession } from '../../../core/blitzkrieg/setSession'; +import { useSession } from '../../../stores/session'; import SessionPage from '../../embeds/session/page'; import { Menu } from './components/Menu'; import * as styles from './page.css'; diff --git a/src/app/tools/tankopedia/[id]/components/AntagonistBar.tsx b/src/app/tools/tankopedia/[id]/components/AntagonistBar.tsx index ffe8033f1..9ed4b869b 100644 --- a/src/app/tools/tankopedia/[id]/components/AntagonistBar.tsx +++ b/src/app/tools/tankopedia/[id]/components/AntagonistBar.tsx @@ -19,7 +19,7 @@ import { pushTankopediaPath } from '../../../../../core/blitzkrieg/pushTankopedi import { SHELL_NAMES, TIER_ROMAN_NUMERALS, -} from '../../../../../core/blitzkrieg/tankDefinitions'; +} from '../../../../../core/blitzkrieg/tankDefinitions/constants'; import { mutateDuel, useDuel } from '../../../../../stores/duel'; import { mutateTankopediaTemporary, diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx index fc258968c..3f3f113ce 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx @@ -1,6 +1,6 @@ import { Flex, Heading } from '@radix-ui/themes'; import { ModuleButton } from '../../../../../../../components/ModuleButtons/ModuleButton'; -import { TIER_ROMAN_NUMERALS } from '../../../../../../../core/blitzkrieg/tankDefinitions'; +import { TIER_ROMAN_NUMERALS } from '../../../../../../../core/blitzkrieg/tankDefinitions/constants'; import { mutateDuel, useDuel } from '../../../../../../../stores/duel'; import { mutateTankopediaTemporary } from '../../../../../../../stores/tankopedia'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index 48efd9cc0..f0f77649c 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -18,7 +18,7 @@ import { CREW_MEMBER_NAMES, GUN_TYPE_NAMES, SHELL_NAMES, -} from '../../../../../../core/blitzkrieg/tankDefinitions'; +} from '../../../../../../core/blitzkrieg/tankDefinitions/constants'; import { unionBoundingBox } from '../../../../../../core/blitzkrieg/unionBoundingBox'; import { useConsumable } from '../../../../../../hooks/useConsumable'; import { useEquipment } from '../../../../../../hooks/useEquipment'; @@ -268,9 +268,13 @@ export function Characteristics() { <> {gun.reload.at(-1)! < gun.reload.at(-2)! - ? (shell.damage.armor / (gun.reload.at(-1)! + gun.intraClip)) * + ? ((damageCoefficient * shell.damage.armor) / + (gun.reload.at(-1)! * reloadCoefficient + + gun.intraClip * intraClipCoefficient)) * 60 - : (shell.damage.armor / gun.reload[0]) * 60} + : ((damageCoefficient * shell.damage.armor) / + (gun.reload[0] * reloadCoefficient)) * + 60} {gun.reload.at(-1)! < gun.reload.at(-2)! - ? (shell.damage.armor / (gun.reload.at(-1)! + gun.intraClip)) * + ? ((damageCoefficient * shell.damage.armor) / + (gun.reload.at(-1)! * reloadCoefficient + + gun.intraClip * intraClipCoefficient)) * (60 - - (gun.reload.slice(0, -1).length - 1) * gun.intraClip) + - shell.damage.armor * gun.reload.slice(0, -1).length - : (shell.damage.armor / (gun.reload[0] + gun.intraClip)) * - (60 - (gun.reload.slice(1).length - 1) * gun.intraClip) + - shell.damage.armor * gun.reload.slice(1).length} + (gun.reload.slice(0, -1).length - 1) * + gun.intraClip * + intraClipCoefficient) + + damageCoefficient * + shell.damage.armor * + gun.reload.slice(0, -1).length + : ((damageCoefficient * shell.damage.armor) / + (gun.reload[0] * reloadCoefficient + + gun.intraClip * intraClipCoefficient)) * + (60 - + (gun.reload.slice(1).length - 1) * + gun.intraClip * + intraClipCoefficient) + + damageCoefficient * + shell.damage.armor * + gun.reload.slice(1).length} ( + async (resolve) => { + resolve({ + inProduction: true, + inPublic: true, + + command: await addPeriodicFilterOptions( + createLocalizedCommand('breakdown'), + (option) => option.addStringOption(addUsernameChoices), + ), + + async handler(interaction) { + const player = await resolvePlayerFromCommand(interaction); + const period = resolvePeriodFromCommand(player.region, interaction); + const filters = await getFiltersFromCommand(interaction); + const path = commandToURL(interaction, { + ...player, + ...getCustomPeriodParams(interaction), + ...filters, + }); + + return [ + ...(await renderBreakdown( + player, + period, + filters, + interaction.locale, + )), + buttonRefresh(interaction, path), + await getBlitzStarsLinkButton(player.region, player.id), + ]; + }, + + autocomplete: (interaction) => { + autocompleteUsername(interaction); + autocompleteTanks(interaction); + }, + + async button(interaction) { + const player = await resolvePlayerFromButton(interaction); + const period = resolvePeriodFromButton(player.region, interaction); + const filters = getFiltersFromButton(interaction); + + return await renderBreakdown( + player, + period, + filters, + interaction.locale, + ); + }, + }); + }, +); diff --git a/src/commands/breakdown.tsx b/src/commands/breakdown/render.tsx similarity index 69% rename from src/commands/breakdown.tsx rename to src/commands/breakdown/render.tsx index a231eda2d..ff7b087ca 100644 --- a/src/commands/breakdown.tsx +++ b/src/commands/breakdown/render.tsx @@ -1,43 +1,25 @@ import { Locale } from 'discord.js'; import { chunk } from 'lodash'; -import * as Breakdown from '../components/Breakdown'; -import CommandWrapper from '../components/CommandWrapper'; -import NoData from '../components/NoData'; -import TitleBar from '../components/TitleBar'; -import { AllStats, getAccountInfo } from '../core/blitz/getAccountInfo'; -import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo'; -import getTankStats from '../core/blitz/getTankStats'; -import { filtersToDescription } from '../core/blitzkrieg/filtersToDescription'; +import * as Breakdown from '../../components/Breakdown'; +import CommandWrapper from '../../components/CommandWrapper'; +import NoData from '../../components/NoData'; +import TitleBar from '../../components/TitleBar'; +import { AllStats, getAccountInfo } from '../../core/blitz/getAccountInfo'; +import { getClanAccountInfo } from '../../core/blitz/getClanAccountInfo'; +import getTankStats from '../../core/blitz/getTankStats'; +import { filtersToDescription } from '../../core/blitzkrieg/filtersToDescription'; import { TankDefinition, tankDefinitions, -} from '../core/blitzkrieg/tankDefinitions'; -import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton'; -import getStatsInPeriod from '../core/blitzstars/getStatsInPeriod'; -import { tankAverages } from '../core/blitzstars/tankAverages'; -import addPeriodicFilterOptions from '../core/discord/addPeriodicFilterOptions'; -import addUsernameChoices from '../core/discord/addUsernameChoices'; -import autocompleteTanks from '../core/discord/autocompleteTanks'; -import autocompleteUsername from '../core/discord/autocompleteUsername'; -import { buttonRefresh } from '../core/discord/buttonRefresh'; -import commandToURL from '../core/discord/commandToURL'; -import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; -import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams'; -import { getFiltersFromButton } from '../core/discord/getFiltersFromButton'; -import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand'; -import resolvePeriodFromButton from '../core/discord/resolvePeriodFromButton'; -import resolvePeriodFromCommand, { - ResolvedPeriod, -} from '../core/discord/resolvePeriodFromCommand'; -import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton'; -import resolvePlayerFromCommand, { - ResolvedPlayer, -} from '../core/discord/resolvePlayerFromCommand'; -import { translator } from '../core/localization/translator'; -import calculateWN8 from '../core/statistics/calculateWN8'; -import { StatFilters, filterStats } from '../core/statistics/filterStats'; -import getWN8Percentile from '../core/statistics/getWN8Percentile'; -import { CommandRegistry } from '../events/interactionCreate'; +} from '../../core/blitzkrieg/tankDefinitions'; +import getStatsInPeriod from '../../core/blitzstars/getStatsInPeriod'; +import { tankAverages } from '../../core/blitzstars/tankAverages'; +import { ResolvedPeriod } from '../../core/discord/resolvePeriodFromCommand'; +import { ResolvedPlayer } from '../../core/discord/resolvePlayerFromCommand'; +import { translator } from '../../core/localization/translator'; +import calculateWN8 from '../../core/statistics/calculateWN8'; +import { StatFilters, filterStats } from '../../core/statistics/filterStats'; +import getWN8Percentile from '../../core/statistics/getWN8Percentile'; const ROWS_PER_PAGE = 8; const MAX_PAGES = 9; @@ -296,57 +278,3 @@ export async function renderBreakdown( ]; } } - -export const breakdownCommand = new Promise( - async (resolve) => { - resolve({ - inProduction: true, - inPublic: true, - - command: await addPeriodicFilterOptions( - createLocalizedCommand('breakdown'), - (option) => option.addStringOption(addUsernameChoices), - ), - - async handler(interaction) { - const player = await resolvePlayerFromCommand(interaction); - const period = resolvePeriodFromCommand(player.region, interaction); - const filters = await getFiltersFromCommand(interaction); - const path = commandToURL(interaction, { - ...player, - ...getCustomPeriodParams(interaction), - ...filters, - }); - - return [ - ...(await renderBreakdown( - player, - period, - filters, - interaction.locale, - )), - buttonRefresh(interaction, path), - await getBlitzStarsLinkButton(player.region, player.id), - ]; - }, - - autocomplete: (interaction) => { - autocompleteUsername(interaction); - autocompleteTanks(interaction); - }, - - async button(interaction) { - const player = await resolvePlayerFromButton(interaction); - const period = resolvePeriodFromButton(player.region, interaction); - const filters = getFiltersFromButton(interaction); - - return await renderBreakdown( - player, - period, - filters, - interaction.locale, - ); - }, - }); - }, -); diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index 52dd4c4d4..75233426f 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -1,6 +1,7 @@ import { Locale, SlashCommandSubcommandGroupBuilder } from 'discord.js'; import CommandWrapper from '../components/CommandWrapper'; import * as Graph from '../components/Graph'; +import { LineColor } from '../components/Graph/components/Line/constants'; import NoData from '../components/NoData'; import TitleBar from '../components/TitleBar'; import { getAccountInfo } from '../core/blitz/getAccountInfo'; @@ -93,7 +94,7 @@ async function render( xMaxLabel={new Date(maxTime * 1000).toLocaleDateString(locale)} > {Graph.Line({ - color: Graph.LineColor.Red, + color: LineColor.Red, plot: plot, minY, maxY, diff --git a/src/commands/ownedTanks.tsx b/src/commands/ownedTanks.tsx index 88037733d..c5faee701 100644 --- a/src/commands/ownedTanks.tsx +++ b/src/commands/ownedTanks.tsx @@ -7,12 +7,11 @@ import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo'; import getTankStats from '../core/blitz/getTankStats'; import { emblemIdToURL } from '../core/blitzkrieg/emblemIdToURL'; import { - TIER_ROMAN_NUMERALS, TankDefinition, Tier, tankDefinitions, } from '../core/blitzkrieg/tankDefinitions'; -import { tankIcon } from '../core/blitzkrieg/tankIcon'; +import { TIER_ROMAN_NUMERALS } from '../core/blitzkrieg/tankDefinitions/constants'; import addTierChoices from '../core/discord/addTierChoices'; import addUsernameChoices from '../core/discord/addUsernameChoices'; import autocompleteUsername from '../core/discord/autocompleteUsername'; @@ -100,7 +99,6 @@ export const ownedTanksCommand = new Promise((resolve) => { key={tank.id} name={tank.name} tankType={tank.class} - image={tankIcon(tank.id)} treeType={tank.treeType} /> )), @@ -113,7 +111,6 @@ export const ownedTanksCommand = new Promise((resolve) => { key={tank.id} name={tank.name} tankType={tank.class} - image={tankIcon(tank.id)} treeType={tank.treeType} /> )), diff --git a/src/commands/searchPlayers.ts b/src/commands/searchPlayers.ts index 6ca66ff17..ed816c1f2 100644 --- a/src/commands/searchPlayers.ts +++ b/src/commands/searchPlayers.ts @@ -3,10 +3,8 @@ import markdownEscape from 'markdown-escape'; import { Region } from '../constants/regions'; import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID'; import fetchBlitz from '../core/blitz/fetchBlitz'; -import { - AccountList, - usernamePattern, -} from '../core/blitz/searchPlayersAcrossRegions'; +import { AccountList } from '../core/blitz/searchPlayersAcrossRegions'; +import { usernamePattern } from '../core/blitz/searchPlayersAcrossRegions/constants'; import addRegionChoices from '../core/discord/addRegionChoices'; import addUsernameChoices from '../core/discord/addUsernameChoices'; import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; diff --git a/src/commands/today.ts b/src/commands/today.ts index 1e2bc06e7..cc0fc5c06 100644 --- a/src/commands/today.ts +++ b/src/commands/today.ts @@ -15,7 +15,7 @@ import resolvePeriodFromCommand from '../core/discord/resolvePeriodFromCommand'; import resolvePlayerFromButton from '../core/discord/resolvePlayerFromButton'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand'; import { CommandRegistry } from '../events/interactionCreate'; -import { renderBreakdown } from './breakdown'; +import { renderBreakdown } from './breakdown/render'; export const todayCommand = new Promise(async (resolve) => { const nations = await NATIONS; diff --git a/src/components/AllStatsOverview/components/WN8Display/index.tsx b/src/components/AllStatsOverview/components/WN8Display/index.tsx index 8be77a70f..9248a9456 100644 --- a/src/components/AllStatsOverview/components/WN8Display/index.tsx +++ b/src/components/AllStatsOverview/components/WN8Display/index.tsx @@ -3,7 +3,7 @@ import { Percentile } from '../../../../constants/percentiles'; import { translator } from '../../../../core/localization/translator'; import getWN8Percentile from '../../../../core/statistics/getWN8Percentile'; import { theme } from '../../../../stitches.config'; -import { PERCENTILE_COLORS } from '../../../PercentileIndicator'; +import { PERCENTILE_COLORS } from '../../../PercentileIndicator/constants'; import { Glow } from './components/Glow'; export interface WN8DisplayProps { diff --git a/src/components/Armor/components/CoreArmorSceneComponent/index.tsx b/src/components/Armor/components/CoreArmorSceneComponent/index.tsx index c646ee157..3a3d5955b 100644 --- a/src/components/Armor/components/CoreArmorSceneComponent/index.tsx +++ b/src/components/Armor/components/CoreArmorSceneComponent/index.tsx @@ -1,12 +1,6 @@ import { useFrame } from '@react-three/fiber'; import { useEffect } from 'react'; -import { - MeshBasicMaterial, - Object3D, - ShaderMaterial, - Vector2, - WebGLRenderTarget, -} from 'three'; +import { MeshBasicMaterial, Object3D, ShaderMaterial, Vector2 } from 'three'; import { degToRad } from 'three/src/math/MathUtils'; import { canSplash } from '../../../../core/blitz/canSplash'; import { isExplosive } from '../../../../core/blitz/isExplosive'; @@ -21,8 +15,7 @@ import { } from '../../../../stores/tankopedia'; import fragmentShader from './shaders/fragment.glsl'; import vertexShader from './shaders/vertex.glsl'; - -export const spacedArmorRenderTarget = new WebGLRenderTarget(); +import { spacedArmorRenderTarget } from './target'; interface CoreArmorSceneComponentProps { thickness: number; diff --git a/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl b/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl index e03696067..7975e2c20 100644 --- a/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl +++ b/src/components/Armor/components/CoreArmorSceneComponent/shaders/fragment.glsl @@ -53,7 +53,7 @@ void main() { float spacedArmorThickness = spacedArmorBufferFragment.r * penetration; remainingPenetration -= spacedArmorThickness; - if (isExplosive && !canSplash && remainingPenetration > 0.0) { + if (isExplosive && remainingPenetration > 0.0) { // there is a 50% penetration loss per meter for HEAT shells remainingPenetration -= 0.5 * remainingPenetration * distanceFromSpacedArmor; } diff --git a/src/components/Armor/components/CoreArmorSceneComponent/target.tsx b/src/components/Armor/components/CoreArmorSceneComponent/target.tsx new file mode 100644 index 000000000..b61b76f7e --- /dev/null +++ b/src/components/Armor/components/CoreArmorSceneComponent/target.tsx @@ -0,0 +1,3 @@ +import { WebGLRenderTarget } from 'three'; + +export const spacedArmorRenderTarget = new WebGLRenderTarget(); diff --git a/src/components/Armor/components/ShotDisplay.tsx b/src/components/Armor/components/ShotDisplay.tsx index 6b470feb4..512815160 100644 --- a/src/components/Armor/components/ShotDisplay.tsx +++ b/src/components/Armor/components/ShotDisplay.tsx @@ -1,4 +1,4 @@ -import { Card, Flex, Inset, Text } from '@radix-ui/themes'; +import { Card, Flex, Text } from '@radix-ui/themes'; import { Html } from '@react-three/drei'; import { useFrame } from '@react-three/fiber'; import { useEffect, useRef } from 'react'; @@ -182,33 +182,38 @@ export function ShotDisplay() { pointerEvents: 'none', }} > - - - {hasMultipleLayers && ( - - {layer.index + 1} - - )} - - + {hasMultipleLayers && ( + + {layer.index + 1} + + )} + diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx index 5bed3de2c..9f1890888 100644 --- a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx +++ b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx @@ -170,7 +170,7 @@ export function SpacedArmorSceneComponent({ const distance = ( shot.layers.at(-1) as ShotLayerBase ).point.distanceTo(intersections[0].point); - if (explosive && !splashing) + if (explosive) remainingPenetration -= 0.5 * remainingPenetration * distance; const blocked = remainingPenetration < 0; @@ -196,7 +196,7 @@ export function SpacedArmorSceneComponent({ const previousIntersection = intersections[layerIndex - 1]; const distance = intersection.distance - previousIntersection.distance; - if (explosive && !splashing) + if (explosive) remainingPenetration -= 0.5 * remainingPenetration * distance; const wasted = remainingPenetration < 0; diff --git a/src/components/Armor/index.tsx b/src/components/Armor/index.tsx index 67ac23c84..ed82f3a9f 100644 --- a/src/components/Armor/index.tsx +++ b/src/components/Armor/index.tsx @@ -2,7 +2,7 @@ import { createPortal, useFrame } from '@react-three/fiber'; import { memo, useState } from 'react'; import { DepthTexture, Scene, Vector2 } from 'three'; import { CoreArmorScene } from './components/CoreArmorScene'; -import { spacedArmorRenderTarget } from './components/CoreArmorSceneComponent'; +import { spacedArmorRenderTarget } from './components/CoreArmorSceneComponent/target'; import { SpacedArmorScene } from './components/SpacedArmorScene'; export const Armor = memo(() => { diff --git a/src/components/Breakdown/components/Root.tsx b/src/components/Breakdown/components/Root.tsx index 654367d17..47c6d0ec6 100644 --- a/src/components/Breakdown/components/Root.tsx +++ b/src/components/Breakdown/components/Root.tsx @@ -1,6 +1,6 @@ import { ReactNode } from 'react'; -export interface RootProps { +interface RootProps { children: ReactNode; } diff --git a/src/components/Breakdown/components/Row.tsx b/src/components/Breakdown/components/Row.tsx index 36097debe..e2258d9d0 100644 --- a/src/components/Breakdown/components/Row.tsx +++ b/src/components/Breakdown/components/Row.tsx @@ -5,7 +5,8 @@ import { GrayColor, PALETTES, } from '../../../constants/radixColors'; -import { TREE_TYPE_ICONS, TankClass, TreeType } from '../../Tanks'; +import { TankClass, TreeType } from '../../Tanks'; +import { TREE_TYPE_ICONS } from '../../Tanks/components/Item/constants'; import { RowStat } from './RowStat'; export interface RowStatItem { diff --git a/src/components/Breakdown/components/RowStat.tsx b/src/components/Breakdown/components/RowStat.tsx index 88f912911..799bde959 100644 --- a/src/components/Breakdown/components/RowStat.tsx +++ b/src/components/Breakdown/components/RowStat.tsx @@ -7,7 +7,7 @@ import { } from '../../../constants/radixColors'; import PercentileIndicator from '../../PercentileIndicator'; -export interface RowStatProps { +interface RowStatProps { name: string; value?: string | number; delta?: number; diff --git a/src/components/GenericAllStats/components/Card.tsx b/src/components/GenericAllStats/components/Card.tsx index 0b570a837..26d9399d2 100644 --- a/src/components/GenericAllStats/components/Card.tsx +++ b/src/components/GenericAllStats/components/Card.tsx @@ -2,13 +2,13 @@ import { Percentile } from '../../../constants/percentiles'; import { theme } from '../../../stitches.config'; import PercentileIndicator from '../../PercentileIndicator'; -export interface CardItem { +interface CardItem { label: string; value: string | number | undefined; percentile?: Percentile; } -export interface CardProps { +interface CardProps { items: CardItem[]; title: string; } diff --git a/src/components/GenericAllStats/components/Root.tsx b/src/components/GenericAllStats/components/Root.tsx index 0cf26bfde..5c362f44b 100644 --- a/src/components/GenericAllStats/components/Root.tsx +++ b/src/components/GenericAllStats/components/Root.tsx @@ -1,4 +1,4 @@ -export interface RootProps { +interface RootProps { children: React.ReactNode; } diff --git a/src/components/GenericAllStats/components/Row.tsx b/src/components/GenericAllStats/components/Row.tsx index dcb083a60..bd5cfa17e 100644 --- a/src/components/GenericAllStats/components/Row.tsx +++ b/src/components/GenericAllStats/components/Row.tsx @@ -1,4 +1,4 @@ -export interface RowProps { +interface RowProps { children: React.ReactNode; } diff --git a/src/components/GenericAllStats/index.tsx b/src/components/GenericAllStats/index.tsx index c315011fc..2e2ff3bb5 100644 --- a/src/components/GenericAllStats/index.tsx +++ b/src/components/GenericAllStats/index.tsx @@ -7,7 +7,7 @@ import { Card } from './components/Card'; import { Root } from './components/Root'; import { Row } from './components/Row'; -export interface GenericAllStatsProps { +interface GenericAllStatsProps { stats: AllStats; supplementaryStats?: SupplementaryStats; locale: Locale; diff --git a/src/components/GenericStats/components/GenericStatsColumn.tsx b/src/components/GenericStats/components/GenericStatsColumn.tsx index e8b3e6f00..a0ba47497 100644 --- a/src/components/GenericStats/components/GenericStatsColumn.tsx +++ b/src/components/GenericStats/components/GenericStatsColumn.tsx @@ -1,8 +1,8 @@ -import { Stat } from '..'; +import { GenericStat } from '..'; import GenericStatsRow from './GenericStatsRow'; -export interface GenericStatsColumnProps { - stats: Stat[]; +interface GenericStatsColumnProps { + stats: GenericStat[]; } export default function GenericStatsColumn({ stats }: GenericStatsColumnProps) { diff --git a/src/components/GenericStats/components/GenericStatsRow.tsx b/src/components/GenericStats/components/GenericStatsRow.tsx index bb3d85d35..1f458a158 100644 --- a/src/components/GenericStats/components/GenericStatsRow.tsx +++ b/src/components/GenericStats/components/GenericStatsRow.tsx @@ -1,9 +1,9 @@ -import { Stat } from '..'; +import { GenericStat } from '..'; import { theme } from '../../../stitches.config'; import PercentileIndicator from '../../PercentileIndicator'; -export interface GenericStatsRowProps { - stat: Stat; +interface GenericStatsRowProps { + stat: GenericStat; } export default function GenericStatsRow({ stat }: GenericStatsRowProps) { diff --git a/src/components/GenericStats/index.tsx b/src/components/GenericStats/index.tsx index b22dce987..08a376db0 100644 --- a/src/components/GenericStats/index.tsx +++ b/src/components/GenericStats/index.tsx @@ -1,12 +1,12 @@ import { Percentile } from '../../constants/percentiles'; import GenericStatsColumn from './components/GenericStatsColumn'; -export type Stat = +export type GenericStat = | [string, string | number | undefined] | [string, string | number | undefined, Percentile | undefined]; export interface GenericStatsProps { - stats: Stat[]; + stats: GenericStat[]; columnCount?: number; } @@ -16,7 +16,7 @@ export default function GenericStats({ }: GenericStatsProps) { const filteredStats = stats.filter(([, value]) => value !== undefined); const itemsPerRow = Math.ceil(filteredStats.length / columnCount); - const columns: Stat[][] = []; + const columns: GenericStat[][] = []; filteredStats.forEach((stat, index) => { const column = Math.floor(index / itemsPerRow); diff --git a/src/components/Graph/components/Line/constants.ts b/src/components/Graph/components/Line/constants.ts new file mode 100644 index 000000000..74170a3a8 --- /dev/null +++ b/src/components/Graph/components/Line/constants.ts @@ -0,0 +1,11 @@ +export enum LineColor { + Red, + Green, + Blue, + White, +} +export enum LineStyle { + Solid, + Dashes, + DashesAndDots, +} diff --git a/src/components/Graph/components/Line.tsx b/src/components/Graph/components/Line/index.tsx similarity index 85% rename from src/components/Graph/components/Line.tsx rename to src/components/Graph/components/Line/index.tsx index 8a3e0d0ec..3894b1a75 100644 --- a/src/components/Graph/components/Line.tsx +++ b/src/components/Graph/components/Line/index.tsx @@ -1,12 +1,6 @@ import { blue, green, red, slateDark } from '@radix-ui/colors'; -import { GRAPH_HEIGHT, GRAPH_WIDTH } from './Root'; - -export enum LineColor { - Red, - Green, - Blue, - White, -} +import { GRAPH_HEIGHT, GRAPH_WIDTH } from '../Root/constants'; +import { LineColor, LineStyle } from './constants'; const LINE_COLORS = { [LineColor.Red]: red.red9, @@ -15,12 +9,6 @@ const LINE_COLORS = { [LineColor.White]: slateDark.slate11, }; -export enum LineStyle { - Solid, - Dashes, - DashesAndDots, -} - const LINE_STYLES = { [LineStyle.Solid]: undefined, [LineStyle.Dashes]: '8, 8', @@ -28,9 +16,9 @@ const LINE_STYLES = { }; export type PlotItem = [number, number]; -export type Plot = PlotItem[]; +type Plot = PlotItem[]; -export interface LineProps { +interface LineProps { plot: Plot; minY?: number; maxY?: number; diff --git a/src/components/Graph/components/Margin/constants.ts b/src/components/Graph/components/Margin/constants.ts new file mode 100644 index 000000000..fab153d6c --- /dev/null +++ b/src/components/Graph/components/Margin/constants.ts @@ -0,0 +1,4 @@ +export enum MarginOrientation { + Vertical, + Horizontal, +} diff --git a/src/components/Graph/components/Margin.tsx b/src/components/Graph/components/Margin/index.tsx similarity index 83% rename from src/components/Graph/components/Margin.tsx rename to src/components/Graph/components/Margin/index.tsx index 292847455..66b64df5e 100644 --- a/src/components/Graph/components/Margin.tsx +++ b/src/components/Graph/components/Margin/index.tsx @@ -1,13 +1,9 @@ import { times } from 'lodash'; -import { theme } from '../../../stitches.config'; -import { MarginInputProps } from './Root'; +import { theme } from '../../../../stitches.config'; +import { MarginInputProps } from '../Root'; +import { MarginOrientation } from './constants'; -export enum MarginOrientation { - Vertical, - Horizontal, -} - -export interface MarginProps extends MarginInputProps { +interface MarginProps extends MarginInputProps { verticalSeparations: number; orientation?: MarginOrientation; } diff --git a/src/components/Graph/components/Root/constants.ts b/src/components/Graph/components/Root/constants.ts new file mode 100644 index 000000000..0ff4e7d6b --- /dev/null +++ b/src/components/Graph/components/Root/constants.ts @@ -0,0 +1,2 @@ +export const GRAPH_WIDTH = 384; +export const GRAPH_HEIGHT = 320; diff --git a/src/components/Graph/components/Root.tsx b/src/components/Graph/components/Root/index.tsx similarity index 91% rename from src/components/Graph/components/Root.tsx rename to src/components/Graph/components/Root/index.tsx index 7f838ace8..6f621f07d 100644 --- a/src/components/Graph/components/Root.tsx +++ b/src/components/Graph/components/Root/index.tsx @@ -1,10 +1,9 @@ import { times } from 'lodash'; import { ReactNode } from 'react'; -import { theme } from '../../../stitches.config'; -import { Margin, MarginOrientation } from './Margin'; - -export const GRAPH_WIDTH = 384; -export const GRAPH_HEIGHT = 320; +import { theme } from '../../../../stitches.config'; +import { Margin } from '../Margin'; +import { MarginOrientation } from '../Margin/constants'; +import { GRAPH_HEIGHT, GRAPH_WIDTH } from './constants'; export interface MarginInputProps { min: number; @@ -13,7 +12,7 @@ export interface MarginInputProps { precision?: number; } -export interface RootProps { +interface RootProps { children: ReactNode; verticalMargin?: MarginInputProps; horizontalMargin?: MarginInputProps; diff --git a/src/components/Leaderboard/components/Gap.tsx b/src/components/Leaderboard/components/Gap.tsx index ea99825a0..f1fa3f16c 100644 --- a/src/components/Leaderboard/components/Gap.tsx +++ b/src/components/Leaderboard/components/Gap.tsx @@ -1,6 +1,6 @@ import { theme } from '../../../stitches.config'; -export interface GapProps { +interface GapProps { message: string; } diff --git a/src/components/Leaderboard/components/Item.tsx b/src/components/Leaderboard/components/Item.tsx index 79a707ebe..9cf080992 100644 --- a/src/components/Leaderboard/components/Item.tsx +++ b/src/components/Leaderboard/components/Item.tsx @@ -2,7 +2,7 @@ import { ComponentProps } from 'react'; import { RatingsReward } from '../../../commands/ratings'; import { theme } from '../../../stitches.config'; -export interface ItemProps extends ComponentProps<'div'> { +interface ItemProps extends ComponentProps<'div'> { position: number; deltaPosition?: number; score?: number; diff --git a/src/components/Leaderboard/components/Root.tsx b/src/components/Leaderboard/components/Root.tsx index 9f40d82f9..8abe555e9 100644 --- a/src/components/Leaderboard/components/Root.tsx +++ b/src/components/Leaderboard/components/Root.tsx @@ -1,6 +1,6 @@ import { ReactNode } from 'react'; -export interface RootProps { +interface RootProps { children: ReactNode; } diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 0d437c4a6..c50f0fbe5 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -1,8 +1,8 @@ import { DiscordLogoIcon } from '@radix-ui/react-icons'; import { Flex, Text, Theme } from '@radix-ui/themes'; import Link from 'next/link'; -import { theme } from '../../stitches.config'; import { BlitzkriegWormWide } from '../../icons/BlitzkriegWormWide'; +import { theme } from '../../stitches.config'; export default function Navbar() { return ( diff --git a/src/components/NoData/constants.ts b/src/components/NoData/constants.ts new file mode 100644 index 000000000..a01763279 --- /dev/null +++ b/src/components/NoData/constants.ts @@ -0,0 +1,5 @@ +export enum NoDataType { + BattlesInPeriod, + PlayersInPeriod, + TanksFound, +} diff --git a/src/components/NoData.tsx b/src/components/NoData/index.tsx similarity index 71% rename from src/components/NoData.tsx rename to src/components/NoData/index.tsx index 3f28d8fdf..bc4774558 100644 --- a/src/components/NoData.tsx +++ b/src/components/NoData/index.tsx @@ -1,14 +1,8 @@ import { Locale } from 'discord.js'; -import { translator } from '../core/localization/translator'; -import { theme } from '../stitches.config'; +import { translator } from '../../core/localization/translator'; +import { theme } from '../../stitches.config'; -export enum NoDataType { - BattlesInPeriod, - PlayersInPeriod, - TanksFound, -} - -export interface NoDataProps { +interface NoDataProps { type: 'battles_in_period' | 'players_in_period' | 'tanks_found'; locale: Locale; } diff --git a/src/components/PercentileIndicator.tsx b/src/components/PercentileIndicator/constants.ts similarity index 57% rename from src/components/PercentileIndicator.tsx rename to src/components/PercentileIndicator/constants.ts index 25fe22e6c..ae4fface8 100644 --- a/src/components/PercentileIndicator.tsx +++ b/src/components/PercentileIndicator/constants.ts @@ -10,11 +10,7 @@ import { slate, teal, } from '@radix-ui/colors'; -import { Percentile } from '../constants/percentiles'; - -export interface PercentileIndicatorProps { - percentile: Percentile; -} +import { Percentile } from '../../constants/percentiles'; export const PERCENTILE_COLORS = { [Percentile.VeryBad]: slate.slate9, @@ -28,18 +24,3 @@ export const PERCENTILE_COLORS = { [Percentile.Unicum]: pink.pink9, [Percentile.SuperUnicum]: purple.purple9, }; - -export default function PercentileIndicator({ - percentile, -}: PercentileIndicatorProps) { - return ( -
- ); -} diff --git a/src/components/PercentileIndicator/index.tsx b/src/components/PercentileIndicator/index.tsx new file mode 100644 index 000000000..2099966a3 --- /dev/null +++ b/src/components/PercentileIndicator/index.tsx @@ -0,0 +1,21 @@ +import { Percentile } from '../../constants/percentiles'; +import { PERCENTILE_COLORS } from './constants'; + +interface PercentileIndicatorProps { + percentile: Percentile; +} + +export default function PercentileIndicator({ + percentile, +}: PercentileIndicatorProps) { + return ( +
+ ); +} diff --git a/src/components/Tanks/components/Column.tsx b/src/components/Tanks/components/Column.tsx index 7215c6186..0ec567ab6 100644 --- a/src/components/Tanks/components/Column.tsx +++ b/src/components/Tanks/components/Column.tsx @@ -1,6 +1,6 @@ import { ReactNode } from 'react'; -export interface ColumnProps { +interface ColumnProps { children: ReactNode; } diff --git a/src/components/Tanks/components/Item/constants.ts b/src/components/Tanks/components/Item/constants.ts new file mode 100644 index 000000000..e0eda4cf9 --- /dev/null +++ b/src/components/Tanks/components/Item/constants.ts @@ -0,0 +1,31 @@ +import { TankClass, TreeType } from '.'; +import { + TANK_ICONS, + TANK_ICONS_COLLECTOR, + TANK_ICONS_PREMIUM, +} from '../../../../core/blitzkrieg/tankDefinitions/constants'; + +export const TREE_TYPES = ['researchable', 'premium', 'collector'] as const; // BIG TODO: REMOVE THIS AFTER LOCALIZATION + +export const TANK_CLASSES = [ + 'lightTank', + 'mediumTank', + 'heavyTank', + 'AT-SPG', +] as const; + +export const TREE_TYPE_NAMES: Record = { + researchable: 'Tech tree', + premium: 'Premium', + collector: 'Collector', +}; +export const TREE_TYPE_IMAGES: Record = { + researchable: 'https://i.imgur.com/pJxO2XY.png', + premium: 'https://i.imgur.com/mZzSwOU.png', + collector: 'https://i.imgur.com/7A0RsG5.png', +}; +export const TREE_TYPE_ICONS: Record> = { + researchable: TANK_ICONS, + premium: TANK_ICONS_PREMIUM, + collector: TANK_ICONS_COLLECTOR, +}; diff --git a/src/components/Tanks/components/Item.tsx b/src/components/Tanks/components/Item/index.tsx similarity index 60% rename from src/components/Tanks/components/Item.tsx rename to src/components/Tanks/components/Item/index.tsx index 2d1818a2e..abfb60a72 100644 --- a/src/components/Tanks/components/Item.tsx +++ b/src/components/Tanks/components/Item/index.tsx @@ -1,37 +1,10 @@ -import { - TANK_ICONS, - TANK_ICONS_COLLECTOR, - TANK_ICONS_PREMIUM, -} from '../../../core/blitzkrieg/tankDefinitions'; -import { theme } from '../../../stitches.config'; - -export const TANK_CLASSES = [ - 'lightTank', - 'mediumTank', - 'heavyTank', - 'AT-SPG', -] as const; - -export const TREE_TYPES = ['researchable', 'premium', 'collector'] as const; +import { theme } from '../../../../stitches.config'; +import { TANK_CLASSES, TREE_TYPES, TREE_TYPE_ICONS } from './constants'; export type TankClass = (typeof TANK_CLASSES)[number]; export type TreeType = (typeof TREE_TYPES)[number]; -// BIG TODO: REMOVE THIS AFTER LOCALIZATION -export const TREE_TYPE_NAMES: Record = { - researchable: 'Tech tree', - premium: 'Premium', - collector: 'Collector', -}; - -export const TREE_TYPE_IMAGES: Record = { - researchable: 'https://i.imgur.com/pJxO2XY.png', - premium: 'https://i.imgur.com/mZzSwOU.png', - collector: 'https://i.imgur.com/7A0RsG5.png', -}; - export interface ItemProps { - image?: string; tankType?: TankClass; name: string; treeType: TreeType; @@ -43,13 +16,7 @@ const TREE_TYPE_COLOR = { collector: '_blue', } as const; -export const TREE_TYPE_ICONS: Record> = { - researchable: TANK_ICONS, - premium: TANK_ICONS_PREMIUM, - collector: TANK_ICONS_COLLECTOR, -}; - -export function Item({ image, tankType, name, treeType }: ItemProps) { +export function Item({ tankType, name, treeType }: ItemProps) { return (
>; -export interface TierWeightsProps { +interface TierWeightsProps { weights: TierWeightsRecord; } diff --git a/src/components/TitleBar.tsx b/src/components/TitleBar.tsx index ef5b284cc..861e2116f 100644 --- a/src/components/TitleBar.tsx +++ b/src/components/TitleBar.tsx @@ -1,6 +1,6 @@ import { theme } from '../stitches.config'; -export interface TitleBarProps { +interface TitleBarProps { title: string; image?: string; description?: string; diff --git a/src/core/blitz/encyclopediaInfo.ts b/src/core/blitz/encyclopediaInfo.ts deleted file mode 100644 index e27f70593..000000000 --- a/src/core/blitz/encyclopediaInfo.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; -import fetchBlitz from './fetchBlitz'; - -export interface EncyclopediaInfo { - achievement_sections: Record; - tanks_updated_at: number; - languages: Record; - vehicle_types: Record; - vehicle_nations: Record; - game_version: string; -} - -export const encyclopediaInfo = fetchBlitz( - `https://api.wotblitz.com/wotb/encyclopedia/info/?application_id=${WARGAMING_APPLICATION_ID}`, -); diff --git a/src/core/blitz/extractArmor.ts b/src/core/blitz/extractArmor.ts index b2819ff05..9ccf7f76c 100644 --- a/src/core/blitz/extractArmor.ts +++ b/src/core/blitz/extractArmor.ts @@ -6,13 +6,9 @@ import { VertexAttribute } from '../streams/scpg'; import { vertexAttributeGLTFName, vertexAttributeGltfVectorSizes, -} from './extractModel'; +} from './extractModel/constants'; import { readDVPLFile } from './readDVPLFile'; -Buffer.prototype.toJSON = function () { - return [...(this as Buffer)].map((int) => int.toString(16)).join(''); -}; - export async function extractArmor(data: string, fileName: string) { const sc2Path = `${data}/3d/Tanks/CollisionMeshes/${fileName}.sc2.dvpl`; const scgPath = `${data}/3d/Tanks/CollisionMeshes/${fileName}.scg.dvpl`; diff --git a/src/core/blitz/extractModel/constants.ts b/src/core/blitz/extractModel/constants.ts new file mode 100644 index 000000000..2e560c9af --- /dev/null +++ b/src/core/blitz/extractModel/constants.ts @@ -0,0 +1,19 @@ +import { vertexAttributeVectorSizes } from '../../streams/scg'; +import { VertexAttribute } from '../../streams/scpg'; + +export const vertexAttributeGLTFName: Partial> = + { + [VertexAttribute.VERTEX]: 'POSITION', + [VertexAttribute.NORMAL]: 'NORMAL', + [VertexAttribute.TEXCOORD0]: 'TEXCOORD_0', + [VertexAttribute.TEXCOORD1]: 'TEXCOORD_0', + [VertexAttribute.TEXCOORD2]: 'TEXCOORD_0', + [VertexAttribute.TEXCOORD3]: 'TEXCOORD_0', + [VertexAttribute.TANGENT]: 'TANGENT', + [VertexAttribute.JOINTINDEX]: 'JOINT_0', + [VertexAttribute.JOINTWEIGHT]: 'WEIGHT_0', + }; +export const vertexAttributeGltfVectorSizes = { + ...vertexAttributeVectorSizes, + [VertexAttribute.TANGENT]: 4, +} as const; diff --git a/src/core/blitz/extractModel.ts b/src/core/blitz/extractModel/index.ts similarity index 85% rename from src/core/blitz/extractModel.ts rename to src/core/blitz/extractModel/index.ts index 427672617..68060ccc2 100644 --- a/src/core/blitz/extractModel.ts +++ b/src/core/blitz/extractModel/index.ts @@ -1,51 +1,26 @@ import { Document, Material, Node, Scene } from '@gltf-transform/core'; import { times } from 'lodash'; import { dirname } from 'path'; +import { Matrix4, Quaternion, Vector3, Vector4Tuple } from 'three'; +import { readTexture } from '../../blitzkrieg/readTexture'; +import { TextureMutation } from '../../blitzkrieg/readTexture/constants'; +import { Hierarchy, Sc2ReadStream, Textures } from '../../streams/sc2'; +import { ScgReadStream } from '../../streams/scg'; +import { VertexAttribute } from '../../streams/scpg'; +import { readDVPLFile } from '../readDVPLFile'; import { - Matrix4, - Quaternion, - Vector3, - Vector3Tuple, - Vector4Tuple, -} from 'three'; -import { TextureMutation, readTexture } from '../blitzkrieg/readTexture'; -import { Hierarchy, Sc2ReadStream, Textures } from '../streams/sc2'; -import { ScgReadStream, vertexAttributeVectorSizes } from '../streams/scg'; -import { VertexAttribute } from '../streams/scpg'; -import { readDVPLFile } from './readDVPLFile'; + vertexAttributeGLTFName, + vertexAttributeGltfVectorSizes, +} from './constants'; const ERROR_ON_UNKNOWN_COMPONENT = false; -const MAX_FLOAT32 = 2 ** 127 * (2 - 2 ** -23); - -export const vertexAttributeGLTFName: Partial> = - { - [VertexAttribute.VERTEX]: 'POSITION', - [VertexAttribute.NORMAL]: 'NORMAL', - [VertexAttribute.TEXCOORD0]: 'TEXCOORD_0', - [VertexAttribute.TEXCOORD1]: 'TEXCOORD_0', - [VertexAttribute.TEXCOORD2]: 'TEXCOORD_0', - [VertexAttribute.TEXCOORD3]: 'TEXCOORD_0', - [VertexAttribute.TANGENT]: 'TANGENT', - [VertexAttribute.JOINTINDEX]: 'JOINT_0', - [VertexAttribute.JOINTWEIGHT]: 'WEIGHT_0', - }; - -export const vertexAttributeGltfVectorSizes = { - ...vertexAttributeVectorSizes, - - [VertexAttribute.TANGENT]: 4, -} as const; const omitMeshNames = { start: ['chassis_chassis_', 'chassis_track_crash_', 'HP_'], end: ['_POINT'], }; -export async function extractModel( - data: string, - path: string, - baseColor?: Vector3Tuple, -) { +export async function extractModel(data: string, path: string) { const sc2Path = `${data}/3d/${path}.sc2.dvpl`; const scgPath = `${data}/3d/${path}.scg.dvpl`; const sc2 = new Sc2ReadStream((await readDVPLFile(sc2Path)).buffer).sc2(); @@ -86,9 +61,7 @@ export async function extractModel( .setImage( await readTexture( `${data}/3d/${dirname(path)}/${textures.albedo}`, - baseColor - ? { mutation: TextureMutation.BaseColor, baseColor } - : undefined, + TextureMutation.Albedo, ), ), ); @@ -101,7 +74,7 @@ export async function extractModel( .setImage( await readTexture( `${data}/3d/${dirname(path)}/${textures.baseRMMap}`, - { mutation: TextureMutation.RoughnessMetallicness }, + TextureMutation.RoughnessMetallicness, ), ), ); @@ -119,7 +92,7 @@ export async function extractModel( `${data}/3d/${dirname(path)}/${ textures.baseNormalMap ?? textures.normalmap }`, - isBase ? { mutation: TextureMutation.Normal } : undefined, + isBase ? TextureMutation.Normal : undefined, ), ), ); @@ -133,7 +106,7 @@ export async function extractModel( .setImage( await readTexture( `${data}/3d/${dirname(path)}/${textures.miscMap}`, - { mutation: TextureMutation.Miscellaneous }, + TextureMutation.Miscellaneous, ), ), ); diff --git a/src/core/blitz/fetchBlitz.ts b/src/core/blitz/fetchBlitz.ts index 566f1715b..973c7a204 100644 --- a/src/core/blitz/fetchBlitz.ts +++ b/src/core/blitz/fetchBlitz.ts @@ -1,4 +1,4 @@ -export type BlitzResponse = +type BlitzResponse = | { status: 'error'; error: { field: string; message: string; code: 402; value: null }; diff --git a/src/core/blitz/getClanAccountInfo.ts b/src/core/blitz/getClanAccountInfo.ts index ffb334ca2..de5a73cf4 100644 --- a/src/core/blitz/getClanAccountInfo.ts +++ b/src/core/blitz/getClanAccountInfo.ts @@ -4,7 +4,7 @@ import fetchBlitz from './fetchBlitz'; import { normalizeExtra } from './normalizeExtra'; import { normalizeIds } from './normalizeIds'; -export type IndividualClanAccountInfo = { +type IndividualClanAccountInfo = { account_id: number; joined_at: number; clan_id: number; @@ -21,7 +21,7 @@ export type IndividualClanAccountInfo = { }; } | null; -export interface ClanAccountInfo { +interface ClanAccountInfo { [accountId: number]: IndividualClanAccountInfo; } diff --git a/src/core/blitz/getClanInfo.ts b/src/core/blitz/getClanInfo.ts index 85cfa154f..e61a828c2 100644 --- a/src/core/blitz/getClanInfo.ts +++ b/src/core/blitz/getClanInfo.ts @@ -3,7 +3,7 @@ import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID import fetchBlitz from './fetchBlitz'; import { normalizeIds } from './normalizeIds'; -export interface IndividualClanInfo { +interface IndividualClanInfo { recruiting_options: { vehicles_level: number; wins_ratio: number; @@ -32,7 +32,7 @@ export interface IndividualClanInfo { description: string; } -export interface ClanInfo { +interface ClanInfo { [clanId: number]: IndividualClanInfo; } diff --git a/src/core/blitz/searchClansAcrossRegions.ts b/src/core/blitz/searchClansAcrossRegions.ts index 45539244b..de5e7a224 100644 --- a/src/core/blitz/searchClansAcrossRegions.ts +++ b/src/core/blitz/searchClansAcrossRegions.ts @@ -1,12 +1,8 @@ import { Region } from '../../constants/regions'; import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; -import { Clan, ClanList } from '../../types/clanList'; +import { ClanList } from '../../types/clanList'; import fetchBlitz from './fetchBlitz'; -export type ClanListWithRegion = (Clan & { - region: 'com' | 'eu' | 'asia'; -})[]; - export default async function searchClansAcrossRegions( search: string, limit = 25, diff --git a/src/core/blitz/searchPlayersAcrossRegions/constants.ts b/src/core/blitz/searchPlayersAcrossRegions/constants.ts new file mode 100644 index 000000000..4a16941a4 --- /dev/null +++ b/src/core/blitz/searchPlayersAcrossRegions/constants.ts @@ -0,0 +1,2 @@ +export const usernamePattern = /^[a-zA-Z0-9_]{3,24}$/; +export const usernamePatternWithoutPosition = /[a-zA-Z0-9_]{3,24}/; diff --git a/src/core/blitz/searchPlayersAcrossRegions.ts b/src/core/blitz/searchPlayersAcrossRegions/index.ts similarity index 85% rename from src/core/blitz/searchPlayersAcrossRegions.ts rename to src/core/blitz/searchPlayersAcrossRegions/index.ts index 98dc76754..92c7d7ae9 100644 --- a/src/core/blitz/searchPlayersAcrossRegions.ts +++ b/src/core/blitz/searchPlayersAcrossRegions/index.ts @@ -1,6 +1,7 @@ -import { Region } from '../../constants/regions'; -import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; -import fetchBlitz from './fetchBlitz'; +import { Region } from '../../../constants/regions'; +import { WARGAMING_APPLICATION_ID } from '../../../constants/wargamingApplicationID'; +import fetchBlitz from '../fetchBlitz'; +import { usernamePattern } from './constants'; export interface AccountListItem { nickname: string; @@ -11,9 +12,6 @@ export type AccountListWithServer = (AccountListItem & { region: Region; })[]; -export const usernamePattern = /^[a-zA-Z0-9_]{3,24}$/; -export const usernamePatternWithoutPosition = /[a-zA-Z0-9_]{3,24}/; - export default async function searchPlayersAcrossRegions( search: string, limit = 25, diff --git a/src/core/blitz/writeDVPL.ts b/src/core/blitz/writeDVPL.ts new file mode 100644 index 000000000..01617086f --- /dev/null +++ b/src/core/blitz/writeDVPL.ts @@ -0,0 +1,50 @@ +import { crc32 } from 'crc'; +import { encodeBlockHC } from 'lz4'; + +/** + * Thanks Maddoxkkm! Modernized heavily. + * + * https://github.com/Maddoxkkm/dvpl_converter/ + */ +export function writeDVPL(buffer: Buffer) { + let output = Buffer.alloc(buffer.length); + const compressedBlockSize = encodeBlockHC(buffer, output); + + if (compressedBlockSize === 0 || compressedBlockSize >= buffer.length) { + const footerBuffer = toDVPLFooter( + buffer.length, + buffer.length, + crc32(buffer), + 0, + ); + + return Buffer.concat([buffer, footerBuffer], buffer.length + 20); + } else { + output = output.subarray(0, compressedBlockSize); + const footerBuffer = toDVPLFooter( + buffer.length, + compressedBlockSize, + crc32(output), + 2, + ); + + return Buffer.concat([output, footerBuffer], compressedBlockSize + 20); + } +} + +function toDVPLFooter( + inputSize: number, + compressedSize: number, + crc32: number, + type: number, +) { + const result = Buffer.alloc(20); + + result.writeUInt32LE(inputSize, 0); + result.writeUInt32LE(compressedSize, 4); + result.writeUInt32LE(crc32, 8); + result.writeUInt32LE(type, 12); + result.write('DVPL', 16, 4, 'utf8'); + + return result; +} diff --git a/src/core/blitzkrieg/assignDuelMember.ts b/src/core/blitzkrieg/assignDuelMember.ts index dd204dd7b..e7329823b 100644 --- a/src/core/blitzkrieg/assignDuelMember.ts +++ b/src/core/blitzkrieg/assignDuelMember.ts @@ -1,9 +1,6 @@ import { degToRad } from 'three/src/math/MathUtils'; -import { - DuelMember, - genericDefaultEquipmentMatrix, - mutateDuel, -} from '../../stores/duel'; +import { DuelMember, mutateDuel } from '../../stores/duel'; +import { genericDefaultEquipmentMatrix } from '../../stores/duel/constants'; import { availableProvisions } from './availableProvisions'; import { modelDefinitions } from './modelDefinitions'; import { provisionDefinitions } from './provisionDefinitions'; diff --git a/src/core/blitzkrieg/discordBlitz.ts b/src/core/blitzkrieg/discordBlitz.ts index fd644e944..6af53d2c0 100644 --- a/src/core/blitzkrieg/discordBlitz.ts +++ b/src/core/blitzkrieg/discordBlitz.ts @@ -1,7 +1,5 @@ -import { PrismaClient } from '@prisma/client'; import { Region } from '../../constants/regions'; - -export const discordBlitzDB = new PrismaClient(); +import { discordBlitzDB } from './discordBlitzDB'; export function linkBlitzAndDiscord( discord: number, diff --git a/src/core/blitzkrieg/discordBlitzDB.ts b/src/core/blitzkrieg/discordBlitzDB.ts new file mode 100644 index 000000000..cfabf3e73 --- /dev/null +++ b/src/core/blitzkrieg/discordBlitzDB.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from '@prisma/client'; + +export const discordBlitzDB = new PrismaClient(); diff --git a/src/core/blitzkrieg/fetchCdonLz4.ts b/src/core/blitzkrieg/fetchCdonLz4.ts index f7d40ac8d..0fbf1e4db 100644 --- a/src/core/blitzkrieg/fetchCdonLz4.ts +++ b/src/core/blitzkrieg/fetchCdonLz4.ts @@ -1,7 +1,7 @@ import { superDecompress } from './superDecompress'; export async function fetchCdonLz4(url: string) { - return await fetch(url, { cache: 'no-cache' }) + return await fetch(url, { cache: 'no-store' }) .then((response) => response.arrayBuffer()) .then((buffer) => superDecompress(new Uint8Array(buffer))); } diff --git a/src/core/blitzkrieg/filtersToDescription.ts b/src/core/blitzkrieg/filtersToDescription.ts index 9a6b91ce0..c22714aad 100644 --- a/src/core/blitzkrieg/filtersToDescription.ts +++ b/src/core/blitzkrieg/filtersToDescription.ts @@ -1,7 +1,8 @@ import { Locale } from 'discord.js'; import { translator } from '../localization/translator'; import { StatFilters } from '../statistics/filterStats'; -import { TIER_ROMAN_NUMERALS, Tier, tankDefinitions } from './tankDefinitions'; +import { Tier, tankDefinitions } from './tankDefinitions'; +import { TIER_ROMAN_NUMERALS } from './tankDefinitions/constants'; export async function filtersToDescription( { nation, tier, tankType, treeType, tank }: StatFilters, diff --git a/src/core/blitzkrieg/getArchivedRatingsMidnightLeaderboard.ts b/src/core/blitzkrieg/getArchivedRatingsMidnightLeaderboard.ts index 9e210a561..72d39cd29 100644 --- a/src/core/blitzkrieg/getArchivedRatingsMidnightLeaderboard.ts +++ b/src/core/blitzkrieg/getArchivedRatingsMidnightLeaderboard.ts @@ -1,8 +1,6 @@ import { BlitzkriegRatingsLeaderboard } from '../../../scripts/buildRatingsLeaderboard'; import { Region } from '../../constants/regions'; -export const DATABASE_REPO = { owner: 'tresabhi', repo: 'blitzkrieg-assets' }; - const MIDNIGHT_LEADERBOARD_CACHE: Record< Region, Record diff --git a/src/core/blitzkrieg/getTankHistories.ts b/src/core/blitzkrieg/getTankHistories.ts index 542a777c7..bba997d01 100644 --- a/src/core/blitzkrieg/getTankHistories.ts +++ b/src/core/blitzkrieg/getTankHistories.ts @@ -7,7 +7,7 @@ import { getHistoriesDefaultOptions, } from '../../types/histories'; import getTankStats from '../blitz/getTankStats'; -import { emptyAllStats } from '../blitzstars/getStatsInPeriod'; +import { emptyAllStats } from '../blitzstars/getStatsInPeriod/constants'; export interface TankHistory extends History { tank_id: number; @@ -27,7 +27,7 @@ export interface GetTankHistoriesOptions extends GetHistoriesOptions { tankId?: number; } -export const getTankHistoriesDefaultOptions: GetTankHistoriesOptions = { +const getTankHistoriesDefaultOptions: GetTankHistoriesOptions = { ...getHistoriesDefaultOptions, tankId: undefined, }; diff --git a/src/core/blitzkrieg/getTimeDaysAgo.ts b/src/core/blitzkrieg/getTimeDaysAgo.ts index 485561e9d..0d388ddce 100644 --- a/src/core/blitzkrieg/getTimeDaysAgo.ts +++ b/src/core/blitzkrieg/getTimeDaysAgo.ts @@ -1,6 +1,6 @@ import { Region } from '../../constants/regions'; -export const TIME_ZONE_MAPPINGS: Record = { +const TIME_ZONE_MAPPINGS: Record = { com: -5, // Central North American Time eu: +1, // Central European Time asia: +7, // Central Asia Standard Time diff --git a/src/core/blitzkrieg/jsxToSvg/index.ts b/src/core/blitzkrieg/jsxToSvg/index.ts index 791bcd719..66f0b5b07 100644 --- a/src/core/blitzkrieg/jsxToSvg/index.ts +++ b/src/core/blitzkrieg/jsxToSvg/index.ts @@ -1,19 +1,13 @@ import { readFileSync } from 'fs'; import satori from 'satori'; +import robotoBlack from './Roboto-Black.ttf'; +import robotoBold from './Roboto-Bold.ttf'; +import roboto from './Roboto.ttf'; const fonts = [ - { - file: require('./Roboto.ttf') as string, - weight: 400 as const, - }, - { - file: require('./Roboto-Bold.ttf') as string, - weight: 700 as const, - }, - { - file: require('./Roboto-Black.ttf') as string, - weight: 900 as const, - }, + { file: roboto, weight: 400 as const }, + { file: robotoBold, weight: 700 as const }, + { file: robotoBlack, weight: 900 as const }, ]; export default async function jsxToSvg(jsx: JSX.Element) { diff --git a/src/core/blitzkrieg/processes.ts b/src/core/blitzkrieg/processes.ts index 9834d616c..dd579c3de 100644 --- a/src/core/blitzkrieg/processes.ts +++ b/src/core/blitzkrieg/processes.ts @@ -1,5 +1,5 @@ import { client } from '../discord/client'; -import { discordBlitzDB } from './discordBlitz'; +import { discordBlitzDB } from './discordBlitzDB'; const EXIT_EVENTS = [ 'beforeExit', diff --git a/src/core/blitzkrieg/readTexture.ts b/src/core/blitzkrieg/readTexture.ts deleted file mode 100644 index 81fe709fb..000000000 --- a/src/core/blitzkrieg/readTexture.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { existsSync } from 'fs'; -import sharp from 'sharp'; -import { Vector3Tuple } from 'three'; -import { readDVPLFile } from '../blitz/readDVPLFile'; -import { DdsReadStream } from '../streams/dds'; -import { PvrReadStream } from '../streams/pvr'; - -export enum TextureMutation { - Normal, - RoughnessMetallicness, - BaseColor, - Miscellaneous, -} - -type ReadTextureOptions = - | { - mutation: - | TextureMutation.Normal - | TextureMutation.RoughnessMetallicness - | TextureMutation.Miscellaneous; - } - | { - mutation: TextureMutation.BaseColor; - /** - * Normalized between 0 and 1 - */ - baseColor: Vector3Tuple; - }; - -export async function readTexture(path: string, options?: ReadTextureOptions) { - const ddsTexturePath = path.replace('.tex', '.dx11.dds.dvpl'); - const isDds = existsSync(ddsTexturePath); - const resolvedTexturePath = isDds - ? ddsTexturePath - : ddsTexturePath.replace('.dds', '.pvr'); - const decompressedDvpl = await readDVPLFile(resolvedTexturePath); - - const raw = isDds - ? await new DdsReadStream(decompressedDvpl.buffer).dds() - : new PvrReadStream(decompressedDvpl.buffer).pvr(); - const channels = 4 * raw.width * raw.height; - - switch (options?.mutation) { - case TextureMutation.Normal: { - for (let index = 0; index < channels; index += 4) { - /** - * Red is always 255 and blue is always 0. Only alpha and green contain any - * sort of information. - */ - let x = raw.data[index + 3] * (2 / 255) - 1; - let y = raw.data[index + 1] * (2 / 255) - 1; - const underSqrt = 1 - x ** 2 - y ** 2; - let z = underSqrt > 0 ? Math.sqrt(underSqrt) : -Math.sqrt(-underSqrt); - - raw.data[index] = Math.round((x + 1) * (255 / 2)); - raw.data[index + 1] = Math.round((y + 1) * (255 / 2)); - raw.data[index + 2] = Math.round((z + 1) * (255 / 2)); - raw.data[index + 3] = 255; - } - - break; - } - - case TextureMutation.RoughnessMetallicness: { - for (let index = 0; index < channels; index += 4) { - /** - * Same channel situation as normal maps. - */ - const metallicness = raw.data[index + 1]; - const roughness = raw.data[index + 3]; - - raw.data[index] = 0; - raw.data[index + 1] = roughness; - raw.data[index + 2] = metallicness; - raw.data[index + 3] = 255; - } - - break; - } - - case TextureMutation.Miscellaneous: { - for (let index = 0; index < channels; index += 4) { - /** - * Alpha is ambient occlusion and green is emissive. But very few tanks - * use emissive so I am ignoring it for now. - */ - // const emissive = raw.data[index + 1]; - const occlusion = raw.data[index + 3]; - - raw.data[index] = occlusion; - raw.data[index + 1] = 0; - raw.data[index + 2] = 0; - raw.data[index + 3] = 255; - } - - break; - } - - case TextureMutation.BaseColor: { - for (let index = 0; index < channels; index += 4) { - // alpha map is specularity but I am ignoring it for now - raw.data[index + 3] = 255; - } - - break; - } - } - - return await sharp(raw.data, { raw: raw }).png().toBuffer(); -} diff --git a/src/core/blitzkrieg/readTexture/constants.ts b/src/core/blitzkrieg/readTexture/constants.ts new file mode 100644 index 000000000..560a59f5f --- /dev/null +++ b/src/core/blitzkrieg/readTexture/constants.ts @@ -0,0 +1,6 @@ +export enum TextureMutation { + Normal, + RoughnessMetallicness, + Albedo, + Miscellaneous, +} diff --git a/src/core/blitzkrieg/readTexture/index.ts b/src/core/blitzkrieg/readTexture/index.ts new file mode 100644 index 000000000..9f55a3fea --- /dev/null +++ b/src/core/blitzkrieg/readTexture/index.ts @@ -0,0 +1,79 @@ +import { existsSync } from 'fs'; +import sharp from 'sharp'; +import { readDVPLFile } from '../../blitz/readDVPLFile'; +import { DdsReadStream } from '../../streams/dds'; +import { PvrReadStream } from '../../streams/pvr'; +import { TextureMutation } from './constants'; + +export async function readTexture(path: string, mutation?: TextureMutation) { + const ddsTexturePath = path.replace('.tex', '.dx11.dds.dvpl'); + const isDds = existsSync(ddsTexturePath); + const resolvedTexturePath = isDds + ? ddsTexturePath + : ddsTexturePath.replace('.dds', '.pvr'); + const decompressedDvpl = await readDVPLFile(resolvedTexturePath); + + const raw = isDds + ? await new DdsReadStream(decompressedDvpl.buffer).dds() + : new PvrReadStream(decompressedDvpl.buffer).pvr(); + + switch (mutation) { + case TextureMutation.Normal: { + const bytes = 4 * raw.width * raw.height; + for (let index = 0; index < bytes; index += 4) { + /** + * Red is always 255 and blue is always 0. Only alpha and green contain any + * sort of information. + */ + let x = raw.data[index + 3] * (2 / 255) - 1; + let y = raw.data[index + 1] * (2 / 255) - 1; + const underSqrt = 1 - x ** 2 - y ** 2; + let z = underSqrt > 0 ? Math.sqrt(underSqrt) : -Math.sqrt(-underSqrt); + + raw.data[index] = Math.round((x + 1) * (255 / 2)); + raw.data[index + 1] = Math.round((y + 1) * (255 / 2)); + raw.data[index + 2] = Math.round((z + 1) * (255 / 2)); + raw.data[index + 3] = 255; + } + + return await sharp(raw.data, { raw }).png().toBuffer(); + } + + case TextureMutation.RoughnessMetallicness: { + const newImage = sharp(Buffer.alloc(raw.width * raw.height), { + raw: { ...raw, channels: 1 }, + }); + const metallicness = sharp(raw.data, { raw }) + .extractChannel('green') + .png() + .toBuffer(); + const roughness = sharp(raw.data, { raw }) + .extractChannel('alpha') + .png() + .toBuffer(); + + return await newImage + .joinChannel(await Promise.all([roughness, metallicness])) + .png() + .toBuffer(); + } + + case TextureMutation.Miscellaneous: { + /** + * Alpha is ambient occlusion and green is emissive. But very few tanks + * use emissive so I am ignoring it for now. + */ + return await sharp(raw.data, { raw }) + .extractChannel('alpha') + .png() + .toBuffer(); + } + + case TextureMutation.Albedo: { + return await sharp(raw.data, { raw }).removeAlpha().png().toBuffer(); + } + + default: + return await sharp(raw.data, { raw }).png().toBuffer(); + } +} diff --git a/src/core/blitzkrieg/resetSession.ts b/src/core/blitzkrieg/resetSession.ts new file mode 100644 index 000000000..3164ba54d --- /dev/null +++ b/src/core/blitzkrieg/resetSession.ts @@ -0,0 +1,8 @@ +import { useSession } from '../../stores/session'; +import { setSession } from './setSession'; + +export function resetSession() { + const session = useSession.getState(); + if (!session.isTracking) return; + setSession(session.region, session.id, session.nickname); +} diff --git a/src/core/blitzkrieg/resolveDpm.ts b/src/core/blitzkrieg/resolveDpm.ts index 9224442b8..028602fac 100644 --- a/src/core/blitzkrieg/resolveDpm.ts +++ b/src/core/blitzkrieg/resolveDpm.ts @@ -20,8 +20,8 @@ export function resolveDpm( } else { return ( ((alpha * gun.count) / - (gun.reload.reduce((a, b) => a + b, 0) + - (gun.count - 1) * gun.intraClip)) * + (reloadCoefficient * gun.reload.reduce((a, b) => a + b, 0) + + (gun.count - 1) * gun.intraClip * intraClipCoefficient)) * 60 ); } diff --git a/src/core/blitzkrieg/secrets.ts b/src/core/blitzkrieg/secrets.ts index 5cb7ae534..35d968746 100644 --- a/src/core/blitzkrieg/secrets.ts +++ b/src/core/blitzkrieg/secrets.ts @@ -2,7 +2,7 @@ import { config } from 'dotenv'; config(); -export const SECRET_KEYS = [ +const SECRET_KEYS = [ 'DISCORD_TOKEN', 'GH_TOKEN', 'DISCORD_BLITZ_DB', diff --git a/src/core/blitzkrieg/setSession.ts b/src/core/blitzkrieg/setSession.ts new file mode 100644 index 000000000..fea967a3d --- /dev/null +++ b/src/core/blitzkrieg/setSession.ts @@ -0,0 +1,30 @@ +import { Region } from '../../constants/regions'; +import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; +import { useSession } from '../../stores/session'; +import { NormalizedTankStats, TanksStats } from '../../types/tanksStats'; +import fetchBlitz from '../blitz/fetchBlitz'; + +export async function setSession(region: Region, id: number, nickname: string) { + // TODO: generalize this function and also check for more of these kind + const rawTankStats = ( + await fetchBlitz( + `https://api.wotblitz.${region}/wotb/tanks/stats/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, + ) + )[id]; + const tankStats = rawTankStats.reduce( + (accumulator, tank) => ({ + ...accumulator, + [tank.tank_id]: tank, + }), + {}, + ); + + useSession.setState({ + isTracking: true, + id, + region, + nickname, + tankStats, + time: Date.now(), + }); +} diff --git a/src/core/blitzkrieg/tankDefinitions/constants.ts b/src/core/blitzkrieg/tankDefinitions/constants.ts new file mode 100644 index 000000000..b7f928d6c --- /dev/null +++ b/src/core/blitzkrieg/tankDefinitions/constants.ts @@ -0,0 +1,52 @@ +import { CrewMember, GunDefinition, ShellType, Tier } from '.'; +import { TankClass } from '../../../components/Tanks'; + +export const SHELL_NAMES: Record = { + ap: 'AP', + ap_cr: 'APCR', + hc: 'HEAT', + he: 'HE', +}; +export const CREW_MEMBER_NAMES: Record = { + commander: 'Commander', + radioman: 'Radioman', + gunner: 'Gunner', + driver: 'Driver', + loader: 'Loader', +}; +export const GUN_TYPE_NAMES: Record = { + regular: 'Regular', + autoLoader: 'Auto loader', + autoReloader: 'Auto reloader', +}; +export const TANK_ICONS: Record = { + 'AT-SPG': 'https://i.imgur.com/BIHSEH0.png', + lightTank: 'https://i.imgur.com/CSNha5V.png', + mediumTank: 'https://i.imgur.com/wvf3ltm.png', + heavyTank: 'https://i.imgur.com/ECeqlZa.png', +}; +export const TANK_ICONS_PREMIUM: Record = { + 'AT-SPG': 'https://i.imgur.com/TCu3EdR.png', + lightTank: 'https://i.imgur.com/zdkpTRb.png', + mediumTank: 'https://i.imgur.com/3z7eHX6.png', + heavyTank: 'https://i.imgur.com/P3vbmyA.png', +}; +export const TANK_ICONS_COLLECTOR: Record = { + 'AT-SPG': 'https://i.imgur.com/WTjeirB.png', + lightTank: 'https://i.imgur.com/EwhtKkU.png', + mediumTank: 'https://i.imgur.com/u8YDMBh.png', + heavyTank: 'https://i.imgur.com/8xRf3nc.png', +}; +export const TIERS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as const; +export const TIER_ROMAN_NUMERALS: Record = { + 1: 'I', + 2: 'II', + 3: 'III', + 4: 'IV', + 5: 'V', + 6: 'VI', + 7: 'VII', + 8: 'VIII', + 9: 'IX', + 10: 'X', +}; diff --git a/src/core/blitzkrieg/tankDefinitions.ts b/src/core/blitzkrieg/tankDefinitions/index.ts similarity index 70% rename from src/core/blitzkrieg/tankDefinitions.ts rename to src/core/blitzkrieg/tankDefinitions/index.ts index 3322f34f9..7edca84ff 100644 --- a/src/core/blitzkrieg/tankDefinitions.ts +++ b/src/core/blitzkrieg/tankDefinitions/index.ts @@ -1,18 +1,12 @@ import { deburr } from 'lodash'; import { Vector2Tuple } from 'three'; -import { TankClass, TreeType } from '../../components/Tanks'; -import { asset } from './asset'; -import { fetchCdonLz4 } from './fetchCdonLz4'; +import { TankClass, TreeType } from '../../../components/Tanks'; +import { asset } from '../asset'; +import { fetchCdonLz4 } from '../fetchCdonLz4'; +import { TIERS } from './constants'; export type ShellType = 'ap' | 'ap_cr' | 'hc' | 'he'; -export const SHELL_NAMES: Record = { - ap: 'AP', - ap_cr: 'APCR', - hc: 'HEAT', - he: 'HE', -}; - export type CrewMember = | 'commander' | 'radioman' @@ -20,13 +14,6 @@ export type CrewMember = | 'driver' | 'loader'; export type TankDefinitions = Record; -export const CREW_MEMBER_NAMES: Record = { - commander: 'Commander', - radioman: 'Radioman', - gunner: 'Gunner', - driver: 'Driver', - loader: 'Loader', -}; export interface Crew { type: CrewMember; count?: number; @@ -148,12 +135,6 @@ export type ShellDefinition = { explosionRadius?: number; }; -export const GUN_TYPE_NAMES: Record = { - regular: 'Regular', - autoLoader: 'Auto loader', - autoReloader: 'Auto reloader', -}; - export const tankDefinitions = fetchCdonLz4( asset('definitions/tanks.cdon.lz4'), ); @@ -180,44 +161,8 @@ export const tankNames = tanksDefinitionsArray.then((tanks) => ), ); -export const TANK_ICONS: Record = { - 'AT-SPG': 'https://i.imgur.com/BIHSEH0.png', - lightTank: 'https://i.imgur.com/CSNha5V.png', - mediumTank: 'https://i.imgur.com/wvf3ltm.png', - heavyTank: 'https://i.imgur.com/ECeqlZa.png', -}; - -export const TANK_ICONS_PREMIUM: Record = { - 'AT-SPG': 'https://i.imgur.com/TCu3EdR.png', - lightTank: 'https://i.imgur.com/zdkpTRb.png', - mediumTank: 'https://i.imgur.com/3z7eHX6.png', - heavyTank: 'https://i.imgur.com/P3vbmyA.png', -}; - -export const TANK_ICONS_COLLECTOR: Record = { - 'AT-SPG': 'https://i.imgur.com/WTjeirB.png', - lightTank: 'https://i.imgur.com/EwhtKkU.png', - mediumTank: 'https://i.imgur.com/u8YDMBh.png', - heavyTank: 'https://i.imgur.com/8xRf3nc.png', -}; - -export const TIERS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] as const; - export type Tier = (typeof TIERS)[number]; -export const TIER_ROMAN_NUMERALS: Record = { - 1: 'I', - 2: 'II', - 3: 'III', - 4: 'IV', - 5: 'V', - 6: 'VI', - 7: 'VII', - 8: 'VIII', - 9: 'IX', - 10: 'X', -}; - export const NATIONS = tanksDefinitionsArray.then((tanks) => { const nations = Array.from( new Set(Object.values(tanks).map((tank) => tank.nation)), diff --git a/src/core/blitzstars/getPlayerHistories.ts b/src/core/blitzstars/getPlayerHistories.ts index b64bcc617..5d876ebd0 100644 --- a/src/core/blitzstars/getPlayerHistories.ts +++ b/src/core/blitzstars/getPlayerHistories.ts @@ -7,7 +7,7 @@ import { } from '../../types/histories'; import { getAccountInfo } from '../blitz/getAccountInfo'; import { PlayerStats } from './getPlayerStats'; -import { emptyAllStats } from './getStatsInPeriod'; +import { emptyAllStats } from './getStatsInPeriod/constants'; export default async function getPlayerHistories( server: Region, diff --git a/src/core/blitzstars/getPlayerStats.ts b/src/core/blitzstars/getPlayerStats.ts index effff133b..a9c8980fe 100644 --- a/src/core/blitzstars/getPlayerStats.ts +++ b/src/core/blitzstars/getPlayerStats.ts @@ -1,7 +1,7 @@ import { Region } from '../../constants/regions'; import { AllStats } from '../blitz/getAccountInfo'; -export interface IndividualPlayerStats { +interface IndividualPlayerStats { clan: { clan_id: number; name: string; tag: string }; statistics: { all: AllStats; diff --git a/src/core/blitzstars/getStatsInPeriod/constants.ts b/src/core/blitzstars/getStatsInPeriod/constants.ts new file mode 100644 index 000000000..9e41e3dda --- /dev/null +++ b/src/core/blitzstars/getStatsInPeriod/constants.ts @@ -0,0 +1,21 @@ +import { AllStats } from '../../blitz/getAccountInfo'; + +export const emptyAllStats: AllStats = { + battles: 0, + capture_points: 0, + damage_dealt: 0, + damage_received: 0, + dropped_capture_points: 0, + frags: 0, + frags8p: 0, + hits: 0, + losses: 0, + max_frags: 0, + max_xp: 0, + shots: 0, + spotted: 0, + survived_battles: 0, + xp: 0, + win_and_survived: 0, + wins: 0, +}; diff --git a/src/core/blitzstars/getStatsInPeriod.ts b/src/core/blitzstars/getStatsInPeriod/index.ts similarity index 86% rename from src/core/blitzstars/getStatsInPeriod.ts rename to src/core/blitzstars/getStatsInPeriod/index.ts index 9b20c2e64..650bb40ac 100644 --- a/src/core/blitzstars/getStatsInPeriod.ts +++ b/src/core/blitzstars/getStatsInPeriod/index.ts @@ -1,32 +1,13 @@ import { Locale } from 'discord.js'; -import { Region } from '../../constants/regions'; -import { AllStats } from '../blitz/getAccountInfo'; +import { Region } from '../../../constants/regions'; +import { AllStats } from '../../blitz/getAccountInfo'; import getTankHistories, { TankHistories, TankHistoryRaw, -} from '../blitzkrieg/getTankHistories'; +} from '../../blitzkrieg/getTankHistories'; +import { emptyAllStats } from './constants'; -export const emptyAllStats: AllStats = { - battles: 0, - capture_points: 0, - damage_dealt: 0, - damage_received: 0, - dropped_capture_points: 0, - frags: 0, - frags8p: 0, - hits: 0, - losses: 0, - max_frags: 0, - max_xp: 0, - shots: 0, - spotted: 0, - survived_battles: 0, - xp: 0, - win_and_survived: 0, - wins: 0, -}; - -export const emptyTankHistoryNode: TankHistoryRaw = { +const emptyTankHistoryNode: TankHistoryRaw = { account_id: 0, battle_life_time: 0, last_battle_time: 0, diff --git a/src/core/blitzstars/tankAverages.ts b/src/core/blitzstars/tankAverages.ts index 7ce28099f..4a80d832f 100644 --- a/src/core/blitzstars/tankAverages.ts +++ b/src/core/blitzstars/tankAverages.ts @@ -2,7 +2,7 @@ import { AllStats } from '../blitz/getAccountInfo'; import { context } from '../blitzkrieg/context'; import { tankDefinitions } from '../blitzkrieg/tankDefinitions'; -export interface SpecialStats { +interface SpecialStats { winrate: number; damageRatio: number; kdr: number; diff --git a/src/core/discord/addFilterOptions.ts b/src/core/discord/addFilterOptions.ts index d8d345e8e..3c874f7e5 100644 --- a/src/core/discord/addFilterOptions.ts +++ b/src/core/discord/addFilterOptions.ts @@ -4,7 +4,10 @@ import { SlashCommandBuilder, SlashCommandSubcommandBuilder, } from 'discord.js'; -import { TANK_CLASSES, TREE_TYPES } from '../../components/Tanks'; +import { + TANK_CLASSES, + TREE_TYPES, +} from '../../components/Tanks/components/Item/constants'; import { translator } from '../localization/translator'; import addTankChoices from './addTankChoices'; import addTierChoices from './addTierChoices'; diff --git a/src/core/discord/autocompleteClan/constants.ts b/src/core/discord/autocompleteClan/constants.ts new file mode 100644 index 000000000..26b7f01f6 --- /dev/null +++ b/src/core/discord/autocompleteClan/constants.ts @@ -0,0 +1,2 @@ +export const DISCORD_CHOICES_MAX_NAME_SIZE = 25; +export const OVERFLOW_SUFFIX = '…'; diff --git a/src/core/discord/autocompleteClan.ts b/src/core/discord/autocompleteClan/index.ts similarity index 85% rename from src/core/discord/autocompleteClan.ts rename to src/core/discord/autocompleteClan/index.ts index 142282ad2..ea317791b 100644 --- a/src/core/discord/autocompleteClan.ts +++ b/src/core/discord/autocompleteClan/index.ts @@ -3,11 +3,9 @@ import { AutocompleteInteraction, CacheType, } from 'discord.js'; -import searchClansAcrossRegions from '../blitz/searchClansAcrossRegions'; -import { translator } from '../localization/translator'; - -export const DISCORD_CHOICES_MAX_NAME_SIZE = 25; -export const OVERFLOW_SUFFIX = '…'; +import searchClansAcrossRegions from '../../blitz/searchClansAcrossRegions'; +import { translator } from '../../localization/translator'; +import { DISCORD_CHOICES_MAX_NAME_SIZE, OVERFLOW_SUFFIX } from './constants'; export default async function autocompleteClan( interaction: AutocompleteInteraction, diff --git a/src/core/discord/autocompleteTanks.ts b/src/core/discord/autocompleteTanks.ts index 479850e26..ac05a3b84 100644 --- a/src/core/discord/autocompleteTanks.ts +++ b/src/core/discord/autocompleteTanks.ts @@ -8,7 +8,7 @@ import { tankNames } from '../blitzkrieg/tankDefinitions'; import { DISCORD_CHOICES_MAX_NAME_SIZE, OVERFLOW_SUFFIX, -} from './autocompleteClan'; +} from './autocompleteClan/constants'; export default async function autocompleteTanks( interaction: AutocompleteInteraction, diff --git a/src/core/discord/autocompleteUsername.ts b/src/core/discord/autocompleteUsername.ts index a41b3860c..7f459d1fd 100644 --- a/src/core/discord/autocompleteUsername.ts +++ b/src/core/discord/autocompleteUsername.ts @@ -8,7 +8,7 @@ import { translator } from '../localization/translator'; import { DISCORD_CHOICES_MAX_NAME_SIZE, OVERFLOW_SUFFIX, -} from './autocompleteClan'; +} from './autocompleteClan/constants'; export default async function autocompleteUsername( interaction: AutocompleteInteraction, diff --git a/src/core/discord/getPeriodOptionName.ts b/src/core/discord/getPeriodOptionName.ts new file mode 100644 index 000000000..f4a58e3ad --- /dev/null +++ b/src/core/discord/getPeriodOptionName.ts @@ -0,0 +1,10 @@ +import { Locale } from 'discord.js'; +import { translator } from '../localization/translator'; +import { PeriodSize } from './addPeriodSubCommands'; + +export function getPeriodOptionName(period: PeriodSize, locale: Locale) { + const { translate } = translator(locale); + if (period === 'career') return translate('bot.common.periods.career'); + if (period === 'today') return translate('bot.common.periods.today'); + return translate('bot.common.periods.days', [period]); +} diff --git a/src/core/discord/localizationObject.ts b/src/core/discord/localizationObject.ts index 1721c00ba..af09b9833 100644 --- a/src/core/discord/localizationObject.ts +++ b/src/core/discord/localizationObject.ts @@ -1,5 +1,5 @@ import { Locale } from 'discord.js'; -import { SUPPORTED_LOCALES } from '../localization/strings'; +import { SUPPORTED_LOCALES } from '../localization/strings/constants'; import { translator } from '../localization/translator'; export function localizationObject(path: string, literals?: string[]) { diff --git a/src/core/discord/resolveClanFromCommand.ts b/src/core/discord/resolveClanFromCommand.ts index ff2e709c5..5b062736b 100644 --- a/src/core/discord/resolveClanFromCommand.ts +++ b/src/core/discord/resolveClanFromCommand.ts @@ -4,7 +4,7 @@ import { Region } from '../../constants/regions'; import { UserError } from '../../hooks/userError'; import searchClansAcrossRegions from '../blitz/searchClansAcrossRegions'; import { translator } from '../localization/translator'; -import { serverAndIdPattern } from './resolvePlayerFromCommand'; +import { serverAndIdPattern } from './resolvePlayerFromCommand/constants'; export default async function resolveClanFromCommand( interaction: ChatInputCommandInteraction, diff --git a/src/core/discord/resolvePeriodFromButton.ts b/src/core/discord/resolvePeriodFromButton.ts index ecaf7f155..ce1bc95ec 100644 --- a/src/core/discord/resolvePeriodFromButton.ts +++ b/src/core/discord/resolvePeriodFromButton.ts @@ -4,10 +4,8 @@ import getPeriodNow from '../blitzkrieg/getPeriodNow'; import getPeriodStart from '../blitzkrieg/getPeriodStart'; import getTimeDaysAgo from '../blitzkrieg/getTimeDaysAgo'; import { PeriodType } from './addPeriodSubCommands'; -import { - ResolvedPeriod, - getPeriodOptionName, -} from './resolvePeriodFromCommand'; +import { getPeriodOptionName } from './getPeriodOptionName'; +import { ResolvedPeriod } from './resolvePeriodFromCommand'; export default function resolvePeriodFromButton( region: Region, diff --git a/src/core/discord/resolvePeriodFromCommand.ts b/src/core/discord/resolvePeriodFromCommand.ts index 6681fd51f..4accc8e7e 100644 --- a/src/core/discord/resolvePeriodFromCommand.ts +++ b/src/core/discord/resolvePeriodFromCommand.ts @@ -1,17 +1,11 @@ -import { CacheType, ChatInputCommandInteraction, Locale } from 'discord.js'; +import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import { Region } from '../../constants/regions'; import getPeriodNow from '../blitzkrieg/getPeriodNow'; import getPeriodStart from '../blitzkrieg/getPeriodStart'; import getTimeDaysAgo from '../blitzkrieg/getTimeDaysAgo'; import { translator } from '../localization/translator'; -import { PeriodSize, PeriodType } from './addPeriodSubCommands'; - -export function getPeriodOptionName(period: PeriodSize, locale: Locale) { - const { translate } = translator(locale); - if (period === 'career') return translate('bot.common.periods.career'); - if (period === 'today') return translate('bot.common.periods.today'); - return translate('bot.common.periods.days', [period]); -} +import { PeriodType } from './addPeriodSubCommands'; +import { getPeriodOptionName } from './getPeriodOptionName'; export interface ResolvedPeriod { name: string; diff --git a/src/core/discord/resolvePlayerFromCommand/constants.ts b/src/core/discord/resolvePlayerFromCommand/constants.ts new file mode 100644 index 000000000..382368043 --- /dev/null +++ b/src/core/discord/resolvePlayerFromCommand/constants.ts @@ -0,0 +1 @@ +export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; diff --git a/src/core/discord/resolvePlayerFromCommand.ts b/src/core/discord/resolvePlayerFromCommand/index.ts similarity index 78% rename from src/core/discord/resolvePlayerFromCommand.ts rename to src/core/discord/resolvePlayerFromCommand/index.ts index 74044a20e..0dd292756 100644 --- a/src/core/discord/resolvePlayerFromCommand.ts +++ b/src/core/discord/resolvePlayerFromCommand/index.ts @@ -1,12 +1,11 @@ import { CacheType, ChatInputCommandInteraction } from 'discord.js'; import markdownEscape from 'markdown-escape'; -import { Region } from '../../constants/regions'; -import { UserError } from '../../hooks/userError'; -import searchPlayersAcrossRegions from '../blitz/searchPlayersAcrossRegions'; -import { getBlitzFromDiscord } from '../blitzkrieg/discordBlitz'; -import { translator } from '../localization/translator'; - -export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; +import { Region } from '../../../constants/regions'; +import { UserError } from '../../../hooks/userError'; +import searchPlayersAcrossRegions from '../../blitz/searchPlayersAcrossRegions'; +import { getBlitzFromDiscord } from '../../blitzkrieg/discordBlitz'; +import { translator } from '../../localization/translator'; +import { serverAndIdPattern } from './constants'; export interface ResolvedPlayer { region: Region; diff --git a/src/core/localization/strings/constants.ts b/src/core/localization/strings/constants.ts new file mode 100644 index 000000000..333ea32a2 --- /dev/null +++ b/src/core/localization/strings/constants.ts @@ -0,0 +1,3 @@ +import { Locale } from 'discord.js'; + +export const SUPPORTED_LOCALES: Locale[] = [Locale.SpanishES]; diff --git a/src/core/localization/strings.ts b/src/core/localization/strings/index.ts similarity index 61% rename from src/core/localization/strings.ts rename to src/core/localization/strings/index.ts index b8cde5f81..fa6057bc6 100644 --- a/src/core/localization/strings.ts +++ b/src/core/localization/strings/index.ts @@ -1,6 +1,6 @@ import { Locale } from 'discord.js'; - -export const SUPPORTED_LOCALES: Locale[] = [Locale.EnglishUS, Locale.SpanishES]; +import enUS from '../../../lang/en-US.json'; +import { SUPPORTED_LOCALES } from './constants'; export type TranslationFragmentTree = { [key: string]: TranslationFragment; @@ -11,11 +11,13 @@ export type TranslationFragment = string | TranslationFragmentTree; export const translations = SUPPORTED_LOCALES.map((locale) => ({ locale, - translations: require(`../../lang/${locale}.json`), + translations: require(`../../../lang/${locale}.json`), })).reduce( (table, { locale, translations }) => ({ ...table, [locale]: translations, }), - {}, -) as Record; + { + [Locale.EnglishUS]: enUS, + }, +) as Partial>; diff --git a/src/core/localization/translator.ts b/src/core/localization/translator.ts index 5cccbf6e7..a4f8c4265 100644 --- a/src/core/localization/translator.ts +++ b/src/core/localization/translator.ts @@ -1,11 +1,13 @@ import { Locale } from 'discord.js'; -import { SUPPORTED_LOCALES, translations } from './strings'; +import { translations } from './strings'; +import { SUPPORTED_LOCALES } from './strings/constants'; export function translator(localeRaw: Locale) { - const locale = SUPPORTED_LOCALES.includes(localeRaw) - ? localeRaw - : Locale.EnglishUS; - const strings = translations[locale]; + const locale = + localeRaw !== Locale.EnglishUS && SUPPORTED_LOCALES.includes(localeRaw) + ? localeRaw + : Locale.EnglishUS; + const strings = translations[locale]!; function translate(path: string, literals?: string[]): string { const pathArray = path.split('.'); diff --git a/src/core/statistics/getWN8Percentile.ts b/src/core/statistics/getWN8Percentile.ts index b0ece4d77..d73538d33 100644 --- a/src/core/statistics/getWN8Percentile.ts +++ b/src/core/statistics/getWN8Percentile.ts @@ -1,6 +1,6 @@ import { Percentile } from '../../constants/percentiles'; -export const WN8_PERCENTILES: [number, Percentile][] = [ +const WN8_PERCENTILES: [number, Percentile][] = [ [0, Percentile.VeryBad], [300, Percentile.Bad], [450, Percentile.BelowAverage], diff --git a/src/core/statistics/sumStats.ts b/src/core/statistics/sumStats.ts index 10c692c0b..adcdceeaa 100644 --- a/src/core/statistics/sumStats.ts +++ b/src/core/statistics/sumStats.ts @@ -1,5 +1,5 @@ import { AllStats } from '../blitz/getAccountInfo'; -import { emptyAllStats } from '../blitzstars/getStatsInPeriod'; +import { emptyAllStats } from '../blitzstars/getStatsInPeriod/constants'; export default function sumStats(allStatsCollection: AllStats[]) { return allStatsCollection.reduce((accumulated, current) => { diff --git a/src/events/guildMemberAdd.ts b/src/events/guildMemberAdd.ts index 01bf564f1..0f837d9ce 100644 --- a/src/events/guildMemberAdd.ts +++ b/src/events/guildMemberAdd.ts @@ -1,7 +1,7 @@ import { AttachmentBuilder, GuildMember, TextChannel } from 'discord.js'; import discord from '../../discord.json' assert { type: 'json' }; -export default async function (member: GuildMember) { +export default async function guildMemberAdd(member: GuildMember) { if (member.guild.id === discord.sklld_guild_id) { await ( member.guild.channels.cache.get( diff --git a/src/stores/duel/constants.ts b/src/stores/duel/constants.ts new file mode 100644 index 000000000..24cc39aea --- /dev/null +++ b/src/stores/duel/constants.ts @@ -0,0 +1,7 @@ +import { EquipmentMatrix } from '.'; + +export const genericDefaultEquipmentMatrix: EquipmentMatrix = [ + [-1, 1, -1], + [0, 0, 0], + [0, 0, 0], +]; diff --git a/src/stores/duel.ts b/src/stores/duel/index.ts similarity index 88% rename from src/stores/duel.ts rename to src/stores/duel/index.ts index e629f2921..b1897ffe4 100644 --- a/src/stores/duel.ts +++ b/src/stores/duel/index.ts @@ -8,7 +8,7 @@ import { TankDefinition, TrackDefinition, TurretDefinition, -} from '../core/blitzkrieg/tankDefinitions'; +} from '../../core/blitzkrieg/tankDefinitions'; type EquipmentMatrixItem = -1 | 0 | 1; type EquipmentMatrixRow = [ @@ -54,9 +54,3 @@ export const useDuel = create()( export function mutateDuel(recipe: (draft: Duel) => void) { useDuel.setState(produce(recipe)); } - -export const genericDefaultEquipmentMatrix: EquipmentMatrix = [ - [-1, 1, -1], - [0, 0, 0], - [0, 0, 0], -]; diff --git a/src/stores/session.ts b/src/stores/session.ts index 3a2011e9f..cf4cfe48c 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -5,9 +5,7 @@ import { persist } from 'zustand/middleware'; import { CustomColumnDisplay } from '../app/tools/session/components/CustomColumn'; import { AccentColor, GrayColor } from '../constants/radixColors'; import { Region } from '../constants/regions'; -import { WARGAMING_APPLICATION_ID } from '../constants/wargamingApplicationID'; -import fetchBlitz from '../core/blitz/fetchBlitz'; -import { NormalizedTankStats, TanksStats } from '../types/tanksStats'; +import { NormalizedTankStats } from '../types/tanksStats'; type Session = ( | { @@ -35,37 +33,6 @@ type Session = ( color: AccentColor | GrayColor; }; -export async function setSession(region: Region, id: number, nickname: string) { - // TODO: generalize this function and also check for more of these kind - const rawTankStats = ( - await fetchBlitz( - `https://api.wotblitz.${region}/wotb/tanks/stats/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, - ) - )[id]; - const tankStats = rawTankStats.reduce( - (accumulator, tank) => ({ - ...accumulator, - [tank.tank_id]: tank, - }), - {}, - ); - - useSession.setState({ - isTracking: true, - id, - region, - nickname, - tankStats, - time: Date.now(), - }); -} - -export function resetSession() { - const session = useSession.getState(); - if (!session.isTracking) return; - setSession(session.region, session.id, session.nickname); -} - export const useSession = create()( persist( (set) => ({ diff --git a/tsconfig.json b/tsconfig.json index 48adb851b..c910f50ff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,11 +10,7 @@ "noEmit": true, "resolveJsonModule": true, "jsx": "preserve", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "incremental": true, "isolatedModules": true, @@ -24,13 +20,6 @@ } ] }, - "include": [ - "src/**/*", - "scripts/**/*", - "dist/website/types/**/*.ts" - ], - "exclude": [ - "node_modules", - "dist" - ] + "include": ["src/**/*", "scripts/**/*", "dist/website/types/**/*.ts"], + "exclude": ["node_modules", "dist", "scripts"] }