Compare commits

...
15 Commits
Author SHA1 Message Date
tresabhi 59108d7637 update (4) 2026-08-01 15:08:33 -05:00
tresabhi f85d097c16 rename 2026-08-01 14:55:57 -05:00
tresabhi ed92440b94 update (3) 2026-08-01 14:54:40 -05:00
tresabhi d41d45abae update (2) 2026-08-01 14:48:18 -05:00
tresabhi 32a7db238b update (1) 2026-08-01 14:44:23 -05:00
tresabhi 2dc23ba09d some returns 2026-08-01 14:32:25 -05:00
tresabhi 30522bfda0 caching 2026-08-01 14:21:11 -05:00
tresabhi ed31f40876 (5) some implementation 2026-08-01 14:13:18 -05:00
tresabhi 6ad64c9bd9 (4) some implementation 2026-08-01 14:01:34 -05:00
tresabhi bd7c952478 (3) some implementation 2026-08-01 13:59:56 -05:00
tresabhi f7180f0e1a (2) some implementation 2026-08-01 13:53:00 -05:00
tresabhi b0611d7d72 (1) some implementation 2026-08-01 13:44:44 -05:00
tresabhi 244968bbbf (3) some definitions headers 2026-08-01 13:26:45 -05:00
tresabhi fd8448b0a6 (2) some definitions headers 2026-08-01 13:07:04 -05:00
tresabhi 17c54be1c8 some definitions headers 2026-08-01 12:56:12 -05:00
113 changed files with 2371 additions and 2138 deletions

No files matched your search

