Compare commits

...
20 Commits
Author SHA1 Message Date
tresabhi ba17aae706 feat: bump int size 2025-03-25 15:29:41 -05:00
TrèsAbhi 30ca5c053a Update tankNames.ts 2025-03-14 12:14:55 -05:00
tresabhi c36419f5b6 fix: don't include cue4 2025-03-11 10:40:02 -05:00
tresabhi 1879895db2 feat: add 124 support 2025-03-11 10:13:02 -05:00
tresabhi c964e3c8ec feat: google crawler 2025-03-03 17:49:45 -06:00
tresabhi 2ef6d18f82 lol why cue4??? 2025-03-03 16:19:43 -06:00
tresabhi 10b672572b feat: try appending dvpl? 2025-03-03 16:15:58 -06:00
TrèsAbhi 2a4efa8cd2 fix: check for changes for real 2025-03-03 12:29:25 -06:00
TrèsAbhi 5a8435da29 Update Footer.astro 2025-03-03 12:15:05 -06:00
TrèsAbhi 3461349a96 Update Footer.astro 2025-03-03 12:13:06 -06:00
TrèsAbhi 3791e9df12 New Crowdin updates (#147)
* New translations en.json (French)

* New translations en.json (French)

* New translations en.json (Ukrainian)

* New translations en.json (Ukrainian)

* New translations en.json (Portuguese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (French)

* New translations en.json (French)

* New translations en.json (Ukrainian)

* New translations en.json (French)

* New translations en.json (French)

* New translations en.json (Ukrainian)

* New translations en.json (Ukrainian)

* New translations en.json (Japanese)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Portuguese)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Russian)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Russian)
2025-03-03 11:10:15 -06:00
TrèsAbhi b3c36aac93 New Crowdin updates (#146)
* New translations en.json (Polish)

* New translations en.json (Polish)

* New translations en.json (Japanese)

* New translations en.json (Japanese)

* New translations en.json (Japanese)

* New translations en.json (Japanese)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Ukrainian)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Spanish)

* New translations en.json (Ukrainian)

* New translations en.json (Ukrainian)

* New translations en.json (Portuguese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Polish)

* New translations en.json (Polish)

* New translations en.json (Spanish)

* New translations en.json (Japanese)

* New translations en.json (Chinese Simplified)

* New translations en.json (Japanese)

* New translations en.json (Japanese)

* New translations en.json (Ukrainian)

* New translations en.json (Polish)

* New translations en.json (Chinese Simplified)

* New translations en.json (Ukrainian)

* New translations en.json (Ukrainian)

* New translations en.json (Russian)

* New translations en.json (French)

* New translations en.json (Chinese Simplified)

* New translations en.json (Chinese Simplified)

* New translations en.json (Ukrainian)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Ukrainian)

* New translations en.json (Ukrainian)

* New translations en.json (Portuguese)

* New translations en.json (Portuguese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Portuguese)

* New translations en.json (Portuguese)

* New translations en.json (Portuguese)

