mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: move tankopedia to tankDefinitions
This commit is contained in:
1 parent
cfe71e15a4
commit
ad0fc69596
25 files changed
+270
-295
No files matched your search
Vendored
+1
@@ -28,6 +28,7 @@
|
||||
"playerinfo",
|
||||
"ratingsleaderboard",
|
||||
"ratingsplot",
|
||||
"researchable",
|
||||
"Resvg",
|
||||
"roboto",
|
||||
"searchclans",
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
"build:website": "next build",
|
||||
"build:docs": "vitepress build docs",
|
||||
"build:ratingsleaderboard": "vite-node --script scripts/buildRatingsLeaderboard",
|
||||
"build:tankopedia": "vite-node --script scripts/buildTankopedia",
|
||||
"build:assets": "vite-node --script scripts/buildAssets",
|
||||
"build:ratingsplot": "vite-node --script scripts/buildRatingsPlot",
|
||||
"dev:bot": "yarn build:bot && yarn start:bot",
|
||||
"dev:docs": "vitepress dev docs",
|
||||
|
||||
@@ -2,13 +2,16 @@ import { Octokit } from '@octokit/rest';
|
||||
import decompress from 'decompress';
|
||||
import { config } from 'dotenv';
|
||||
import { writeFileSync } from 'fs';
|
||||
import { cp, mkdir, readFile, readdir, rm, writeFile } from 'fs/promises';
|
||||
import { readFile, readdir, rm } from 'fs/promises';
|
||||
import { load } from 'js-yaml';
|
||||
import { argv, env } from 'process';
|
||||
import { ElementCompact, xml2js } from 'xml-js';
|
||||
import { parse } from 'yaml';
|
||||
import { NATION_IDS } from '../src/constants/nations';
|
||||
import { BlitzkriegTankopedia, Tier } from '../src/core/blitzkrieg/tankopedia';
|
||||
import {
|
||||
TankDefinitions,
|
||||
Tier,
|
||||
} from '../src/core/blitzkrieg/definitions/tanks';
|
||||
import commitMultipleFiles, { FileChange } from './commitMultipleFiles';
|
||||
|
||||
config();
|
||||
@@ -34,27 +37,19 @@ const directoriesOfInterest = {
|
||||
};
|
||||
const directoriesOfInterestArray = Object.values(directoriesOfInterest);
|
||||
|
||||
console.log('Removing old tankopedia files...');
|
||||
await rm('dist/tankopedia', { recursive: true, force: true });
|
||||
if (!noRewrite) {
|
||||
console.log('Removing old temp files...');
|
||||
await rm(TEMP, { recursive: true, force: true });
|
||||
|
||||
console.log('Extracting Blitz files...');
|
||||
await decompress(apkFile, TEMP, {
|
||||
filter: (file) =>
|
||||
directoriesOfInterestArray.some((dir) => file.path.startsWith(dir)),
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Creating new tankopedia folder');
|
||||
await mkdir('dist/tankopedia');
|
||||
|
||||
const strings = await readFile(
|
||||
`${TEMP}/${directoriesOfInterest.strings}/${LANGUAGE}.yaml`,
|
||||
'utf-8',
|
||||
).then((data) => load(data) as Record<string, string>);
|
||||
const tankopedia: BlitzkriegTankopedia = {};
|
||||
const tankDefinitions: TankDefinitions = {};
|
||||
const tankIds: number[] = [];
|
||||
const images: Record<number, { big: string; small: string }> = {};
|
||||
const nations = await readdir(
|
||||
@@ -76,7 +71,6 @@ Promise.all(
|
||||
await Promise.all(
|
||||
Object.entries<ElementCompact>(list.root).map(
|
||||
async ([vehicle, vehicleData]) => {
|
||||
// Tankopedia
|
||||
const nationVehicleId = parseInt(list.root[vehicle].id._text);
|
||||
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
|
||||
const name = strings[vehicleData.userString._text];
|
||||
@@ -94,7 +88,7 @@ Promise.all(
|
||||
}
|
||||
|
||||
tankIds.push(id);
|
||||
tankopedia[id] = {
|
||||
tankDefinitions[id] = {
|
||||
id,
|
||||
name,
|
||||
name_short,
|
||||
@@ -121,101 +115,91 @@ Promise.all(
|
||||
.replace(/~res:\//, '')
|
||||
.replace(/\..+/, '')}.packed.webp`,
|
||||
};
|
||||
|
||||
if (!publish) {
|
||||
cp(images[id].small, `dist/tankopedia/icons/small/${id}.webp`);
|
||||
cp(images[id].big, `dist/tankopedia/icons/big/${id}.webp`);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
).then(async () => {
|
||||
if (publish) {
|
||||
const octokit = new Octokit({ auth: env.GH_TOKEN });
|
||||
// const tankopediaChange: FileChange = {
|
||||
// content: JSON.stringify(tankopedia),
|
||||
// path: 'tankopedia.json',
|
||||
// encoding: 'utf-8',
|
||||
// };
|
||||
// const iconsChange = (
|
||||
// await Promise.all(
|
||||
// tankIds.map(async (id) => {
|
||||
// try {
|
||||
// const [contentSmall, contentBig] = await Promise.all([
|
||||
// readFile(images[id].small, { encoding: 'base64' }),
|
||||
// readFile(images[id].big, { encoding: 'base64' }),
|
||||
// ]);
|
||||
if (!publish) return;
|
||||
|
||||
// return [
|
||||
// {
|
||||
// content: contentBig,
|
||||
// path: `icons/big/${id}.webp`,
|
||||
// encoding: 'base64',
|
||||
// },
|
||||
// {
|
||||
// content: contentSmall,
|
||||
// path: `icons/small/${id}.webp`,
|
||||
// encoding: 'base64',
|
||||
// },
|
||||
// ];
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// return undefined;
|
||||
// }
|
||||
// }),
|
||||
// )
|
||||
// ).flat() as FileChange[];
|
||||
const flags = await readdir(`${TEMP}/${directoriesOfInterest.flags}`);
|
||||
// const scratchedFlags = await Promise.all(
|
||||
// flags
|
||||
// .filter((flag) => flag.startsWith('flag_tutor-tank_'))
|
||||
// .map(async (flag) => {
|
||||
// const content = await readFile(
|
||||
// `${TEMP}/${directoriesOfInterest.flags}/${flag}`,
|
||||
// { encoding: 'base64' },
|
||||
// );
|
||||
// const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1];
|
||||
const octokit = new Octokit({ auth: env.GH_TOKEN });
|
||||
// const tankDefinitionsChange: FileChange = {
|
||||
// content: JSON.stringify(tankDefinitions),
|
||||
// path: 'definitions/tanks.json',
|
||||
// encoding: 'utf-8',
|
||||
// };
|
||||
// const iconsChange = (
|
||||
// await Promise.all(
|
||||
// tankIds.map(async (id) => {
|
||||
// try {
|
||||
// const [contentSmall, contentBig] = await Promise.all([
|
||||
// readFile(images[id].small, { encoding: 'base64' }),
|
||||
// readFile(images[id].big, { encoding: 'base64' }),
|
||||
// ]);
|
||||
|
||||
// return {
|
||||
// content,
|
||||
// encoding: 'base64',
|
||||
// path: `flags/scratched/${name}.webp`,
|
||||
// } satisfies FileChange;
|
||||
// }),
|
||||
// );
|
||||
const circleFlags = await Promise.all(
|
||||
flags
|
||||
.filter((flag) => flag.startsWith('flag_profile-stat_'))
|
||||
.map(async (flag) => {
|
||||
const content = await readFile(
|
||||
`${TEMP}/${directoriesOfInterest.flags}/${flag}`,
|
||||
{ encoding: 'base64' },
|
||||
);
|
||||
const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1];
|
||||
// return [
|
||||
// {
|
||||
// content: contentBig,
|
||||
// path: `icons/big/${id}.webp`,
|
||||
// encoding: 'base64',
|
||||
// },
|
||||
// {
|
||||
// content: contentSmall,
|
||||
// path: `icons/small/${id}.webp`,
|
||||
// encoding: 'base64',
|
||||
// },
|
||||
// ];
|
||||
// } catch (error) {
|
||||
// console.log(error);
|
||||
// return undefined;
|
||||
// }
|
||||
// }),
|
||||
// )
|
||||
// ).flat() as FileChange[];
|
||||
const flags = await readdir(`${TEMP}/${directoriesOfInterest.flags}`);
|
||||
// const scratchedFlags = await Promise.all(
|
||||
// flags
|
||||
// .filter((flag) => flag.startsWith('flag_tutor-tank_'))
|
||||
// .map(async (flag) => {
|
||||
// const content = await readFile(
|
||||
// `${TEMP}/${directoriesOfInterest.flags}/${flag}`,
|
||||
// { encoding: 'base64' },
|
||||
// );
|
||||
// const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1];
|
||||
|
||||
return {
|
||||
content,
|
||||
encoding: 'base64',
|
||||
path: `flags/circle/${name}.webp`,
|
||||
} satisfies FileChange;
|
||||
}),
|
||||
);
|
||||
// return {
|
||||
// content,
|
||||
// encoding: 'base64',
|
||||
// path: `flags/scratched/${name}.webp`,
|
||||
// } satisfies FileChange;
|
||||
// }),
|
||||
// );
|
||||
const circleFlags = await Promise.all(
|
||||
flags
|
||||
.filter((flag) => flag.startsWith('flag_profile-stat_'))
|
||||
.map(async (flag) => {
|
||||
const content = await readFile(
|
||||
`${TEMP}/${directoriesOfInterest.flags}/${flag}`,
|
||||
{ encoding: 'base64' },
|
||||
);
|
||||
const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1];
|
||||
|
||||
console.log('Writing files...');
|
||||
await commitMultipleFiles(
|
||||
octokit,
|
||||
'tresabhi',
|
||||
'blitzkrieg-assets',
|
||||
'main',
|
||||
new Date().toString(),
|
||||
circleFlags,
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
writeFile(
|
||||
'dist/tankopedia/tankopedia.json',
|
||||
JSON.stringify(tankopedia, null, 2),
|
||||
);
|
||||
}
|
||||
return {
|
||||
content,
|
||||
encoding: 'base64',
|
||||
path: `flags/circle/${name}.webp`,
|
||||
} satisfies FileChange;
|
||||
}),
|
||||
);
|
||||
|
||||
console.log('Writing files...');
|
||||
await commitMultipleFiles(
|
||||
octokit,
|
||||
'tresabhi',
|
||||
'blitzkrieg-assets',
|
||||
'main',
|
||||
new Date().toString(),
|
||||
circleFlags,
|
||||
true,
|
||||
);
|
||||
});
|
||||
@@ -7,9 +7,9 @@ import { TreeTypeEnum } from '../../../components/Tanks';
|
||||
import { WARGAMING_APPLICATION_ID } from '../../../constants/wargamingApplicationID';
|
||||
import fetchBlitz from '../../../core/blitz/fetchBlitz';
|
||||
import {
|
||||
BlitzkriegTankopediaEntry,
|
||||
tankopedia,
|
||||
} from '../../../core/blitzkrieg/tankopedia';
|
||||
TankDefinition,
|
||||
tankDefinitions,
|
||||
} from '../../../core/blitzkrieg/definitions/tanks';
|
||||
import { tankAverages } from '../../../core/blitzstars/tankAverages';
|
||||
import calculateWN8 from '../../../core/statistics/calculateWN8';
|
||||
import { deltaTankStats } from '../../../core/statistics/deltaTankStats';
|
||||
@@ -30,7 +30,7 @@ export default function SessionPage() {
|
||||
|
||||
list: {
|
||||
stats: IndividualTankStats;
|
||||
tankopedia?: BlitzkriegTankopediaEntry;
|
||||
tankDefinitions?: TankDefinition;
|
||||
career: IndividualTankStats;
|
||||
currentWN8?: number;
|
||||
careerWN8?: number;
|
||||
@@ -88,7 +88,7 @@ export default function SessionPage() {
|
||||
}),
|
||||
{},
|
||||
);
|
||||
const awaitedTankopedia = await tankopedia;
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedTankAverages = await tankAverages;
|
||||
const careerWN8 =
|
||||
careerRaw[id].reduce(
|
||||
@@ -119,7 +119,7 @@ export default function SessionPage() {
|
||||
).map((stats) => {
|
||||
return {
|
||||
stats,
|
||||
tankopedia: awaitedTankopedia[stats.tank_id],
|
||||
tankDefinitions: awaitedTankDefinitions[stats.tank_id],
|
||||
career: career[stats.tank_id],
|
||||
currentWN8: awaitedTankAverages[stats.tank_id]
|
||||
? calculateWN8(
|
||||
@@ -238,95 +238,97 @@ export default function SessionPage() {
|
||||
.sort(
|
||||
(a, b) => b.stats.last_battle_time - a.stats.last_battle_time,
|
||||
)
|
||||
.map(({ stats, tankopedia, career, careerWN8, currentWN8 }) => {
|
||||
const rowStats: Record<
|
||||
CustomColumnDisplay,
|
||||
Breakdown.RowStatItem | undefined
|
||||
> = {
|
||||
battles: {
|
||||
title: 'Battles',
|
||||
current: stats.all.battles.toLocaleString(),
|
||||
career: career.all.battles.toLocaleString(),
|
||||
},
|
||||
winrate: {
|
||||
title: 'Winrate',
|
||||
current: `${(
|
||||
100 *
|
||||
(stats.all.wins / stats.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
career: `${(
|
||||
100 *
|
||||
(career.all.wins / career.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
delta:
|
||||
stats.all.wins / stats.all.battles -
|
||||
career.all.wins / career.all.battles,
|
||||
},
|
||||
wn8: {
|
||||
title: 'WN8',
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(currentWN8).toLocaleString(),
|
||||
career:
|
||||
careerWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(careerWN8).toLocaleString(),
|
||||
percentile:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
damage: {
|
||||
title: 'Damage',
|
||||
current: Math.round(
|
||||
stats.all.damage_dealt / stats.all.battles,
|
||||
).toLocaleString(),
|
||||
career: Math.round(
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
).toLocaleString(),
|
||||
delta:
|
||||
stats.all.damage_dealt / stats.all.battles -
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
},
|
||||
none: undefined,
|
||||
};
|
||||
.map(
|
||||
({ stats, tankDefinitions, career, careerWN8, currentWN8 }) => {
|
||||
const rowStats: Record<
|
||||
CustomColumnDisplay,
|
||||
Breakdown.RowStatItem | undefined
|
||||
> = {
|
||||
battles: {
|
||||
title: 'Battles',
|
||||
current: stats.all.battles.toLocaleString(),
|
||||
career: career.all.battles.toLocaleString(),
|
||||
},
|
||||
winrate: {
|
||||
title: 'Winrate',
|
||||
current: `${(
|
||||
100 *
|
||||
(stats.all.wins / stats.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
career: `${(
|
||||
100 *
|
||||
(career.all.wins / career.all.battles)
|
||||
).toFixed(2)}%`,
|
||||
delta:
|
||||
stats.all.wins / stats.all.battles -
|
||||
career.all.wins / career.all.battles,
|
||||
},
|
||||
wn8: {
|
||||
title: 'WN8',
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(currentWN8).toLocaleString(),
|
||||
career:
|
||||
careerWN8 === undefined
|
||||
? undefined
|
||||
: Math.round(careerWN8).toLocaleString(),
|
||||
percentile:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
damage: {
|
||||
title: 'Damage',
|
||||
current: Math.round(
|
||||
stats.all.damage_dealt / stats.all.battles,
|
||||
).toLocaleString(),
|
||||
career: Math.round(
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
).toLocaleString(),
|
||||
delta:
|
||||
stats.all.damage_dealt / stats.all.battles -
|
||||
career.all.damage_dealt / career.all.battles,
|
||||
},
|
||||
none: undefined,
|
||||
};
|
||||
|
||||
return (
|
||||
<Breakdown.Row
|
||||
color={session.color}
|
||||
key={stats.tank_id}
|
||||
minimized={!session.showCareer}
|
||||
title={
|
||||
tankopedia?.name_short ??
|
||||
tankopedia?.name ??
|
||||
`Unknown tank ${stats.tank_id}`
|
||||
}
|
||||
type="tank"
|
||||
tankType={tankopedia?.type}
|
||||
treeType={(() => {
|
||||
if (tankopedia?.tree_type === 'collector')
|
||||
return TreeTypeEnum.Collector;
|
||||
if (tankopedia?.tree_type === 'premium')
|
||||
return TreeTypeEnum.Premium;
|
||||
})()}
|
||||
stats={session.customColumns.map((customColumn) => {
|
||||
const rowStat = rowStats[customColumn.display];
|
||||
return (
|
||||
<Breakdown.Row
|
||||
color={session.color}
|
||||
key={stats.tank_id}
|
||||
minimized={!session.showCareer}
|
||||
title={
|
||||
tankDefinitions?.name_short ??
|
||||
tankDefinitions?.name ??
|
||||
`Unknown tank ${stats.tank_id}`
|
||||
}
|
||||
type="tank"
|
||||
tankType={tankDefinitions?.type}
|
||||
treeType={(() => {
|
||||
if (tankDefinitions?.tree_type === 'collector')
|
||||
return TreeTypeEnum.Collector;
|
||||
if (tankDefinitions?.tree_type === 'premium')
|
||||
return TreeTypeEnum.Premium;
|
||||
})()}
|
||||
stats={session.customColumns.map((customColumn) => {
|
||||
const rowStat = rowStats[customColumn.display];
|
||||
|
||||
if (!rowStat) return undefined;
|
||||
if (!rowStat) return undefined;
|
||||
|
||||
return {
|
||||
...rowStat,
|
||||
delta:
|
||||
customColumn.showDelta &&
|
||||
rowStat.percentile === undefined
|
||||
? rowStat.delta
|
||||
: undefined,
|
||||
};
|
||||
})}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
return {
|
||||
...rowStat,
|
||||
delta:
|
||||
customColumn.showDelta &&
|
||||
rowStat.percentile === undefined
|
||||
? rowStat.delta
|
||||
: undefined,
|
||||
};
|
||||
})}
|
||||
/>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</Breakdown.Root>
|
||||
</div>
|
||||
</ContextMenu.Trigger>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
NATIONS,
|
||||
TIERS,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from '../../../../core/blitzkrieg/tankopedia';
|
||||
} from '../../../../core/blitzkrieg/definitions/tanks';
|
||||
import mutateTankopedia, {
|
||||
TankopediaSortBy,
|
||||
TankopediaSortDirection,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { CaretLeftIcon, CaretRightIcon } from '@radix-ui/react-icons';
|
||||
import { Button, Flex, TextField } from '@radix-ui/themes';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { BlitzkriegTankopediaEntry } from '../../../../core/blitzkrieg/tankopedia';
|
||||
import { TankDefinition } from '../../../../core/blitzkrieg/definitions/tanks';
|
||||
|
||||
interface PageTurnerProps {
|
||||
page: number;
|
||||
setPage: (page: number) => void;
|
||||
searchedList: BlitzkriegTankopediaEntry[];
|
||||
searchedList: TankDefinition[];
|
||||
tanksPerPage: number;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@ import { go } from 'fuzzysort';
|
||||
import { Suspense, use, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import PageWrapper from '../../../components/PageWrapper';
|
||||
import { asset } from '../../../core/blitzkrieg/asset';
|
||||
import { tankIcon } from '../../../core/blitzkrieg/tankIcon';
|
||||
import {
|
||||
BlitzkriegTankopediaEntry,
|
||||
TANK_ICONS,
|
||||
TANK_ICONS_COLLECTOR,
|
||||
TANK_ICONS_PREMIUM,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
tanks,
|
||||
} from '../../../core/blitzkrieg/tankopedia';
|
||||
TankDefinition,
|
||||
tanksDefinitionsArray,
|
||||
} from '../../../core/blitzkrieg/definitions/tanks';
|
||||
import { tankIcon } from '../../../core/blitzkrieg/tankIcon';
|
||||
import { theme } from '../../../stitches.config';
|
||||
import { useTankopedia } from '../../../stores/tankopedia';
|
||||
import { Options } from './components/Options';
|
||||
@@ -26,7 +26,7 @@ const TANKS_PER_PAGE = 3 * 2 ** 4;
|
||||
|
||||
export default function Page() {
|
||||
const tankopediaState = useTankopedia();
|
||||
const awaitedTanks = use(tanks);
|
||||
const awaitedTanks = use(tanksDefinitionsArray);
|
||||
const input = useRef<HTMLInputElement>(null);
|
||||
const searchableTanks = useMemo(
|
||||
() =>
|
||||
@@ -102,7 +102,7 @@ export default function Page() {
|
||||
'name',
|
||||
'name_short',
|
||||
'id',
|
||||
] satisfies (keyof BlitzkriegTankopediaEntry)[],
|
||||
] satisfies (keyof TankDefinition)[],
|
||||
}).map(({ obj }) => obj),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
|
||||
import getTankStats from '../core/blitz/getTankStats';
|
||||
import getTreeType from '../core/blitz/getTreeType';
|
||||
import resolveTankName from '../core/blitz/resolveTankName';
|
||||
import { tankDefinitions } from '../core/blitzkrieg/definitions/tanks';
|
||||
import { filtersToDescription } from '../core/blitzkrieg/filtersToDescription';
|
||||
import { tankopedia } from '../core/blitzkrieg/tankopedia';
|
||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
||||
import getStatsInPeriod from '../core/blitzstars/getStatsInPeriod';
|
||||
import { tankAverages } from '../core/blitzstars/tankAverages';
|
||||
@@ -44,7 +44,7 @@ async function render(
|
||||
{ start, end, name }: ResolvedPeriod,
|
||||
filters: StatFilters,
|
||||
) {
|
||||
const awaitedTankopedia = await tankopedia;
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedTankAverages = await tankAverages;
|
||||
const statsInPeriod = await getStatsInPeriod(region, id, start, end);
|
||||
const { filteredOrder } = await filterStats(statsInPeriod, filters);
|
||||
@@ -183,7 +183,7 @@ async function render(
|
||||
|
||||
await Promise.all(
|
||||
filteredOrder.map(async (id, index) => {
|
||||
const tankopediaEntry = awaitedTankopedia[id];
|
||||
const tankDefinition = awaitedTankDefinitions[id];
|
||||
const current = orderedCurrentStats[index];
|
||||
const career = orderedCareerStats[index];
|
||||
const currentWN8 = orderedCurrentWN8[index];
|
||||
@@ -193,8 +193,8 @@ async function render(
|
||||
<Breakdown.Row
|
||||
key={id}
|
||||
type="tank"
|
||||
tankType={tankopediaEntry?.type}
|
||||
treeType={tankopediaEntry ? await getTreeType(id) : undefined}
|
||||
tankType={tankDefinition?.type}
|
||||
treeType={tankDefinition ? await getTreeType(id) : undefined}
|
||||
title={await resolveTankName(id)}
|
||||
stats={[
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { getAccountInfo } from '../core/blitz/getAccountInfo';
|
||||
import { tankDefinitions } from '../core/blitzkrieg/definitions/tanks';
|
||||
import getPeriodNow from '../core/blitzkrieg/getPeriodNow';
|
||||
import getTimeDaysAgo from '../core/blitzkrieg/getTimeDaysAgo';
|
||||
import { tankopedia } from '../core/blitzkrieg/tankopedia';
|
||||
import getStatsInPeriod from '../core/blitzstars/getStatsInPeriod';
|
||||
import { tankAverages } from '../core/blitzstars/tankAverages';
|
||||
import addUsernameChoices from '../core/discord/addUsernameChoices';
|
||||
@@ -66,11 +66,11 @@ export const eligibleCommand: CommandRegistry = {
|
||||
(await entries.reduce<PossiblyPromise<number>>(
|
||||
async (accumulator, [tankIdString, stats]) => {
|
||||
const tankId = parseInt(tankIdString);
|
||||
const tankopediaEntry = (await tankopedia)[tankId];
|
||||
const tankDefinition = (await tankDefinitions)[tankId];
|
||||
|
||||
if (!tankopediaEntry) return accumulator;
|
||||
if (!tankDefinition) return accumulator;
|
||||
|
||||
const tankTier = tankopediaEntry.tier;
|
||||
const tankTier = tankDefinition.tier;
|
||||
|
||||
return (await accumulator) + tankTier * stats.battles;
|
||||
},
|
||||
@@ -79,9 +79,9 @@ export const eligibleCommand: CommandRegistry = {
|
||||
(await entries.reduce<PossiblyPromise<number>>(
|
||||
async (accumulator, [tankIdString, stats]) => {
|
||||
const tankId = parseInt(tankIdString);
|
||||
const tankopediaEntry = (await tankopedia)[tankId];
|
||||
const tankDefinition = (await tankDefinitions)[tankId];
|
||||
|
||||
if (!tankopediaEntry) return accumulator;
|
||||
if (!tankDefinition) return accumulator;
|
||||
|
||||
return stats.battles;
|
||||
},
|
||||
@@ -110,7 +110,7 @@ export const eligibleCommand: CommandRegistry = {
|
||||
async (accumulator, [tankIdString, stats]) => {
|
||||
const tankId = parseInt(tankIdString);
|
||||
|
||||
if ((await tankopedia)[tankId]?.tier === 10) {
|
||||
if ((await tankDefinitions)[tankId]?.tier === 10) {
|
||||
const tankStats = diffed[tankId];
|
||||
return (await accumulator) + tankStats.damage_dealt;
|
||||
} else return accumulator;
|
||||
@@ -121,7 +121,7 @@ export const eligibleCommand: CommandRegistry = {
|
||||
async (accumulator, [tankIdString, stats]) => {
|
||||
const tankId = parseInt(tankIdString);
|
||||
|
||||
if ((await tankopedia)[tankId]?.tier === 10) {
|
||||
if ((await tankDefinitions)[tankId]?.tier === 10) {
|
||||
const tankStats = diffed[tankId];
|
||||
return (await accumulator) + tankStats.battles;
|
||||
} else return accumulator;
|
||||
|
||||
+15
-15
@@ -3,20 +3,20 @@ import NoData, { NoDataType } from '../components/NoData';
|
||||
import * as Tanks from '../components/Tanks';
|
||||
import TitleBar from '../components/TitleBar';
|
||||
import Wrapper from '../components/Wrapper';
|
||||
import { encyclopediaInfo } from '../core/blitz/encyclopediaInfo';
|
||||
import { getAccountInfo } from '../core/blitz/getAccountInfo';
|
||||
import { getClanAccountInfo } from '../core/blitz/getClanAccountInfo';
|
||||
import getTankStats from '../core/blitz/getTankStats';
|
||||
import getTreeType from '../core/blitz/getTreeType';
|
||||
import resolveTankName from '../core/blitz/resolveTankName';
|
||||
import { tankopediaInfo } from '../core/blitz/tankopediaInfo';
|
||||
import {
|
||||
TIER_ROMAN_NUMERALS,
|
||||
TankDefinition,
|
||||
Tier,
|
||||
tankDefinitions,
|
||||
} from '../core/blitzkrieg/definitions/tanks';
|
||||
import { emblemIdToURL } from '../core/blitzkrieg/emblemIdToURL';
|
||||
import { tankIcon } from '../core/blitzkrieg/tankIcon';
|
||||
import {
|
||||
BlitzkriegTankopediaEntry,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
Tier,
|
||||
tankopedia,
|
||||
} from '../core/blitzkrieg/tankopedia';
|
||||
import addTierChoices from '../core/discord/addTierChoices';
|
||||
import addUsernameChoices from '../core/discord/addUsernameChoices';
|
||||
import autocompleteUsername from '../core/discord/autocompleteUsername';
|
||||
@@ -42,21 +42,21 @@ export const ownedTanksCommand: CommandRegistry = {
|
||||
const filteredTanks = (
|
||||
await Promise.all(
|
||||
tankStats.map(async (tankData) => ({
|
||||
tankopedia: (await tankopedia)[tankData.tank_id]!,
|
||||
tankDefinitions: (await tankDefinitions)[tankData.tank_id]!,
|
||||
id: tankData.tank_id,
|
||||
})),
|
||||
)
|
||||
).filter((tank) => tank.tankopedia?.tier === tier);
|
||||
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
||||
const clanAccountInfo = await getClanAccountInfo(server, id, ['clan']);
|
||||
const groupedTanks: Record<string, BlitzkriegTankopediaEntry[]> = {};
|
||||
const groupedTanks: Record<string, TankDefinition[]> = {};
|
||||
const nations: string[] = [];
|
||||
|
||||
filteredTanks.forEach((tank) => {
|
||||
if (groupedTanks[tank.tankopedia.nation] === undefined) {
|
||||
groupedTanks[tank.tankopedia.nation] = [tank.tankopedia];
|
||||
nations.push(tank.tankopedia.nation);
|
||||
if (groupedTanks[tank.tankDefinitions.nation] === undefined) {
|
||||
groupedTanks[tank.tankDefinitions.nation] = [tank.tankDefinitions];
|
||||
nations.push(tank.tankDefinitions.nation);
|
||||
} else {
|
||||
groupedTanks[tank.tankopedia.nation].push(tank.tankopedia);
|
||||
groupedTanks[tank.tankDefinitions.nation].push(tank.tankDefinitions);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ export const ownedTanksCommand: CommandRegistry = {
|
||||
return (
|
||||
<Tanks.Root>
|
||||
<Tanks.Title>
|
||||
{(await tankopediaInfo).vehicle_nations[nation]}
|
||||
{(await encyclopediaInfo).vehicle_nations[nation]}
|
||||
</Tanks.Title>
|
||||
|
||||
<Tanks.Row>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SlashCommandBuilder } from 'discord.js';
|
||||
import { go } from 'fuzzysort';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import { tankNamesDiacritics } from '../core/blitzkrieg/tankopedia';
|
||||
import { tankNamesDiacritics } from '../core/blitzkrieg/definitions/tanks';
|
||||
import addTankChoices from '../core/discord/addTankChoices';
|
||||
import embedInfo from '../core/discord/embedInfo';
|
||||
import { CommandRegistry } from '../events/interactionCreate';
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
TANK_ICONS,
|
||||
TANK_ICONS_COLLECTOR,
|
||||
TANK_ICONS_PREMIUM,
|
||||
} from '../../../core/blitzkrieg/tankopedia';
|
||||
} from '../../../core/blitzkrieg/definitions/tanks';
|
||||
import { theme } from '../../../stitches.config';
|
||||
|
||||
export enum TreeTypeEnum {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Tier } from '../core/blitzkrieg/tankopedia';
|
||||
import { Tier } from '../core/blitzkrieg/definitions/tanks';
|
||||
import { theme } from '../stitches.config';
|
||||
|
||||
export type TierWeightsRecord = Partial<Record<Tier, number>>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID';
|
||||
import fetchBlitz from './fetchBlitz';
|
||||
|
||||
export interface TankopediaInfo {
|
||||
export interface EncyclopediaInfo {
|
||||
achievement_sections: Record<string, { name: string; order: number }>;
|
||||
tanks_updated_at: number;
|
||||
languages: Record<string, string>;
|
||||
@@ -10,6 +10,6 @@ export interface TankopediaInfo {
|
||||
game_version: string;
|
||||
}
|
||||
|
||||
export const tankopediaInfo = fetchBlitz<TankopediaInfo>(
|
||||
export const encyclopediaInfo = fetchBlitz<EncyclopediaInfo>(
|
||||
`https://api.wotblitz.com/wotb/encyclopedia/info/?application_id=${WARGAMING_APPLICATION_ID}`,
|
||||
);
|
||||
@@ -1,8 +1,8 @@
|
||||
import { TreeTypeEnum } from '../../components/Tanks';
|
||||
import { tankopedia } from '../blitzkrieg/tankopedia';
|
||||
import { tankDefinitions } from '../blitzkrieg/definitions/tanks';
|
||||
|
||||
export default async function getTreeType(id: number) {
|
||||
const entry = (await tankopedia)[id];
|
||||
const entry = (await tankDefinitions)[id];
|
||||
|
||||
if (entry.tree_type === 'collector') return TreeTypeEnum.Collector;
|
||||
if (entry.tree_type === 'premium') return TreeTypeEnum.Premium;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { go } from 'fuzzysort';
|
||||
import { tankopedia, tanks } from '../blitzkrieg/tankopedia';
|
||||
import {
|
||||
tankDefinitions,
|
||||
tanksDefinitionsArray,
|
||||
} from '../blitzkrieg/definitions/tanks';
|
||||
import { UserError } from '../blitzkrieg/userError';
|
||||
|
||||
export default async function resolveTankId(tank: string | number) {
|
||||
const number = typeof tank === 'string' ? parseInt(tank) : tank;
|
||||
|
||||
if (Number.isNaN(number)) {
|
||||
const searchResult = go(`${tank}`, await tanks, {
|
||||
const searchResult = go(`${tank}`, await tanksDefinitionsArray, {
|
||||
keys: ['name'],
|
||||
limit: 1,
|
||||
});
|
||||
@@ -19,7 +22,7 @@ export default async function resolveTankId(tank: string | number) {
|
||||
return searchResult[0].obj.id;
|
||||
}
|
||||
} else {
|
||||
if ((await tankopedia)[number]) {
|
||||
if ((await tankDefinitions)[number]) {
|
||||
return number;
|
||||
} else {
|
||||
throw new UserError('Tank not found', {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { tankopedia } from '../blitzkrieg/tankopedia';
|
||||
import { tankDefinitions } from '../blitzkrieg/definitions/tanks';
|
||||
|
||||
export default async function resolveTankName(tankId: number) {
|
||||
const awaitedTankopedia = await tankopedia;
|
||||
const entry = awaitedTankopedia[tankId];
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const entry = awaitedTankDefinitions[tankId];
|
||||
|
||||
return entry?.name_short ?? entry?.name ?? `Unknown Tank ${tankId}`;
|
||||
}
|
||||
@@ -1,24 +1,8 @@
|
||||
import { deburr } from 'lodash';
|
||||
import { TankType, TreeTypeString } from '../../components/Tanks';
|
||||
import { asset } from './asset';
|
||||
import { TankType, TreeTypeString } from '../../../components/Tanks';
|
||||
import { asset } from '../asset';
|
||||
|
||||
export interface TankopediaEntry {
|
||||
name: string;
|
||||
nation: string;
|
||||
is_premium: boolean;
|
||||
is_collectible: boolean;
|
||||
tier: Tier;
|
||||
cost: { price_credit: number; price_gold: number };
|
||||
images: { preview: string; normal: string };
|
||||
tank_id: number;
|
||||
type: string;
|
||||
description: string;
|
||||
}
|
||||
export interface Tankopedia {
|
||||
[id: number]: TankopediaEntry | undefined;
|
||||
}
|
||||
|
||||
export interface BlitzkriegTankopediaEntry {
|
||||
export interface TankDefinition {
|
||||
id: number;
|
||||
nation: string;
|
||||
name: string;
|
||||
@@ -28,15 +12,16 @@ export interface BlitzkriegTankopediaEntry {
|
||||
type: TankType;
|
||||
}
|
||||
|
||||
export type BlitzkriegTankopedia = Record<number, BlitzkriegTankopediaEntry>;
|
||||
export type TankDefinitions = Record<number, TankDefinition>;
|
||||
|
||||
export const tankopedia = fetch(asset('tankopedia.json'), {
|
||||
export const tankDefinitions = fetch(asset('definitions/tanks.json'), {
|
||||
cache: 'no-store',
|
||||
}).then(async (response) => response.json() as Promise<BlitzkriegTankopedia>);
|
||||
const entries = new Promise<BlitzkriegTankopediaEntry[]>(async (resolve) => {
|
||||
resolve(Object.entries(await tankopedia).map(([, entry]) => entry));
|
||||
}).then(async (response) => response.json() as Promise<TankDefinitions>);
|
||||
|
||||
const entries = new Promise<TankDefinition[]>(async (resolve) => {
|
||||
resolve(Object.entries(await tankDefinitions).map(([, entry]) => entry));
|
||||
});
|
||||
export const tanks = new Promise<BlitzkriegTankopediaEntry[]>(
|
||||
export const tanksDefinitionsArray = new Promise<TankDefinition[]>(
|
||||
async (resolve) => {
|
||||
resolve((await entries).map((entry) => entry));
|
||||
},
|
||||
@@ -47,7 +32,7 @@ export const tankNames = new Promise<string[]>(async (resolve) => {
|
||||
export const tankNamesDiacritics = tankNames.then((tankNames) =>
|
||||
Promise.all(
|
||||
tankNames.map(async (tankName, index) => {
|
||||
const { id } = (await tanks)[index];
|
||||
const { id } = (await tanksDefinitionsArray)[index];
|
||||
const name = tankName ?? `Unknown Tank ${id}`;
|
||||
const diacriticless = deburr(name);
|
||||
|
||||
@@ -99,7 +84,7 @@ export const TIER_ROMAN_NUMERALS: Record<Tier, string> = {
|
||||
10: 'X',
|
||||
};
|
||||
|
||||
export const NATIONS = tanks.then((tanks) => {
|
||||
export const NATIONS = tanksDefinitionsArray.then((tanks) => {
|
||||
const nationsObject: Record<string, true> = {};
|
||||
|
||||
tanks.forEach(({ nation }) => {
|
||||
@@ -1,8 +1,8 @@
|
||||
import { TREE_TYPE_NAMES } from '../../components/Tanks';
|
||||
import { encyclopediaInfo } from '../blitz/encyclopediaInfo';
|
||||
import resolveTankName from '../blitz/resolveTankName';
|
||||
import { tankopediaInfo } from '../blitz/tankopediaInfo';
|
||||
import { StatFilters } from '../statistics/filterStats';
|
||||
import { TIER_ROMAN_NUMERALS, Tier } from './tankopedia';
|
||||
import { TIER_ROMAN_NUMERALS, Tier } from './definitions/tanks';
|
||||
|
||||
export async function filtersToDescription({
|
||||
nation,
|
||||
@@ -11,13 +11,13 @@ export async function filtersToDescription({
|
||||
treeType,
|
||||
tank,
|
||||
}: StatFilters) {
|
||||
const awaitedTankopediaInfo = await tankopediaInfo;
|
||||
const awaitedEncyclopediaInfo = await encyclopediaInfo;
|
||||
const info: string[] = [];
|
||||
|
||||
if (tank) return await resolveTankName(tank);
|
||||
if (nation) info.push(awaitedTankopediaInfo.vehicle_nations[nation]);
|
||||
if (nation) info.push(awaitedEncyclopediaInfo.vehicle_nations[nation]);
|
||||
if (tier) info.push(`Tier ${TIER_ROMAN_NUMERALS[tier as Tier]}`);
|
||||
if (tankType) info.push(awaitedTankopediaInfo.vehicle_types[tankType]);
|
||||
if (tankType) info.push(awaitedEncyclopediaInfo.vehicle_types[tankType]);
|
||||
if (treeType) info.push(TREE_TYPE_NAMES[treeType]);
|
||||
|
||||
return info.length === 0 ? 'No filters' : info.join(', ');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AllStats } from '../blitz/getAccountInfo';
|
||||
import { context } from '../blitzkrieg/context';
|
||||
import { tankopedia } from '../blitzkrieg/tankopedia';
|
||||
import { tankDefinitions } from '../blitzkrieg/definitions/tanks';
|
||||
|
||||
export interface SpecialStats {
|
||||
winrate: number;
|
||||
@@ -80,7 +80,7 @@ export interface IndividualTankAverage {
|
||||
last_update: number;
|
||||
}
|
||||
|
||||
tankopedia;
|
||||
tankDefinitions;
|
||||
|
||||
export type TankAverages = Record<number, IndividualTankAverage>;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
SlashCommandSubcommandGroupBuilder,
|
||||
} from 'discord.js';
|
||||
import { TREE_TYPE_NAMES, TreeTypeString } from '../../components/Tanks';
|
||||
import { tankopediaInfo } from '../blitz/tankopediaInfo';
|
||||
import { encyclopediaInfo } from '../blitz/encyclopediaInfo';
|
||||
import addPeriodSubCommands from './addPeriodSubCommands';
|
||||
import addTankChoices from './addTankChoices';
|
||||
import addTierChoices from './addTierChoices';
|
||||
@@ -17,7 +17,7 @@ export default async function addFilterOptions<
|
||||
option: SlashCommandSubcommandBuilder,
|
||||
) => SlashCommandSubcommandBuilder = (option) => option,
|
||||
): Promise<OptionType> {
|
||||
const awaitedTankopediaInfo = await tankopediaInfo;
|
||||
const awaitedEncyclopediaInfo = await encyclopediaInfo;
|
||||
|
||||
addPeriodSubCommands(option, (option) => {
|
||||
extra(option);
|
||||
@@ -28,7 +28,7 @@ export default async function addFilterOptions<
|
||||
.setName('nation')
|
||||
.setDescription('Nation')
|
||||
.addChoices(
|
||||
...Object.entries(awaitedTankopediaInfo.vehicle_nations).map(
|
||||
...Object.entries(awaitedEncyclopediaInfo.vehicle_nations).map(
|
||||
([type, name]) => ({ name, value: type }),
|
||||
),
|
||||
)
|
||||
@@ -40,7 +40,7 @@ export default async function addFilterOptions<
|
||||
.setName('tank-type')
|
||||
.setDescription('Tank type')
|
||||
.addChoices(
|
||||
...Object.entries(awaitedTankopediaInfo.vehicle_types).map(
|
||||
...Object.entries(awaitedEncyclopediaInfo.vehicle_types).map(
|
||||
([type, name]) => ({
|
||||
name: name.replace(' Tank', ''),
|
||||
value: type,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
CacheType,
|
||||
} from 'discord.js';
|
||||
import { go } from 'fuzzysort';
|
||||
import { tankNamesDiacritics } from '../blitzkrieg/tankopedia';
|
||||
import { tankNamesDiacritics } from '../blitzkrieg/definitions/tanks';
|
||||
import {
|
||||
DISCORD_CHOICES_MAX_NAME_SIZE,
|
||||
OVERFLOW_SUFFIX,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { TreeTypeString } from '../../components/Tanks';
|
||||
import { tankopedia } from '../blitzkrieg/tankopedia';
|
||||
import { tankDefinitions } from '../blitzkrieg/definitions/tanks';
|
||||
import { DiffedTankStats } from '../blitzstars/getStatsInPeriod';
|
||||
import { tankAverages } from '../blitzstars/tankAverages';
|
||||
import calculateWN8 from './calculateWN8';
|
||||
@@ -20,10 +20,10 @@ export async function filterStats(
|
||||
// tank, if provided, takes priority over all other filters
|
||||
if (filters.tank) filters = { tank: filters.tank };
|
||||
|
||||
const awaitedTankopedia = await tankopedia;
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedTankAverages = await tankAverages;
|
||||
const filteredOrder = order.filter((id) => {
|
||||
const entry = awaitedTankopedia[id];
|
||||
const entry = awaitedTankDefinitions[id];
|
||||
|
||||
return (
|
||||
entry &&
|
||||
@@ -44,9 +44,9 @@ export async function filterStats(
|
||||
awaitedTankAverages[id] ? accumulator + diff[id].battles : accumulator,
|
||||
0,
|
||||
);
|
||||
const battlesOfTanksWithTankopediaEntry = filteredOrder.reduce<number>(
|
||||
const battlesOfTanksWithTankDefinition = filteredOrder.reduce<number>(
|
||||
(accumulator, id) =>
|
||||
awaitedTankopedia[id] ? accumulator + diff[id].battles : accumulator,
|
||||
awaitedTankDefinitions[id] ? accumulator + diff[id].battles : accumulator,
|
||||
0,
|
||||
);
|
||||
const supplementary = {
|
||||
@@ -63,11 +63,11 @@ export async function filterStats(
|
||||
tier:
|
||||
filteredOrder.reduce<number>(
|
||||
(accumulator, id) =>
|
||||
awaitedTankopedia[id]
|
||||
? accumulator + awaitedTankopedia[id]!.tier * diff[id].battles
|
||||
awaitedTankDefinitions[id]
|
||||
? accumulator + awaitedTankDefinitions[id]!.tier * diff[id].battles
|
||||
: accumulator,
|
||||
0,
|
||||
) / battlesOfTanksWithTankopediaEntry,
|
||||
) / battlesOfTanksWithTankDefinition,
|
||||
};
|
||||
|
||||
return { stats, supplementary, filteredOrder };
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { TierWeightsRecord } from '../../components/TierWeights';
|
||||
import { AllStats } from '../blitz/getAccountInfo';
|
||||
import { tankopedia } from '../blitzkrieg/tankopedia';
|
||||
import { tankDefinitions } from '../blitzkrieg/definitions/tanks';
|
||||
|
||||
export async function getTierWeights(
|
||||
stats: Record<number, AllStats>,
|
||||
order: number[] = Object.keys(stats).map(parseInt),
|
||||
) {
|
||||
const awaitedTankopedia = await tankopedia;
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const tierWeights: TierWeightsRecord = {};
|
||||
|
||||
order.forEach((id) => {
|
||||
const entry = awaitedTankopedia[id];
|
||||
const entry = awaitedTankDefinitions[id];
|
||||
|
||||
if (!entry) return;
|
||||
if (!tierWeights[entry.tier]) tierWeights[entry.tier] = 0;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { produce } from 'immer';
|
||||
import { create } from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { TankType, TreeTypeString } from '../components/Tanks';
|
||||
import { Tier } from '../core/blitzkrieg/tankopedia';
|
||||
import { Tier } from '../core/blitzkrieg/definitions/tanks';
|
||||
|
||||
export type TankopediaSortBy = 'tier' | 'name';
|
||||
export type TankopediaSortDirection = 'ascending' | 'descending';
|
||||
|
||||
Reference in new issue
Block a user