feat: equipment icons

This commit is contained in:
TrèsAbhi committed 2024-01-16 16:58:00 -06:00
1 parent a741cc305a
commit 5adc69977b
20 files changed
+428 -218

No files matched your search

+3 -3
View File
@@ -3,10 +3,10 @@ import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
export async function circleFlags() {
const flags = await readdir(`${DATA}/${DOI.flags}`);
const flags = await readdir(`${DATA}/${POI.flags}`);
commitMultipleFiles(
'tresabhi',
@@ -21,7 +21,7 @@ export async function circleFlags() {
!flag.endsWith('@2x.packed.webp.dvpl'),
)
.map(async (flag) => {
const content = await readBase64DVPL(`${DATA}/${DOI.flags}/${flag}`);
const content = await readBase64DVPL(`${DATA}/${POI.flags}/${flag}`);
const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1];
return {
+9 -1
View File
@@ -1,6 +1,7 @@
export const DATA =
'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data';
export const DOI = {
export const POI = {
vehicleDefinitions: 'XML/item_defs/vehicles',
strings: 'Strings',
tankParameters: '3d/Tanks/Parameters',
@@ -11,4 +12,11 @@ export const DOI = {
bigShellIcons: 'Gfx/Shared/tank-supply/ammunition/big',
moduleIcons: 'Gfx/UI/ModulesTechTree',
collisionMeshes: '3d/Tanks/CollisionMeshes',
optionalDevices: 'XML/item_defs/vehicles/common/optional_devices.xml',
optionalDeviceSlots:
'XML/item_defs/vehicles/common/optional_device_slots.xml',
optionalDeviceImageMappings:
'UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml',
optionalDevicesImage:
'Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp',
} as const;
+54 -8
View File
@@ -17,7 +17,7 @@ import {
TankDefinitions,
Tier,
} from '../../src/core/blitzkrieg/tankDefinitions';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
type BlitzTankType = 'AT-SPG' | 'lightTank' | 'mediumTank' | 'heavyTank';
interface Strings {
@@ -49,6 +49,7 @@ type VehicleDefinitionArmor = Record<
>;
interface VehicleDefinitions {
invisibility: { moving: number; still: number; firePenalty: number };
optDevicePreset: string;
hull: {
armor: VehicleDefinitionArmor;
turretPositions: { turret: string };
@@ -151,6 +152,42 @@ interface GunDefinitionsList {
};
}
export interface OptionalDevices {
[key: string]: {
id: number;
userString: string;
description: string;
icon: string;
script: unknown;
display_params: unknown;
};
}
interface OptionalDeviceSlots {
presets: {
[key: string]: {
level0: OptionalDeviceSlotRow;
level1: OptionalDeviceSlotRow;
level2: OptionalDeviceSlotRow;
};
};
}
interface OptionalDeviceSlotRow {
attack: {
device0: string;
device1: string;
};
defence: {
device0: string;
device1: string;
};
support: {
device0: string;
device1: string;
};
}
const blitzTankTypeToBlitzkrieg: Record<BlitzTankType, TankType> = {
'AT-SPG': 'tank_destroyer',
lightTank: 'light',
@@ -170,32 +207,38 @@ export async function buildDefinitions() {
const tankDefinitions: TankDefinitions = {};
const modelDefinitions: ModelDefinitions = {};
const nations = await readdir(`${DATA}/${DOI.vehicleDefinitions}`).then(
const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then(
(nations) => nations.filter((nation) => nation !== 'common'),
);
const strings = await readYAMLDVPL<Strings>(
`${DATA}/${DOI.strings}/${LANGUAGE}.yaml.dvpl`,
`${DATA}/${POI.strings}/${LANGUAGE}.yaml.dvpl`,
);
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
`${DATA}/${POI.optionalDevices}`,
);
const optionalDeviceSlots = await readXMLDVPL<{
root: OptionalDeviceSlots;
}>(`${DATA}/${POI.optionalDeviceSlots}`);
await Promise.all(
nations.map(async (nation) => {
const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
);
const turretList = await readXMLDVPL<{
root: TurretDefinitionsList;
}>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/components/turrets.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/components/turrets.xml.dvpl`,
);
const gunList = await readXMLDVPL<{
root: GunDefinitionsList;
}>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/components/guns.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/components/guns.xml.dvpl`,
);
const shellList = await readXMLDVPL<{
root: ShellDefinitionsList;
}>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/components/shells.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/components/shells.xml.dvpl`,
);
for (const tankKey in tankList.root) {
@@ -205,7 +248,7 @@ export async function buildDefinitions() {
? { type: 'credits', value: tank.price }
: { type: 'gold', value: tank.price['#text'] };
const tankDefinition = await readXMLDVPL<{ root: VehicleDefinitions }>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/${tankKey}.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/${tankKey}.xml.dvpl`,
);
const turretOrigin = tankDefinition.root.hull.turretPositions.turret
.split(' ')
@@ -215,6 +258,7 @@ export async function buildDefinitions() {
const hullArmor: ModelArmor = { thickness: {} };
const trackArmorRaw = Object.values(tankDefinition.root.chassis).at(-1)!
.armor.leftTrack;
const equipment = tankDefinition.root.optDevicePreset;
Object.keys(tankDefinition.root.hull.armor)
.filter((name) => name.startsWith('armor_'))
@@ -239,6 +283,7 @@ export async function buildDefinitions() {
tankDefinitions[tankId] = {
id: tankId,
equipment,
name:
(tank.shortUserString
? strings[tank.shortUserString]
@@ -492,6 +537,7 @@ export async function buildDefinitions() {
}),
);
return;
console.log('Committing definitions...');
await commitMultipleFiles(
'tresabhi',
+101
View File
@@ -0,0 +1,101 @@
import sharp from 'sharp';
import { readDVPLFile } from '../../src/core/blitz/readDVPLFile';
import { readStringDVPL } from '../../src/core/blitz/readStringDVPL';
import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL';
import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, POI } from './constants';
import { OptionalDevices } from './definitions';
interface Mappings {
Header: { version: number };
StyleSheets: {
selectors: string[];
properties: { 'bg-sprite': string };
}[];
}
export async function equipmentIcons() {
console.log('Building equipment icons...');
const changes: FileChange[] = [];
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
`${DATA}/${POI.optionalDevices}.dvpl`,
);
const mappings = await readYAMLDVPL<Mappings>(
`${DATA}/${POI.optionalDeviceImageMappings}.dvpl`,
);
const image = sharp(
await readDVPLFile(`${DATA}/${POI.optionalDevicesImage}.dvpl`),
);
await Promise.all(
Object.entries(optionalDevices.root).map(
async ([optionalDeviceKey, optionalDevice]) => {
if (optionalDeviceKey === 'nextAvailableId') return;
const mapping = mappings.StyleSheets.find((mapping) =>
mapping.selectors.includes(
`.optional_device_item.${optionalDevice.icon} #Img`,
),
);
if (!mapping) {
console.warn(
`No mapping found for ${optionalDevice.icon}; skipping...`,
);
return;
}
const configPathRaw = mapping.properties['bg-sprite'];
const configPath = configPathRaw.replace('~res:/', '');
if (configPath.startsWith('Gfx/Lobby')) {
const configPathWebp = configPath.replace('.txt', '');
const buffer = await readDVPLFile(
`${DATA}/${configPathWebp}.packed.webp.dvpl`,
);
changes.push({
path: `icons/equipment/${optionalDevice.id}.webp`,
encoding: 'base64',
content: buffer.toString('base64'),
});
} else {
const config = await readStringDVPL(`${DATA}/${configPath}.dvpl`);
const sizes = config.split('\n')[4].split(' ').map(Number);
const content = (
await image
.clone()
.extract({
left: sizes[0],
top: sizes[1],
width: sizes[2],
height: sizes[3],
})
.toBuffer()
).toString('base64');
changes.push({
path: `icons/equipment/${optionalDevice.id}.webp`,
encoding: 'base64',
content,
});
}
},
),
);
console.log('Committing equipment icons...');
commitMultipleFiles(
'tresabhi',
'blitzkrieg-assets',
'main',
'equipment icons',
changes,
true,
);
}
+5
View File
@@ -2,6 +2,7 @@ import { config } from 'dotenv';
import { argv } from 'process';
import { circleFlags } from './circleFlags';
import { buildDefinitions } from './definitions';
import { equipmentIcons } from './equipmentIcons';
import { buildModuleIcons } from './moduleIcons';
import { buildScratchedFlags } from './scratchedFlags';
import { buildShellIcons } from './shellIcons';
@@ -57,3 +58,7 @@ if (allTargets || targets?.includes('moduleIcons')) {
if (allTargets || targets?.includes('tankArmor')) {
await buildTankArmors();
}
if (allTargets || targets?.includes('equipmentIcons')) {
await equipmentIcons();
}
+3 -3
View File
@@ -3,13 +3,13 @@ import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
export async function buildModuleIcons() {
console.log('Building module icons...');
const changes = await Promise.all(
(await readdir(`${DATA}/${DOI.moduleIcons}`))
(await readdir(`${DATA}/${POI.moduleIcons}`))
.filter(
(file) =>
!file.endsWith('@2x.packed.webp.dvpl') && file.startsWith('vehicle'),
@@ -18,7 +18,7 @@ export async function buildModuleIcons() {
const nameRaw = file.match(/vehicle(.+)\.packed\.webp\.dvpl/)![1];
const name = nameRaw[0].toLowerCase() + nameRaw.slice(1);
const content = await readBase64DVPL(
`${DATA}/${DOI.moduleIcons}/${file}`,
`${DATA}/${POI.moduleIcons}/${file}`,
);
return {
+3 -3
View File
@@ -3,12 +3,12 @@ import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
export async function buildScratchedFlags() {
console.log('Building scratched flags...');
const flags = await readdir(`${DATA}/${DOI.flags}`);
const flags = await readdir(`${DATA}/${POI.flags}`);
console.log('Committing scratched flags...');
commitMultipleFiles(
@@ -24,7 +24,7 @@ export async function buildScratchedFlags() {
!flag.endsWith('@2x.packed.webp.dvpl'),
)
.map(async (flag) => {
const content = await readBase64DVPL(`${DATA}/${DOI.flags}/${flag}`);
const content = await readBase64DVPL(`${DATA}/${POI.flags}/${flag}`);
const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1];
return {
+4 -4
View File
@@ -5,24 +5,24 @@ import { readStringDVPL } from '../../src/core/blitz/readStringDVPL';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
export async function buildShellIcons() {
console.log('Building shell icons...');
const image = sharp(
await readDVPLFile(
`${DATA}/${DOI.bigShellIcons}/texture0.packed.webp.dvpl`,
`${DATA}/${POI.bigShellIcons}/texture0.packed.webp.dvpl`,
),
);
const changes = await Promise.all(
(await readdir(`${DATA}/${DOI.bigShellIcons}`))
(await readdir(`${DATA}/${POI.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}`)
await readStringDVPL(`${DATA}/${POI.bigShellIcons}/${file}`)
)
.split('\n')[4]
.split(' ')
+3 -3
View File
@@ -6,7 +6,7 @@ import { toUniqueId } from '../../src/core/blitz/toUniqueId';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
import { VehicleDefinitionList } from './definitions';
export async function buildTankArmors() {
@@ -14,14 +14,14 @@ export async function buildTankArmors() {
const changes: FileChange[] = [];
const nodeIO = new NodeIO();
const nations = await readdir(`${DATA}/${DOI.vehicleDefinitions}`).then(
const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then(
(nations) => nations.filter((nation) => nation !== 'common'),
);
await Promise.all(
nations.map(async (nation) => {
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
);
await Promise.all(
+4 -4
View File
@@ -6,7 +6,7 @@ import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
import { VehicleDefinitionList } from './definitions';
export interface TankParameters {
@@ -21,14 +21,14 @@ export async function buildTankIcons(big?: boolean, small?: boolean) {
console.log('Building tank icons...');
const changes: FileChange[] = [];
const nations = await readdir(`${DATA}/${DOI.vehicleDefinitions}`).then(
const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then(
(nations) => nations.filter((nation) => nation !== 'common'),
);
await Promise.all(
nations.map(async (nation) => {
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
);
for (const tankIndex in tanks.root) {
@@ -36,7 +36,7 @@ export async function buildTankIcons(big?: boolean, small?: boolean) {
const nationVehicleId = tank.id;
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/${DOI.tankParameters}/${nation}/${tankIndex}.yaml.dvpl`,
`${DATA}/${POI.tankParameters}/${nation}/${tankIndex}.yaml.dvpl`,
);
const small = `${DATA}/${parameters.resourcesPath.smallIconPath
.replace(/~res:\//, '')
+5 -5
View File
@@ -8,7 +8,7 @@ import { toUniqueId } from '../../src/core/blitz/toUniqueId';
import commitMultipleFiles, {
FileChange,
} from '../../src/core/blitzkrieg/commitMultipleFiles';
import { DATA, DOI } from './constants';
import { DATA, POI } from './constants';
import { VehicleDefinitionList } from './definitions';
import { TankParameters } from './tankIcons';
@@ -21,17 +21,17 @@ export async function buildTankModels() {
const changes: FileChange[] = [];
const nodeIO = new NodeIO();
const nations = await readdir(`${DATA}/${DOI.vehicleDefinitions}`).then(
const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then(
(nations) => nations.filter((nation) => nation !== 'common'),
);
await Promise.all(
nations.map(async (nation) => {
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`,
);
const customization = await readXMLDVPL<{ root: VehicleCustomization }>(
`${DATA}/${DOI.vehicleDefinitions}/${nation}/customization.xml.dvpl`,
`${DATA}/${POI.vehicleDefinitions}/${nation}/customization.xml.dvpl`,
);
const baseColor = customization.root.armorColor
.split(' ')
@@ -48,7 +48,7 @@ export async function buildTankModels() {
console.log(`Building model ${id} @ ${nation}/${tankKey}`);
const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/${DOI.tankParameters}/${nation}/${tankKey}.yaml.dvpl`,
`${DATA}/${POI.tankParameters}/${nation}/${tankKey}.yaml.dvpl`,
);
const model = await extractModel(
DATA,