* New translations en.json (Chinese Simplified)
2025-02-03 11:07:41 -06:00
TrèsAbhi c0895409bc Update index.ts 2025-01-24 11:27:45 -06:00
TrèsAbhi 438b565cbb New Crowdin updates (#145) 2025-01-19 13:00:15 -06:00
tresabhi cf1a82e89b fix: remove default 2025-01-19 12:51:26 -06:00
tresabhi 0506e361b2 feat: more prune 2025-01-19 12:46:57 -06:00
tresabhi d6a1357a82 Merge branch 'main' into dev 2025-01-19 12:41:06 -06:00
tresabhi a5a1dbd51b fix: [Oo] for /debug 2025-01-18 14:16:49 -06:00
tresabhi 5201350e44 fix: [Oo] for /stats 2025-01-18 14:16:26 -06:00
tresabhi 6a84b9d5ae fix: stricter pattern 2025-01-18 14:07:47 -06:00
33 changed files with 7770 additions and 6105 deletions

No files matched your search

+1
View File
@@ -27,3 +27,4 @@ target
/.vercel
/.astro
.vercel
/src
+7
View File
@@ -0,0 +1,7 @@
# BlitzKit 1.27.2
This update only affects the website.
## Fixes
- The new Improved Vertical Stabilizer equipment which only affects the gun depression found on the Type 63 now works
+9
View File
@@ -0,0 +1,9 @@
# BlitzKit 1.27.3
This update only affects the bot.
## Fixes
- Added support for 64-bit IDs allowing users with new accounts to link with BlitzKit
- This comes at the added cost of resetting the links of all other accounts
- Just re-link and you're good to go
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "blitzkit",
"private": true,
"version": "1.27.1",
"version": "1.27.3",
"description": "🎉 Tools for everything World of Tanks Blitz",
"type": "module",
"types": "./types.d.ts",
+1 -1
View File
@@ -17,7 +17,7 @@ export const debugCommand = new Promise<CommandRegistry>((resolve) => {
const list = [
[strings.bot.commands.debug.body.version, packageJSON.version],
[
strings.bot.commands.debug.body.shard,
strings.bot.commands.debug.body.shard.label,
client.shard?.ids[0] ?? strings.bot.commands.debug.body.shard.default,
],
[
@@ -8,12 +8,12 @@ export async function filtersToDescription(
{ nation, tier, type, class: tankClass, tank }: StatFilters,
locale: Locale,
) {
const { strings } = translator(locale);
const { strings, bkLocale } = translator(locale);
const awaitedTankDefinitions = await fetchTankDefinitions();
const info: string[] = [];
// TODO: somehow localize tank names?
if (tank) return awaitedTankDefinitions.tanks[tank].name;
if (tank) return awaitedTankDefinitions.tanks[tank].name.locales[bkLocale];
if (nation)
info.push((strings.common.nations as Record<string, string>)[nation]);
if (tier) {
@@ -8,6 +8,8 @@ export async function getBlitzFromDiscord(discordId: bigint) {
if (unique === null) return null;
await flagUserActivity(unique.blitz_id);
return { id: unique.blitz_id, region: idToRegion(unique.blitz_id) };
const id = Number(unique.blitz_id);
await flagUserActivity(id);
return { id, region: idToRegion(id) };
}
@@ -3,7 +3,8 @@ import { Locale } from 'discord.js';
import { SUPPORTED_LOCALES_DISCORD } from '../localization/strings/constants';
import { translator } from '../localization/translator';
const validNameRegex = /^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$/u;
const validNameRegex =
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
export function localizationObject(
path: (strings: BlitzKitStrings) => string,
@@ -12,8 +12,9 @@ export function translator(localeRaw: Locale) {
SUPPORTED_LOCALES_DISCORD.includes(localeRaw)
? localeRaw
: DEFAULT_LOCALE_DISCORD;
const strings = STRINGS[SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]];
const unwrap = unwrapper(SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]);
const bkLocale = SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale];
const strings = STRINGS[bkLocale];
const unwrap = unwrapper(bkLocale);
return { locale, strings, unwrap };
return { locale, strings, unwrap, bkLocale };
}
+3 -1
View File
@@ -26,8 +26,10 @@ export async function fetchTankNames() {
searchableName: tank.name_full ?? tank.name,
searchableNameDeburr,
camouflages: tank.camouflages
?.map((id) => camouflageDefinitions.camouflages[id]?.name)
?.map((id) => SUPPORTED_LOCALES.map((locale) => camouflageDefinitions.camouflages[id]?.name.locales[locale]))
.flat()
.filter(Boolean)
.map(deburr)
.join(' '),
treeType: tank.type,
};
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+5 -3
View File
@@ -1,5 +1,4 @@
import { assertSecret } from '@blitzkit/core';
import { existsSync } from 'fs';
import { mkdir, writeFile } from 'fs/promises';
import { parse as parsePath } from 'path';
import ProgressBar from 'progress';
@@ -57,9 +56,12 @@ while (true) {
console.warn(`Failed to make directory "${dir}"`);
}
const isDvpl = path.endsWith('.dvpl');
const buffer = Buffer.from(data);
await writeFile(
`${DATA}/${path}`,
new Uint8Array(writeDVPL(Buffer.from(data))),
`${DATA}/${path}${isDvpl ? '' : '.dvpl'}`,
new Uint8Array(isDvpl ? buffer : writeDVPL(buffer)),
);
bar.tick();
@@ -6,7 +6,7 @@ import { TextureMutation } from './constants';
export async function readTexture(path: string, mutation?: TextureMutation) {
const ddsTexturePath = path.replace('.tex', '.dx11.dds');
const isDds = existsSync(ddsTexturePath);
const isDds = existsSync(`${ddsTexturePath}.dvpl`);
const resolvedTexturePath = isDds
? ddsTexturePath
: ddsTexturePath.replace('.dds', '.pvr');
@@ -30,10 +30,7 @@ export async function commitMultipleFiles(
} else if (response.status === 200) {
const buffer = Buffer.from(await response.arrayBuffer());
// we discard blob if they're the same size; it's unlikely their
// contents will be different; I love playing russian roulette!
const equal = buffer.length === change.content.length || buffer.equals(change.content);
if (!equal) {
if (!buffer.equals(change.content)) {
const diff = change.content.length - buffer.length;
console.log(
+7 -3
View File
@@ -8,7 +8,7 @@ import { writeFile } from 'fs/promises';
const ROOT = '@blitzkit/i18n/strings';
const WORKING_ROOT = '../../packages/i18n/strings';
const defaultStrings = await import(`${ROOT}/${DEFAULT_LOCALE}.json`);
const defaultStrings = require(`${ROOT}/${DEFAULT_LOCALE}.json`).default;
const nonDefaultLocales = SUPPORTED_LOCALES.filter(
(locale) => locale !== DEFAULT_LOCALE,
);
@@ -19,9 +19,13 @@ function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
if (typeof defaultStrings[key] === typeof strings[key]) {
if (typeof strings[key] === 'string') {
if (
// are equivalent regardless of %s flavor
(defaultStrings[key] as string).replaceAll(/%s\d/g, '%s') ===
(strings[key] as string).replaceAll(/%s\d/g, '%s') ||
strings[key] === ''
// string is empty
strings[key] === '' ||
// string has old flavor of %s
strings[key].match(/%s([^\d]|$)/g) !== null
) {
delete strings[key];
}
@@ -42,7 +46,7 @@ function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
for (const locale of nonDefaultLocales) {
console.log(`Pruning ${locale}...`);
const strings = await import(`${ROOT}/${locale}.json`);
const strings = require(`${ROOT}/${locale}.json`).default;
const pruned = prune(defaultStrings, strings);
writeFile(`${WORKING_ROOT}/${locale}.json`, JSON.stringify(pruned, null, 2));
@@ -180,6 +180,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const hasDownImprovedVerticalStabilizer = await hasEquipment(
124,
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const boundingRect = canvas.getBoundingClientRect();
delta.set(event.clientX, event.clientY).sub(position);
@@ -191,6 +196,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
@@ -275,6 +281,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const hasDownImprovedVerticalStabilizer = await hasEquipment(
124,
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const boundingRect = canvas.getBoundingClientRect();
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
@@ -285,6 +296,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
@@ -357,6 +369,11 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const hasDownImprovedVerticalStabilizer = await hasEquipment(
124,
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const boundingRect = canvas.getBoundingClientRect();
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
@@ -367,6 +384,7 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
@@ -107,6 +107,7 @@ export function Characteristics() {
const hasSupercharger = useEquipment(107);
const hasCalibratedShells = useEquipment(103);
const hasImprovedVerticalStabilizer = useEquipment(122);
const hasDownImprovedVerticalStabilizer = useEquipment(124);
const penetrationCoefficient = coefficient([
hasCalibratedShells,
resolvePenetrationCoefficient(true, shell.type) - 1,
@@ -129,9 +130,10 @@ export function Characteristics() {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
});
}, [hasImprovedVerticalStabilizer]);
}, [hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer]);
return (
<Flex
@@ -25,6 +25,7 @@ export function QuickInputs() {
const initialGunPitch =
tankModelDefinition.initial_turret_rotation?.pitch ?? 0;
const hasImprovedVerticalStabilizer = useEquipment(122);
const hasDownImprovedVerticalStabilizer = useEquipment(124);
useEffect(() => {
if (!yawInput.current) return;
@@ -92,6 +93,7 @@ export function QuickInputs() {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
mutateDuel((state) => {
@@ -133,6 +135,7 @@ export function QuickInputs() {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
mutateDuel((state) => {
@@ -118,6 +118,11 @@ export function Controls({ naked }: ControlsProps) {
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const hasDownImprovedVerticalStabilizer = await hasEquipment(
124,
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
switch (event) {
case Pose.HullDown: {
@@ -127,6 +132,7 @@ export function Controls({ naked }: ControlsProps) {
protagonistGunModelDefinition.pitch,
protagonistTurretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
camera.position
@@ -159,6 +165,7 @@ export function Controls({ naked }: ControlsProps) {
protagonistGunModelDefinition.pitch,
protagonistTurretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
camera.position
@@ -185,6 +185,11 @@ export function TankModel() {
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const hasDownImprovedVerticalStabilizer = await hasEquipment(
124,
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const boundingRect = canvas.getBoundingClientRect();
delta.set(event.clientX, event.clientY).sub(position);
@@ -196,6 +201,7 @@ export function TankModel() {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
@@ -287,6 +293,11 @@ export function TankModel() {
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const hasDownImprovedVerticalStabilizer = await hasEquipment(
124,
duel.protagonist.tank.equipment_preset,
duel.protagonist.equipmentMatrix,
);
const boundingRect = canvas.getBoundingClientRect();
delta.set(event.clientX, event.clientY).sub(position);
position.set(event.clientX, event.clientY);
@@ -297,6 +308,7 @@ export function TankModel() {
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
}
@@ -41,6 +41,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
const canvas = useRef<HTMLCanvasElement>(null);
const hasImprovedVerticalStabilizer = useEquipment(122);
const hasDownImprovedVerticalStabilizer = useEquipment(124);
const protagonistGun = Duel.use((state) => state.protagonist.gun);
const protagonistTurret = Duel.use((state) => state.protagonist.turret);
const mutateDuel = Duel.useMutation();
@@ -82,6 +83,7 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
gunModelDefinition.pitch,
turretModelDefinition.yaw,
hasImprovedVerticalStabilizer,
hasDownImprovedVerticalStabilizer,
);
modelTransformEvent.emit({ pitch, yaw });
@@ -12,6 +12,7 @@ export function applyPitchYawLimits(
pitchLimits: PitchLimits, // deg
yawLimits?: YawLimits, // deg
verticalStabilizer = false,
downVerticalStabilizer = false,
) {
let newPitch = pitch;
let newYaw = yaw;
@@ -22,7 +23,8 @@ export function applyPitchYawLimits(
);
}
const depressionBuff = verticalStabilizer ? degToRad(3) : 0;
const depressionBuff =
verticalStabilizer || downVerticalStabilizer ? degToRad(3) : 0;
const elevationBuff = verticalStabilizer ? degToRad(4) : 0;
let lowerPitch = -degToRad(pitchLimits.max) - depressionBuff;
let upperPitch = -degToRad(pitchLimits.min) + elevationBuff;
@@ -109,6 +109,7 @@ export function tankCharacteristics(
const hasEngineAccelerator = equipment(117);
const hasCamouflageNet = equipment(115);
const hasImprovedVerticalStabilizer = equipment(122);
const hasDownImprovedVerticalStabilizer = equipment(124);
const hasImprovedSuspension = equipment(123);
const hasTungsten = consumable(45);
@@ -425,7 +426,8 @@ export function tankCharacteristics(
const gunDepression =
gunModelDefinition.pitch.max +
gunDefaultPitch +
(hasImprovedVerticalStabilizer ? 3 : 0);
(hasImprovedVerticalStabilizer ? 3 : 0) +
(hasDownImprovedVerticalStabilizer ? 3 : 0);
const gunElevation =
-gunModelDefinition.pitch.min -
gunDefaultPitch +
@@ -39,7 +39,11 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
window.location.pathname.startsWith(`/${locale}`),
);
if (!isAPI && bestLocale !== currentPathLocale) {
if (
!isAPI && // not an api, duh!
localStorage.getItem('preferred-locale') !== null && // no preference, so probably google's crawler
bestLocale !== currentPathLocale // we need to redirect
) {
window.location.pathname = isI18nPath
? window.location.pathname.replace(
`/${currentPathLocale}`,
+3 -16
View File
@@ -9,28 +9,15 @@ datasource db {
}
model User {
blitz_id Int @id @map("blitz") // map: "blitz" was too vague
last_used DateTime? @default(now())
tank_votes TankVote[]
blitz_id BigInt @id @map("blitz") // map: "blitz" was too vague
last_used DateTime? @default(now())
@@map("Users") // map: "Users" was mistakenly plural
}
model TankVote {
id Int @id
last_updated DateTime @default(now())
easiness Int?
firepower Int?
maneuverability Int?
survivability Int?
user User @relation(fields: [user_blitz_id], references: [blitz_id])
user_blitz_id Int
}
model DiscordUser {
discord_id BigInt @id @map("discord") // map: "discord" was too vague
blitz_id Int @map("blitz") // map: "blitz" was too vague
blitz_id BigInt @map("blitz") // map: "blitz" was too vague
@@map("DiscordUsers") // map: "DiscordUsers" was mistakenly plural
}