mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
Merge branch 'main' into ue
This commit is contained in:
commit
d9c7d31017
17 files changed
+228
-43
No files matched your search
@@ -0,0 +1,12 @@
|
|||||||
|
# BlitzKit 1.30.2
|
||||||
|
|
||||||
|
Thank you to [GonnaHetzMe](https://github.com/karelpak1) for your contributions this update.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- [GonnaHetzMe] Tungsten shells are now properly cropped
|
||||||
|
- Equalizer no longer gives insanely high penetration values
|
||||||
|
- The tank reveal animation no longer repeats when you scroll away and back to the tank sandbox
|
||||||
|
- [GonnaHetzMe] The RHM. Pzw.'s turret no longer has the floating plate
|
||||||
|
- Please give BlitzKit up to 1 hour to update the model
|
||||||
|
- [GonnaHetzMe] Tanks with inclined turret rings like the Minotauro now display the correct pitch in the tank sandbox inputs
|
||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "Nivel",
|
"tier": "Nivel",
|
||||||
"type": "Tipo",
|
"type": "Tipo",
|
||||||
"dev_id": "DEV: ID",
|
"dev_id": "DEV: ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "Precio de compra",
|
"purchase": "Precio de compra",
|
||||||
"restoration": "Precio de restauración",
|
"restoration": "Precio de restauración",
|
||||||
"sale": "Precio de venta",
|
"sale": "Precio de venta",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "",
|
"title": "",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Equalizer",
|
||||||
|
"equalize": "Equalize",
|
||||||
|
"beta": "Beta"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "Módulos",
|
"title": "Módulos",
|
||||||
"stock": "Base",
|
"stock": "Base",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "Limpiar",
|
"clear": "Limpiar",
|
||||||
"maximize": "Maximizar"
|
"maximize": "Maximizar",
|
||||||
|
"equalize": "Equalize"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "Base",
|
"stock": "Base",
|
||||||
|
|||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "Rang",
|
"tier": "Rang",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"dev_id": "DEV: ID",
|
"dev_id": "DEV: ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "Purchase price",
|
"purchase": "Purchase price",
|
||||||
"restoration": "Restoration price",
|
"restoration": "Restoration price",
|
||||||
"sale": "Sale price",
|
"sale": "Sale price",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Configuration",
|
"title": "Configuration",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Equalizer",
|
||||||
|
"equalize": "Equalize",
|
||||||
|
"beta": "Beta"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "Modules",
|
"title": "Modules",
|
||||||
"stock": "Stock",
|
"stock": "Stock",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"maximize": "Maximize"
|
"maximize": "Maximize",
|
||||||
|
"equalize": "Equalize"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "Stock",
|
"stock": "Stock",
|
||||||
|
|||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "Tier",
|
"tier": "Tier",
|
||||||
"type": "タイプ",
|
"type": "タイプ",
|
||||||
"dev_id": "DEV: ID",
|
"dev_id": "DEV: ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "購入価格",
|
"purchase": "購入価格",
|
||||||
"restoration": "再購入価格",
|
"restoration": "再購入価格",
|
||||||
"sale": "売却価格",
|
"sale": "売却価格",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "構成",
|
"title": "構成",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Equalizer",
|
||||||
|
"equalize": "Equalize",
|
||||||
|
"beta": "Beta"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "モジュール",
|
"title": "モジュール",
|
||||||
"stock": "初期装備",
|
"stock": "初期装備",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "クリア",
|
"clear": "クリア",
|
||||||
"maximize": "最大"
|
"maximize": "最大",
|
||||||
|
"equalize": "Equalize"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "初期装備",
|
"stock": "初期装備",
|
||||||
|
|||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "Poziom",
|
"tier": "Poziom",
|
||||||
"type": "Rodzaj",
|
"type": "Rodzaj",
|
||||||
"dev_id": "DEV: ID",
|
"dev_id": "DEV: ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "Purchase price",
|
"purchase": "Purchase price",
|
||||||
"restoration": "Restoration price",
|
"restoration": "Restoration price",
|
||||||
"sale": "Sale price",
|
"sale": "Sale price",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Configuration",
|
"title": "Configuration",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Equalizer",
|
||||||
|
"equalize": "Equalize",
|
||||||
|
"beta": "Beta"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "Modules",
|
"title": "Modules",
|
||||||
"stock": "Stock",
|
"stock": "Stock",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"maximize": "Maximize"
|
"maximize": "Maximize",
|
||||||
|
"equalize": "Equalize"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "Stock",
|
"stock": "Stock",
|
||||||
|
|||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "Nível",
|
"tier": "Nível",
|
||||||
"type": "Tipo",
|
"type": "Tipo",
|
||||||
"dev_id": "DEV: ID",
|
"dev_id": "DEV: ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "Preço de compra",
|
"purchase": "Preço de compra",
|
||||||
"restoration": "Preço de recuperação",
|
"restoration": "Preço de recuperação",
|
||||||
"sale": "Preço de venda",
|
"sale": "Preço de venda",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Configuração",
|
"title": "Configuração",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Equalizer",
|
||||||
|
"equalize": "Equalize",
|
||||||
|
"beta": "Beta"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "Módulos",
|
"title": "Módulos",
|
||||||
"stock": "Padrão",
|
"stock": "Padrão",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "Limpar",
|
"clear": "Limpar",
|
||||||
"maximize": "Maximizar"
|
"maximize": "Maximizar",
|
||||||
|
"equalize": "Equalize"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "Padrão",
|
"stock": "Padrão",
|
||||||
|
|||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "Уровень",
|
"tier": "Уровень",
|
||||||
"type": "Тип",
|
"type": "Тип",
|
||||||
"dev_id": "DEV: ID",
|
"dev_id": "DEV: ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "Цена покупки",
|
"purchase": "Цена покупки",
|
||||||
"restoration": "Цена восстановления",
|
"restoration": "Цена восстановления",
|
||||||
"sale": "Цена продажи",
|
"sale": "Цена продажи",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Конфигурация",
|
"title": "Конфигурация",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Уравнение",
|
||||||
|
"equalize": "Уравнять",
|
||||||
|
"beta": "Бета"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "Модули",
|
"title": "Модули",
|
||||||
"stock": "Сток",
|
"stock": "Сток",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "Очистить",
|
"clear": "Очистить",
|
||||||
"maximize": "Максимум"
|
"maximize": "Максимум",
|
||||||
|
"equalize": "Уравнять"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "Сток",
|
"stock": "Сток",
|
||||||
|
|||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "Рівень",
|
"tier": "Рівень",
|
||||||
"type": "Вид",
|
"type": "Вид",
|
||||||
"dev_id": "DEV: ID",
|
"dev_id": "DEV: ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "Purchase price",
|
"purchase": "Purchase price",
|
||||||
"restoration": "Restoration price",
|
"restoration": "Restoration price",
|
||||||
"sale": "Sale price",
|
"sale": "Sale price",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Configuration",
|
"title": "Configuration",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Equalizer",
|
||||||
|
"equalize": "Equalize",
|
||||||
|
"beta": "Beta"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "Модулі",
|
"title": "Модулі",
|
||||||
"stock": "Stock",
|
"stock": "Stock",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "Очистити",
|
"clear": "Очистити",
|
||||||
"maximize": "Збільшити все"
|
"maximize": "Збільшити все",
|
||||||
|
"equalize": "Equalize"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "Stock",
|
"stock": "Stock",
|
||||||
|
|||||||
@@ -960,6 +960,7 @@
|
|||||||
"tier": "阶级",
|
"tier": "阶级",
|
||||||
"type": "战车类型",
|
"type": "战车类型",
|
||||||
"dev_id": "开发参数:ID",
|
"dev_id": "开发参数:ID",
|
||||||
|
"dev_name": "DEV: NAME",
|
||||||
"purchase": "购买价格",
|
"purchase": "购买价格",
|
||||||
"restoration": "恢复坦克价格",
|
"restoration": "恢复坦克价格",
|
||||||
"sale": "出售价格",
|
"sale": "出售价格",
|
||||||
@@ -980,6 +981,11 @@
|
|||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "配置设定",
|
"title": "配置设定",
|
||||||
|
"equalizer": {
|
||||||
|
"title": "Equalizer",
|
||||||
|
"equalize": "Equalize",
|
||||||
|
"beta": "Beta"
|
||||||
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"title": "坦克模块",
|
"title": "坦克模块",
|
||||||
"stock": "白板",
|
"stock": "白板",
|
||||||
@@ -1149,7 +1155,8 @@
|
|||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"clear": "清除",
|
"clear": "清除",
|
||||||
"maximize": "最大化"
|
"maximize": "最大化",
|
||||||
|
"equalize": "Equalize"
|
||||||
},
|
},
|
||||||
"modules": {
|
"modules": {
|
||||||
"stock": "白板",
|
"stock": "白板",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { AssetUploader } from "../core/github/assetUploader";
|
import { AssetUploader } from "../core/github/assetUploader";
|
||||||
|
import { parsePackedSpriteRect } from "../core/blitz/parsePackedSpriteRect";
|
||||||
import { vfs } from "./constants";
|
import { vfs } from "./constants";
|
||||||
import { ConsumablesCommon, ProvisionsCommon } from "./definitions";
|
import { ConsumablesCommon, ProvisionsCommon } from "./definitions";
|
||||||
|
|
||||||
@@ -13,6 +14,42 @@ interface Mappings {
|
|||||||
|
|
||||||
const listItemsPattern = /<items path="(.+)\.xml"\/>/g;
|
const listItemsPattern = /<items path="(.+)\.xml"\/>/g;
|
||||||
|
|
||||||
|
async function extractPackedIcon(
|
||||||
|
texture: sharp.Sharp,
|
||||||
|
sizes: number[],
|
||||||
|
context: string,
|
||||||
|
) {
|
||||||
|
const [left, top, width, height] = sizes;
|
||||||
|
const bounds = [left, top, width, height];
|
||||||
|
|
||||||
|
if (!bounds.every(Number.isInteger)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid RIFF sprite bounds for ${context}: ${bounds.join(" ")}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = await texture.metadata();
|
||||||
|
|
||||||
|
if (metadata.width === undefined || metadata.height === undefined) {
|
||||||
|
throw new Error(`Failed to read image dimensions for ${context}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
left < 0 ||
|
||||||
|
top < 0 ||
|
||||||
|
width <= 0 ||
|
||||||
|
height <= 0 ||
|
||||||
|
left + width > metadata.width ||
|
||||||
|
top + height > metadata.height
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`Out-of-bounds RIFF sprite for ${context}: ${bounds.join(" ")} in ${metadata.width}x${metadata.height}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await texture.clone().extract({ left, top, width, height }).toBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
export async function consumableProvisionIcons() {
|
export async function consumableProvisionIcons() {
|
||||||
console.log("Building consumable and provision icons...");
|
console.log("Building consumable and provision icons...");
|
||||||
|
|
||||||
@@ -57,8 +94,20 @@ export async function consumableProvisionIcons() {
|
|||||||
.replace(".txt", "");
|
.replace(".txt", "");
|
||||||
|
|
||||||
if (await vfs.resolve(`Data/${configPath}.packed.webp`)) {
|
if (await vfs.resolve(`Data/${configPath}.packed.webp`)) {
|
||||||
const image = sharp(await vfs.file(`Data/${configPath}.packed.webp`));
|
const packedBuffer = await vfs.file(`Data/${configPath}.packed.webp`);
|
||||||
const content = await image.trim({ threshold: 100 }).toBuffer();
|
const consumablesTexture = sharp(packedBuffer);
|
||||||
|
const sizes = parsePackedSpriteRect(packedBuffer);
|
||||||
|
let content: Buffer;
|
||||||
|
|
||||||
|
if (sizes) {
|
||||||
|
content = await extractPackedIcon(
|
||||||
|
consumablesTexture,
|
||||||
|
sizes,
|
||||||
|
`consumable ${consumable.icon}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
content = await consumablesTexture.trim({ threshold: 80 }).toBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
await uploader.add({
|
await uploader.add({
|
||||||
path: `icons/consumables/${consumable.id}.webp`,
|
path: `icons/consumables/${consumable.id}.webp`,
|
||||||
@@ -122,8 +171,20 @@ export async function consumableProvisionIcons() {
|
|||||||
.replace(".txt", "");
|
.replace(".txt", "");
|
||||||
|
|
||||||
if (await vfs.resolve(`Data/${configPath}.packed.webp`)) {
|
if (await vfs.resolve(`Data/${configPath}.packed.webp`)) {
|
||||||
const image = sharp(await vfs.file(`Data/${configPath}.packed.webp`));
|
const packedBuffer = await vfs.file(`Data/${configPath}.packed.webp`);
|
||||||
const content = await image.trim({ threshold: 100 }).toBuffer();
|
const provisionsTexture = sharp(packedBuffer);
|
||||||
|
const sizes = parsePackedSpriteRect(packedBuffer);
|
||||||
|
let content: Buffer;
|
||||||
|
|
||||||
|
if (sizes) {
|
||||||
|
content = await extractPackedIcon(
|
||||||
|
provisionsTexture,
|
||||||
|
sizes,
|
||||||
|
`provision ${provision.icon}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
content = await provisionsTexture.trim({ threshold: 80 }).toBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
await uploader.add({
|
await uploader.add({
|
||||||
path: `icons/provisions/${provision.id}.webp`,
|
path: `icons/provisions/${provision.id}.webp`,
|
||||||
|
|||||||
@@ -170,8 +170,12 @@ export async function extractModel(vfs: AbstractVFS, 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.
|
const localTranslation = component["tc.localTranslation"];
|
||||||
node.setTranslation(component["tc.localTranslation"]);
|
// The game resets top-level node translation to [0, 0, 0] on load.
|
||||||
|
// Child nodes must keep their authored local offsets.
|
||||||
|
node.setTranslation(
|
||||||
|
parent instanceof Scene ? [0, 0, 0] : localTranslation,
|
||||||
|
);
|
||||||
node.setRotation(component["tc.localRotation"]);
|
node.setRotation(component["tc.localRotation"]);
|
||||||
node.setScale(component["tc.localScale"]);
|
node.setScale(component["tc.localScale"]);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
const textDecoder = new TextDecoder();
|
||||||
|
|
||||||
|
function readFourCC(buffer: Uint8Array, offset: number) {
|
||||||
|
return textDecoder.decode(buffer.subarray(offset, offset + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parsePackedSpriteRect(buffer: Uint8Array): number[] | null {
|
||||||
|
if (
|
||||||
|
buffer.length < 12 ||
|
||||||
|
readFourCC(buffer, 0) !== "RIFF" ||
|
||||||
|
readFourCC(buffer, 8) !== "WEBP"
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const view = new DataView(
|
||||||
|
buffer.buffer,
|
||||||
|
buffer.byteOffset,
|
||||||
|
buffer.byteLength,
|
||||||
|
);
|
||||||
|
let offset = 12;
|
||||||
|
|
||||||
|
while (offset + 8 <= buffer.length) {
|
||||||
|
const chunkId = readFourCC(buffer, offset);
|
||||||
|
const chunkSize = view.getUint32(offset + 4, true);
|
||||||
|
const dataStart = offset + 8;
|
||||||
|
const dataEnd = dataStart + chunkSize;
|
||||||
|
|
||||||
|
if (dataEnd > buffer.length) return null;
|
||||||
|
|
||||||
|
if (chunkId === "extr") {
|
||||||
|
const lines = textDecoder
|
||||||
|
.decode(buffer.subarray(dataStart, dataEnd))
|
||||||
|
.replace(/\0/g, "")
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map((line) => line.trim().split(/\s+/).map(Number));
|
||||||
|
|
||||||
|
for (const values of lines) {
|
||||||
|
if (values.length < 4) continue;
|
||||||
|
if (!values.slice(0, 4).every(Number.isFinite)) continue;
|
||||||
|
if (values[2] <= 0 || values[3] <= 0) continue;
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = dataEnd + (chunkSize % 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { assertSecret } from "@blitzkit/core";
|
import { assertSecret, asset } from "@blitzkit/core";
|
||||||
import { Octokit } from "@octokit/rest";
|
import { Octokit } from "@octokit/rest";
|
||||||
import ProgressBar from "progress";
|
import ProgressBar from "progress";
|
||||||
import { compareUint8Arrays } from "./compareUint8Arrays";
|
import { compareUint8Arrays } from "./compareUint8Arrays";
|
||||||
@@ -49,9 +49,8 @@ export class AssetUploader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async add(change: FileChange) {
|
async add(change: FileChange) {
|
||||||
const blobPath = `${this.owner}/${this.repo}/${this.branch}/${change.path}`;
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`https://raw.githubusercontent.com/${blobPath}`,
|
asset(change.path),
|
||||||
{ headers: { "Accept-Encoding": "identity" } },
|
{ headers: { "Accept-Encoding": "identity" } },
|
||||||
);
|
);
|
||||||
let diff: { change: number; status: DiffStatus };
|
let diff: { change: number; status: DiffStatus };
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { assertSecret } from '@blitzkit/core';
|
import { assertSecret } from "@blitzkit/core";
|
||||||
|
|
||||||
const PUBLIC_GOOGLE_TAG_MANAGER_ID = assertSecret(
|
const PUBLIC_GOOGLE_TAG_MANAGER_ID = assertSecret(
|
||||||
import.meta.env.PUBLIC_GOOGLE_TAG_MANAGER_ID,
|
import.meta.env.PUBLIC_GOOGLE_TAG_MANAGER_ID,
|
||||||
@@ -19,7 +19,7 @@ const PUBLIC_GOOGLE_TAG_MANAGER_ID = assertSecret(
|
|||||||
dataLayer.push(arguments);
|
dataLayer.push(arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
gtag('js', new Date());
|
gtag("js", new Date());
|
||||||
|
|
||||||
gtag('config', PUBLIC_GOOGLE_TAG_MANAGER_ID);
|
gtag("config", PUBLIC_GOOGLE_TAG_MANAGER_ID);
|
||||||
</script>
|
</script>
|
||||||
+13
-14
@@ -21,19 +21,20 @@ export function QuickInputs() {
|
|||||||
const turretModelDefinition =
|
const turretModelDefinition =
|
||||||
tankModelDefinition.turrets[protagonist.turret.id];
|
tankModelDefinition.turrets[protagonist.turret.id];
|
||||||
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
|
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
|
||||||
const initialGunPitch =
|
const initialTurretPitch =
|
||||||
tankModelDefinition.initial_turret_rotation?.pitch ?? 0;
|
tankModelDefinition.initial_turret_rotation?.pitch ?? 0;
|
||||||
const hasImprovedVerticalStabilizer = useEquipment(122);
|
const hasImprovedVerticalStabilizer = useEquipment(122);
|
||||||
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
const hasDownImprovedVerticalStabilizer = useEquipment(124);
|
||||||
|
|
||||||
|
function displayPitch(pitch: number) {
|
||||||
|
return radToDeg(pitch) - initialTurretPitch;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function syncInputValues(data: ModelTransformEventData) {
|
function syncInputValues(data: ModelTransformEventData) {
|
||||||
if (!pitchInput.current || !yawInput.current) return;
|
if (!pitchInput.current || !yawInput.current) return;
|
||||||
|
|
||||||
pitchInput.current.value = (
|
pitchInput.current.value = displayPitch(data.pitch).toFixed(1);
|
||||||
radToDeg(data.pitch) +
|
|
||||||
(tankModelDefinition.initial_turret_rotation?.pitch ?? 0)
|
|
||||||
).toFixed(1);
|
|
||||||
yawInput.current.value = radToDeg(data.yaw).toFixed(1);
|
yawInput.current.value = radToDeg(data.yaw).toFixed(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ export function QuickInputs() {
|
|||||||
return () => {
|
return () => {
|
||||||
modelTransformEvent.off(handleTransformEvent);
|
modelTransformEvent.off(handleTransformEvent);
|
||||||
};
|
};
|
||||||
}, [initialGunPitch]);
|
}, [initialTurretPitch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
@@ -115,19 +116,17 @@ export function QuickInputs() {
|
|||||||
size="1"
|
size="1"
|
||||||
radius="full"
|
radius="full"
|
||||||
style={{ flex: 1, textAlign: "right" }}
|
style={{ flex: 1, textAlign: "right" }}
|
||||||
defaultValue={(
|
defaultValue={displayPitch(modelTransformEvent.last!.pitch).toFixed(1)}
|
||||||
radToDeg(modelTransformEvent.last!.pitch) + initialGunPitch
|
|
||||||
).toFixed(1)}
|
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
const value = Number(pitchInput.current!.value);
|
const value = Number(pitchInput.current!.value);
|
||||||
if (isNaN(value)) {
|
if (isNaN(value)) {
|
||||||
pitchInput.current!.value = (
|
pitchInput.current!.value = displayPitch(
|
||||||
radToDeg(modelTransformEvent.last!.pitch) + initialGunPitch
|
modelTransformEvent.last!.pitch,
|
||||||
).toFixed(1);
|
).toFixed(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const [pitch, yaw] = applyPitchYawLimits(
|
const [pitch, yaw] = applyPitchYawLimits(
|
||||||
degToRad(value + initialGunPitch),
|
degToRad(value + initialTurretPitch),
|
||||||
modelTransformEvent.last!.yaw,
|
modelTransformEvent.last!.yaw,
|
||||||
gunModelDefinition.pitch!,
|
gunModelDefinition.pitch!,
|
||||||
turretModelDefinition.yaw,
|
turretModelDefinition.yaw,
|
||||||
@@ -135,8 +134,8 @@ export function QuickInputs() {
|
|||||||
hasDownImprovedVerticalStabilizer,
|
hasDownImprovedVerticalStabilizer,
|
||||||
);
|
);
|
||||||
modelTransformEvent.dispatch({ pitch, yaw });
|
modelTransformEvent.dispatch({ pitch, yaw });
|
||||||
pitchInput.current!.value = (
|
pitchInput.current!.value = displayPitch(
|
||||||
radToDeg(modelTransformEvent.last!.pitch) + initialGunPitch
|
modelTransformEvent.last!.pitch,
|
||||||
).toFixed(1);
|
).toFixed(1);
|
||||||
}}
|
}}
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
|
|||||||
+4
-4
@@ -38,19 +38,19 @@ export function Lighting() {
|
|||||||
draft.revealed = true;
|
draft.revealed = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
t0.current = clock.elapsedTime - REVEAL_ANIMATION_TIME;
|
t0.current = performance.now() / 1000 - REVEAL_ANIMATION_TIME;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useFrame(({ invalidate }) => {
|
useFrame(({ invalidate }) => {
|
||||||
if (transition.current) {
|
if (transition.current) {
|
||||||
transition.current = false;
|
transition.current = false;
|
||||||
t0.current = clock.elapsedTime;
|
t0.current = performance.now() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
const x = clamp(
|
const x = clamp(
|
||||||
(clock.elapsedTime - t0.current) / animationTime.current,
|
(performance.now() / 1000 - t0.current) / animationTime.current,
|
||||||
0,
|
0,
|
||||||
2
|
2,
|
||||||
);
|
);
|
||||||
const t = (0.5 * Math.sin(Math.PI * (x + 0.5)) + 0.5) ** 2;
|
const t = (0.5 * Math.sin(Math.PI * (x + 0.5)) + 0.5) ** 2;
|
||||||
|
|
||||||
|
|||||||
@@ -183,11 +183,12 @@ export function tankCharacteristics(
|
|||||||
(coefficient([hasGunRammer, -0.05]) *
|
(coefficient([hasGunRammer, -0.05]) *
|
||||||
coefficient([true, degressiveStat(loaderMastery)])) /
|
coefficient([true, degressiveStat(loaderMastery)])) /
|
||||||
coefficient([hasAdrenaline && gun.gun_type!.$case === "regular", 0.17]);
|
coefficient([hasAdrenaline && gun.gun_type!.$case === "regular", 0.17]);
|
||||||
const penetrationCoefficient =
|
const penetrationCoefficient = resolvePenetrationCoefficient(
|
||||||
coefficient([
|
hasCalibratedShells,
|
||||||
hasCalibratedShells,
|
equalize,
|
||||||
resolvePenetrationCoefficient(true, equalize, shell.type, equalizer) - 1,
|
shell.type,
|
||||||
]) * equalizer.penetration;
|
equalizer,
|
||||||
|
);
|
||||||
const healthCoefficient =
|
const healthCoefficient =
|
||||||
coefficient(
|
coefficient(
|
||||||
[hasSandbagArmor, 0.03],
|
[hasSandbagArmor, 0.03],
|
||||||
|
|||||||
Reference in new issue
Block a user