+20 -2
View File
@@ -1,5 +1,23 @@
import { GameDefinitions } from "../../protos";
import {
CamouflageDefinitions,
ConsumableDefinitions,
EquipmentDefinitions,
GameDefinitions,
MapDefinitions,
ModelDefinitions,
ProvisionDefinitions,
SkillDefinitions,
TankDefinitions,
} from "@blitzkit/core";
export abstract class BlitzKitAPI {
abstract game(): Promise<GameDefinitions>;
abstract skillDefinitions(): Promise<SkillDefinitions>;
abstract provisionDefinitions(): Promise<ProvisionDefinitions>;
abstract consumableDefinitions(): Promise<ConsumableDefinitions>;
abstract equipmentDefinitions(): Promise<EquipmentDefinitions>;
abstract mapDefinitions(): Promise<MapDefinitions>;
abstract modelDefinitions(): Promise<ModelDefinitions>;
abstract camouflageDefinitions(): Promise<CamouflageDefinitions>;
abstract tankDefinitions(): Promise<TankDefinitions>;
abstract gameDefinitions(): Promise<GameDefinitions>;
}
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,4 +1,4 @@
export function assertSecret<Type>(secret?: Type) {
export function assertSecret(secret?: string) {
if (secret === undefined) throw new Error("Missing secret");
return secret;
}
-5
View File
@@ -1,5 +0,0 @@
import { assertSecret } from "./assertSecret";
export function asset(path: string) {
return `${assertSecret(import.meta.env.PUBLIC_ASSET_BASE)}/${path}`;
}
@@ -1,6 +1,6 @@
import { fetchPB } from '../../protobuf';
import { AverageDefinitions } from '../../protos';
import { asset } from '../asset';
import { staticAsset } from "@blitzkit/core";
import { fetchPB } from "../../protobuf";
import { AverageDefinitions } from "../../protos";
export interface AverageDefinitionsManifest {
version: 1;
@@ -11,13 +11,7 @@ export interface AverageDefinitionsManifest {
}
export async function fetchAverageDefinitions() {
const manifestResponse = await fetch(asset('averages/manifest.json'));
const manifestJson =
(await manifestResponse.json()) as AverageDefinitionsManifest;
return await fetchPB(
asset(`averages/${manifestJson.latest}.pb`),
AverageDefinitions,
);
return await fetchPB(staticAsset("averages.pb"), AverageDefinitions);
}
export * from './constants';
export * from "./constants";
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { CamouflageDefinitions } from '../protos';
import { asset } from './asset';
export function fetchCamouflageDefinitions() {
return fetchPB(asset('definitions/camouflages.pb'), CamouflageDefinitions);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { ConsumableDefinitions } from '../protos';
import { asset } from './asset';
export function fetchConsumableDefinitions() {
return fetchPB(asset('definitions/consumables.pb'), ConsumableDefinitions);
}
@@ -1,4 +1,4 @@
import { asset } from './asset';
import { staticAsset } from "@blitzkit/core";
export interface DiscoveredIdsDefinitions {
time: number;
@@ -7,6 +7,6 @@ export interface DiscoveredIdsDefinitions {
}
export async function fetchDiscoveredIdsDefinitions() {
const response = await fetch(asset('ids/manifest.json'));
const response = await fetch(staticAsset("ids/manifest.json"));
return response.json() as Promise<DiscoveredIdsDefinitions>;
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { EquipmentDefinitions } from '../protos';
import { asset } from './asset';
export function fetchEquipmentDefinitions() {
return fetchPB(asset('definitions/equipment.pb'), EquipmentDefinitions);
}
-7
View File
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { Gallery } from '../protos';
import { asset } from './asset';
export function fetchGallery() {
return fetchPB(asset('definitions/gallery.pb'), Gallery);
}
@@ -1,23 +0,0 @@
import type { Region } from "../blitz/regions";
import { RatingLeaderboard } from "../protos";
import { asset } from "./asset";
const cache: Record<Region, Record<number, RatingLeaderboard>> = {
asia: {},
eu: {},
com: {},
};
export async function getArchivedRatingLeaderboard(
region: Region,
season: number
) {
if (!cache[region][season]) {
const info = await fetch(asset(`regions/${region}/rating/${season}.pb`))
.then((response) => response.arrayBuffer())
.then((buffer) => RatingLeaderboard.decode(new Uint8Array(buffer)));
cache[region][season] = info;
}
return cache[region][season];
}
+8 -25
View File
@@ -1,39 +1,27 @@
export * from "./api";
export * from "./assertSecret";
export * from "./asset";
export * from "./availableProvisions";
export * from "./averageDefinitions";
// export * from './camouflageDefinitions';
// export * from './checkConsumableProvisionInclusivity';
export * from "./coefficient";
export * from "./consumableDefinitions";
// export * from './context';
export * from "./api";
export * from "./createDefaultProvisions";
export * from "./createDefaultSkills";
export * from "./degressiveStat";
export * from "./discoveredIdDefinitions";
export * from "./emblemURL";
export * from "./equipmentDefinitions";
export * from "./eventManager";
export * from "./getArchivedLatestSeasonNumber";
export * from "./sluggify";
export * from "./vfs";
// export * from './getArchivedRatingInfo';
export * from "./getArchivedRatingLeaderboard";
// export * from './getArchivedRatingMidnightLeaderboard';
export * from "./getTimeDaysAgo";
export * from "./isExplosive";
export * from "./mapDefinitions";
export * from "./modelDefinitions";
export * from "./metaSortTank";
export * from "./normalizeBoundingBox";
// export * from './parseBkni';
// export * from './patientFetch';
export * from "./patientFetchJSON";
export * from "./popularTanks";
export * from "./progressiveStat";
export * from "./provisionDefinitions";
export * from "./resolveDpm";
export * from "./resolvePenetrationCoefficient";
export * from "./reviews";
export * from "./skillDefinitions";
export * from "./romanize";
export * from "./sluggify";
export * from "./staticAsset";
export * from "./sum";
export * from "./tankDefinitions";
export * from "./tankIcon";
@@ -41,11 +29,6 @@ export * from "./tankNames";
export * from "./unionBoundingBox";
export * from "./uniqueGuns";
export * from "./unwrapBlitzkitResponse";
export * from "./vfs";
export * from "./votes";
// export * from './withCORSProxy';
export * from "./createDefaultProvisions";
export * from "./gallery";
export * from "./metaSortTank";
export * from "./popularTanks";
export * from "./romanize";
export * from "./youtubers";
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { MapDefinitions } from '../protos';
import { asset } from './asset';
export function fetchMapDefinitions() {
return fetchPB(asset('definitions/maps.pb'), MapDefinitions);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { ModelDefinitions } from '../protos';
import { asset } from './asset';
export function fetchModelDefinitions() {
return fetchPB(asset('definitions/models.pb'), ModelDefinitions);
}
+4 -4
View File
@@ -1,7 +1,7 @@
import { fetchPB } from '../protobuf';
import { PopularTanks } from '../protos';
import { asset } from './asset';
import { staticAsset } from "@blitzkit/core";
import { fetchPB } from "../protobuf";
import { PopularTanks } from "../protos";
export function fetchPopularTanks() {
return fetchPB(asset('definitions/popular-tanks.pb'), PopularTanks);
return fetchPB(staticAsset("definitions/popular-tanks.pb"), PopularTanks);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { ProvisionDefinitions } from '../protos';
import { asset } from './asset';
export function fetchProvisionDefinitions() {
return fetchPB(asset('definitions/provisions.pb'), ProvisionDefinitions);
}
+4 -4
View File
@@ -1,7 +1,7 @@
import { fetchPB } from '../protobuf';
import { Reviews } from '../protos';
import { asset } from './asset';
import { staticAsset } from "@blitzkit/core";
import { fetchPB } from "../protobuf";
import { Reviews } from "../protos";
export function fetchReviews() {
return fetchPB(asset('definitions/reviews.pb'), Reviews);
return fetchPB(staticAsset("definitions/reviews.pb"), Reviews);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { SkillDefinitions } from '../protos';
import { asset } from './asset';
export function fetchSkillDefinitions() {
return fetchPB(asset('definitions/skills.pb'), SkillDefinitions);
}
@@ -0,0 +1,5 @@
import { assertSecret } from "./assertSecret";
export function staticAsset(path: string) {
return `${assertSecret(import.meta.env.PUBLIC_STATIC_ASSET_BASE)}/${path}`;
}
@@ -1,9 +1 @@
import { fetchPB } from '../../protobuf';
import { TankDefinitions } from '../../protos';
import { asset } from '../asset';
export function fetchTankDefinitions() {
return fetchPB(asset('definitions/tanks.pb'), TankDefinitions);
}
export * from './constants';
export * from "./constants";
+1 -3
View File
@@ -1,7 +1,5 @@
import { asset } from "./asset";
export const BLITZKIT_TANK_ICON_SIZE = { width: 40 * 16, height: 30 * 16 };
export function tankIcon(id: number, size: "big" | "small" = "big") {
return asset(`icons/tanks/${size}/${id}.webp`);
return `/api/tanks/${id}/icons/${size}.webp`;
}
+4 -5
View File
@@ -1,13 +1,12 @@
import { BlitzKitAPI } from "@blitzkit/core";
import locales from "@blitzkit/i18n/locales.json";
import { deburr } from "lodash-es";
import { I18nString } from "../protos";
import { fetchCamouflageDefinitions } from "./camouflageDefinitions";
import { fetchTankDefinitions } from "./tankDefinitions";
export async function fetchTankNames() {
export async function fetchTankNames(api: BlitzKitAPI) {
const [tankDefinitions, camouflageDefinitions] = await Promise.all([
fetchTankDefinitions(),
fetchCamouflageDefinitions(),
api.tankDefinitions(),
api.camouflageDefinitions(),
]);
const tankDefinitionsArray = Object.values(tankDefinitions.tanks);
@@ -0,0 +1,10 @@
export type BlitzModuleType = {
[key in "vehicle" | "engine" | "chassis" | "turret" | "gun"]:
| UnlocksInner
| UnlocksInner[];
};
interface UnlocksInner {
cost: number | string;
"#text": number;
}
+3
View File
@@ -0,0 +1,3 @@
export interface BlitzStrings {
[key: string]: string;
}
@@ -0,0 +1 @@
export type BlitzTankFilterDefinitionCategory = "clip";
+33
View File
@@ -0,0 +1,33 @@
export interface CamouflagesXml {
camouflages: Record<
string,
{
id: number;
userString: string;
description: string;
category: string;
group: string;
kind: string;
notInShop: boolean;
unlockCostCategory?: string;
vehicleFilter: {
include?: CamouflagesInclude | CamouflagesInclude[];
};
script: string[] | string;
icon?: string;
unlockPremium?: string;
unlockQuest?: string;
unlockClanLevel?: number;
unlockShopBundle?: string;
unlockTankRank?: number;
}
>;
}
type CamouflagesInclude =
| {
nations?: string;
}
| {
vehicle?: { name?: string; minLevel?: number; maxLevel?: number };
};
@@ -0,0 +1,7 @@
export type CamouflagesYaml = Record<
string,
{
userString?: string;
shortUserString?: string;
}
>;
@@ -0,0 +1,4 @@
export interface ChassisDefinitionsList {
nextAvailableId: number;
ids: Record<string, number>;
}
@@ -0,0 +1,7 @@
export type CombatRolesYaml = Record<
string,
{
id: number;
default_abilities: string[];
}
>;
@@ -0,0 +1,24 @@
import { ConsumablesVehicleFilter } from "./consumablesVehicleFilter";
export interface ConsumablesCommon {
[key: string]: {
id: number;
userString: string;
description: string;
icon: string;
category: string;
tags: string;
vehicleFilter?: {
include: { vehicle: ConsumablesVehicleFilter; nations?: string };
exclude?: { vehicle: ConsumablesVehicleFilter; nations?: string };
};
script: {
"#text": string;
automatic?: boolean;
cooldown: number;
duration?: number;
shotEffect?: string;
bonusValues?: { [key: string]: number };
} & Record<string, string>;
};
}
@@ -0,0 +1,4 @@
export type ConsumablesVehicleFilter =
| { minLevel: number; maxLevel: number }
| { name: string }
| { extendedTags: string };
@@ -0,0 +1,13 @@
export interface EngineDefinitionsList {
nextAvailableId: number;
ids: Record<string, number>;
shared: {
[key: string]: {
userString: string;
level: number;
fireStartingChance: number;
weight: number;
power: number;
};
};
}
@@ -0,0 +1,31 @@
export interface GunDefinitionsList {
nextAvailableId: number;
ids: Record<string, number>;
shared: {
[key: string]: {
rotationSpeed: number;
weight: number;
shotDispersionFactors: {
turretRotation: number;
afterShot: number;
whileGunDamaged: number;
};
maxAmmo: number;
aimingTime: number;
shotDispersionRadius: number;
userString: string;
tags: string;
level: number;
pitchLimits: string;
burst?: { count: number; rate: number };
clip?: { count: number; rate: number };
shots: {
[key: string]: {
speed: number;
piercingPower: string;
maxDistance: number;
};
};
};
};
}
+22
View File
@@ -1,4 +1,26 @@
export * from "./availableNationsYaml";
export * from "./blitzModuleType";
export * from "./blitzStrings";
export * from "./blitzTankFilterDefinitionCategory";
export * from "./camouflagesXml";
export * from "./camouflagesYaml";
export * from "./chassisDefinitionsList";
export * from "./combatRolesYaml";
export * from "./consumablesCommon";
export * from "./consumablesVehicleFilter";
export * from "./engineDefinitionsList";
export * from "./glossary";
export * from "./gunDefinitionsList";
export * from "./mapsYaml";
export * from "./optionalDevices";
export * from "./optionalDeviceSlots";
export * from "./provisionsCommon";
export * from "./shellDefinitionsList";
export * from "./squadBattleTypeStylesYaml";
export * from "./tankmenAvatar";
export * from "./tankParameters";
export * from "./tanksStats";
export * from "./turretDefinitionsList";
export * from "./vehicleDefinitionArmor";
export * from "./vehicleDefinitionList";
export * from "./vehicleDefinitions";
+24
View File
@@ -0,0 +1,24 @@
export interface MapsYaml {
maps: {
[key: string]: {
id: number;
tags?: string;
localName: string;
avaliableInTrainingRoom: boolean; // lol wg typo
spriteFrame: number;
supremacyPointsThreshold?: number;
availableModes: number[];
shadowMapsAvailable?: boolean;
assaultRespawnPoints: {
allies: MapAlly[];
enemies: MapAlly[];
};
levels?: number[];
};
};
}
export interface MapAlly {
respawnNumber: number;
points: Array<number[]>;
}
@@ -0,0 +1,13 @@
export interface OptionalDeviceSlots {
presets: {
[key: string]: {
level0: OptionalDeviceSlotRow;
level1: OptionalDeviceSlotRow;
level2: OptionalDeviceSlotRow;
};
};
}
interface OptionalDeviceSlotRow {
[key: string]: { device0: string; device1: string };
}
@@ -0,0 +1,10 @@
export interface OptionalDevices {
[key: string]: {
id: number;
userString: string;
description: string;
icon: string;
script: unknown;
display_params: unknown;
};
}
@@ -0,0 +1,22 @@
import { ConsumablesVehicleFilter } from "./consumablesVehicleFilter";
export interface ProvisionsCommon {
[key: string]: {
id: number;
userString: string;
description: string;
icon: string;
category: string;
tags: string;
vehicleFilter?: {
include: { vehicle: ConsumablesVehicleFilter; nations?: string };
exclude?: { vehicle: ConsumablesVehicleFilter; nations?: string };
};
script: {
"#text": string;
automatic?: boolean;
shotEffect?: string;
bonusValues?: { [key: string]: number };
} & Record<string, string>;
};
}
@@ -0,0 +1,22 @@
export type ShellDefinitionsList = Record<
string,
{
id: number;
userString: string;
icon: string;
kind: ShellKind;
caliber: number;
damage: { armor: number; devices: number };
normalizationAngle?: number;
ricochetAngle?: number;
explosionRadius?: number;
}
> & {
icons: Record<string, string>;
};
export type ShellKind =
| "ARMOR_PIERCING"
| "ARMOR_PIERCING_CR"
| "HIGH_EXPLOSIVE"
| "HOLLOW_CHARGE";
+33
View File
@@ -0,0 +1,33 @@
import { Vector3Tuple } from "three";
export interface TankParameters {
resourcesPath: {
smallIconPath: string;
bigIconPath: string;
blitzModelPath: string;
};
collision: {
[key: string]: {
points: Vector3Tuple;
bbox: {
min: Vector3Tuple;
max: Vector3Tuple;
};
averageThickness?: Record<string, number>;
};
};
maskSlice?: {
[key: string]:
| {
enabled: boolean;
planePosition: Vector3Tuple;
planeNormal: Vector3Tuple;
planeAxis: Vector3Tuple;
frustumConeBaseRadius: number;
frustumConeAngleDegrees: number;
planeSliceMode: number;
frustumConeSliceMode: number;
}
| undefined;
};
}
+20
View File
@@ -0,0 +1,20 @@
import { TankClass } from "@blitzkit/core";
export interface TankmenAvatar {
roles: unknown;
skillsByClasses: Record<TankClass, string>;
skills: {
[name: string]: {
userString: string;
effectDescription: string;
tipDescription: string;
icon: SkillIcon | SkillIcon[];
type: "continuous" | "trigger";
};
};
}
interface SkillIcon {
name: string;
state: number;
}
@@ -0,0 +1,4 @@
export interface TurretDefinitionsList {
nextAvailableId: number;
ids: Record<string, number>;
}
@@ -0,0 +1,4 @@
export type VehicleDefinitionArmor = Record<
string,
number | { vehicleDamageFactor: 0; "#text": number } | number[]
>;
@@ -0,0 +1,16 @@
export interface VehicleDefinitionList {
[key: string]: {
id: number;
userString: string;
shortUserString?: string;
description: string;
price: number | { gold: ""; "#text": number };
sellPrice?: { gold: ""; "#text": number };
enrichmentPermanentCost: number;
notInShop?: boolean;
tags: string;
level: number;
combatRole?: Record<string, string>;
configurationModes: string;
};
}
@@ -0,0 +1,152 @@
import { BlitzModuleType } from "@blitzkit/core";
export interface VehicleDefinitions {
invisibility: {
moving: number;
still: number;
firePenalty: number;
};
crew: Record<BlitzCrewType, string | string[]>;
speedLimits: {
forward: number;
backward: number;
};
consumableSlots: number;
provisionSlots: number;
optDevicePreset: string | string[];
hull: {
armor: VehicleDefinitionArmor;
turretPositions: { turret: string };
turretInitialRotation?: { yaw: 0; pitch: 6.5; roll: 0 };
maxHealth: number;
weight: number;
};
chassis: {
[key: string]: {
unlocks: UnlocksListing;
weight: number;
terrainResistance: string;
rotationSpeed: number;
userString: string;
shotDispersionFactors: {
vehicleMovement: number;
vehicleRotation: number;
};
level: number;
hullPosition: string;
armor: {
leftTrack:
| number
| {
chanceToHitByProjectile: number;
chanceToHitByExplosion: number;
"#text": number;
};
rightTrack:
| number
| {
chanceToHitByProjectile: number;
chanceToHitByExplosion: number;
"#text": number;
};
};
};
};
engines: {
[key: string]: {
unlocks: UnlocksListing;
};
};
turrets0: {
[key: string]: {
unlocks: UnlocksListing;
rotationSpeed: number;
weight: number;
circularVisionRadius: number;
maxHealth: number;
armor: VehicleDefinitionArmor;
userString: string;
level: number;
yawLimits: string | string[];
gunPosition: string | string[];
models: { undamaged: string };
hitTester: {
collisionModel: string;
};
guns: {
[key: string]: {
unlocks: UnlocksListing;
armor: VehicleDefinitionArmor & {
gun?:
| number
| {
chanceToHitByProjectile: number;
chanceToHitByExplosion: number;
"#text": number;
};
};
invisibilityFactorAtShot: number | number[];
reloadTime: number;
aimingTime?: number;
shotDispersionRadius: number;
shotDispersionFactors?: {
turretRotation: number;
afterShot: number;
whileGunDamaged: number;
};
maxAmmo: number;
extraPitchLimits?: {
front?: string;
back?: string;
transition?: number | number[];
};
pitchLimits?: string | string[];
pumpGunMode?: boolean;
pumpGunReloadTimes?: string;
clip?: { count: number; rate: number };
burst?: { count: number; rate: number };
models: { undamaged: string };
extras?: {
trayShell?: {
kinds: string;
sectors: Record<
string,
{ id: number; distance: number; factor: number }[]
>;
};
};
};
};
};
};
extras?: {
armorsStatesController?: {
state: [
{
id: 0;
armors: string;
type: "default";
enabled: true;
factorsModifiers: "";
default: "";
},
{
id: 1;
armors: string;
type: "default";
enabled: false;
factorsModifiers: "";
},
];
};
};
}
export type BlitzCrewType =
| "commander"
| "radioman"
| "gunner"
| "driver"
| "loader";
export type UnlocksListing = BlitzModuleType | undefined;
@@ -1,9 +1,11 @@
import { assertSecret } from "@blitzkit/core";
import { AbstractVFS } from "../core/vfs/abstract";
import { LocalVFS } from "../core/vfs/local";
import { MixedVFS } from "../core/vfs/mixed";
import { SteamVFS } from "../core/vfs/steam";
import { ZipVFS } from "../core/vfs/zip";
import {
AbstractVFS,
assertSecret,
LocalVFS,
MixedVFS,
SteamVFS,
ZipVFS,
} from "@blitzkit/core";
export const PATCHES_ROOT = "../../temp/patches";
@@ -1,6 +1,6 @@
import sharp from "sharp";
import { AssetUploader } from "../core/github/assetUploader";
import { parsePackedSpriteRect } from "../core/blitz/parsePackedSpriteRect";
import { AssetUploader } from "../core/github/assetUploader";
import { vfs } from "./constants";
import { ConsumablesCommon, ProvisionsCommon } from "./definitions";
File diff suppressed because it is too large. Load diff
+1 -21
View File
@@ -1,31 +1,11 @@
import { TankClass } from "@blitzkit/core";
import sharp from "sharp";
import { AssetUploader } from "../core/github/assetUploader";
import { vfs } from "./constants";
interface SkillIcon {
name: string;
state: number;
}
export interface Avatar {
roles: unknown;
skillsByClasses: Record<TankClass, string>;
skills: {
[name: string]: {
userString: string;
effectDescription: string;
tipDescription: string;
icon: SkillIcon | SkillIcon[];
type: "continuous" | "trigger";
};
};
}
export async function skillIcons() {
console.log("Building skill icons...");
const avatar = await vfs.xml<{ root: Avatar }>(
const avatar = await vfs.xml<{ root: TankmenAvatar }>(
`Data/XML/item_defs/tankmen/avatar.xml`,
);
const uploader = new AssetUploader("skill icons");
@@ -1,43 +1,10 @@
import { NATION_IDS } from "@blitzkit/core";
import sharp from "sharp";
import type { Vector3Tuple } from "three";
import { parsePackedSpriteRect } from "../core/blitz/parsePackedSpriteRect";
import { AssetUploader } from "../core/github/assetUploader";
import { vfs } from "./constants";
import type { VehicleDefinitionList } from "./definitions";
export interface TankParameters {
resourcesPath: {
smallIconPath: string;
bigIconPath: string;
blitzModelPath: string;
};
collision: {
[key: string]: {
points: Vector3Tuple;
bbox: {
min: Vector3Tuple;
max: Vector3Tuple;
};
averageThickness?: Record<string, number>;
};
};
maskSlice?: {
[key: string]:
| {
enabled: boolean;
planePosition: Vector3Tuple;
planeNormal: Vector3Tuple;
planeAxis: Vector3Tuple;
frustumConeBaseRadius: number;
frustumConeAngleDegrees: number;
planeSliceMode: number;
frustumConeSliceMode: number;
}
| undefined;
};
}
async function extractPackedTankIcon(packedBuffer: Buffer, context: string) {
const texture = sharp(packedBuffer);
const spriteRect = parsePackedSpriteRect(packedBuffer);
+10 -6
View File
@@ -12,7 +12,7 @@ import { tools } from "./src/constants/tools";
const POSSIBLE_TARGETS = ["app", "web"];
const target = process.env.PUBLIC_TARGET ;
const target = process.env.PUBLIC_TARGET;
if (!target || !POSSIBLE_TARGETS.includes(target)) {
throw new Error("Invalid target");
@@ -21,7 +21,11 @@ if (!target || !POSSIBLE_TARGETS.includes(target)) {
export default defineConfig({
devToolbar: { enabled: false },
vite: { server: { allowedHosts: [] } },
vite: {
server: { allowedHosts: [] },
esbuild: { target: "es2022" },
},
output: target === "web" ? "static" : "server",
site: "https://blitzkit.app",
outDir: "../../dist/website",
@@ -50,15 +54,15 @@ export default defineConfig({
return {
name: strings.website.tools[stringId].name,
name_localized: wrapper(
(strings) => strings.website.tools[stringId].name
(strings) => strings.website.tools[stringId].name,
),
description: strings.website.tools[stringId].description,
description_localized: wrapper(
(strings) => strings.website.tools[stringId].description
(strings) => strings.website.tools[stringId].description,
),
short_name: strings.website.tools[stringId].name,
short_name_localized: wrapper(
(strings) => strings.website.tools[stringId].name
(strings) => strings.website.tools[stringId].name,
),
url: `/${tool.id}`,
icon: `public/assets/images/tools/${tool.id}.webp`,
@@ -68,7 +72,7 @@ export default defineConfig({
manifest: {
description: strings.website.home.seo_description,
description_localized: wrapper(
(strings) => strings.website.home.seo_description
(strings) => strings.website.home.seo_description,
),
dir: "ltr",
+1 -1
View File
@@ -11,7 +11,7 @@ export interface Props {
locale: string;
}
const gameDefinitions = await api.game();
const gameDefinitions = await api.gameDefinitions();
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_BRANCH);
const { locale } = Astro.props;
const strings = getStrings(locale);
@@ -1,12 +1,8 @@
import {
asset,
fetchTankDefinitions,
TankType,
type TankDefinition,
} from "@blitzkit/core";
import { asset, TankType, type TankDefinition } from "@blitzkit/core";
import { Flex, Text, type TextProps } from "@radix-ui/themes";
import { uniq } from "lodash-es";
import { forwardRef, type ReactNode } from "react";
import { api } from "../../core/blitzkit/api";
import { useLocale } from "../../hooks/useLocale";
import { TankopediaPersistent } from "../../stores/tankopediaPersistent";
import { classIcons } from "../ClassIcon";
@@ -21,7 +17,7 @@ type TankCardProps = TextProps & {
noLink?: boolean;
};
const tankDefinitions = await fetchTankDefinitions();
const tankDefinitions = await api.tankDefinitions();
export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
(
@@ -5,7 +5,7 @@ import {
type TankDefinition,
} from "@blitzkit/core";
import { useMemo } from "react";
import { awaitableModelDefinitions } from "../../../core/awaitables/modelDefinitions";
import { api } from "../../../core/blitzkit/api";
import { resolveReload } from "../../../core/blitzkit/resolveReload";
import { TankSort } from "../../../stores/tankopediaSort";
import { TankCard } from "../../TankCard";
@@ -15,7 +15,7 @@ interface TankSearchCardProps {
onSelect?: (tank: TankDefinition) => void;
}
const modelDefinitions = await awaitableModelDefinitions;
const modelDefinitions = await api.modelDefinitions();
export function TankSearchCard({ tank, onSelect }: TankSearchCardProps) {
const by = TankSort.use((state) => state.by);
@@ -1,5 +1,4 @@
import {
asset,
GunDefinition,
ShellType,
TANK_CLASSES,
@@ -27,10 +26,7 @@ import {
} from "@radix-ui/themes";
import { times } from "lodash-es";
import { Fragment, type ComponentProps, type ReactNode } from "react";
import { awaitableConsumableDefinitions } from "../../../core/awaitables/consumableDefinitions";
import { awaitableGameDefinitions } from "../../../core/awaitables/gameDefinitions";
import { awaitableProvisionDefinitions } from "../../../core/awaitables/provisionDefinitions";
import { awaitableTankDefinitions } from "../../../core/awaitables/tankDefinitions";
import { api } from "../../../core/blitzkit/api";
import { useLocale } from "../../../hooks/useLocale";
import { App } from "../../../stores/app";
import { TankFilters, type CaseType } from "../../../stores/tankFilters";
@@ -43,10 +39,10 @@ import { ResearchedIcon } from "../../ResearchedIcon";
import { ScienceIcon } from "../../ScienceIcon";
import { ScienceOffIcon } from "../../ScienceOffIcon";
const gameDefinitions = await awaitableGameDefinitions;
const consumableDefinitions = await awaitableConsumableDefinitions;
const provisionDefinitions = await awaitableProvisionDefinitions;
const tankDefinitions = await awaitableTankDefinitions;
const gameDefinitions = await api.gameDefinitions();
const consumableDefinitions = await api.consumableDefinitions();
const provisionDefinitions = await api.provisionDefinitions();
const tankDefinitions = await api.tankDefinitions();
const gameModeRoleSets: Record<number, Set<number>> = {};
@@ -313,7 +309,7 @@ function NationsFilter() {
width: "1.25em",
height: "1.25em",
}}
src={asset(`flags/circle/${nation}.webp`)}
src={`/api/flags/circle/${nation}.webp`}
/>
))}
</Flex>
@@ -350,9 +346,7 @@ function NationsFilter() {
right="0"
mr="-2"
style={{
backgroundImage: `url(${asset(
`flags/scratched/${nation}.webp`,
)})`,
backgroundImage: `url(${`/api/flags/scratched/${nation}.webp`})`,
backgroundSize: "100%",
backgroundRepeat: "no-repeat",
backgroundPosition: "5rem center",
@@ -685,11 +679,9 @@ function IndividualShellFilter({
{shells[index] !== null && (
<img
style={{ width: "1em", height: "1em" }}
src={asset(
`icons/shells/${shellTypeIcons[shells[index]]}${
premium ? "_premium" : ""
}.webp`,
)}
src={`/api/icons/shells/${shellTypeIcons[shells[index]]}${
premium ? "_premium" : ""
}.webp`}
/>
)}
</IconButton>
@@ -720,11 +712,9 @@ function IndividualShellFilter({
color={selected ? undefined : "gray"}
>
<img
src={asset(
`icons/shells/${shellTypeIcons[shellType]}${
premium ? "_premium" : ""
}.webp`,
)}
src={`/api/icons/shells/${shellTypeIcons[shellType]}${
premium ? "_premium" : ""
}.webp`}
style={{ width: "1.25em", height: "1.25em" }}
/>
@@ -893,7 +883,7 @@ function ConsumablesFilter() {
height: "1.25em",
objectFit: "contain",
}}
src={asset(`icons/consumables/${consumable}.webp`)}
src={`/api/icons/consumables/${consumable}.webp`}
/>
))}
@@ -938,7 +928,7 @@ function ConsumablesFilter() {
height: "1.25em",
objectFit: "contain",
}}
src={asset(`icons/consumables/${consumable}.webp`)}
src={`/api/icons/consumables/${consumable}.webp`}
/>
{unwrap(consumableDefinition.name!)}
@@ -987,7 +977,7 @@ function ProvisionsFilter() {
height: "1.25em",
objectFit: "contain",
}}
src={asset(`icons/provisions/${provision}.webp`)}
src={`/api/icons/provisions/${provision}.webp`}
/>
))}
@@ -1032,7 +1022,7 @@ function ProvisionsFilter() {
height: "1.25em",
objectFit: "contain",
}}
src={asset(`icons/provisions/${provision}.webp`)}
src={`/api/icons/provisions/${provision}.webp`}
/>
{unwrap(provisionDefinition.name!)}
@@ -1075,8 +1065,8 @@ function GameModeAbilitiesFilter() {
: rawPowers;
const icons = [
...abilities.map((ability) => `icons/consumables/${ability}.webp`),
...powers.map((power) => `icons/provisions/${power}.webp`),
...abilities.map((ability) => `api/icons/consumables/${ability}.webp`),
...powers.map((power) => `api/icons/provisions/${power}.webp`),
];
return (
@@ -1094,7 +1084,7 @@ function GameModeAbilitiesFilter() {
height: "1.25em",
objectFit: "contain",
}}
src={asset(icon)}
src={icon}
/>
))}
@@ -1161,7 +1151,7 @@ function GameModeAbilitiesFilter() {
height: "1.25em",
objectFit: "contain",
}}
src={asset(`icons/consumables/${consumable}.webp`)}
src={`/api/icons/consumables/${consumable}.webp`}
/>
{unwrap(abilityDefinition.name!)}
@@ -1210,7 +1200,7 @@ function GameModeAbilitiesFilter() {
height: "1.25em",
objectFit: "contain",
}}
src={asset(`icons/provisions/${provision}.webp`)}
src={`/api/icons/provisions/${provision}.webp`}
/>
{unwrap(powerDefinition.name!)}
@@ -1,7 +1,7 @@
import { Flex, Separator, Text } from "@radix-ui/themes";
import { isEqual } from "lodash-es";
import { useMemo } from "react";
import { awaitableTankDefinitions } from "../../../core/awaitables/tankDefinitions";
import { api } from "../../../core/blitzkit/api";
import { useLocale } from "../../../hooks/useLocale";
import { TankFilters } from "../../../stores/tankFilters";
import { TankopediaPersistent } from "../../../stores/tankopediaPersistent";
@@ -9,23 +9,23 @@ import { TankSort } from "../../../stores/tankopediaSort";
import { TankCard } from "../../TankCard";
import { TankCardWrapper } from "./TankCardWrapper";
const tankDefinitions = await awaitableTankDefinitions;
const tankDefinitions = await api.tankDefinitions();
export function RecentlyViewed() {
const filters = TankFilters.use();
// non-reactive because it is a little weird that it updates instantly even before the page loads
const recentlyViewed = TankopediaPersistent.state.recentlyViewed.filter(
(id) => id in tankDefinitions.tanks
(id) => id in tankDefinitions.tanks,
);
const hasFilters = useMemo(
() =>
Object.entries(filters).some(([key, value]) => {
return !isEqual(
value,
TankFilters.initial[key as keyof typeof TankFilters.initial]
TankFilters.initial[key as keyof typeof TankFilters.initial],
);
}),
[filters]
[filters],
);
const { strings } = useLocale();
const by = TankSort.use((state) => state.by);
@@ -12,10 +12,8 @@ import fuzzysort from "fuzzysort";
import { times, uniq } from "lodash-es";
import { memo, useEffect, useMemo, useState } from "react";
import usePromise from "react-promise-suspense";
import { awaitableGameDefinitions } from "../../core/awaitables/gameDefinitions";
import { awaitableModelDefinitions } from "../../core/awaitables/modelDefinitions";
import { awaitableTankDefinitions } from "../../core/awaitables/tankDefinitions";
import { awaitableTankNames } from "../../core/awaitables/tankNames";
import { api } from "../../core/blitzkit/api";
import { filterTanks } from "../../core/blitzkit/filterTanks";
import { resolveReload } from "../../core/blitzkit/resolveReload";
import { useLocale } from "../../hooks/useLocale";
@@ -47,9 +45,9 @@ const DEFAULT_LOADED_CARDS = 64;
const [gameDefinitions, modelDefinitions, tankDefinitions, tankNames] =
await Promise.all([
awaitableGameDefinitions,
awaitableModelDefinitions,
awaitableTankDefinitions,
api.gameDefinitions(),
api.modelDefinitions(),
api.tankDefinitions(),
awaitableTankNames,
]);
@@ -1,3 +0,0 @@
import { fetchConsumableDefinitions } from '@blitzkit/core';
export const awaitableConsumableDefinitions = fetchConsumableDefinitions();
@@ -1,3 +0,0 @@
import { fetchGameDefinitions } from '@blitzkit/core';
export const awaitableGameDefinitions = fetchGameDefinitions();
@@ -1,3 +0,0 @@
import { fetchModelDefinitions } from '@blitzkit/core';
export const awaitableModelDefinitions = fetchModelDefinitions();
@@ -1,3 +0,0 @@
import { fetchProvisionDefinitions } from '@blitzkit/core';
export const awaitableProvisionDefinitions = fetchProvisionDefinitions();
@@ -1,3 +0,0 @@
import { fetchTankDefinitions } from '@blitzkit/core';
export const awaitableTankDefinitions = fetchTankDefinitions();
@@ -1,3 +1,4 @@
import { fetchTankNames } from '@blitzkit/core';
import { fetchTankNames } from "@blitzkit/core";
import { api } from "../blitzkit/api";
export const awaitableTankNames = fetchTankNames();
export const awaitableTankNames = fetchTankNames(api);
+2 -1
View File
@@ -3,11 +3,12 @@ import {
ServerBlitzKitAPI,
type BlitzKitAPI,
} from "@blitzkit/core";
import { vfs } from "./vfs";
let _api: BlitzKitAPI;
if (import.meta.env.SSR) {
_api = new ServerBlitzKitAPI();
_api = await new ServerBlitzKitAPI(vfs).init();
} else {
_api = new ClientBlitzKitAPI();
}
@@ -0,0 +1,15 @@
import { assertSecret } from "@blitzkit/core";
import type { GetStaticPaths } from "astro";
export function chunkedStaticPaths(chunk: string) {
return function () {
const chunksEnv = assertSecret(import.meta.env.CHUNKS);
const chunks = chunksEnv.split(",");
if (chunksEnv !== "*" && !chunks.includes(chunk)) {
return [];
}
return [{ params: { [`chunk_${chunk}`]: chunk } }];
} satisfies GetStaticPaths;
}
@@ -1,21 +1,19 @@
import type { TankDefinition } from "@blitzkit/core";
import { checkConsumableProvisionInclusivity } from "@blitzkit/core/src/blitzkit/checkConsumableProvisionInclusivity";
import { times } from "lodash-es";
import { awaitableConsumableDefinitions } from "../../core/awaitables/consumableDefinitions";
import type { TankFilters } from "../../stores/tankFilters";
import { awaitableGameDefinitions } from "../awaitables/gameDefinitions";
import { awaitableProvisionDefinitions } from "../awaitables/provisionDefinitions";
import { api } from "./api";
const SHELLS = times(3, (index) => index);
const consumableDefinitions = await awaitableConsumableDefinitions;
const provisionDefinitions = await awaitableProvisionDefinitions;
const gameDefinitions = await awaitableGameDefinitions;
const consumableDefinitions = await api.consumableDefinitions();
const provisionDefinitions = await api.provisionDefinitions();
const gameDefinitions = await api.gameDefinitions();
export async function filterTank(
filters: TankFilters,
tank: TankDefinition,
owned: number[] = []
owned: number[] = [],
) {
return (
((filters.showOwned && owned.includes(tank.id)) ||
@@ -29,15 +27,15 @@ export async function filterTank(
(filters.gunType.length === 0 ||
(filters.gunType.includes("regular") &&
tank.turrets.some((turret) =>
turret.guns.some((gun) => gun.gun_type!.$case === "regular")
turret.guns.some((gun) => gun.gun_type!.$case === "regular"),
)) ||
(filters.gunType.includes("auto_loader") &&
tank.turrets.some((turret) =>
turret.guns.some((gun) => gun.gun_type!.$case === "auto_loader")
turret.guns.some((gun) => gun.gun_type!.$case === "auto_loader"),
)) ||
(filters.gunType.includes("auto_reloader") &&
tank.turrets.some((turret) =>
turret.guns.some((gun) => gun.gun_type!.$case === "auto_reloader")
turret.guns.some((gun) => gun.gun_type!.$case === "auto_reloader"),
))) &&
tank.turrets.some((turret) =>
turret.guns.some((gun) =>
@@ -45,9 +43,9 @@ export async function filterTank(
(index) =>
filters.shells[index] === null ||
gun.shells[index] === undefined ||
gun.shells[index].type === filters.shells[index]
)
)
gun.shells[index].type === filters.shells[index],
),
),
) &&
(filters.consumables.length === 0 ||
filters.consumables.every((consumable) =>
@@ -56,10 +54,10 @@ export async function filterTank(
checkConsumableProvisionInclusivity(
consumableDefinitions.consumables[consumable],
tank,
gun
)
)
)
gun,
),
),
),
)) &&
(filters.provisions.length === 0 ||
filters.provisions.every((provision) =>
@@ -68,22 +66,22 @@ export async function filterTank(
checkConsumableProvisionInclusivity(
provisionDefinitions.provisions[provision],
tank,
gun
)
)
)
gun,
),
),
),
)) &&
(filters.abilities.length === 0 ||
Object.values(tank.roles).some((id) =>
gameDefinitions.roles[id as unknown as number].consumables.some(
(consumable) => filters.abilities.includes(consumable)
)
(consumable) => filters.abilities.includes(consumable),
),
)) &&
(filters.powers.length === 0 ||
Object.values(tank.roles).some((id) =>
gameDefinitions.roles[id as unknown as number].provisions.some(
(consumable) => filters.powers.includes(consumable)
)
(consumable) => filters.powers.includes(consumable),
),
))
);
}
@@ -0,0 +1,32 @@
import type {
GetStaticPathsItem,
GetStaticPathsOptions,
GetStaticPathsResult,
} from "astro";
type Promisable<T> = T | Promise<T>;
export function mixStaticPaths<
TypeA extends GetStaticPathsItem,
TypeB extends GetStaticPathsItem,
>(
a: (options: GetStaticPathsOptions) => Promisable<TypeA[]>,
b: (options: GetStaticPathsOptions) => Promisable<TypeB[]>,
) {
return async function (options: GetStaticPathsOptions) {
const pathsA = await a(options);
const pathsB = await b(options);
const paths: GetStaticPathsResult = [];
for (const pathA of pathsA) {
for (const pathB of pathsB) {
paths.push({
params: { ...pathA.params, ...pathB.params },
props: { ...pathA.props, ...pathB.props },
});
}
}
return paths as (TypeA & TypeB)[];
};
}
@@ -0,0 +1,5 @@
import { LocalVFS } from "@blitzkit/core";
export const vfs = new LocalVFS(
"/run/media/tresabhi/Windows/Program Files/WindowsApps/7458BE2C.WorldofTanksBlitz_11.19.272.0_x64__x4tje2y229k00",
);
@@ -0,0 +1,3 @@
import { chunkedStaticPaths } from "../../core/blitzkit/chunkedStaticPaths";
export const getStaticPaths = chunkedStaticPaths("api");
@@ -0,0 +1,39 @@
import type { APIContext, GetStaticPathsItem } from "astro";
import sharp from "sharp";
import { mixStaticPaths } from "../../../../core/blitzkit/mixStaticPaths";
import { vfs } from "../../../../core/blitzkit/vfs";
import { getStaticPaths as _getStaticPaths } from "../../_index";
export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => {
const paths: GetStaticPathsItem[] = [];
const circleFiles = await vfs
.dir(`Data/Gfx/Lobby/flags`)
.then((files) =>
files.filter(
(flag) =>
flag.startsWith("flag_profile-stat_") &&
!flag.endsWith("@2x.packed.webp"),
),
);
for (const flag of circleFiles) {
const path = `Data/Gfx/Lobby/flags/${flag}`;
const id = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1];
paths.push({
params: { id },
props: { path },
});
}
return paths;
});
export async function GET({ props }: APIContext<{ path: string }>) {
const image = sharp(await vfs.file(props.path));
const content = await image.trim({ threshold: 100 }).toBuffer();
const bytes = new Uint8Array(content);
return new Response(bytes);
}
@@ -1,7 +1,7 @@
---
import ToolOpenGraph from "../../../components/ToolOpenGraph.astro";
import { tools } from "../../../constants/tools";
import BaseLayout from "../../../layouts/BaseLayout.astro";
import ToolOpenGraph from "../../../../components/ToolOpenGraph.astro";
import { tools } from "../../../../constants/tools";
import BaseLayout from "../../../../layouts/BaseLayout.astro";
import type { getStaticPaths } from "../index.astro";
import { Page } from "./_index";
Loaded 100 of 113 files, more files were not shown because too many files have changed in this diff. Show more