mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: equipment icons
This commit is contained in:
1 parent
a741cc305a
commit
5adc69977b
20 files changed
+428
-218
No files matched your search
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
@@ -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,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,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 {
|
||||
|
||||
@@ -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(' ')
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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:\//, '')
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user