feat: shell icons and modes

This commit is contained in:
TrèsAbhi committed 2023-12-12 23:35:08 -06:00
1 parent f8f88ff8f2
commit 634bd2ea07
8 files changed
+1110 -639

No files matched your search

+1
View File
@@ -5,6 +5,7 @@
"accountinfo", "accountinfo",
"alphatest", "alphatest",
"apcr", "apcr",
"atgm",
"bepaint", "bepaint",
"BINORMAL", "BINORMAL",
"blitzstars", "blitzstars",
+1 -1
View File
@@ -1,6 +1,6 @@
import { createVanillaExtractPlugin } from '@vanilla-extract/next-plugin'; import { createVanillaExtractPlugin } from '@vanilla-extract/next-plugin';
const withVanillaExtract = createVanillaExtractPlugin(); const withVanillaExtract = createVanillaExtractPlugin({ tests: /\.css$/ });
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
+2
View File
@@ -45,6 +45,7 @@
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"esbuild": "^0.19.3", "esbuild": "^0.19.3",
"express": "^4.18.2", "express": "^4.18.2",
"false": "^0.0.4",
"fuzzysort": "^2.0.4", "fuzzysort": "^2.0.4",
"immer": "^10.0.2", "immer": "^10.0.2",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
@@ -55,6 +56,7 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-fuzzysort": "^1.0.1", "react-fuzzysort": "^1.0.1",
"satori": "^0.10.8", "satori": "^0.10.8",
"sharp": "^0.33.0",
"three": "^0.159.0", "three": "^0.159.0",
"vite-node": "^0.34.5", "vite-node": "^0.34.5",
"vitepress": "^1.0.0-rc.20", "vitepress": "^1.0.0-rc.20",
+57 -2
View File
@@ -2,10 +2,13 @@ import { config } from 'dotenv';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import { mkdir, readdir, rm } from 'fs/promises'; import { mkdir, readdir, rm } from 'fs/promises';
import { argv } from 'process'; import { argv } from 'process';
import sharp from 'sharp';
import { TankType } from '../src/components/Tanks'; import { TankType } from '../src/components/Tanks';
import { NATION_IDS } from '../src/constants/nations'; import { NATION_IDS } from '../src/constants/nations';
import { SCPGStream } from '../src/core/blitz/SCPGStream'; import { SCPGStream } from '../src/core/blitz/SCPGStream';
import { readBase64DVPL } from '../src/core/blitz/readBase64DVPL'; import { readBase64DVPL } from '../src/core/blitz/readBase64DVPL';
import { readDVPLFile } from '../src/core/blitz/readDVPLFile';
import { readStringDVPL } from '../src/core/blitz/readStringDVPL';
import { readXMLDVPL } from '../src/core/blitz/readXMLDVPL'; import { readXMLDVPL } from '../src/core/blitz/readXMLDVPL';
import { readYAMLDVPL } from '../src/core/blitz/readYAMLDVPL'; import { readYAMLDVPL } from '../src/core/blitz/readYAMLDVPL';
import { toUniqueId } from '../src/core/blitz/toUniqueId'; import { toUniqueId } from '../src/core/blitz/toUniqueId';
@@ -122,9 +125,9 @@ const blitzTankTypeToBlitzkrieg: Record<BlitzTankType, TankType> = {
}; };
const blitzShellKindToBLitzkrieg: Record<ShellKind, ShellType> = { const blitzShellKindToBLitzkrieg: Record<ShellKind, ShellType> = {
ARMOR_PIERCING: 'ap', ARMOR_PIERCING: 'ap',
ARMOR_PIERCING_CR: 'apcr', ARMOR_PIERCING_CR: 'ap_cr',
HIGH_EXPLOSIVE: 'he', HIGH_EXPLOSIVE: 'he',
HOLLOW_CHARGE: 'heat', HOLLOW_CHARGE: 'hc',
}; };
const DATA = const DATA =
'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data'; 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data';
@@ -137,6 +140,7 @@ const DOI = {
bigIcons: 'Gfx/UI/BigTankIcons', bigIcons: 'Gfx/UI/BigTankIcons',
flags: 'Gfx/Lobby/flags', flags: 'Gfx/Lobby/flags',
'3d': '3d', '3d': '3d',
bigShellIcons: 'Gfx/Shared/tank-supply/ammunition/big',
}; };
const allTargets = argv.includes('--all-targets'); const allTargets = argv.includes('--all-targets');
@@ -217,6 +221,7 @@ if (allTargets || targets?.includes('definitions')) {
normalization: shell.normalizationAngle, normalization: shell.normalizationAngle,
ricochet: shell.ricochetAngle, ricochet: shell.ricochetAngle,
type: blitzShellKindToBLitzkrieg[shell.kind], type: blitzShellKindToBLitzkrieg[shell.kind],
icon: shell.icon,
}; };
return shellId; return shellId;
@@ -487,3 +492,53 @@ if (allTargets || targets?.includes('tankModels')) {
}), }),
); );
} }
if (allTargets || targets?.includes('shellIcons')) {
console.log('Building shell icons...');
const image = sharp(
await readDVPLFile(
`${DATA}/${DOI.bigShellIcons}/texture0.packed.webp.dvpl`,
),
);
const changes = await Promise.all(
(await readdir(`${DATA}/${DOI.bigShellIcons}`))
.filter((file) => file.endsWith('_l.txt.dvpl'))
.map(async (file) => {
const name = file.match(/(.+)_l\.txt\.dvpl/)![1];
const sizes = (
await readStringDVPL(`${DATA}/${DOI.bigShellIcons}/${file}`)
)
.split('\n')[4]
.split(' ')
.map(Number);
return {
content: (
await image
.clone()
.extract({
left: sizes[0],
top: sizes[1],
width: sizes[2],
height: sizes[3],
})
.toBuffer()
).toString('base64'),
encoding: 'base64',
path: `shells/${name}.webp`,
} satisfies FileChange;
}),
);
console.log('Committing shell icons...');
commitMultipleFiles(
'tresabhi',
'blitzkrieg-assets',
'main',
'shell icons',
changes,
true,
);
}
+78 -58
View File
@@ -1,16 +1,15 @@
'use client'; 'use client';
import { ArrowLeftIcon } from '@radix-ui/react-icons'; import { ArrowLeftIcon, CaretRightIcon } from '@radix-ui/react-icons';
import { import {
AspectRatio,
Button, Button,
Card, Card,
Checkbox, Checkbox,
Dialog,
Flex, Flex,
Heading, Heading,
Inset,
Select,
Slider, Slider,
Tabs,
Text, Text,
Theme, Theme,
Tooltip, Tooltip,
@@ -21,19 +20,23 @@ import Link from 'next/link';
import { use, useEffect, useState } from 'react'; import { use, useEffect, useState } from 'react';
import { Flag } from '../../../../components/Flag'; import { Flag } from '../../../../components/Flag';
import PageWrapper from '../../../../components/PageWrapper'; import PageWrapper from '../../../../components/PageWrapper';
import { asset } from '../../../../core/blitzkrieg/asset';
import { gunDefinitions } from '../../../../core/blitzkrieg/definitions/guns'; import { gunDefinitions } from '../../../../core/blitzkrieg/definitions/guns';
import { shellDefinitions } from '../../../../core/blitzkrieg/definitions/shells'; import { shellDefinitions } from '../../../../core/blitzkrieg/definitions/shells';
import { import {
TIER_ROMAN_NUMERALS, TIER_ROMAN_NUMERALS,
tankDefinitions, tankDefinitions,
tanksDefinitionsArray,
} from '../../../../core/blitzkrieg/definitions/tanks'; } from '../../../../core/blitzkrieg/definitions/tanks';
import { turretDefinitions } from '../../../../core/blitzkrieg/definitions/turrets'; import { turretDefinitions } from '../../../../core/blitzkrieg/definitions/turrets';
import * as styles from '../page.css';
const SIZE = 0.05; type Mode = 'model' | 'armor';
export default function Page({ params }: { params: { id: string } }) { export default function Page({ params }: { params: { id: string } }) {
const id = parseInt(params.id); const id = parseInt(params.id);
const awaitedTankDefinitions = use(tankDefinitions); const awaitedTankDefinitions = use(tankDefinitions);
const awaitedTanksDefinitionsArray = use(tanksDefinitionsArray);
const awaitedTurretDefinitions = use(turretDefinitions); const awaitedTurretDefinitions = use(turretDefinitions);
const awaitedGunDefinitions = use(gunDefinitions); const awaitedGunDefinitions = use(gunDefinitions);
const awaitedShellDefinitions = use(shellDefinitions); const awaitedShellDefinitions = use(shellDefinitions);
@@ -43,6 +46,12 @@ export default function Page({ params }: { params: { id: string } }) {
); );
const [gun, setGun] = useState(awaitedGunDefinitions[turret.guns[0]]); const [gun, setGun] = useState(awaitedGunDefinitions[turret.guns[0]]);
const [crew, setCrew] = useState(100); const [crew, setCrew] = useState(100);
const [versusTank, setVersusTank] = useState(
awaitedTanksDefinitionsArray[0].id,
);
const [mode, setMode] = useState<Mode>('model');
console.log(versusTank);
useEffect(() => setGun(awaitedGunDefinitions[turret.guns[0]]), [turret]); useEffect(() => setGun(awaitedGunDefinitions[turret.guns[0]]), [turret]);
@@ -62,16 +71,24 @@ export default function Page({ params }: { params: { id: string } }) {
</Link> </Link>
<Flex gap="2" align="center"> <Flex gap="2" align="center">
<Heading>{tank.name}</Heading>
<Flag nation={tank.nation} /> <Flag nation={tank.nation} />
<Heading>{tank.name}</Heading>
</Flex> </Flex>
</Flex> </Flex>
<AspectRatio ratio={16 / 9}> <Card style={{ position: 'relative' }}>
<Card <Flex direction="column" gap="2">
style={{ width: '100%', height: '100%', position: 'relative' }} <Tabs.Root
> value={mode}
<Inset style={{ height: 'calc(100% + 24px)' }}> onValueChange={(value) => setMode(value as Mode)}
>
<Tabs.List>
<Tabs.Trigger value="model">Model</Tabs.Trigger>
<Tabs.Trigger value="armor">Armor</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
<div style={{ height: '50vh', maxHeight: 576 }}>
<Canvas onPointerDown={(event) => event.preventDefault()}> <Canvas onPointerDown={(event) => event.preventDefault()}>
<OrbitControls /> <OrbitControls />
@@ -80,58 +97,61 @@ export default function Page({ params }: { params: { id: string } }) {
<mesh> <mesh>
<torusKnotGeometry args={[undefined, undefined, 128, 16]} /> <torusKnotGeometry args={[undefined, undefined, 128, 16]} />
<meshStandardMaterial color="red" /> <meshStandardMaterial color="cyan" />
</mesh> </mesh>
</Canvas> </Canvas>
</Inset> </div>
<Flex {mode === 'armor' && (
gap="2" <Flex gap="2" align="center" className={styles.enhancedArmor}>
align="center" <Checkbox defaultChecked />
style={{ <Text>Enhanced armor</Text>
position: 'absolute', </Flex>
left: 16, )}
bottom: 16,
}}
>
<Checkbox defaultChecked />
<Text>Enhanced armor</Text>
</Flex>
</Card>
</AspectRatio>
<Card style={{}}>
<Flex align="center" justify="between" gap="2">
<Flex align="center" gap="4">
<Text>Versus</Text>
<Select.Root value="1">
<Select.Trigger variant="ghost" />
<Select.Content>
<Select.Item value="1">XM66F</Select.Item>
</Select.Content>
</Select.Root>
</Flex>
<Flex gap="2" align="center">
<Checkbox defaultChecked />
<Text>Calibrated shells</Text>
</Flex>
<Flex gap="1">
<Button variant="solid" radius="small">
<img src="/images/ammo/ap.png" width={24} height={24} />
</Button>
<Button variant="soft" radius="small" color="gray">
<img src="/images/ammo/hcp.png" width={24} height={24} />
</Button>
<Button variant="soft" radius="small" color="gray">
<img src="/images/ammo/he.png" width={24} height={24} />
</Button>
</Flex>
</Flex> </Flex>
</Card> </Card>
{mode === 'armor' && (
<Card>
<Flex align="center" justify="between" gap="2">
<Flex align="center" gap="4">
<Text>Versus</Text>
<Dialog.Root>
<Dialog.Trigger>
<Button variant="ghost">
{awaitedTankDefinitions[versusTank].name}
<CaretRightIcon />
</Button>
</Dialog.Trigger>
<Dialog.Content>Do something lol</Dialog.Content>
</Dialog.Root>
</Flex>
<Flex gap="2" align="center">
<Checkbox defaultChecked />
<Text>Calibrated shells</Text>
</Flex>
<Flex gap="1">
<Button variant="solid" radius="small">
<img src={asset('shells/ap.webp')} width={24} height={24} />
</Button>
<Button variant="soft" radius="small" color="gray">
<img
src={asset('shells/hc_premium.webp')}
width={24}
height={24}
/>
</Button>
<Button variant="soft" radius="small" color="gray">
<img src={asset('shells/he.webp')} width={24} height={24} />
</Button>
</Flex>
</Flex>
</Card>
)}
</Flex> </Flex>
<Flex gap="6" direction="column"> <Flex gap="6" direction="column">
@@ -40,3 +40,18 @@ export const listingImage = style({
transform: 'translate(-25%, 10%)', transform: 'translate(-25%, 10%)',
}, },
}); });
export const enhancedArmor = style({
'@media': {
'screen and (min-width: 400px)': {
position: 'absolute',
right: 16,
top: 16,
},
'screen and (max-width: 399px)': {
// left: 16,
// bottom: 16,
},
},
});
+2 -1
View File
@@ -1,6 +1,6 @@
import { asset } from '../asset'; import { asset } from '../asset';
export type ShellType = 'ap' | 'apcr' | 'he' | 'heat'; export type ShellType = 'ap' | 'ap_cr' | 'hc' | 'he';
export interface BlitzkriegShellDefinition { export interface BlitzkriegShellDefinition {
id: number; id: number;
@@ -11,6 +11,7 @@ export interface BlitzkriegShellDefinition {
normalization: number; normalization: number;
ricochet: number; ricochet: number;
type: ShellType; type: ShellType;
icon: string;
} }
export type BlitzkriegShellDefinitions = Record< export type BlitzkriegShellDefinitions = Record<
+954 -577
View File
File diff suppressed because it is too large. Load diff