Compare commits

...
7 Commits
Author SHA1 Message Date
TrèsAbhi 7b93b12fcb Merge pull request #222 from karelpak1/Position-fix 2026-03-23 19:56:17 -05:00
GonnaHetzMe ed252d5dfe Reset localTranslation for model extraction 2026-03-23 13:17:42 +01:00
TrèsAbhi c365993541 feat: remove discord bot
.
2026-03-19 09:21:58 -05:00
TrèsAbhi 30f9475208 feat: disable bot 2026-03-19 09:19:28 -05:00
tresabhi 8394f2ec1e feat: logs 2026-03-11 16:51:32 -05:00
tresabhi f14e73d811 fix: alpha clipping 2026-03-11 16:50:18 -05:00
TrèsAbhi 427b189a34 New Crowdin updates (#217) 2026-03-04 17:42:01 -06:00
17 changed files with 131 additions and 60 deletions

No files matched your search

-6
View File
@@ -1,13 +1,7 @@
name: Host name: Host
on: on:
push:
branches: main
schedule:
- cron: "0 */5 * * *"
workflow_dispatch: workflow_dispatch:
release:
types: [created, published, released, edited]
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
+5
View File
@@ -0,0 +1,5 @@
# BlitzKit 1.29.15
## Fixes
- Tanks now use alpha clipping to render translucency, fixing a lot of "ghostly" looking tanks
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "blitzkit", "name": "blitzkit",
"version": "1.29.14", "version": "1.29.15",
"license": "BlitzKit License", "license": "BlitzKit License",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -0,0 +1,3 @@
export function bufferToBigInt(buffer: ArrayBuffer) {
return new DataView(buffer).getBigUint64(0, true);
}
+2
View File
@@ -1,4 +1,5 @@
export * from './buffer'; export * from './buffer';
export * from './bufferToBigInt';
export * from './dds'; export * from './dds';
export * from './dids'; export * from './dids';
export * from './pvr'; export * from './pvr';
@@ -7,3 +8,4 @@ export * from './sc2';
export * from './scg'; export * from './scg';
export * from './scpg'; export * from './scpg';
export * from './windows'; export * from './windows';
+10 -3
View File
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
"replay": { "replay": {
"name": "repetición", "name": "repetición",
"description": "Mostrar resultados de la repetición" "description": "Mostrar resultados de la repetición",
"options": {
"file": {
"name": "file",
"description": "Replay file"
}
}
}, },
"research": { "research": {
"name": "desarollar", "name": "desarollar",
@@ -1005,8 +1012,8 @@
"title": "Características", "title": "Características",
"compare": { "compare": {
"label": "Comparar con", "label": "Comparar con",
"class": "Tier {tier} {class}", "class": "{tier} {class}",
"tier": "All of tier {tier}", "tier": "All tier {tier}",
"all": "Todos los tanques" "all": "Todos los tanques"
}, },
"values": { "values": {
+10 -3
View File
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
"replay": { "replay": {
"name": "rejouer", "name": "rejouer",
"description": "Afficher les résultats de la relecture" "description": "Afficher les résultats de la relecture",
"options": {
"file": {
"name": "file",
"description": "Replay file"
}
}
}, },
"research": { "research": {
"name": "recherche", "name": "recherche",
@@ -1005,8 +1012,8 @@
"title": "Characteristics", "title": "Characteristics",
"compare": { "compare": {
"label": "Compare against", "label": "Compare against",
"class": "Tier {tier} {class}", "class": "{tier} {class}",
"tier": "All of tier {tier}", "tier": "All tier {tier}",
"all": "All tanks" "all": "All tanks"
}, },
"values": { "values": {
+10 -3
View File
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
"replay": { "replay": {
"name": "replay", "name": "replay",
"description": "Display replay results" "description": "Display replay results",
"options": {
"file": {
"name": "file",
"description": "Replay file"
}
}
}, },
"research": { "research": {
"name": "研究", "name": "研究",
@@ -1005,8 +1012,8 @@
"title": "性能値", "title": "性能値",
"compare": { "compare": {
"label": "比較対象", "label": "比較対象",
"class": "Tier {tier} {class}", "class": "{tier} {class}",
"tier": "All of tier {tier}", "tier": "All tier {tier}",
"all": "全車輌" "all": "全車輌"
}, },
"values": { "values": {
+11 -4
View File
@@ -1,7 +1,7 @@
{ {
"test": { "test": {
"default": "", "default": "",
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is {fruit} because it has the color of {color}. I like it so much that I will say its name 3 times! {fruit}! {fruit}! {fruit}! Once again, it's {color}, not {not_color}.", "long": ".",
"fox": "Szybki brązowy lis przeskoczył nad leniwym psem." "fox": "Szybki brązowy lis przeskoczył nad leniwym psem."
}, },
"common": { "common": {
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
"replay": { "replay": {
"name": "powtórz", "name": "powtórz",
"description": "Wyświetl wyniki powtórki" "description": "Wyświetl wyniki powtórki",
"options": {
"file": {
"name": "file",
"description": "Replay file"
}
}
}, },
"research": { "research": {
"name": "badanie", "name": "badanie",
@@ -1005,8 +1012,8 @@
"title": "Characteristics", "title": "Characteristics",
"compare": { "compare": {
"label": "Compare against", "label": "Compare against",
"class": "Tier {tier} {class}", "class": "{tier} {class}",
"tier": "All of tier {tier}", "tier": "All tier {tier}",
"all": "All tanks" "all": "All tanks"
}, },
"values": { "values": {
+10 -3
View File
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
"replay": { "replay": {
"name": "replay", "name": "replay",
"description": "Exibir resultados de replays" "description": "Exibir resultados de replays",
"options": {
"file": {
"name": "file",
"description": "Replay file"
}
}
}, },
"research": { "research": {
"name": "pesquisa", "name": "pesquisa",
@@ -1005,8 +1012,8 @@
"title": "Características", "title": "Características",
"compare": { "compare": {
"label": "Comparar com", "label": "Comparar com",
"class": "Tier {tier} {class}", "class": "{tier} {class}",
"tier": "All of tier {tier}", "tier": "All tier {tier}",
"all": "Todos os tanques" "all": "Todos os tanques"
}, },
"values": { "values": {
+10 -3
View File
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": ".",
"replay": { "replay": {
"name": "повтор", "name": "повтор",
"description": "Показать результаты повтора" "description": "Показать результаты повтора",
"options": {
"file": {
"name": "Файл",
"description": "Запись повтора"
}
}
}, },
"research": { "research": {
"name": "исследование", "name": "исследование",
@@ -1005,8 +1012,8 @@
"title": "Характеристики", "title": "Характеристики",
"compare": { "compare": {
"label": "Сравнивать с", "label": "Сравнивать с",
"class": "{class} {tier} уровня", "class": "Уровень Тип",
"tier": "Все {tier} уровня", "tier": "Все уровни",
"all": "Все танки" "all": "Все танки"
}, },
"values": { "values": {
+21 -14
View File
@@ -1,7 +1,7 @@
{ {
"test": { "test": {
"default": "тест", "default": "тест",
"long": "{fruit}", "long": "{color}{fruit}",
"fox": "Швидка бура лисиця перестрибує через лінивого собаку." "fox": "Швидка бура лисиця перестрибує через лінивого собаку."
}, },
"common": { "common": {
@@ -23,7 +23,7 @@
}, },
"shells": { "shells": {
"ap": "ББ", "ap": "ББ",
"ap_cr": "APCR", "ap_cr": "",
"hc": "HEAT", "hc": "HEAT",
"he": "ОФ" "he": "ОФ"
}, },
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": ".",
"replay": { "replay": {
"name": "реплей", "name": "реплей",
"description": "Показати результати реплею" "description": "Показати результати реплею",
"options": {
"file": {
"name": "",
"description": "Replay filehttps://crowdin.com/editor/blitzkrieg/80/en-uk?view=side-by-side#9706"
}
}
}, },
"research": { "research": {
"name": "дослідження", "name": "дослідження",
@@ -660,7 +667,7 @@
}, },
"tank_search": { "tank_search": {
"select_dialog_title": "Знайти танк", "select_dialog_title": "Знайти танк",
"swap_dialog_title": "Swap tank", "swap_dialog_title": "Резервуар підміни",
"clear_filters": "Очистити", "clear_filters": "Очистити",
"login": "Увійдіть, щоб скористатися", "login": "Увійдіть, щоб скористатися",
"search_bar_hint": "Шукайте техніку...", "search_bar_hint": "Шукайте техніку...",
@@ -671,8 +678,8 @@
"sorting_by": "Відсортувати за {name}", "sorting_by": "Відсортувати за {name}",
"clear": "Clear", "clear": "Clear",
"tier": "Рівень {tier}", "tier": "Рівень {tier}",
"passive": "{name} (Passive)", "passive": "",
"active": "{name} (Active)", "active": "{name}{name}",
"no_tanks_found": { "no_tanks_found": {
"body": "Нічого не знайдено.", "body": "Нічого не знайдено.",
"search_again": "Спробуйте шукати заново.", "search_again": "Спробуйте шукати заново.",
@@ -735,11 +742,11 @@
}, },
"home": { "home": {
"pwa": { "pwa": {
"title": "Install the BlitzKit App", "title": "",
"new": "", "new": "",
"checking": "Checking compatibility...", "checking": "",
"instructions": "Instructions for Apple devices.", "instructions": ".",
"install": "Install", "install": "",
"dismiss": "Dismiss" "dismiss": "Dismiss"
}, },
"discord": { "discord": {
@@ -823,7 +830,7 @@
"help": { "help": {
"title": "Partially reveal tank?", "title": "Partially reveal tank?",
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!", "description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
"cancel": "Cancel", "cancel": "",
"reveal": "Reveal" "reveal": "Reveal"
}, },
"clear": "Clear", "clear": "Clear",
@@ -1005,8 +1012,8 @@
"title": "Characteristics", "title": "Characteristics",
"compare": { "compare": {
"label": "Compare against", "label": "Compare against",
"class": "Tier {tier} {class}", "class": "{tier} {class}",
"tier": "All of tier {tier}", "tier": "All tier {tier}",
"all": "Усі танки" "all": "Усі танки"
}, },
"values": { "values": {
@@ -1274,7 +1281,7 @@
"button": "Generate URL", "button": "Generate URL",
"title": "Generate URL", "title": "Generate URL",
"subtitle": "Search an account to track", "subtitle": "Search an account to track",
"cancel": "Cancel", "cancel": "",
"success": { "success": {
"title": "Copy URL", "title": "Copy URL",
"info": "Generated the URL for {name}. The embed will start tracking as soon as the URL is pasted. Reset at any time by right-clicking on PC or long-pressing on mobile and then selecting \"Reset\".", "info": "Generated the URL for {name}. The embed will start tracking as soon as the URL is pasted. Reset at any time by right-clicking on PC or long-pressing on mobile and then selecting \"Reset\".",
+10 -3
View File
@@ -320,9 +320,16 @@
} }
}, },
"commands": { "commands": {
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
"replay": { "replay": {
"name": "回放", "name": "回放",
"description": "显示重播结果" "description": "显示重播结果",
"options": {
"file": {
"name": "file",
"description": "Replay file"
}
}
}, },
"research": { "research": {
"name": "研发", "name": "研发",
@@ -1005,8 +1012,8 @@
"title": "属性", "title": "属性",
"compare": { "compare": {
"label": "比较", "label": "比较",
"class": "{tier}阶 {class}", "class": "{tier} {class}",
"tier": "所有 {tier} 阶", "tier": "All tier {tier}",
"all": "所有坦克" "all": "所有坦克"
}, },
"values": { "values": {
@@ -12,12 +12,14 @@ export async function tankModels() {
using uploader = new AssetUploader("tank models"); using uploader = new AssetUploader("tank models");
const nodeIO = new NodeIO().registerExtensions(ALL_EXTENSIONS); const nodeIO = new NodeIO().registerExtensions(ALL_EXTENSIONS);
const nations = vfs.dir(`Data/XML/item_defs/vehicles`).filter((nation) => nation !== "common") const nations = vfs
.dir(`Data/XML/item_defs/vehicles`)
.filter((nation) => nation !== "common");
for (const nationIndex in nations) { for (const nationIndex in nations) {
const nation = nations[nationIndex]; const nation = nations[nationIndex];
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>( const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
`Data/XML/item_defs/vehicles/${nation}/list.xml` `Data/XML/item_defs/vehicles/${nation}/list.xml`,
); );
const entries = Object.entries(tanks.root); const entries = Object.entries(tanks.root);
@@ -26,11 +28,11 @@ export async function tankModels() {
const id = toUniqueId(nation, tank.id); const id = toUniqueId(nation, tank.id);
const parameters = await vfs.yaml<TankParameters>( const parameters = await vfs.yaml<TankParameters>(
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml` `Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
); );
const model = await extractModel( const model = await extractModel(
vfs, vfs,
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, "") parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ""),
); );
const content = Buffer.from(await nodeIO.writeBinary(model)); const content = Buffer.from(await nodeIO.writeBinary(model));
@@ -6,13 +6,13 @@ import {
} from "@blitzkit/core"; } from "@blitzkit/core";
import { Accessor, Document, Node, Scene } from "@gltf-transform/core"; import { Accessor, Document, Node, Scene } from "@gltf-transform/core";
import { times } from "lodash-es"; import { times } from "lodash-es";
import { SteamVFS } from "../vfs/steam"; import { AbstractVFS } from "../vfs/abstract";
import { import {
vertexAttributeGLTFName, vertexAttributeGLTFName,
vertexAttributeGltfVectorSizes, vertexAttributeGltfVectorSizes,
} from "./extractModel/constants"; } from "./extractModel/constants";
export async function extractArmor(vfs: SteamVFS, fileName: string) { export async function extractArmor(vfs: AbstractVFS, fileName: string) {
const sc2Path = `Data/3d/Tanks/CollisionMeshes/${fileName}.sc2`; const sc2Path = `Data/3d/Tanks/CollisionMeshes/${fileName}.sc2`;
const scgPath = `Data/3d/Tanks/CollisionMeshes/${fileName}.scg`; const scgPath = `Data/3d/Tanks/CollisionMeshes/${fileName}.scg`;
const sc2 = new Sc2ReadStream( const sc2 = new Sc2ReadStream(
@@ -1,4 +1,5 @@
import { import {
bufferToBigInt,
Hierarchy, Hierarchy,
Sc2ReadStream, Sc2ReadStream,
ScgReadStream, ScgReadStream,
@@ -9,7 +10,7 @@ import { Document, Material, Node, Scene } from "@gltf-transform/core";
import { dedup, prune } from "@gltf-transform/functions"; import { dedup, prune } from "@gltf-transform/functions";
import { times } from "lodash-es"; import { times } from "lodash-es";
import { dirname } from "path"; import { dirname } from "path";
import { SteamVFS } from "../../vfs/steam"; import { AbstractVFS } from "../../vfs/abstract";
import { readBaseColor } from "../readBaseColor"; import { readBaseColor } from "../readBaseColor";
import { readNormal } from "../readNormal"; import { readNormal } from "../readNormal";
import { readRoughnessMetallic } from "../readRoughnessMetallic"; import { readRoughnessMetallic } from "../readRoughnessMetallic";
@@ -25,7 +26,7 @@ const omitMeshNames = {
end: ["_POINT"], end: ["_POINT"],
}; };
export async function extractModel(vfs: SteamVFS, path: string) { export async function extractModel(vfs: AbstractVFS, path: string) {
const sc2Path = `Data/3d/${path}.sc2`; const sc2Path = `Data/3d/${path}.sc2`;
const scgPath = `Data/3d/${path}.scg`; const scgPath = `Data/3d/${path}.scg`;
const sc2 = new Sc2ReadStream( const sc2 = new Sc2ReadStream(
@@ -40,7 +41,7 @@ export async function extractModel(vfs: SteamVFS, path: string) {
const materials = new Map<bigint, Material | bigint | undefined>(); const materials = new Map<bigint, Material | bigint | undefined>();
for (const node of sc2["#dataNodes"]) { for (const node of sc2["#dataNodes"]) {
const id = new DataView(node["#id"]).getBigUint64(0, true); const id = bufferToBigInt(node["#id"]);
if (node.parentMaterialKey !== undefined) { if (node.parentMaterialKey !== undefined) {
/** /**
@@ -80,8 +81,20 @@ export async function extractModel(vfs: SteamVFS, path: string) {
configIndex < node.configCount; configIndex < node.configCount;
configIndex++ configIndex++
) { ) {
if (!hasAlpha) continue; const archive = node[`configArchive_${configIndex}`];
material.setAlphaMode("BLEND").setDoubleSided(true);
if (
archive.configName !== "Default" ||
!archive.enabledPresets?.AlphaTest
) {
continue;
}
const view = new DataView(archive.properties.alphatestThreshold);
const _ = view.getUint8(0); // only god knows what these flags are
const alphaCutoff = view.getFloat32(1, true);
material.setAlphaMode("MASK").setAlphaCutoff(alphaCutoff);
} }
} }
@@ -116,7 +129,7 @@ export async function extractModel(vfs: SteamVFS, path: string) {
); );
} }
materials.set(new DataView(node["#id"]).getBigUint64(0, true), material); materials.set(id, material);
} }
} }
@@ -157,6 +170,7 @@ export async function extractModel(vfs: SteamVFS, path: string) {
break; break;
case "TransformComponent": { case "TransformComponent": {
component["tc.localTranslation"] = [0, 0, 0]; // Game when is loading model resets position to [0, 0, 0], so any set value is ignored.
node.setTranslation(component["tc.localTranslation"]); node.setTranslation(component["tc.localTranslation"]);
node.setRotation(component["tc.localRotation"]); node.setRotation(component["tc.localRotation"]);
node.setScale(component["tc.localScale"]); node.setScale(component["tc.localScale"]);
-5
View File
@@ -55,11 +55,6 @@ export const tools: Record<string, Tool> = {
id: "session", id: "session",
button: "blue", button: "blue",
}, },
discord: {
id: "discord",
href: "https://discord.com/application-directory/1097673957865443370",
button: "indigo",
},
tier_list: { tier_list: {
id: "tier-list", id: "tier-list",
strings: "tier_list", strings: "tier_list",