From 4bfe34ba530afd7555cbb901ffa48ac8dc92e236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:59:58 -0600 Subject: [PATCH] feat: read dvpl --- .vscode/settings.json | 3 +++ package.json | 3 +++ scripts/buildAssets.ts | 49 +++++++++++++++++++------------------- src/core/blitz/readDVPL.ts | 49 ++++++++++++++++++++++++++++++++++++++ yarn.lock | 41 +++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 src/core/blitz/readDVPL.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 7ccf745d0..12fd07bf9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,8 @@ "customperiod", "deburr", "diacriticless", + "dvpl", + "DVPLCRC", "Everytime", "fullstats", "fuzzysort", @@ -38,6 +40,7 @@ "Smri", "startcase", "statsfull", + "steamapps", "Stringifying", "strvk", "subnation", diff --git a/package.json b/package.json index 1605e113d..2407827c9 100644 --- a/package.json +++ b/package.json @@ -65,12 +65,15 @@ "@types/express": "^4.17.18", "@types/js-yaml": "^4.0.8", "@types/lodash": "^4.14.199", + "@types/lz4": "^0.6.4", "@types/markdown-escape": "^1.1.0", "@types/node": "^20.6.5", "@types/react": "^18.2.22", "@vanilla-extract/next-plugin": "^2.3.1", "compare-versions": "^6.1.0", + "crc": "^4.3.2", "knip": "^3.4.0", + "lz4": "^0.6.5", "prettier": "^3.0.3", "prisma": "^5.4.1", "typescript": "^5.2.2" diff --git a/scripts/buildAssets.ts b/scripts/buildAssets.ts index e8604ba44..8c563b980 100644 --- a/scripts/buildAssets.ts +++ b/scripts/buildAssets.ts @@ -1,13 +1,13 @@ import { Octokit } from '@octokit/rest'; -import decompress from 'decompress'; import { config } from 'dotenv'; import { writeFileSync } from 'fs'; -import { readFile, readdir, rm } from 'fs/promises'; +import { readFile, readdir } 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 { readDVPL } from '../src/core/blitz/readDVPL'; import { TankDefinitions, Tier, @@ -16,39 +16,40 @@ import commitMultipleFiles, { FileChange } from './commitMultipleFiles'; config(); +const DATA = + 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data'; const LANGUAGE = 'en'; -const TEMP = 'temp/blitz'; -const publish = argv.includes('--publish'); -const apkFile = argv - .find((argument) => argument.startsWith('--file')) - ?.split('=')[1]; -const noRewrite = argv.includes('--no-rewrite'); +const targets = argv + .find((argument) => argument.startsWith('--target')) + ?.split('=')[1] + .split(','); -if (!apkFile) throw new Error('No file specified'); +if (!targets) throw new Error('No target(s) specified'); const directoriesOfInterest = { - vehicleDefinitions: 'assets/Data/XML/item_defs/vehicles', - strings: 'assets/Data/Strings', - tankParameters: 'assets/Data/3d/Tanks/Parameters', - smallIcons: 'assets/Data/Gfx/UI/BattleScreenHUD/SmallTankIcons', - bigIcons: 'assets/Data/Gfx/UI/BigTankIcons', - flags: 'assets/Data/Gfx/Lobby/flags', + vehicleDefinitions: 'XML/item_defs/vehicles', + strings: 'Strings', + tankParameters: '3d/Tanks/Parameters', + smallIcons: 'Gfx/UI/BattleScreenHUD/SmallTankIcons', + bigIcons: 'Gfx/UI/BigTankIcons', + flags: 'Gfx/Lobby/flags', }; -const directoriesOfInterestArray = Object.values(directoriesOfInterest); -if (!noRewrite) { - await rm(TEMP, { recursive: true, force: true }); - await decompress(apkFile, TEMP, { - filter: (file) => - directoriesOfInterestArray.some((dir) => file.path.startsWith(dir)), - }); -} +console.log( + ( + await readDVPL( + `${DATA}/${directoriesOfInterest.strings}/${LANGUAGE}.yaml.dvpl`, + ) + ).toString(), +); +throw new Error('stop'); const strings = await readFile( - `${TEMP}/${directoriesOfInterest.strings}/${LANGUAGE}.yaml`, + `${DATA}/${directoriesOfInterest.strings}/${LANGUAGE}.yaml.dvpl`, 'utf-8', ).then((data) => load(data) as Record); + const tankDefinitions: TankDefinitions = {}; const tankIds: number[] = []; const images: Record = {}; diff --git a/src/core/blitz/readDVPL.ts b/src/core/blitz/readDVPL.ts new file mode 100644 index 000000000..85812065f --- /dev/null +++ b/src/core/blitz/readDVPL.ts @@ -0,0 +1,49 @@ +import { crc32 } from 'crc'; +import { readFile } from 'fs/promises'; +import { decodeBlock } from 'lz4'; + +/** + * Thanks Maddoxkkm! Modernized heavily. + * + * https://github.com/Maddoxkkm/dvpl_converter/ + */ +export async function readDVPL(file: string) { + const buffer = await readFile(file); + const footerBuffer = buffer.slice(buffer.length - 20, buffer.length); + + if ( + footerBuffer.toString('utf8', 16, 20) !== 'DVPL' || + footerBuffer.length !== 20 + ) { + throw 'InvalidDVPLFooter'; + } + + const footerData = { + oSize: footerBuffer.readUInt32LE(0), + cSize: footerBuffer.readUInt32LE(4), + crc32: footerBuffer.readUInt32LE(8), + type: footerBuffer.readUInt32LE(12), + }; + const targetBlock = buffer.slice(0, buffer.length - 20); + + if (targetBlock.length !== footerData.cSize) throw 'DVPLSizeMismatch'; + if (crc32(targetBlock) !== footerData.crc32) throw 'DVPLCRC32Mismatch'; + if (footerData.type === 0) { + if (!(footerData.oSize === footerData.cSize && footerData.type === 0)) { + throw 'DVPLTypeSizeMismatch'; + } + + return targetBlock; + } else if (footerData.type === 1 || footerData.type === 2) { + const deDVPLBlock = Buffer.alloc(footerData.oSize); + const DecompressedBlockSize = decodeBlock(targetBlock, deDVPLBlock); + + if (DecompressedBlockSize !== footerData.oSize) { + throw 'DVPLDecodeSizeMismatch'; + } + + return deDVPLBlock; + } else { + throw new TypeError('Unknown DVPL format'); + } +} diff --git a/yarn.lock b/yarn.lock index e827f3060..74b22a608 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2027,6 +2027,13 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8" integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== +"@types/lz4@^0.6.4": + version "0.6.4" + resolved "https://registry.yarnpkg.com/@types/lz4/-/lz4-0.6.4.tgz#eba8c0bb9e6a997e78107092953c8cfa92733a46" + integrity sha512-vvxMIkowyHbY6zkCantyYwAK83N5E04bzFZSPJICG1SDpaL89L7lObs9DhLuhJhXHCQMkjzN3LYoAH6LjfwMFQ== + dependencies: + "@types/node" "*" + "@types/markdown-escape@^1.1.0": version "1.1.3" resolved "https://registry.yarnpkg.com/@types/markdown-escape/-/markdown-escape-1.1.3.tgz#b880ab7c1e23c76b1d663e5a5640107c493e0c3e" @@ -2781,6 +2788,11 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +crc@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/crc/-/crc-4.3.2.tgz#49b7821cbf2cf61dfd079ed93863bbebd5469b9a" + integrity sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A== + cross-spawn@^7.0.0: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2834,6 +2846,11 @@ csstype@^3.0.2, csstype@^3.0.7, csstype@^3.1.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== +cuint@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" + integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== + data-uri-to-buffer@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" @@ -3937,6 +3954,16 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lz4@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/lz4/-/lz4-0.6.5.tgz#ae8b7522681b6ab155023e6c56bf73087090122b" + integrity sha512-KSZcJU49QZOlJSItaeIU3p8WoAvkTmD9fJqeahQXNu1iQ/kR0/mQLdbrK8JY9MY8f6AhJoMrihp1nu1xDbscSQ== + dependencies: + buffer "^5.2.1" + cuint "^0.2.2" + nan "^2.13.2" + xxhashjs "^0.2.2" + magic-bytes.js@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/magic-bytes.js/-/magic-bytes.js-1.6.0.tgz#ee4354ac41a9b86f410e2690bc25dc4c264fb55d" @@ -4168,6 +4195,11 @@ ms@2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +nan@^2.13.2: + version "2.18.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" + integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== + nanoid@^3.3.6, nanoid@^3.3.7: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" @@ -4896,6 +4928,7 @@ streamsearch@^1.1.0: integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: + name string-width-cjs version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4946,6 +4979,7 @@ stringify-entities@^4.0.0: character-entities-legacy "^3.0.0" "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + name strip-ansi-cjs version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5460,6 +5494,13 @@ xtend@^4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +xxhashjs@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" + integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw== + dependencies: + cuint "^0.2.2" + yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"