feat: update all

This commit is contained in:
TrèsAbhi committed 2025-11-26 13:18:44 -06:00
1 parent 3efe807e35
commit a0bccc7973
21 files changed
+160 -306

No files matched your search

+7 -9
View File
@@ -4,12 +4,10 @@ import { mkdir, writeFile } from "fs/promises";
import { parse as parsePath } from "path";
import ProgressBar from "progress";
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
import { readStringDVPL } from "../src/core/blitz/readStringDVPL";
import { DATA } from "./buildAssets/constants";
import { readYAMLDVPL } from "./core/blitz/readYAMLDVPL";
import { vfs } from "./buildAssets/constants";
import { writeDVPL } from "./core/blitz/writeDVPL";
const versionTextFile = await readStringDVPL(`${DATA}/version.txt`);
const versionTextFile = await vfs.text(`Data/version.txt`);
const currentVersion = versionTextFile
.split(" ")[0]
.split(".")
@@ -51,7 +49,7 @@ while (true) {
const { dir } = parsePath(path);
try {
await mkdir(`${DATA}/${dir}`, { recursive: true });
await mkdir(`Data/${dir}`, { recursive: true });
} catch (error) {
console.warn(`Failed to make directory "${dir}"`);
}
@@ -60,7 +58,7 @@ while (true) {
const buffer = Buffer.from(data);
await writeFile(
`${DATA}/${path}${isDvpl ? "" : ".dvpl"}`,
`Data/${path}${isDvpl ? "" : ".dvpl"}`,
new Uint8Array(isDvpl ? buffer : writeDVPL(buffer))
);
@@ -76,14 +74,14 @@ while (true) {
}/en.yaml`
);
const newStrings = parseYaml(await localizationsResponse.text());
const oldStrings = await readYAMLDVPL<Record<string, string>>(
`${DATA}/Strings/en.yaml`
const oldStrings = await vfs.yaml<Record<string, string>>(
`Data/Strings/en.yaml`
);
const patchedStrings = { ...oldStrings, ...newStrings };
const patchedContent = stringifyYaml(patchedStrings);
await writeFile(
`${DATA}/Strings/en.yaml`,
`Data/Strings/en.yaml`,
new Uint8Array(writeDVPL(Buffer.from(patchedContent)))
);
}
@@ -1,19 +1,16 @@
import { readdir } from "fs/promises";
import sharp from "sharp";
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { readStringDVPL } from "../../src/core/blitz/readStringDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
export async function boosterIcons() {
console.log("Building booster icons...");
using uploader = new AssetUploader("booster icons");
const boosterFiles = (await readdir(`${DATA}/Gfx/Shared/boosters`)).filter(
const boosterFiles = (vfs.dir(`Data/Gfx/Shared/boosters`)).filter(
(file) => !file.includes("@2x.txt") && !file.startsWith("texture0")
);
const image = sharp(
await readDVPLFile(`${DATA}/Gfx/Shared/boosters/texture0.packed.webp`)
await vfs.file(`Data/Gfx/Shared/boosters/texture0.packed.webp`)
);
for (const file of boosterFiles) {
@@ -21,7 +18,7 @@ export async function boosterIcons() {
if (name === undefined) continue;
const sizes = (await readStringDVPL(`${DATA}/Gfx/Shared/boosters/${file}`))
const sizes = (await vfs.text(`Data/Gfx/Shared/boosters/${file}`))
.split("\n")[4]
.split(" ")
.map(Number);
@@ -1,13 +1,12 @@
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
export async function camouflageIcons() {
console.log("Building camouflage icons...");
using uploader = new AssetUploader("camo icons");
const content = await readDVPLFile(
`${DATA}/Gfx/UI/Hangar/IconCamouflage.packed.webp`
const content = await vfs.file(
`Data/Gfx/UI/Hangar/IconCamouflage.packed.webp`
);
await uploader.add({ content, path: "icons/camo.webp" });
@@ -1,11 +1,6 @@
import { existsSync } from "fs";
import sharp from "sharp";
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { readStringDVPL } from "../../src/core/blitz/readStringDVPL";
import { readXMLDVPL } from "../core/blitz/readXMLDVPL";
import { readYAMLDVPL } from "../core/blitz/readYAMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
import { ConsumablesCommon, ProvisionsCommon } from "./definitions";
interface Mappings {
@@ -33,20 +28,20 @@ export async function consumableProvisionIcons() {
styles.map(async (path) =>
Object.values(
(
await readYAMLDVPL<Mappings>(`${DATA}/${path}`)
await vfs.yaml<Mappings>(`Data/${path}`)
).StyleSheets
)
)
).then((array) => array.flat());
for (const match of (
await readStringDVPL(
`${DATA}/XML/item_defs/vehicles/common/consumables/list.xml`
await vfs.text(
`Data/XML/item_defs/vehicles/common/consumables/list.xml`
)
).matchAll(listItemsPattern)) {
const consumablesCommon = await readXMLDVPL<{
const consumablesCommon = await vfs.xml<{
root: ConsumablesCommon;
}>(`${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml`);
}>(`Data/XML/item_defs/vehicles/common/consumables/${match[1]}.xml`);
for (const consumable of Object.values(consumablesCommon.root)) {
const styleSheet = styleSheets.find((styleSheet) =>
@@ -67,9 +62,9 @@ export async function consumableProvisionIcons() {
.replace(".psd", "")
.replace(".txt", "");
if (existsSync(`${DATA}/${configPath}.packed.webp`)) {
if (vfs.has(`Data/${configPath}.packed.webp`)) {
const image = sharp(
await readDVPLFile(`${DATA}/${configPath}.packed.webp`)
await vfs.file(`Data/${configPath}.packed.webp`)
);
const content = await image.trim({ threshold: 100 }).toBuffer();
@@ -79,14 +74,14 @@ export async function consumableProvisionIcons() {
});
} else {
const consumablesTexture = sharp(
await readDVPLFile(
`${`${DATA}/${configPath}`
await vfs.file(
`${`Data/${configPath}`
.split("/")
.slice(0, -1)
.join("/")}/texture0.packed.webp`
)
);
const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt`))
const sizes = (await vfs.text(`Data/${configPath}.txt`))
.split("\n")[4]
.split(" ")
.map(Number);
@@ -109,13 +104,13 @@ export async function consumableProvisionIcons() {
}
for (const match of (
await readStringDVPL(
`${DATA}/XML/item_defs/vehicles/common/provisions/list.xml`
await vfs.text(
`Data/XML/item_defs/vehicles/common/provisions/list.xml`
)
).matchAll(listItemsPattern)) {
const provisionsCommon = await readXMLDVPL<{
const provisionsCommon = await vfs.xml<{
root: ProvisionsCommon;
}>(`${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml`);
}>(`Data/XML/item_defs/vehicles/common/provisions/${match[1]}.xml`);
for (const provision of Object.values(provisionsCommon.root)) {
const styleSheet = styleSheets.find((styleSheet) =>
@@ -136,9 +131,9 @@ export async function consumableProvisionIcons() {
.replace(".psd", "")
.replace(".txt", "");
if (existsSync(`${DATA}/${configPath}.packed.webp`)) {
if (vfs.has(`Data/${configPath}.packed.webp`)) {
const image = sharp(
await readDVPLFile(`${DATA}/${configPath}.packed.webp`)
await vfs.file(`Data/${configPath}.packed.webp`)
);
const content = await image.trim({ threshold: 100 }).toBuffer();
@@ -148,14 +143,14 @@ export async function consumableProvisionIcons() {
});
} else {
const provisionsTexture = sharp(
await readDVPLFile(
`${`${DATA}/${configPath}`
await vfs.file(
`${`Data/${configPath}`
.split("/")
.slice(0, -1)
.join("/")}/texture0.packed.webp`
)
);
const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt`))
const sizes = (await vfs.text(`Data/${configPath}.txt`))
.split("\n")[4]
.split(" ")
.map(Number);
@@ -1,8 +1,7 @@
import { assertSecret, BlitzGlossary } from "@blitzkit/core";
import sharp from "sharp";
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
const ICONS = [
["currency_silver_m.packed.webp", "silver"],
@@ -21,7 +20,7 @@ export async function currencies() {
for (const [file, name] of ICONS) {
const content = await sharp(
await readDVPLFile(`${DATA}/Gfx/Lobby/currency/${file}`)
await vfs.file(`Data/Gfx/Lobby/currency/${file}`)
)
.trim()
.toBuffer();
@@ -1,10 +1,6 @@
import sharp from "sharp";
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { readStringDVPL } from "../../src/core/blitz/readStringDVPL";
import { readXMLDVPL } from "../core/blitz/readXMLDVPL";
import { readYAMLDVPL } from "../core/blitz/readYAMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
import { OptionalDevices } from "./definitions";
interface Mappings {
@@ -20,15 +16,15 @@ export async function equipmentIcons() {
console.log("Building equipment icons...");
using uploader = new AssetUploader("equipment icons");
const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>(
`${DATA}/XML/item_defs/vehicles/common/optional_devices.xml`
const optionalDevices = await vfs.xml<{ root: OptionalDevices }>(
`Data/XML/item_defs/vehicles/common/optional_devices.xml`
);
const mappings = await readYAMLDVPL<Mappings>(
`${DATA}/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml`
const mappings = await vfs.yaml<Mappings>(
`Data/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml`
);
const image = sharp(
await readDVPLFile(
`${DATA}/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp`
await vfs.file(
`Data/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp`
)
);
@@ -54,7 +50,7 @@ export async function equipmentIcons() {
if (configPath.startsWith("Gfx/Lobby")) {
const configPathWebp = configPath.replace(".txt", "");
const image = sharp(
await readDVPLFile(`${DATA}/${configPathWebp}.packed.webp`)
await vfs.file(`Data/${configPathWebp}.packed.webp`)
);
const content = await image.trim().toBuffer();
@@ -63,7 +59,7 @@ export async function equipmentIcons() {
content,
});
} else {
const config = await readStringDVPL(`${DATA}/${configPath}`);
const config = await vfs.text(`Data/${configPath}`);
const sizes = config.split("\n")[4].split(" ").map(Number);
const content = await image
.clone()
+8 -17
View File
@@ -1,37 +1,28 @@
import { readdir } from "fs/promises";
import sharp from "sharp";
import { readDVPLFile } from "../core/blitz/readDVPLFile";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
export async function flags() {
console.log("Building flags...");
using uploader = new AssetUploader("flags");
const circleFiles = await readdir(`${DATA}/Gfx/Lobby/flags`).then((files) =>
files.filter(
const circleFiles = vfs.dir(`Data/Gfx/Lobby/flags`).filter(
(flag) =>
flag.startsWith("flag_profile-stat_") &&
!flag.endsWith("@2x.packed.webp")
)
);
const scratchedFiles = await readdir(`${DATA}/Gfx/Lobby/flags`).then(
(files) =>
files.filter(
);
const scratchedFiles = vfs.dir(`Data/Gfx/Lobby/flags`).filter(
(flag) =>
flag.startsWith("flag_tutor-tank_") &&
!flag.endsWith("@2x.packed.webp")
)
);
const fadedFiles = await readdir(`${DATA}/Gfx/Lobby/flags`).then((files) =>
files.filter(
const fadedFiles = vfs.dir(`Data/Gfx/Lobby/flags`).filter(
(flag) =>
flag.startsWith("flag_filter_") && flag.endsWith("@2x.packed.webp")
)
);
for (const flag of circleFiles) {
const image = sharp(await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`));
const image = sharp(await vfs.file(`Data/Gfx/Lobby/flags/${flag}`));
const content = await image.trim({ threshold: 100 }).toBuffer();
const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1];
@@ -42,7 +33,7 @@ export async function flags() {
}
for (const flag of scratchedFiles) {
const content = await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`);
const content = await vfs.file(`Data/Gfx/Lobby/flags/${flag}`);
const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1];
uploader.add({
@@ -53,7 +44,7 @@ export async function flags() {
for (const flag of fadedFiles) {
const content = await sharp(
await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`)
await vfs.file(`Data/Gfx/Lobby/flags/${flag}`)
)
.trim({
threshold: 100,
@@ -1,19 +1,17 @@
import sharp from "sharp";
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { readYAMLDVPL } from "../core/blitz/readYAMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
import { SquadBattleTypeStyles } from "./definitions";
export async function gameModeBanners() {
console.log("Building game mode banners...");
using uploader = new AssetUploader("game mode banners");
const gameTypeSelectorStyles = await readYAMLDVPL<SquadBattleTypeStyles>(
`${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml`
const gameTypeSelectorStyles = await vfs.yaml<SquadBattleTypeStyles>(
`Data/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml`
);
const squadBattleTypeStyles = await readYAMLDVPL<SquadBattleTypeStyles>(
`${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml`
const squadBattleTypeStyles = await vfs.yaml<SquadBattleTypeStyles>(
`Data/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml`
);
const bannerMatches: { name: string; path: string }[] = [];
@@ -37,7 +35,7 @@ export async function gameModeBanners() {
}
const content = await sharp(
await readDVPLFile(`${DATA}${path}.packed.webp`)
await vfs.file(`Data${path}.packed.webp`)
)
.trim({ background: { r: 0, g: 0, b: 0, alpha: 0 } })
.toBuffer();
@@ -1,8 +1,6 @@
import { toUniqueId } from "@blitzkit/core";
import { readdir } from "fs/promises";
import { readXMLDVPL } from "../core/blitz/readXMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
import { VehicleDefinitionList } from "./definitions";
export async function migration() {
@@ -10,13 +8,11 @@ export async function migration() {
using uploader = new AssetUploader("migration map");
const map: Record<string, number> = {};
const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then(
(nations) => nations.filter((nation) => nation !== "common")
);
const nations = vfs.dir(`Data/XML/item_defs/vehicles`).filter((nation) => nation !== "common");
for (const nation of nations) {
const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`
const tankList = await vfs.xml<{ root: VehicleDefinitionList }>(
`Data/XML/item_defs/vehicles/${nation}/list.xml`
);
for (const tankKey in tankList.root) {
@@ -1,24 +1,20 @@
import { readdir } from "fs/promises";
import sharp from "sharp";
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
export async function moduleIcons() {
console.log("Building module icons...");
using uploader = new AssetUploader("module icons");
const files = await readdir(`${DATA}/Gfx/UI/ModulesTechTree`).then((dir) =>
dir.filter(
const files = vfs.dir(`Data/Gfx/UI/ModulesTechTree`).filter(
(file) => !file.endsWith("@2x.packed.webp") && file.startsWith("vehicle")
)
);
for (const file of files) {
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}`)
await vfs.file(`Data/Gfx/UI/ModulesTechTree/${file}`)
)
.trim()
.toBuffer();
+8 -11
View File
@@ -1,28 +1,25 @@
import { readdir } from "fs/promises";
import sharp from "sharp";
import { readDVPLFile } from "../../src/core/blitz/readDVPLFile";
import { readStringDVPL } from "../../src/core/blitz/readStringDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
export async function shellIcons() {
console.log("Building shell icons...");
using uploader = new AssetUploader("shell icons");
const image = sharp(
await readDVPLFile(
`${DATA}/Gfx/Shared/tank-supply/ammunition/big/texture0.packed.webp`
await vfs.file(
`Data/Gfx/Shared/tank-supply/ammunition/big/texture0.packed.webp`
)
);
const files = await readdir(
`${DATA}/Gfx/Shared/tank-supply/ammunition/big`
).then((files) => files.filter((file) => file.endsWith("_l.txt")));
const files = vfs.dir(
`Data/Gfx/Shared/tank-supply/ammunition/big`
).filter((file) => file.endsWith("_l.txt"))
for (const file of files) {
const name = file.match(/(.+)_l\.txt/)![1];
const sizes = (
await readStringDVPL(
`${DATA}/Gfx/Shared/tank-supply/ammunition/big/${file}`
await vfs.text(
`Data/Gfx/Shared/tank-supply/ammunition/big/${file}`
)
)
.split("\n")[4]
@@ -1,9 +1,7 @@
import { TankClass } from "@blitzkit/core";
import sharp from "sharp";
import { readDVPLFile } from "../core/blitz/readDVPLFile";
import { readXMLDVPL } from "../core/blitz/readXMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
interface SkillIcon {
name: string;
@@ -27,8 +25,8 @@ export interface Avatar {
export async function skillIcons() {
console.log("Building skill icons...");
const avatar = await readXMLDVPL<{ root: Avatar }>(
`${DATA}/XML/item_defs/tankmen/avatar.xml`
const avatar = await vfs.xml<{ root: Avatar }>(
`Data/XML/item_defs/tankmen/avatar.xml`
);
using uploader = new AssetUploader("skill icons");
@@ -36,8 +34,8 @@ export async function skillIcons() {
const skill = avatar.root.skills[key];
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`;
const image = sharp(await readDVPLFile(path)).trim();
const path = `Data${icon.name.replace("~res:", "")}.packed.webp`;
const image = sharp(await vfs.file(path)).trim();
const content = await image.toBuffer();
await uploader.add({ content, path: `icons/skills/${name}.webp` });
@@ -1,10 +1,8 @@
import { toUniqueId } from "@blitzkit/core";
import { NodeIO } from "@gltf-transform/core";
import { readdir } from "fs/promises";
import { extractArmor } from "../core/blitz/extractArmor";
import { readXMLDVPL } from "../core/blitz/readXMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
import { VehicleDefinitionList } from "./definitions";
export async function tankArmors() {
@@ -12,13 +10,11 @@ export async function tankArmors() {
using uploader = new AssetUploader("tank armors");
const nodeIO = new NodeIO();
const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then(
(nations) => nations.filter((nation) => nation !== "common")
);
const nations = vfs.dir(`Data/XML/item_defs/vehicles`).filter((nation) => nation !== "common");
for (const nation of nations) {
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
`Data/XML/item_defs/vehicles/${nation}/list.xml`
);
for (const tankKey in tanks.root) {
@@ -27,7 +23,7 @@ export async function tankArmors() {
if (tankKey.includes("tutorial_bot")) continue;
const id = toUniqueId(nation, tank.id);
const model = await extractArmor(DATA, `${nation}-${tankKey}`);
const model = await extractArmor(vfs, `${nation}-${tankKey}`);
const content = await nodeIO.writeBinary(model);
await uploader.add({ path: `3d/tanks/armor/${id}.glb`, content });
+10 -16
View File
@@ -1,12 +1,8 @@
import { NATION_IDS } from "@blitzkit/core";
import { readdir } from "fs/promises";
import sharp from "sharp";
import type { Vector3Tuple } from "three";
import { readDVPLFile } from "../core/blitz/readDVPLFile";
import { readXMLDVPL } from "../core/blitz/readXMLDVPL";
import { readYAMLDVPL } from "../core/blitz/readYAMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
import type { VehicleDefinitionList } from "./definitions";
export interface TankParameters {
@@ -45,13 +41,11 @@ export async function tankIcons() {
console.log("Building tank icons...");
using uploader = new AssetUploader("tank icons");
const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then(
(nations) => nations.filter((nation) => nation !== "common")
);
const nations = vfs.dir(`Data/XML/item_defs/vehicles`).filter((nation) => nation !== "common")
for (const nation of nations) {
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
`Data/XML/item_defs/vehicles/${nation}/list.xml`
);
for (const tankKey in tanks.root) {
@@ -62,19 +56,19 @@ 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`
const parameters = await vfs.yaml<TankParameters>(
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
);
const smallPath = `${DATA}/${parameters.resourcesPath.smallIconPath
const smallPath = `Data/${parameters.resourcesPath.smallIconPath
.replace(/~res:\//, "")
.replace(/\..+/, "")}.packed.webp`;
const bigPath = `${DATA}/${parameters.resourcesPath.bigIconPath
const bigPath = `Data/${parameters.resourcesPath.bigIconPath
.replace(/~res:\//, "")
.replace(/\..+/, "")}.packed.webp`;
const big = await sharp(await readDVPLFile(bigPath))
const big = await sharp(await vfs.file(bigPath))
.trim()
.toBuffer();
const small = await sharp(await readDVPLFile(smallPath))
const small = await sharp(await vfs.file(smallPath))
.trim()
.toBuffer();
+7 -12
View File
@@ -1,12 +1,9 @@
import { toUniqueId } from "@blitzkit/core";
import { NodeIO } from "@gltf-transform/core";
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
import { readdir } from "fs/promises";
import { extractModel } from "../core/blitz/extractModel";
import { readXMLDVPL } from "../core/blitz/readXMLDVPL";
import { readYAMLDVPL } from "../core/blitz/readYAMLDVPL";
import { AssetUploader } from "../core/github/assetUploader";
import { DATA } from "./constants";
import { vfs } from "./constants";
import { VehicleDefinitionList } from "./definitions";
import { TankParameters } from "./tankIcons";
@@ -15,14 +12,12 @@ export async function tankModels() {
using uploader = new AssetUploader("tank models");
const nodeIO = new NodeIO().registerExtensions(ALL_EXTENSIONS);
const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then(
(nations) => nations.filter((nation) => nation !== "common")
);
const nations = vfs.dir(`Data/XML/item_defs/vehicles`).filter((nation) => nation !== "common")
for (const nationIndex in nations) {
const nation = nations[nationIndex];
const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>(
`${DATA}/XML/item_defs/vehicles/${nation}/list.xml`
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
`Data/XML/item_defs/vehicles/${nation}/list.xml`
);
const entries = Object.entries(tanks.root);
@@ -30,11 +25,11 @@ export async function tankModels() {
if (tankKey.includes("tutorial_bot")) continue;
const id = toUniqueId(nation, tank.id);
const parameters = await readYAMLDVPL<TankParameters>(
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
const parameters = await vfs.yaml<TankParameters>(
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
);
const model = await extractModel(
DATA,
vfs,
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, "")
);
const content = Buffer.from(await nodeIO.writeBinary(model));
+29 -29
View File
@@ -2,24 +2,24 @@ import {
Hierarchy,
Sc2ReadStream,
ScgReadStream,
SteamVFS,
VertexAttribute,
} from '@blitzkit/core';
import { Accessor, Document, Node, Scene } from '@gltf-transform/core';
import { times } from 'lodash-es';
} from "@blitzkit/core";
import { Accessor, Document, Node, Scene } from "@gltf-transform/core";
import { times } from "lodash-es";
import {
vertexAttributeGLTFName,
vertexAttributeGltfVectorSizes,
} from './extractModel/constants';
import { readDVPLFile } from './readDVPLFile';
} from "./extractModel/constants";
export async function extractArmor(data: string, fileName: string) {
const sc2Path = `${data}/3d/Tanks/CollisionMeshes/${fileName}.sc2`;
const scgPath = `${data}/3d/Tanks/CollisionMeshes/${fileName}.scg`;
export async function extractArmor(vfs: SteamVFS, fileName: string) {
const sc2Path = `Data/3d/Tanks/CollisionMeshes/${fileName}.sc2`;
const scgPath = `Data/3d/Tanks/CollisionMeshes/${fileName}.scg`;
const sc2 = new Sc2ReadStream(
(await readDVPLFile(sc2Path)).buffer as ArrayBuffer,
(await vfs.file(sc2Path)).buffer as ArrayBuffer
).sc2();
const scg = new ScgReadStream(
(await readDVPLFile(scgPath)).buffer as ArrayBuffer,
(await vfs.file(scgPath)).buffer as ArrayBuffer
).scg();
const document = new Document();
const scene = document.createScene();
@@ -29,21 +29,21 @@ export async function extractArmor(data: string, fileName: string) {
hierarchies.forEach((hierarchy) => {
const components = times(
hierarchy.components.count,
(index) => hierarchy.components[index.toString().padStart(4, '0')],
(index) => hierarchy.components[index.toString().padStart(4, "0")]
);
components.forEach((component) => {
switch (component['comp.typename']) {
case 'TransformComponent':
switch (component["comp.typename"]) {
case "TransformComponent":
break;
case 'RenderComponent': {
const batch = component['rc.renderObj']['ro.batches']['0000'];
const polygonGroup = scg.get(batch['rb.datasource']);
case "RenderComponent": {
const batch = component["rc.renderObj"]["ro.batches"]["0000"];
const polygonGroup = scg.get(batch["rb.datasource"]);
if (!polygonGroup) {
console.warn(
`Missing polygon group ${batch['rb.datasource']} (${hierarchy.name}); skipping...`,
`Missing polygon group ${batch["rb.datasource"]} (${hierarchy.name}); skipping...`
);
break;
@@ -73,7 +73,7 @@ export async function extractArmor(data: string, fileName: string) {
VertexAttribute.TANGENT,
attributes
.get(VertexAttribute.TANGENT)!
.map((tangent) => [...tangent, 1]),
.map((tangent) => [...tangent, 1])
);
}
@@ -85,7 +85,7 @@ export async function extractArmor(data: string, fileName: string) {
const vertexSize = vertexAttributeGltfVectorSizes[attribute];
const accessor = document
.createAccessor(name)
.setType(vertexSize === 1 ? 'SCALAR' : `VEC${vertexSize}`)
.setType(vertexSize === 1 ? "SCALAR" : `VEC${vertexSize}`)
.setArray(new Float32Array(value.flat()))
.setBuffer(buffer);
@@ -94,19 +94,19 @@ export async function extractArmor(data: string, fileName: string) {
hardJointIndices.forEach((hardJointIndex) => {
const node = document.createNode(
`${hierarchy.name}_armor_${hardJointIndex}`,
`${hierarchy.name}_armor_${hardJointIndex}`
);
const mesh = document.createMesh(batch['##name']);
const mesh = document.createMesh(batch["##name"]);
const indicesAccessor = document
.createAccessor()
.setType('SCALAR')
.setType("SCALAR")
.setArray(
new Uint16Array(
polygonGroup.indices.filter(
(index) =>
vertexHardJointIndices.get(index) === hardJointIndex,
),
),
vertexHardJointIndices.get(index) === hardJointIndex
)
)
)
.setBuffer(buffer);
const primitive = document
@@ -127,18 +127,18 @@ export async function extractArmor(data: string, fileName: string) {
default:
throw new TypeError(
`Unhandled component type: ${component['comp.typename']}`,
`Unhandled component type: ${component["comp.typename"]}`
);
}
});
if (hierarchy['#hierarchy']) {
parseHierarchies(hierarchy['#hierarchy'], parent);
if (hierarchy["#hierarchy"]) {
parseHierarchies(hierarchy["#hierarchy"], parent);
}
});
}
parseHierarchies(sc2['#hierarchy'], scene);
parseHierarchies(sc2["#hierarchy"], scene);
return document;
}
@@ -2,6 +2,7 @@ import {
Hierarchy,
Sc2ReadStream,
ScgReadStream,
SteamVFS,
Textures,
VertexAttribute,
} from "@blitzkit/core";
@@ -10,7 +11,6 @@ import { dedup, prune } from "@gltf-transform/functions";
import { times } from "lodash-es";
import { dirname } from "path";
import { readBaseColor } from "../readBaseColor";
import { readDVPLFile } from "../readDVPLFile";
import { readNormal } from "../readNormal";
import { readRoughnessMetallic } from "../readRoughnessMetallic";
import {
@@ -25,14 +25,14 @@ const omitMeshNames = {
end: ["_POINT"],
};
export async function extractModel(data: string, path: string) {
const sc2Path = `${data}/3d/${path}.sc2`;
const scgPath = `${data}/3d/${path}.scg`;
export async function extractModel(vfs: SteamVFS, path: string) {
const sc2Path = `Data/3d/${path}.sc2`;
const scgPath = `Data/3d/${path}.scg`;
const sc2 = new Sc2ReadStream(
(await readDVPLFile(sc2Path)).buffer as ArrayBuffer
(await vfs.file(sc2Path)).buffer as ArrayBuffer
).sc2();
const scg = new ScgReadStream(
(await readDVPLFile(scgPath)).buffer as ArrayBuffer
(await vfs.file(scgPath)).buffer as ArrayBuffer
).scg();
const document = new Document();
const scene = document.createScene();
@@ -67,11 +67,11 @@ export async function extractModel(data: string, path: string) {
.setMimeType("image/webp")
.setImage(
await readBaseColor(
`${data}/3d/${dirname(path)}/${
`Data/3d/${dirname(path)}/${
textures.baseColorMap ?? textures.albedo
}`,
textures.miscMap
? `${data}/3d/${dirname(path)}/${textures.miscMap}`
? `Data/3d/${dirname(path)}/${textures.miscMap}`
: undefined
)
)
@@ -103,7 +103,7 @@ export async function extractModel(data: string, path: string) {
.setMimeType("image/webp")
.setImage(
await readRoughnessMetallic(
`${data}/3d/${dirname(path)}/${textures.baseRMMap}`
`Data/3d/${dirname(path)}/${textures.baseRMMap}`
)
)
);
@@ -118,7 +118,7 @@ export async function extractModel(data: string, path: string) {
.setMimeType("image/webp")
.setImage(
await readNormal(
`${data}/3d/${dirname(path)}/${
`Data/3d/${dirname(path)}/${
textures.baseNormalMap ?? textures.normalmap
}`,
isBase
@@ -1,6 +0,0 @@
import { readDVPLFile } from './readDVPLFile';
export async function readBase64DVPL(file: string) {
const buffer = await readDVPLFile(file);
return buffer.toString('base64');
}
@@ -1,21 +0,0 @@
import { readFile } from 'fs/promises';
import { DATA_COMPRESSED } from '../../buildAssets/constants';
import { readDVPL } from './readDVPL';
export async function readDVPLFile(file: string) {
let path: string;
if (DATA_COMPRESSED) {
path = file.endsWith('.dvpl') ? file : `${file}.dvpl`;
} else {
path = file.replace('.dvpl', '');
}
const content = await readFile(path);
if (!DATA_COMPRESSED) return content;
const dvpl = readDVPL(content);
return dvpl;
}
@@ -1,81 +1,17 @@
import { DdsReadStream, PvrReadStream } from "@blitzkit/core";
import { existsSync } from "fs";
import { DATA_COMPRESSED } from "../../../buildAssets/constants";
import { readDVPLFile } from "../readDVPLFile";
import { vfs } from "../../../buildAssets/constants";
export async function readTexture(path: string) {
const ddsTexturePath = path.replace(".tex", ".dx11.dds");
const isDds = existsSync(
`${ddsTexturePath}${DATA_COMPRESSED ? ".dvpl" : ""}`
);
const isDds = vfs.has(ddsTexturePath);
const resolvedTexturePath = isDds
? ddsTexturePath
: ddsTexturePath.replace(".dds", ".pvr");
const decompressedDvpl = await readDVPLFile(`${resolvedTexturePath}.dvpl`);
const decompressedDvpl = await vfs.file(`${resolvedTexturePath}.dvpl`);
const raw = isDds
? await new DdsReadStream(decompressedDvpl.buffer as ArrayBuffer).dds()
: new PvrReadStream(decompressedDvpl.buffer as ArrayBuffer).pvr();
return raw;
// switch (mutation) {
// case TextureMutation.Normal: {
// const bytes = 4 * raw.width * raw.height;
// for (let index = 0; index < bytes; index += 4) {
// /**
// * Red is always 255 and blue is always 0. Only alpha and green contain any
// * sort of information.
// */
// let x = raw.data[index + 3] * (2 / 255) - 1;
// let y = raw.data[index + 1] * (2 / 255) - 1;
// const underSqrt = 1 - x ** 2 - y ** 2;
// let z = underSqrt > 0 ? Math.sqrt(underSqrt) : -Math.sqrt(-underSqrt);
// raw.data[index] = Math.round((x + 1) * (255 / 2));
// raw.data[index + 1] = Math.round((y + 1) * (255 / 2));
// raw.data[index + 2] = Math.round((z + 1) * (255 / 2));
// raw.data[index + 3] = 255;
// }
// return await sharp(raw.data, { raw }).jpeg().toBuffer();
// }
// case TextureMutation.RoughnessMetallicness: {
// const newImage = sharp(Buffer.alloc(raw.width * raw.height), {
// raw: { ...raw, channels: 1 },
// });
// const metallicness = sharp(raw.data, { raw })
// .extractChannel("green")
// .jpeg()
// .toBuffer();
// const roughness = sharp(raw.data, { raw })
// .extractChannel("alpha")
// .jpeg()
// .toBuffer();
// return await newImage
// .joinChannel(await Promise.all([roughness, metallicness]))
// .jpeg()
// .toBuffer();
// }
// case TextureMutation.Miscellaneous: {
// /**
// * Alpha is ambient occlusion and green is emissive. But very few tanks
// * use emissive so I am ignoring it for now.
// */
// return await sharp(raw.data, { raw })
// .extractChannel("alpha")
// .jpeg()
// .toBuffer();
// }
// case TextureMutation.Albedo: {
// return await sharp(raw.data, { raw }).removeAlpha().jpeg().toBuffer();
// }
// default:
// return await sharp(raw.data, { raw }).jpeg().toBuffer();
// }
}
+17 -17
View File
@@ -1,39 +1,39 @@
import decompress from 'decompress';
import { existsSync } from 'fs';
import { mkdir, readdir, writeFile } from 'fs/promises';
import decompress from "decompress";
import { existsSync } from "fs";
import { mkdir, readdir, writeFile } from "fs/promises";
if (!existsSync('../../temp')) {
console.log('Creating temp directory...');
await mkdir('../../temp');
if (!existsSync("../../temp")) {
console.log("Creating temp directory...");
await mkdir("../../temp");
}
console.log('Downloading depot downloader...');
console.log("Downloading depot downloader...");
await fetch(
'https://api.github.com/repos/SteamRE/DepotDownloader/releases/latest',
"https://api.github.com/repos/SteamRE/DepotDownloader/releases/latest"
)
.then(
(response) =>
response.json() as Promise<{
assets: { browser_download_url: string; name: string }[];
}>,
}>
)
.then(({ assets }) => {
const asset = assets.find(({ name }) => name.includes('linux-x64'));
if (!asset) throw new Error('No asset found');
const asset = assets.find(({ name }) => name.includes("linux-x64"));
if (!asset) throw new Error("No asset found");
return fetch(asset.browser_download_url);
})
.then((response) => response.arrayBuffer())
.then((arrayBuffer) =>
writeFile('../../temp/depotDownloader.zip', new Uint8Array(arrayBuffer)),
writeFile("../../temp/depotDownloader.zip", new Uint8Array(arrayBuffer))
);
console.log('Unzipping...');
console.log("Unzipping...");
await decompress(
'../../temp/depotDownloader.zip',
'../../temp/depotDownloader',
"../../temp/depotDownloader.zip",
"../../temp/depotDownloader"
);
console.log(
'Download complete; files:',
await readdir('../../temp/depotDownloader'),
"Download complete; files:",
await readdir("../../temp/depotDownloader")
);