feat: localize game assets

This commit is contained in:
tresabhi committed 2025-01-14 19:22:41 -06:00
1 parent d8459d373c
commit ef9778ea96
90 files changed
+336 -251

No files matched your search

@@ -8,16 +8,16 @@ import { DATA } from './constants';
export async function boosterIcons() {
const boosterFiles = (await readdir(`${DATA}/Gfx/Shared/boosters`)).filter(
(file) => !file.endsWith('@2x.txt.dvpl') && !file.startsWith('texture0'),
(file) => !file.includes('@2x.txt') && !file.startsWith('texture0'),
);
const image = sharp(
await readDVPLFile(`${DATA}/Gfx/Shared/boosters/texture0.packed.webp.dvpl`),
await readDVPLFile(`${DATA}/Gfx/Shared/boosters/texture0.packed.webp`),
);
const changes: FileChange[] = [];
await Promise.all(
boosterFiles.map(async (file) => {
const name = file.match(/booster_(.+).txt.dvpl/)?.[1];
const name = file.match(/booster_(.+).txt/)?.[1];
if (name === undefined) return;
@@ -6,7 +6,7 @@ import { DATA } from './constants';
export async function camouflageIcons() {
console.log('Building camouflage icons...');
const content = await readDVPLFile(
`${DATA}/Gfx/UI/Hangar/IconCamouflage.packed.webp.dvpl`,
`${DATA}/Gfx/UI/Hangar/IconCamouflage.packed.webp`,
);
const changes: FileChange[] = [
{
+28 -6
View File
@@ -1,11 +1,33 @@
import { readdir } from 'fs/promises';
import { argv } from 'process';
const WINDOWS_APPS = 'C:/Program Files/WindowsApps';
const wotbPackageRegex = /7458BE2C\..+_\d+(\.\d+)+_x64__.+/;
const isDepot = argv.includes('--depot');
export const DATA = isDepot
? await (async () => {
const [installationVersion] = await readdir(`../../depots/444202`);
return `../../depots/444202/${installationVersion}/Data`;
})()
: 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data';
let data: string;
let compressed: boolean;
if (isDepot) {
const [installationVersion] = await readdir(`../../depots/444202`);
data = `../../depots/444202/${installationVersion}/Data`;
compressed = true;
} else {
const directories = await readdir(WINDOWS_APPS).then((files) =>
files.filter((file) => wotbPackageRegex.test(file)),
);
if (directories.length !== 1) {
throw new Error(
`Expected 1 directory for WoTB Windows App, got ${directories.length}.`,
);
}
const [windowsApp] = directories;
data = `${WINDOWS_APPS}/${windowsApp}/Data`;
compressed = false;
}
export const DATA = data;
export const DATA_COMPRESSED = compressed;
@@ -34,21 +34,19 @@ export async function consumableProvisionIcons() {
const styleSheets = await Promise.all(
styles.map(async (path) =>
Object.values(
(await readYAMLDVPL<Mappings>(`${DATA}/${path}.dvpl`)).StyleSheets,
(await readYAMLDVPL<Mappings>(`${DATA}/${path}`)).StyleSheets,
),
),
).then((array) => array.flat());
for (const match of (
await readStringDVPL(
`${DATA}/XML/item_defs/vehicles/common/consumables/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/consumables/list.xml`,
)
).matchAll(listItemsPattern)) {
const consumablesCommon = await readXMLDVPL<{
root: ConsumablesCommon;
}>(
`${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml.dvpl`,
);
}>(`${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml`);
await Promise.all(
Object.values(consumablesCommon.root).map(async (consumable) => {
@@ -70,9 +68,9 @@ export async function consumableProvisionIcons() {
.replace('.psd', '')
.replace('.txt', '');
if (existsSync(`${DATA}/${configPath}.packed.webp.dvpl`)) {
if (existsSync(`${DATA}/${configPath}.packed.webp`)) {
const image = sharp(
await readDVPLFile(`${DATA}/${configPath}.packed.webp.dvpl`),
await readDVPLFile(`${DATA}/${configPath}.packed.webp`),
);
const content = await image.trim({ threshold: 100 }).toBuffer();
@@ -83,10 +81,10 @@ export async function consumableProvisionIcons() {
} else {
const consumablesTexture = sharp(
await readDVPLFile(
`${`${DATA}/${configPath}`.split('/').slice(0, -1).join('/')}/texture0.packed.webp.dvpl`,
`${`${DATA}/${configPath}`.split('/').slice(0, -1).join('/')}/texture0.packed.webp`,
),
);
const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt.dvpl`))
const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt`))
.split('\n')[4]
.split(' ')
.map(Number);
@@ -111,12 +109,12 @@ export async function consumableProvisionIcons() {
for (const match of (
await readStringDVPL(
`${DATA}/XML/item_defs/vehicles/common/provisions/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/provisions/list.xml`,
)
).matchAll(listItemsPattern)) {
const provisionsCommon = await readXMLDVPL<{
root: ProvisionsCommon;
}>(`${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml.dvpl`);
}>(`${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml`);
await Promise.all(
Object.values(provisionsCommon.root).map(async (provision) => {
const styleSheet = styleSheets.find((styleSheet) =>
@@ -137,9 +135,9 @@ export async function consumableProvisionIcons() {
.replace('.psd', '')
.replace('.txt', '');
if (existsSync(`${DATA}/${configPath}.packed.webp.dvpl`)) {
if (existsSync(`${DATA}/${configPath}.packed.webp`)) {
const image = sharp(
await readDVPLFile(`${DATA}/${configPath}.packed.webp.dvpl`),
await readDVPLFile(`${DATA}/${configPath}.packed.webp`),
);
const content = await image.trim({ threshold: 100 }).toBuffer();
@@ -150,10 +148,10 @@ export async function consumableProvisionIcons() {
} else {
const provisionsTexture = sharp(
await readDVPLFile(
`${`${DATA}/${configPath}`.split('/').slice(0, -1).join('/')}/texture0.packed.webp.dvpl`,
`${`${DATA}/${configPath}`.split('/').slice(0, -1).join('/')}/texture0.packed.webp`,
),
);
const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt.dvpl`))
const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt`))
.split('\n')[4]
.split(' ')
.map(Number);
@@ -23,7 +23,7 @@ export async function currencies() {
await Promise.all(
ICONS.map(async ([file, name]) => {
const content = await sharp(
await readDVPLFile(`${DATA}/Gfx/Lobby/currency/${file}.dvpl`),
await readDVPLFile(`${DATA}/Gfx/Lobby/currency/${file}`),
)
.trim()
.toBuffer();
+47 -51
View File
@@ -7,7 +7,6 @@ import {
ConsumableTankCategoryFilterCategory,
Crew,
CrewType,
DEFAULT_LOCALE,
encodePBBuffer,
EquipmentDefinitions,
EquipmentSlot,
@@ -23,8 +22,6 @@ import {
ResearchCost,
ShellType,
SkillDefinitions,
SUPPORTED_LOCALE_BLITZ_MAP,
SUPPORTED_LOCALES,
TankClass,
TankDefinitions,
TankPrice,
@@ -34,6 +31,11 @@ import {
Unlock,
Vector3,
} from '@blitzkit/core';
import {
DEFAULT_LOCALE,
SUPPORTED_LOCALE_BLITZ_MAP,
SUPPORTED_LOCALES,
} from '@blitzkit/i18n';
import { readdir } from 'fs/promises';
import { parse as parsePath } from 'path';
import { Vector3Tuple } from 'three';
@@ -513,11 +515,9 @@ export async function definitions() {
console.log('Building definitions...');
const gameDefinitions: GameDefinitions = {
version: (await readStringDVPL(`${DATA}/version.txt.dvpl`)).split(' ')[0],
version: (await readStringDVPL(`${DATA}/version.txt`)).split(' ')[0],
nations: (
await readYAMLDVPL<AvailableNationsYaml>(
`${DATA}/available_nations.yaml.dvpl`,
)
await readYAMLDVPL<AvailableNationsYaml>(`${DATA}/available_nations.yaml`)
).available_nations,
gameModes: {},
roles: {},
@@ -550,26 +550,30 @@ export async function definitions() {
.then((response) => response.text())
.then((string) => parseYaml(string) as BlitzStrings);
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
`${DATA}/XML/item_defs/vehicles/common/optional_devices.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/optional_devices.xml`,
);
const stringsI18n: Record<string, Record<string, string>> = {};
for (const locale of SUPPORTED_LOCALES) {
const blitzLocale = SUPPORTED_LOCALE_BLITZ_MAP[locale];
const cache = await fetch(
`https://stufficons.wgcdn.co/localizations/${blitzLocale}.yaml`,
)
.then((response) => response.text())
.then((string) => parseYaml(string) as BlitzStrings);
const preInstalled = await readYAMLDVPL<BlitzStrings>(
`${DATA}/Strings/${blitzLocale}.yaml.dvpl`,
);
await Promise.all(
SUPPORTED_LOCALES.map(async (locale) => {
const blitzLocale = SUPPORTED_LOCALE_BLITZ_MAP[locale];
const cache = await fetch(
`https://stufficons.wgcdn.co/localizations/${blitzLocale}.yaml`,
)
.then((response) => response.text())
.then((string) => parseYaml(string) as BlitzStrings);
const preInstalled = await readYAMLDVPL<BlitzStrings>(
`${DATA}/Strings/${blitzLocale}.yaml`,
);
stringsI18n[locale] = {
...cache,
...preInstalled,
};
}
stringsI18n[locale] = {
...cache,
...preInstalled,
};
console.log(`Loaded strings for ${locale}`);
}),
);
function getString(name: string) {
const locales: Record<string, string> = {
@@ -594,13 +598,13 @@ export async function definitions() {
const optionalDeviceSlots = await readXMLDVPL<{
root: OptionalDeviceSlots;
}>(`${DATA}/XML/item_defs/vehicles/common/optional_device_slots.xml.dvpl`);
}>(`${DATA}/XML/item_defs/vehicles/common/optional_device_slots.xml`);
const consumables: ConsumablesCommon = {};
const provisions: ProvisionsCommon = {};
for (const match of (
await readStringDVPL(
`${DATA}/XML/item_defs/vehicles/common/consumables/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/consumables/list.xml`,
)
).matchAll(/<items path="(.+)\.xml"\/>/g)) {
if (match[1] === 'prototypes') continue;
@@ -609,7 +613,7 @@ export async function definitions() {
consumables,
(
await readXMLDVPL<{ root: ConsumablesCommon }>(
`${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml`,
)
).root,
);
@@ -617,7 +621,7 @@ export async function definitions() {
for (const match of (
await readStringDVPL(
`${DATA}/XML/item_defs/vehicles/common/provisions/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/provisions/list.xml`,
)
).matchAll(/<items path="(.+)\.xml"\/>/g)) {
if (match[1] === 'prototypes') continue;
@@ -626,33 +630,33 @@ export async function definitions() {
provisions,
(
await readXMLDVPL<{ root: ConsumablesCommon }>(
`${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml`,
)
).root,
);
}
const avatar = await readXMLDVPL<{ root: Avatar }>(
`${DATA}/XML/item_defs/tankmen/avatar.xml.dvpl`,
`${DATA}/XML/item_defs/tankmen/avatar.xml`,
);
const maps = await readYAMLDVPL<Maps>(`${DATA}/maps.yaml.dvpl`);
const maps = await readYAMLDVPL<Maps>(`${DATA}/maps.yaml`);
const tankXps = new Map<number, ResearchCost>();
const camouflagesXml = await readXMLDVPL<{ root: CamouflagesXML }>(
`${DATA}/XML/item_defs/vehicles/common/camouflages.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/camouflages.xml`,
);
const camouflagesYaml = await readYAMLDVPL<CamouflagesYaml>(
`${DATA}/camouflages.yaml.dvpl`,
`${DATA}/camouflages.yaml`,
);
const camouflagesXmlEntries = Object.entries(camouflagesXml.root.camouflages);
const squadBattleTypeStyles = await readYAMLDVPL<SquadBattleTypeStyles>(
`${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`,
`${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml`,
);
const gameTypeSelectorStyles = await readYAMLDVPL<SquadBattleTypeStyles>(
`${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml.dvpl`,
`${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml`,
);
const gameModeNativeNames: Record<string, number> = {};
const combatRoles = await readYAMLDVPL<CombatRolesYaml>(
`${DATA}/XML/item_defs/vehicles/common/combat_roles.yaml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/combat_roles.yaml`,
);
const consumableNativeNames: Record<string, number> = {};
const provisionNativeNames: Record<string, number> = {};
@@ -702,29 +706,23 @@ export async function definitions() {
await Promise.all(
nations.map(async (nation) => {
const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`,
);
const turretList = await readXMLDVPL<{
root: TurretDefinitionsList;
}>(
`${DATA}/XML/item_defs/vehicles/${nation}/components/turrets.xml.dvpl`,
);
}>(`${DATA}/XML/item_defs/vehicles/${nation}/components/turrets.xml`);
const gunList = await readXMLDVPL<{
root: GunDefinitionsList;
}>(`${DATA}/XML/item_defs/vehicles/${nation}/components/guns.xml.dvpl`);
}>(`${DATA}/XML/item_defs/vehicles/${nation}/components/guns.xml`);
const shellList = await readXMLDVPL<{
root: ShellDefinitionsList;
}>(`${DATA}/XML/item_defs/vehicles/${nation}/components/shells.xml.dvpl`);
}>(`${DATA}/XML/item_defs/vehicles/${nation}/components/shells.xml`);
const enginesList = await readXMLDVPL<{
root: EngineDefinitionsList;
}>(
`${DATA}/XML/item_defs/vehicles/${nation}/components/engines.xml.dvpl`,
);
}>(`${DATA}/XML/item_defs/vehicles/${nation}/components/engines.xml`);
const chassisList = await readXMLDVPL<{
root: ChassisDefinitionsList;
}>(
`${DATA}/XML/item_defs/vehicles/${nation}/components/chassis.xml.dvpl`,
);
}>(`${DATA}/XML/item_defs/vehicles/${nation}/components/chassis.xml`);
function resolveUnlocks(unlocks?: BlitzModuleType) {
if (!unlocks) return [];
@@ -776,10 +774,10 @@ export async function definitions() {
const tank = tankList.root[tankKey];
let tankPrice: TankPrice;
const tankDefinition = await readXMLDVPL<{ root: VehicleDefinitions }>(
`${DATA}/XML/item_defs/vehicles/${nation}/${tankKey}.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/${nation}/${tankKey}.xml`,
);
const tankParameters = await readYAMLDVPL<TankParameters>(
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`,
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
);
const turretOrigin = tankDefinition.root.hull.turretPositions.turret
.split(' ')
@@ -1667,8 +1665,6 @@ export async function definitions() {
};
});
return;
await commitAssets('definitions', [
{
content: encodePBBuffer(GameDefinitions, gameDefinitions),
@@ -22,14 +22,14 @@ export async function equipmentIcons() {
const changes: FileChange[] = [];
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
`${DATA}/XML/item_defs/vehicles/common/optional_devices.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/common/optional_devices.xml`,
);
const mappings = await readYAMLDVPL<Mappings>(
`${DATA}/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml.dvpl`,
`${DATA}/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml`,
);
const image = sharp(
await readDVPLFile(
`${DATA}/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp.dvpl`,
`${DATA}/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp`,
),
);
@@ -57,7 +57,7 @@ export async function equipmentIcons() {
if (configPath.startsWith('Gfx/Lobby')) {
const configPathWebp = configPath.replace('.txt', '');
const image = sharp(
await readDVPLFile(`${DATA}/${configPathWebp}.packed.webp.dvpl`),
await readDVPLFile(`${DATA}/${configPathWebp}.packed.webp`),
);
const content = await image.trim().toBuffer();
@@ -66,7 +66,7 @@ export async function equipmentIcons() {
content,
});
} else {
const config = await readStringDVPL(`${DATA}/${configPath}.dvpl`);
const config = await readStringDVPL(`${DATA}/${configPath}`);
const sizes = config.split('\n')[4].split(' ').map(Number);
const content = await image
.clone()
+3 -4
View File
@@ -14,7 +14,7 @@ export async function flags() {
.filter(
(flag) =>
flag.startsWith('flag_profile-stat_') &&
!flag.endsWith('@2x.packed.webp.dvpl'),
!flag.endsWith('@2x.packed.webp'),
)
.map(async (flag) => {
const image = sharp(
@@ -34,7 +34,7 @@ export async function flags() {
.filter(
(flag) =>
flag.startsWith('flag_tutor-tank_') &&
!flag.endsWith('@2x.packed.webp.dvpl'),
!flag.endsWith('@2x.packed.webp'),
)
.map(async (flag) => {
const content = await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`);
@@ -50,8 +50,7 @@ export async function flags() {
(await readdir(`${DATA}/Gfx/Lobby/flags`))
.filter(
(flag) =>
flag.startsWith('flag_filter_') &&
flag.endsWith('@2x.packed.webp.dvpl'),
flag.startsWith('flag_filter_') && flag.endsWith('@2x.packed.webp'),
)
.map(async (flag) => {
const content = await sharp(
@@ -11,10 +11,10 @@ export async function gameModeBanners() {
const changes: FileChange[] = [];
const gameTypeSelectorStyles = await readYAMLDVPL<SquadBattleTypeStyles>(
`${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml.dvpl`,
`${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml`,
);
const squadBattleTypeStyles = await readYAMLDVPL<SquadBattleTypeStyles>(
`${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`,
`${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml`,
);
const bannerMatches: { name: string; path: string }[] = [];
@@ -38,7 +38,7 @@ export async function gameModeBanners() {
}
const content = await sharp(
await readDVPLFile(`${DATA}${path}.packed.webp.dvpl`),
await readDVPLFile(`${DATA}${path}.packed.webp`),
)
.trim({ background: { r: 0, g: 0, b: 0, alpha: 0 } })
.toBuffer();
@@ -12,10 +12,10 @@ export async function moduleIcons() {
(await readdir(`${DATA}/Gfx/UI/ModulesTechTree`))
.filter(
(file) =>
!file.endsWith('@2x.packed.webp.dvpl') && file.startsWith('vehicle'),
!file.endsWith('@2x.packed.webp') && file.startsWith('vehicle'),
)
.map(async (file) => {
const nameRaw = file.match(/vehicle(.+)\.packed\.webp\.dvpl/)![1];
const nameRaw = file.match(/vehicle(.+)\.packed\.webp/)![1];
const name = nameRaw[0].toLowerCase() + nameRaw.slice(1);
const content = await sharp(
await readDVPLFile(`${DATA}/Gfx/UI/ModulesTechTree/${file}`),
@@ -11,15 +11,15 @@ export async function shellIcons() {
const image = sharp(
await readDVPLFile(
`${DATA}/Gfx/Shared/tank-supply/ammunition/big/texture0.packed.webp.dvpl`,
`${DATA}/Gfx/Shared/tank-supply/ammunition/big/texture0.packed.webp`,
),
);
const changes = await Promise.all(
(await readdir(`${DATA}/Gfx/Shared/tank-supply/ammunition/big`))
.filter((file) => file.endsWith('_l.txt.dvpl'))
.filter((file) => file.endsWith('_l.txt'))
.map(async (file) => {
const name = file.match(/(.+)_l\.txt\.dvpl/)![1];
const name = file.match(/(.+)_l\.txt/)![1];
const sizes = (
await readStringDVPL(
`${DATA}/Gfx/Shared/tank-supply/ammunition/big/${file}`,
@@ -29,13 +29,13 @@ export async function skillIcons() {
console.log('Building skill icons...');
const avatar = await readXMLDVPL<{ root: Avatar }>(
`${DATA}/XML/item_defs/tankmen/avatar.xml.dvpl`,
`${DATA}/XML/item_defs/tankmen/avatar.xml`,
);
const changes = await Promise.all(
Object.values(avatar.root.skills).map(async (skill) => {
const icon = Array.isArray(skill.icon) ? skill.icon[0] : skill.icon;
const name = icon.name.split('/').at(-1)!.replace(/_\d$/, '');
const path = `${DATA}${icon.name.replace('~res:', '')}.packed.webp.dvpl`;
const path = `${DATA}${icon.name.replace('~res:', '')}.packed.webp`;
const image = sharp(await readDVPLFile(path)).trim();
const content = await image.toBuffer();
@@ -20,7 +20,7 @@ export async function tankArmors() {
await Promise.all(
nations.map(async (nation) => {
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`,
);
await Promise.all(
@@ -53,7 +53,7 @@ export async function tankIcons() {
await Promise.all(
nations.map(async (nation) => {
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`,
);
await Promise.all(
@@ -63,14 +63,14 @@ export async function tankIcons() {
const nationVehicleId = tank.id;
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`,
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
);
const smallPath = `${DATA}/${parameters.resourcesPath.smallIconPath
.replace(/~res:\//, '')
.replace(/\..+/, '')}.packed.webp.dvpl`;
.replace(/\..+/, '')}.packed.webp`;
const bigPath = `${DATA}/${parameters.resourcesPath.bigIconPath
.replace(/~res:\//, '')
.replace(/\..+/, '')}.packed.webp.dvpl`;
.replace(/\..+/, '')}.packed.webp`;
const big = await sharp(await readDVPLFile(bigPath))
.trim()
.toBuffer();
@@ -23,7 +23,7 @@ export async function tankModels() {
const nation = nations[nationIndex];
const changes: FileChange[] = [];
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`,
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`,
);
console.log(`Building models for ${nation}`);
@@ -35,7 +35,7 @@ export async function tankModels() {
const id = toUniqueId(nation, tank.id);
const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`,
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
);
const model = await extractModel(
DATA,