diff --git a/package.json b/package.json index 7dafc306f..42d36bddd 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ }, "license": "MIT", "dependencies": { + "@octokit/plugin-throttling": "^8.1.3", "@octokit/rest": "^20.0.1", "@prisma/client": "^5.4.1", "@radix-ui/colors": "^3.0.0-rc.4", diff --git a/scripts/buildAssets.ts b/scripts/buildAssets.ts index a968edc14..078e80eef 100644 --- a/scripts/buildAssets.ts +++ b/scripts/buildAssets.ts @@ -1,12 +1,14 @@ -import { Octokit } from '@octokit/rest'; import { config } from 'dotenv'; import { readdir } from 'fs/promises'; -import { argv, env } from 'process'; +import { argv } from 'process'; import { TankType } from '../src/components/Tanks'; import { NATION_IDS } from '../src/constants/nations'; +import { readBase64DVPL } from '../src/core/blitz/readBase64DVPL'; import { readXMLDVPL } from '../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../src/core/blitz/readYAMLDVPL'; -import commitMultipleFiles from '../src/core/blitzkrieg/commitMultipleFiles'; +import commitMultipleFiles, { + FileChange, +} from '../src/core/blitzkrieg/commitMultipleFiles'; import { TankDefinitions, Tier, @@ -34,6 +36,15 @@ interface Strings { [key: string]: string; } type BlitzTankType = 'AT-SPG' | 'lightTank' | 'mediumTank' | 'heavyTank'; +/** + * Warning! This is not exhaustive. + */ +interface TankParameters { + resourcesPath: { + smallIconPath: string; + bigIconPath: string; + }; +} const blitzTankTypeToBlitzkrieg: Record = { 'AT-SPG': 'tank_destroyer', @@ -53,7 +64,7 @@ const DOI = { flags: 'Gfx/Lobby/flags', }; -const octokit = new Octokit({ auth: env.GH_TOKEN }); +const allTargets = argv.includes('--all-targets'); const targets = argv .find((argument) => argument.startsWith('--target')) ?.split('=')[1] @@ -61,7 +72,7 @@ const targets = argv if (!targets) throw new Error('No target(s) specified'); -if (targets.includes('tankDefinitions')) { +if (allTargets || targets.includes('tankDefinitions')) { console.log('Building tank definitions...'); const tankDefinitions: TankDefinitions = {}; @@ -82,7 +93,7 @@ if (targets.includes('tankDefinitions')) { const tank = tanks[tankIndex]; const nationVehicleId = tank.id; const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1; - const name = strings[tank.userString]; + const name = strings[tank.userString] ?? tankIndex; const name_short = tank.shortUserString ? strings[tank.shortUserString] === name ? undefined @@ -94,13 +105,13 @@ if (targets.includes('tankDefinitions')) { const tier = tank.level as Tier; const tags = tank.tags.split(' '); const type = blitzTankTypeToBlitzkrieg[tags[0] as BlitzTankType]; + const testing = tags.includes('testTank') ? true : undefined; if ((name ?? name_short) === undefined) { console.warn(`Missing name for ${tankIndex}`); } tankDefinitions[id] = { - id, name, name_short, nation, @@ -111,6 +122,7 @@ if (targets.includes('tankDefinitions')) { : 'researchable', tier, type, + testing, }; } }), @@ -118,7 +130,6 @@ if (targets.includes('tankDefinitions')) { console.log('Committing tank definitions...'); await commitMultipleFiles( - octokit, 'tresabhi', 'blitzkrieg-assets', 'main', @@ -134,170 +145,126 @@ if (targets.includes('tankDefinitions')) { ); } -// console.log( -// ( -// await readDVPL( -// `${DATA}/${DOI.strings}/${LANGUAGE}.yaml.dvpl`, -// ) -// ).toString(), -// ); +if ( + allTargets || + targets.includes('bigTankIcons') || + targets.includes('smallTankIcons') +) { + console.log('Building tank icons...'); -// const strings = await readFile( -// `${DATA}/${DOI.strings}/${LANGUAGE}.yaml.dvpl`, -// 'utf-8', -// ).then((data) => load(data) as Record); + const changes: FileChange[] = []; + const nations = await readdir(`${DATA}/${DOI.vehicleDefinitions}`).then( + (nations) => nations.filter((nation) => nation !== 'common'), + ); -// const tankDefinitions: TankDefinitions = {}; -// const tankIds: number[] = []; -// const images: Record = {}; -// const nations = await readdir( -// `${TEMP}/${DOI.vehicleDefinitions}`, -// ); + await Promise.all( + nations.map(async (nation) => { + const tanks = await readXMLDVPL( + `${DATA}/${DOI.vehicleDefinitions}/${nation}/list.xml.dvpl`, + ); -// writeFileSync('test.json', JSON.stringify(strings, null, 2)); + for (const tankIndex in tanks) { + const tank = tanks[tankIndex]; + const nationVehicleId = tank.id; + const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1; + const parameters = await readYAMLDVPL( + `${DATA}/${DOI.tankParameters}/${nation}/${tankIndex}.yaml.dvpl`, + ); + const small = `${DATA}/${parameters.resourcesPath.smallIconPath + .replace(/~res:\//, '') + .replace(/\..+/, '')}.packed.webp.dvpl`; + const big = `${DATA}/${parameters.resourcesPath.bigIconPath + .replace(/~res:\//, '') + .replace(/\..+/, '')}.packed.webp.dvpl`; -// Promise.all( -// nations -// .filter((nation) => nation !== 'common') -// .map(async (nation) => { -// const listXML = await readFile( -// `${TEMP}/${DOI.vehicleDefinitions}/${nation}/list.xml`, -// 'utf-8', -// ); -// const list = xml2js(listXML, { compact: true }) as ElementCompact; + if (targets.includes('bigTankIcons')) { + changes.push({ + content: await readBase64DVPL(big), + encoding: 'base64', + path: `icons/big/${id}.webp`, + }); + } + if (targets.includes('smallTankIcons')) { + changes.push({ + content: await readBase64DVPL(small), + encoding: 'base64', + path: `icons/small/${id}.webp`, + }); + } + } + }), + ); -// await Promise.all( -// Object.entries(list.root).map( -// async ([vehicle, vehicleData]) => { -// const nationVehicleId = parseInt(list.root[vehicle].id._text); -// const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1; -// const name = strings[vehicleData.userString._text]; -// const name_short = strings[vehicleData.shortUserString?._text]; -// const isPremium = 'gold' in vehicleData.price; -// const isCollector = vehicleData.sellPrice -// ? 'gold' in vehicleData.sellPrice -// : false; -// const tier = parseInt(vehicleData.level._text) as Tier; -// const tags = vehicleData.tags._text.split(' '); -// const type = tags[0]; + console.log('Committing tank icons...'); + await commitMultipleFiles( + 'tresabhi', + 'blitzkrieg-assets', + 'main', + 'tank icons', + changes, + true, + ); +} -// if ((name ?? name_short) === undefined) { -// console.warn(`Missing name for ${vehicle}`); -// } +if (allTargets || targets.includes('scratchedFlags')) { + console.log('Building scratched flags...'); -// tankIds.push(id); -// tankDefinitions[id] = { -// id, -// name, -// name_short, -// nation, -// tree_type: isCollector -// ? 'collector' -// : isPremium -// ? 'premium' -// : 'researchable', -// tier, -// type, -// }; + const flags = await readdir(`${DATA}/${DOI.flags}`); -// // Tank images -// const parameterPath = `${TEMP}/${DOI.tankParameters}/${nation}/${vehicle}.yaml`; -// const parameterString = await readFile(parameterPath, 'utf-8'); -// const { smallIconPath, bigIconPath } = -// parse(parameterString).resourcesPath; -// images[id] = { -// small: `${TEMP}/assets/Data/${(smallIconPath as string) -// .replace(/~res:\//, '') -// .replace(/\..+/, '')}.packed.webp`, -// big: `${TEMP}/assets/Data/${(bigIconPath as string) -// .replace(/~res:\//, '') -// .replace(/\..+/, '')}.packed.webp`, -// }; -// }, -// ), -// ); -// }), -// ).then(async () => { -// if (!publish) return; + console.log('Committing scratched flags...'); + commitMultipleFiles( + 'tresabhi', + 'blitzkrieg-assets', + 'main', + 'scratched flags', + await Promise.all( + flags + .filter( + (flag) => + flag.startsWith('flag_tutor-tank_') && + !flag.endsWith('@2x.packed.webp.dvpl'), + ) + .map(async (flag) => { + const content = await readBase64DVPL(`${DATA}/${DOI.flags}/${flag}`); + 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; + }), + ), + true, + ); +} -// // 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}/${DOI.flags}`); -// // const scratchedFlags = await Promise.all( -// // flags -// // .filter((flag) => flag.startsWith('flag_tutor-tank_')) -// // .map(async (flag) => { -// // const content = await readFile( -// // `${TEMP}/${DOI.flags}/${flag}`, -// // { encoding: 'base64' }, -// // ); -// // const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1]; +if (allTargets || targets.includes('circleFlags')) { + const flags = await readdir(`${DATA}/${DOI.flags}`); -// // 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}/${DOI.flags}/${flag}`, -// { encoding: 'base64' }, -// ); -// const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1]; + commitMultipleFiles( + 'tresabhi', + 'blitzkrieg-assets', + 'main', + 'circle flags', + await Promise.all( + flags + .filter( + (flag) => + flag.startsWith('flag_profile-stat_') && + !flag.endsWith('@2x.packed.webp.dvpl'), + ) + .map(async (flag) => { + const content = await readBase64DVPL(`${DATA}/${DOI.flags}/${flag}`); + const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1]; -// 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, -// ); -// }); + return { + content, + encoding: 'base64', + path: `flags/circle/${name}.webp`, + } satisfies FileChange; + }), + ), + true, + ); +} diff --git a/src/app/tools/tankopedia/page.tsx b/src/app/tools/tankopedia/page.tsx index 02ececfc3..bdd48959f 100644 --- a/src/app/tools/tankopedia/page.tsx +++ b/src/app/tools/tankopedia/page.tsx @@ -142,18 +142,16 @@ export default function Page() { display: 'flex', }} > - {tank.nation !== 'other' && ( - - )} +
setTimeout(resolve, TIME_PER_BLOB)); diff --git a/src/core/blitzkrieg/definitions/tanks.ts b/src/core/blitzkrieg/definitions/tanks.ts index 224a7424a..27e32a342 100644 --- a/src/core/blitzkrieg/definitions/tanks.ts +++ b/src/core/blitzkrieg/definitions/tanks.ts @@ -3,13 +3,13 @@ import { TankType, TreeTypeString } from '../../../components/Tanks'; import { asset } from '../asset'; export interface TankDefinition { - id: number; nation: string; name: string; name_short?: string; tree_type: TreeTypeString; tier: Tier; type: TankType; + testing?: boolean; } export type TankDefinitions = Record; diff --git a/src/core/blitzkrieg/octokit.ts b/src/core/blitzkrieg/octokit.ts index 509aafa5a..a5fa63fe4 100644 --- a/src/core/blitzkrieg/octokit.ts +++ b/src/core/blitzkrieg/octokit.ts @@ -1,4 +1,7 @@ +import { throttling } from '@octokit/plugin-throttling'; import { Octokit } from '@octokit/rest'; import { secrets } from './secrets'; +Octokit.plugin(throttling); + export const octokit = new Octokit({ auth: secrets.GH_TOKEN }); diff --git a/tsconfig.json b/tsconfig.json index 6c4176c22..48adb851b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,11 @@ "noEmit": true, "resolveJsonModule": true, "jsx": "preserve", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "incremental": true, "isolatedModules": true, @@ -20,6 +24,13 @@ } ] }, - "include": ["src/**/*", "scripts/**/*"], - "exclude": ["node_modules", "dist"] + "include": [ + "src/**/*", + "scripts/**/*", + "dist/website/types/**/*.ts" + ], + "exclude": [ + "node_modules", + "dist" + ] } diff --git a/yarn.lock b/yarn.lock index 5a2b22a56..9a36c8cb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -984,7 +984,7 @@ "@octokit/types" "^12.0.0" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^19.0.2": +"@octokit/openapi-types@^19.0.2", "@octokit/openapi-types@^19.1.0": version "19.1.0" resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-19.1.0.tgz#75ec7e64743870fc73e1ab4bc6ec252ecdd624dc" integrity sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw== @@ -1008,6 +1008,14 @@ dependencies: "@octokit/types" "^12.3.0" +"@octokit/plugin-throttling@^8.1.3": + version "8.1.3" + resolved "https://registry.yarnpkg.com/@octokit/plugin-throttling/-/plugin-throttling-8.1.3.tgz#7fb0e001c0cb9383c6be07740b8ec326ed990f6b" + integrity sha512-pfyqaqpc0EXh5Cn4HX9lWYsZ4gGbjnSmUILeu4u2gnuM50K/wIk9s1Pxt3lVeVwekmITgN/nJdoh43Ka+vye8A== + dependencies: + "@octokit/types" "^12.2.0" + bottleneck "^2.15.3" + "@octokit/request-error@^5.0.0": version "5.0.1" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.0.1.tgz#277e3ce3b540b41525e07ba24c5ef5e868a72db9" @@ -1044,6 +1052,13 @@ dependencies: "@octokit/openapi-types" "^19.0.2" +"@octokit/types@^12.2.0": + version "12.4.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.4.0.tgz#8f97b601e91ce6b9776ed8152217e77a71be7aac" + integrity sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ== + dependencies: + "@octokit/openapi-types" "^19.1.0" + "@pkgjs/parseargs@0.11.0", "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -2532,6 +2547,11 @@ bole@^5.0.0: fast-safe-stringify "^2.0.7" individual "^3.0.0" +bottleneck@^2.15.3: + version "2.19.5" + resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" + integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"