From dcc3ab6e4e618f3986ef1fb4bab7d80343edb83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 12 Dec 2023 15:12:09 -0600 Subject: [PATCH] feat: module ui --- .vscode/settings.json | 1 + scripts/buildAssets.ts | 125 ++++++++++++++----- src/app/tools/tankopedia/[id]/page.tsx | 132 ++++++++------------- src/app/tools/tankopedia/page.tsx | 11 +- src/core/blitzkrieg/definitions/guns.ts | 9 ++ src/core/blitzkrieg/definitions/shells.ts | 25 ++++ src/core/blitzkrieg/definitions/turrets.ts | 8 ++ 7 files changed, 191 insertions(+), 120 deletions(-) create mode 100644 src/core/blitzkrieg/definitions/shells.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index aa8b0487b..f508f0801 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,7 @@ "Abhi", "accountinfo", "alphatest", + "apcr", "bepaint", "BINORMAL", "blitzstars", diff --git a/scripts/buildAssets.ts b/scripts/buildAssets.ts index 1fe8ea164..8131fb517 100644 --- a/scripts/buildAssets.ts +++ b/scripts/buildAssets.ts @@ -13,6 +13,10 @@ import commitMultipleFiles, { FileChange, } from '../src/core/blitzkrieg/commitMultipleFiles'; import { BlitzkriegGunDefinitions } from '../src/core/blitzkrieg/definitions/guns'; +import { + BlitzkriegShellDefinitions, + ShellType, +} from '../src/core/blitzkrieg/definitions/shells'; import { BlitzkriegTankDefinitions, Tier, @@ -54,9 +58,35 @@ interface GunDefinitionsList { pitchLimits: string; burst?: { count: number; rate: number }; clip?: { count: number; rate: number }; + shots: { + [key: string]: { + speed: number; + piercingPower: string; + }; + }; }; }; } +type ShellKind = + | 'ARMOR_PIERCING' + | 'ARMOR_PIERCING_CR' + | 'HIGH_EXPLOSIVE' + | 'HOLLOW_CHARGE'; +type ShellDefinitionsList = Record< + string, + { + id: number; + userString: string; + icon: string; + kind: ShellKind; + caliber: number; + damage: { armor: number; devices: number }; + normalizationAngle: number; + ricochetAngle: number; + } +> & { + icons: Record; +}; interface VehicleDefinitions { turrets0: { [key: string]: { @@ -90,6 +120,12 @@ const blitzTankTypeToBlitzkrieg: Record = { mediumTank: 'medium', heavyTank: 'heavy', }; +const blitzShellKindToBLitzkrieg: Record = { + ARMOR_PIERCING: 'ap', + ARMOR_PIERCING_CR: 'apcr', + HIGH_EXPLOSIVE: 'he', + HOLLOW_CHARGE: 'heat', +}; const DATA = 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data'; const LANGUAGE = 'en'; @@ -117,6 +153,7 @@ if (allTargets || targets?.includes('definitions')) { const tankDefinitions: BlitzkriegTankDefinitions = {}; const turretDefinitions: BlitzkriegTurretDefinitions = {}; const gunDefinitions: BlitzkriegGunDefinitions = {}; + const shellDefinitions: BlitzkriegShellDefinitions = {}; const nations = await readdir(`${DATA}/${DOI.vehicleDefinitions}`).then( (nations) => nations.filter((nation) => nation !== 'common'), ); @@ -139,6 +176,11 @@ if (allTargets || targets?.includes('definitions')) { }>( `${DATA}/${DOI.vehicleDefinitions}/${nation}/components/guns.xml.dvpl`, ); + const shellList = await readXMLDVPL<{ + root: ShellDefinitionsList; + }>( + `${DATA}/${DOI.vehicleDefinitions}/${nation}/components/shells.xml.dvpl`, + ); for (const tankKey in tankList.root) { const tank = tankList.root[tankKey]; @@ -157,6 +199,28 @@ if (allTargets || targets?.includes('definitions')) { const gun = gunList.root.shared[gunKey]; const pitchLimitsRaw = turretGunEntry.pitchLimits ?? gun.pitchLimits; + const gunShells = Object.keys(gun.shots).map((shellKey) => { + const turretShellEntry = gun.shots[shellKey]; + const shell = shellList.root[shellKey]; + const shellId = toUniqueId(nation, shell.id); + + shellDefinitions[shellId] = { + id: shellId, + name: + strings[shell.userString] ?? shellKey.replaceAll('_', ' '), + speed: turretShellEntry.speed, + damage: { + armor: shell.damage.armor, + devices: shell.damage.devices, + }, + caliber: shell.caliber, + normalization: shell.normalizationAngle, + ricochet: shell.ricochetAngle, + type: blitzShellKindToBLitzkrieg[shell.kind], + }; + + return shellId; + }); gunDefinitions[gunId] = { id: gunId, @@ -168,6 +232,7 @@ if (allTargets || targets?.includes('definitions')) { .map(Number) as [number, number], name: strings[gun.userString] ?? gunKey.replaceAll('_', ' '), tier: gun.level, + shells: gunShells, }; return gunId; @@ -217,35 +282,37 @@ if (allTargets || targets?.includes('definitions')) { }), ); - // rmSync('dist/definitions', { force: true, recursive: true }); - // mkdirSync('dist/definitions', { recursive: true }); - // writeFile( - // 'dist/definitions/tanks.json', - // JSON.stringify(tankDefinitions, null, 2), - // ); - // writeFile( - // 'dist/definitions/turrets.json', - // JSON.stringify(turretDefinitions, null, 2), - // ); - // writeFile( - // 'dist/definitions/guns.json', - // JSON.stringify(gunDefinitions, null, 2), - // ); - // console.log('Committing tank definitions...'); - // await commitMultipleFiles( - // 'tresabhi', - // 'blitzkrieg-assets', - // 'main', - // 'tank definitions', - // [ - // { - // content: JSON.stringify(tankDefinitions), - // encoding: 'utf-8', - // path: 'definitions/tanks.json', - // }, - // ], - // true, - // ); + console.log('Committing tank definitions...'); + await commitMultipleFiles( + 'tresabhi', + 'blitzkrieg-assets', + 'main', + 'definitions', + [ + { + content: JSON.stringify(tankDefinitions), + encoding: 'utf-8', + path: 'definitions/tanks.json', + }, + { + content: JSON.stringify(turretDefinitions), + encoding: 'utf-8', + path: 'definitions/turrets.json', + }, + { + content: JSON.stringify(gunDefinitions), + encoding: 'utf-8', + path: 'definitions/guns.json', + }, + { + content: JSON.stringify(shellDefinitions), + encoding: 'utf-8', + path: 'definitions/shells.json', + }, + ], + + true, + ); } if ( diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index 82a3411a5..653a39875 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -1,107 +1,75 @@ 'use client'; -import { Checkbox, Flex, Heading } from '@radix-ui/themes'; -import { OrbitControls } from '@react-three/drei'; -import { Canvas } from '@react-three/fiber'; -import { use, useState } from 'react'; -import { - BufferAttribute, - BufferGeometry, - Mesh, - MeshStandardMaterial, - Vector3Tuple, -} from 'three'; -import model from '../../../../../test.json'; +import { Button, Flex, Heading } from '@radix-ui/themes'; +import { use, useEffect, useState } from 'react'; import { Flag } from '../../../../components/Flag'; import PageWrapper from '../../../../components/PageWrapper'; +import { gunDefinitions } from '../../../../core/blitzkrieg/definitions/guns'; +import { shellDefinitions } from '../../../../core/blitzkrieg/definitions/shells'; import { tankDefinitions } from '../../../../core/blitzkrieg/definitions/tanks'; +import { turretDefinitions } from '../../../../core/blitzkrieg/definitions/turrets'; const SIZE = 0.05; export default function Page({ params }: { params: { id: string } }) { const id = parseInt(params.id); const awaitedTankDefinitions = use(tankDefinitions); - const definition = awaitedTankDefinitions[id]; - const [display, setDisplay] = useState(model.map(() => true)); + const awaitedTurretDefinitions = use(turretDefinitions); + const awaitedGunDefinitions = use(gunDefinitions); + const awaitedShellDefinitions = use(shellDefinitions); + const tank = awaitedTankDefinitions[id]; + const [turret, setTurret] = useState( + awaitedTurretDefinitions[tank.turrets[0]], + ); + const [gun, setGun] = useState(awaitedGunDefinitions[turret.guns[0]]); + const [shell, setShell] = useState(awaitedShellDefinitions[gun.shells[0]]); + + useEffect(() => setGun(awaitedGunDefinitions[turret.guns[0]]), [turret]); + useEffect(() => setShell(awaitedShellDefinitions[gun.shells[0]]), [gun]); return ( - - {definition.name} + + {tank.name} - - + + Turrets - - + {tank.turrets.map((turretId) => ( + + ))} + - - {(model as { vertices: Vector3Tuple[]; indices: number[] }[]).map( - ({ vertices, indices }, index) => { - const geometry = new BufferGeometry(); - const verticesArray = new Float32Array(vertices.flat()); - const positionAttribute = new BufferAttribute(verticesArray, 3); - const indexAttribute = new BufferAttribute( - new Uint16Array(indices), - 1, - ); - const material = new MeshStandardMaterial({ - color: 'white', - metalness: 0.75, - // roughness: 0.2, - }); + + Guns - geometry - .setAttribute('position', positionAttribute) - .setIndex(indexAttribute) - .computeVertexNormals(); + {turret.guns.map((gunId) => ( + + ))} + - return display[index] ? ( - { - event.stopPropagation(); - ( - (event.object as Mesh).material as MeshStandardMaterial - ).color.set('red'); - }} - onPointerOut={(event) => { - event.stopPropagation(); - ( - (event.object as Mesh).material as MeshStandardMaterial - ).color.set('white'); - }} - onClick={(event) => { - event.stopPropagation(); - const newDisplay = [...display]; - newDisplay[index] = !newDisplay[index]; - setDisplay(newDisplay); - }} - /> - ) : null; - }, - )} - - + + Shells - - {model.map((group, index) => ( - { - const newDisplay = [...display]; - newDisplay[index] = value as boolean; - setDisplay(newDisplay); - }} - /> + {gun.shells.map((shellId) => ( + ))} diff --git a/src/app/tools/tankopedia/page.tsx b/src/app/tools/tankopedia/page.tsx index 7aa402b20..e99ec392b 100644 --- a/src/app/tools/tankopedia/page.tsx +++ b/src/app/tools/tankopedia/page.tsx @@ -74,11 +74,7 @@ export default function Page() { diff = a.tier - b.tier; } if (tankopediaState.sort.by === 'name') { - diff = ( - a.name_short ?? - a.name ?? - `Unknown tank ${a.id}` - ).localeCompare(b.name_short ?? b.name ?? `Unknown tank ${b.id}`); + diff = a.name.localeCompare(b.name); } return tankopediaState.sort.direction === 'ascending' ? diff : -diff; @@ -123,7 +119,6 @@ export default function Page() { go(event.target.value, searchableTanks, { keys: [ 'name', - 'name_short', 'id', ] satisfies (keyof BlitzkriegTankDefinition)[], }).map(({ obj }) => obj), @@ -307,9 +302,7 @@ export default function Page() { overflow: 'hidden', }} > - {tank.name_short ?? - tank.name ?? - `Unknown tank ${tank.id}`} + {tank.name} diff --git a/src/core/blitzkrieg/definitions/guns.ts b/src/core/blitzkrieg/definitions/guns.ts index 182c883bb..f540645b7 100644 --- a/src/core/blitzkrieg/definitions/guns.ts +++ b/src/core/blitzkrieg/definitions/guns.ts @@ -1,8 +1,17 @@ +import { asset } from '../asset'; + export interface BlitzkriegGunDefinition { id: number; name: string; tier: number; pitch: [number, number]; + shells: number[]; } export type BlitzkriegGunDefinitions = Record; + +export const gunDefinitions = fetch(asset('definitions/guns.json'), { + cache: 'no-cache', +}).then( + async (response) => response.json() as Promise, +); diff --git a/src/core/blitzkrieg/definitions/shells.ts b/src/core/blitzkrieg/definitions/shells.ts new file mode 100644 index 000000000..03e6ffadd --- /dev/null +++ b/src/core/blitzkrieg/definitions/shells.ts @@ -0,0 +1,25 @@ +import { asset } from '../asset'; + +export type ShellType = 'ap' | 'apcr' | 'he' | 'heat'; + +export interface BlitzkriegShellDefinition { + id: number; + name: string; + speed: number; + damage: { armor: number; devices: number }; + caliber: number; + normalization: number; + ricochet: number; + type: ShellType; +} + +export type BlitzkriegShellDefinitions = Record< + number, + BlitzkriegShellDefinition +>; + +export const shellDefinitions = fetch(asset('definitions/shells.json'), { + cache: 'no-cache', +}).then( + async (response) => response.json() as Promise, +); diff --git a/src/core/blitzkrieg/definitions/turrets.ts b/src/core/blitzkrieg/definitions/turrets.ts index 48bb6c050..a1871850c 100644 --- a/src/core/blitzkrieg/definitions/turrets.ts +++ b/src/core/blitzkrieg/definitions/turrets.ts @@ -1,3 +1,5 @@ +import { asset } from '../asset'; + export interface BlitzkriegTurretDefinition { id: number; name: string; @@ -10,3 +12,9 @@ export type BlitzkriegTurretDefinitions = Record< number, BlitzkriegTurretDefinition >; + +export const turretDefinitions = fetch(asset('definitions/turrets.json'), { + cache: 'no-cache', +}).then( + async (response) => response.json() as Promise, +);