mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-01 06:59:51 +01:00
feat: data driven nations
This commit is contained in:
1 parent
b4bb0dcc67
commit
4927f1315c
4 files changed
+162
-148
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
import { readdir } from 'fs/promises';
|
import { readdir } from 'fs/promises';
|
||||||
import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL';
|
import sharp from 'sharp';
|
||||||
|
import { readDVPLFile } from '../../src/core/blitz/readDVPLFile';
|
||||||
import { commitAssets } from '../../src/core/blitzkit/commitAssets';
|
import { commitAssets } from '../../src/core/blitzkit/commitAssets';
|
||||||
import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles';
|
import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles';
|
||||||
import { DATA, POI } from './constants';
|
import { DATA, POI } from './constants';
|
||||||
@@ -14,7 +15,10 @@ export async function circleFlags(production: boolean) {
|
|||||||
!flag.endsWith('@2x.packed.webp.dvpl'),
|
!flag.endsWith('@2x.packed.webp.dvpl'),
|
||||||
)
|
)
|
||||||
.map(async (flag) => {
|
.map(async (flag) => {
|
||||||
const content = await readBase64DVPL(`${DATA}/${POI.flags}/${flag}`);
|
const image = sharp(await readDVPLFile(`${DATA}/${POI.flags}/${flag}`));
|
||||||
|
const content = (
|
||||||
|
await image.trim({ threshold: 100 }).toBuffer()
|
||||||
|
).toString('base64');
|
||||||
const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1];
|
const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -353,11 +353,15 @@ export interface MapAlly {
|
|||||||
points: Array<number[]>;
|
points: Array<number[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AvailableNationsYaml {
|
||||||
|
available_nations: string[];
|
||||||
|
}
|
||||||
|
|
||||||
const blitzShellKindToBlitzkit: Record<ShellKind, ShellType> = {
|
const blitzShellKindToBlitzkit: Record<ShellKind, ShellType> = {
|
||||||
ARMOR_PIERCING: 'ap',
|
ARMOR_PIERCING: ShellType.AP,
|
||||||
ARMOR_PIERCING_CR: 'ap_cr',
|
ARMOR_PIERCING_CR: ShellType.APCR,
|
||||||
HIGH_EXPLOSIVE: 'he',
|
HIGH_EXPLOSIVE: ShellType.HE,
|
||||||
HOLLOW_CHARGE: 'hc',
|
HOLLOW_CHARGE: ShellType.HEAT,
|
||||||
};
|
};
|
||||||
const missingStrings: Record<string, string> = {
|
const missingStrings: Record<string, string> = {
|
||||||
'#artefacts:tungstentip/name': 'Tungsten Shells',
|
'#artefacts:tungstentip/name': 'Tungsten Shells',
|
||||||
@@ -378,6 +382,11 @@ export async function definitions(production: boolean) {
|
|||||||
.split('.')
|
.split('.')
|
||||||
.slice(0, 3)
|
.slice(0, 3)
|
||||||
.join('.'),
|
.join('.'),
|
||||||
|
nations: (
|
||||||
|
await readYAMLDVPL<AvailableNationsYaml>(
|
||||||
|
`${DATA}/available_nations.yaml.dvpl`,
|
||||||
|
)
|
||||||
|
).available_nations,
|
||||||
};
|
};
|
||||||
const tankDefinitions: TankDefinitions = {};
|
const tankDefinitions: TankDefinitions = {};
|
||||||
const modelDefinitions: ModelDefinitions = {};
|
const modelDefinitions: ModelDefinitions = {};
|
||||||
|
|||||||
+142
-142
@@ -15,27 +15,24 @@ import { Link } from '../../../components/Link';
|
|||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { TANK_CLASSES } from '../../../components/Tanks/components/Item/constants';
|
import { TANK_CLASSES } from '../../../components/Tanks/components/Item/constants';
|
||||||
import { asset } from '../../../core/blitzkit/asset';
|
import { asset } from '../../../core/blitzkit/asset';
|
||||||
|
import { gameDefinitions } from '../../../core/blitzkit/gameDefinitions';
|
||||||
import {
|
import {
|
||||||
NATIONS,
|
|
||||||
Tier,
|
Tier,
|
||||||
tanksDefinitionsArray,
|
tanksDefinitionsArray,
|
||||||
} from '../../../core/blitzkit/tankDefinitions';
|
} from '../../../core/blitzkit/tankDefinitions';
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../core/blitzkit/tankDefinitions/constants';
|
import { TIER_ROMAN_NUMERALS } from '../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { tankIcon } from '../../../core/blitzkit/tankIcon';
|
import { tankIcon } from '../../../core/blitzkit/tankIcon';
|
||||||
import strings from '../../../lang/en-US.json';
|
|
||||||
import { treeTypeOrder } from './components/TankSearch/constants';
|
import { treeTypeOrder } from './components/TankSearch/constants';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
|
||||||
const awaitedNations = use(NATIONS);
|
const awaitedGameDefinitions = use(gameDefinitions);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper color="purple" size={1028 + 256}>
|
<PageWrapper color="purple" size={1028 + 256}>
|
||||||
<Flex gap="8">
|
<Flex gap="8">
|
||||||
<Flex direction="column" gap="4" align="start">
|
<Flex direction="column" gap="4" align="start" pt="9">
|
||||||
<Text mb="-3" weight="bold">
|
<Text mb="-3">Class</Text>
|
||||||
Class
|
|
||||||
</Text>
|
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
@@ -85,9 +82,7 @@ export default function Page() {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Text mb="-3" weight="bold">
|
<Text mb="-3">Type</Text>
|
||||||
Type
|
|
||||||
</Text>
|
|
||||||
<Flex
|
<Flex
|
||||||
overflow="hidden"
|
overflow="hidden"
|
||||||
style={{
|
style={{
|
||||||
@@ -111,26 +106,55 @@ export default function Page() {
|
|||||||
})}
|
})}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Text mb="-3" weight="bold">
|
<Text mb="-3">Nation</Text>
|
||||||
Nation
|
<Flex
|
||||||
</Text>
|
direction="column"
|
||||||
<Flex>
|
overflow="hidden"
|
||||||
{awaitedNations.map((nation) => (
|
style={{
|
||||||
<IconButton
|
borderRadius: 'var(--radius-4)',
|
||||||
variant="soft"
|
}}
|
||||||
color="gray"
|
>
|
||||||
highContrast
|
<Flex>
|
||||||
radius="none"
|
{awaitedGameDefinitions.nations
|
||||||
>
|
.slice(0, Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
||||||
{/* TODO: trim icons */}
|
.map((nation) => (
|
||||||
<img src={asset(`flags/circle/${nation}.webp`)} />
|
<IconButton
|
||||||
</IconButton>
|
style={{ flex: 1 }}
|
||||||
))}
|
variant="soft"
|
||||||
|
color="gray"
|
||||||
|
highContrast
|
||||||
|
radius="none"
|
||||||
|
>
|
||||||
|
{/* TODO: trim icons */}
|
||||||
|
<img
|
||||||
|
style={{ width: '1em', height: '1em' }}
|
||||||
|
src={asset(`flags/circle/${nation}.webp`)}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
<Flex>
|
||||||
|
{awaitedGameDefinitions.nations
|
||||||
|
.slice(Math.ceil(awaitedGameDefinitions.nations.length / 2))
|
||||||
|
.map((nation) => (
|
||||||
|
<IconButton
|
||||||
|
style={{ flex: 1 }}
|
||||||
|
variant="soft"
|
||||||
|
color="gray"
|
||||||
|
highContrast
|
||||||
|
radius="none"
|
||||||
|
>
|
||||||
|
{/* TODO: trim icons */}
|
||||||
|
<img
|
||||||
|
style={{ width: '1em', height: '1em' }}
|
||||||
|
src={asset(`flags/circle/${nation}.webp`)}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Text mb="-3" weight="bold">
|
<Text mb="-3">Test tanks</Text>
|
||||||
Test tanks
|
|
||||||
</Text>
|
|
||||||
<RadioGroup.Root defaultValue="include">
|
<RadioGroup.Root defaultValue="include">
|
||||||
<RadioGroup.Item value="include">Include</RadioGroup.Item>
|
<RadioGroup.Item value="include">Include</RadioGroup.Item>
|
||||||
<RadioGroup.Item value="exclude">Exclude</RadioGroup.Item>
|
<RadioGroup.Item value="exclude">Exclude</RadioGroup.Item>
|
||||||
@@ -141,132 +165,108 @@ export default function Page() {
|
|||||||
<Flex direction="column" gap="8" mt="4" flexGrow="1">
|
<Flex direction="column" gap="8" mt="4" flexGrow="1">
|
||||||
{range(10, 0).map((tierUntyped) => {
|
{range(10, 0).map((tierUntyped) => {
|
||||||
const tier = tierUntyped as Tier;
|
const tier = tierUntyped as Tier;
|
||||||
const tierTanks = awaitedTanksDefinitionsArray.filter(
|
const tierTanks = awaitedTanksDefinitionsArray
|
||||||
(tank) => tank.tier === tier,
|
.filter((tank) => tank.tier === tier)
|
||||||
);
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
treeTypeOrder.indexOf(a.treeType) -
|
||||||
|
treeTypeOrder.indexOf(b.treeType),
|
||||||
|
)
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
|
||||||
|
)
|
||||||
|
.sort(
|
||||||
|
(a, b) =>
|
||||||
|
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
||||||
|
awaitedGameDefinitions.nations.indexOf(b.nation),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex key={tier} direction="column" gap="4">
|
<Flex key={tier} direction="column" gap="4">
|
||||||
<Heading color="gray" mb="4">
|
<Flex align="center" mb="4" gap="4">
|
||||||
Tier {TIER_ROMAN_NUMERALS[tier]}
|
<Heading weight="regular">
|
||||||
</Heading>
|
Tier {TIER_ROMAN_NUMERALS[tier]}
|
||||||
|
</Heading>
|
||||||
|
<Separator style={{ flex: 1 }} />
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Flex direction="column" gap="8">
|
<Grid
|
||||||
{awaitedNations.map((nation, nationIndex) => {
|
flexGrow="1"
|
||||||
const nationTanks = tierTanks
|
columns="repeat(auto-fill, minmax(100px, 1fr))"
|
||||||
.filter((tank) => tank.nation === nation)
|
gap="2"
|
||||||
.sort(
|
gapY="6"
|
||||||
(a, b) =>
|
>
|
||||||
treeTypeOrder.indexOf(a.treeType) -
|
{tierTanks.map((tank) => {
|
||||||
treeTypeOrder.indexOf(b.treeType),
|
const Icon = classIcons[tank.class];
|
||||||
)
|
|
||||||
.sort(
|
|
||||||
(a, b) =>
|
|
||||||
TANK_CLASSES.indexOf(a.class) -
|
|
||||||
TANK_CLASSES.indexOf(b.class),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (nationTanks.length === 0) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex key={nation} direction="column" gap="4">
|
<Link
|
||||||
<Flex align="center">
|
key={tank.id}
|
||||||
<img
|
size="1"
|
||||||
src={asset(`flags/scratched/${nation}.webp`)}
|
color={
|
||||||
|
tank.treeType === 'collector'
|
||||||
|
? 'blue'
|
||||||
|
: tank.treeType === 'premium'
|
||||||
|
? 'amber'
|
||||||
|
: 'gray'
|
||||||
|
}
|
||||||
|
highContrast={tank.treeType === 'researchable'}
|
||||||
|
underline="hover"
|
||||||
|
href={`/tools/tankopedia/${tank.id}`}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 'var(--space-2)',
|
||||||
|
background: `url(${asset(`flags/scratched/${tank.nation}.webp`)})`,
|
||||||
|
backgroundSize: 'contain',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'top left',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt={tank.name}
|
||||||
|
src={tankIcon(tank.id)}
|
||||||
|
height={64}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
objectPosition: 'center right',
|
||||||
|
objectFit: 'contain',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
justify="center"
|
||||||
|
gap="1"
|
||||||
|
align="center"
|
||||||
|
overflow="hidden"
|
||||||
|
width="100%"
|
||||||
|
maxWidth="100%"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
style={{
|
style={{
|
||||||
height: 64,
|
width: '1em',
|
||||||
aspectRatio: '2 / 1',
|
height: '1em',
|
||||||
|
minWidth: '1em',
|
||||||
|
minHeight: '1em',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<Text
|
||||||
<Heading size="5" ml="-8" mr="4" wrap="nowrap">
|
align="center"
|
||||||
{
|
style={{
|
||||||
strings.common.nations[
|
whiteSpace: 'nowrap',
|
||||||
nation as keyof typeof strings.common.nations
|
overflow: 'hidden',
|
||||||
]
|
textOverflow: 'ellipsis',
|
||||||
}
|
}}
|
||||||
</Heading>
|
>
|
||||||
|
{tank.name}
|
||||||
<Separator size="4" />
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
</Link>
|
||||||
<Grid
|
|
||||||
flexGrow="1"
|
|
||||||
columns="repeat(auto-fill, minmax(80px, 1fr))"
|
|
||||||
gap="2"
|
|
||||||
gapY="4"
|
|
||||||
key={nation}
|
|
||||||
>
|
|
||||||
{nationTanks.map((tank) => {
|
|
||||||
const Icon = classIcons[tank.class];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
key={tank.id}
|
|
||||||
size="1"
|
|
||||||
color={
|
|
||||||
tank.treeType === 'collector'
|
|
||||||
? 'blue'
|
|
||||||
: tank.treeType === 'premium'
|
|
||||||
? 'amber'
|
|
||||||
: 'gray'
|
|
||||||
}
|
|
||||||
highContrast={tank.treeType === 'researchable'}
|
|
||||||
underline="hover"
|
|
||||||
href={`/tools/tankopedia/${tank.id}`}
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 'var(--space-2)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt={tank.name}
|
|
||||||
src={tankIcon(tank.id)}
|
|
||||||
height={64}
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
objectPosition: 'center',
|
|
||||||
objectFit: 'contain',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Flex
|
|
||||||
justify="center"
|
|
||||||
gap="1"
|
|
||||||
align="center"
|
|
||||||
overflow="hidden"
|
|
||||||
width="100%"
|
|
||||||
maxWidth="100%"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
style={{
|
|
||||||
width: '1em',
|
|
||||||
height: '1em',
|
|
||||||
minWidth: '1em',
|
|
||||||
minHeight: '1em',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
align="center"
|
|
||||||
style={{
|
|
||||||
whiteSpace: 'nowrap',
|
|
||||||
overflow: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tank.name}
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Grid>
|
|
||||||
</Flex>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Flex>
|
</Grid>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { fetchCdonLz4 } from './fetchCdonLz4';
|
|||||||
|
|
||||||
export interface GameDefinitions {
|
export interface GameDefinitions {
|
||||||
version: string;
|
version: string;
|
||||||
|
nations: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const gameDefinitions = fetchCdonLz4<GameDefinitions>(
|
export const gameDefinitions = fetchCdonLz4<GameDefinitions>(
|
||||||
|
|||||||
Reference in new issue
Block a user