Files
blitzkit/packages/scripts/src/patchNotes.ts
T

319 lines
11 KiB
TypeScript
Raw Normal View History

2025-11-12 13:50:17 -06:00
import {
availableProvisions,
2025-11-12 14:10:02 -06:00
createDefaultProvisions,
createDefaultSkills,
2025-11-12 13:50:17 -06:00
fetchConsumableDefinitions,
fetchEquipmentDefinitions,
2025-11-12 14:10:02 -06:00
fetchModelDefinitions,
2025-11-12 13:50:17 -06:00
fetchProvisionDefinitions,
2025-11-12 14:10:02 -06:00
fetchSkillDefinitions,
2025-11-12 13:50:17 -06:00
fetchTankDefinitions,
TankDefinition,
2025-11-12 14:18:54 -06:00
tankIcon,
2025-11-12 13:50:17 -06:00
} from "@blitzkit/core";
import { checkConsumableProvisionInclusivity } from "@blitzkit/core/src/blitzkit/checkConsumableProvisionInclusivity";
2025-11-12 14:10:02 -06:00
import strings from "@blitzkit/i18n/strings/en.json";
2025-11-12 13:50:17 -06:00
import { writeFile } from "fs/promises";
import { isEqual } from "lodash-es";
2025-11-12 14:10:02 -06:00
import { tankCharacteristics } from "../../website/src/core/blitzkit/tankCharacteristics";
import { genericDefaultEquipmentMatrix } from "../../website/src/stores/duel/constants";
2025-11-12 13:50:17 -06:00
const domain = "https://opentest.blitzkit.app";
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets";
const currentTankDefinitions = await fetchTankDefinitions();
const currentConsumableDefinitions = await fetchConsumableDefinitions();
const currentProvisionDefinitions = await fetchProvisionDefinitions();
const currentEquipmentDefinitions = await fetchEquipmentDefinitions();
2025-11-12 14:10:02 -06:00
const currentSkillDefinitions = await fetchSkillDefinitions();
const currentModelDefinitions = await fetchModelDefinitions();
2025-11-12 13:50:17 -06:00
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets-preview";
const previewTankDefinitions = await fetchTankDefinitions();
const previewConsumableDefinitions = await fetchConsumableDefinitions();
const previewProvisionDefinitions = await fetchProvisionDefinitions();
const previewEquipmentDefinitions = await fetchEquipmentDefinitions();
2025-11-12 14:10:02 -06:00
const previewSkillDefinitions = await fetchSkillDefinitions();
const previewModelDefinitions = await fetchModelDefinitions();
2025-11-12 13:50:17 -06:00
let notes = "# BlitzKit OpenTest Patch Notes\n\n";
const newTanks: TankDefinition[] = [];
for (const id in previewTankDefinitions.tanks) {
if (!(id in currentTankDefinitions.tanks)) {
newTanks.push(previewTankDefinitions.tanks[id]);
}
}
newTanks.sort((a, b) => b.tier - a.tier);
2025-11-12 14:18:54 -06:00
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets-preview";
2025-11-12 13:50:17 -06:00
if (newTanks.length > 0) {
notes += "## New Tanks\n\n";
for (const tank of newTanks) {
2026-03-31 14:11:45 -05:00
notes += `### [${tank.name!.locales.en}](${domain}/tanks/${tank.slug})\n`;
2025-11-12 14:18:54 -06:00
notes += `![](${tankIcon(tank.id)})\n\n`;
2025-11-12 13:50:17 -06:00
}
notes += "\n";
}
const changedTanks: [TankDefinition, TankDefinition][] = [];
for (const stringId in previewTankDefinitions.tanks) {
const id = Number(stringId);
if (newTanks.some((tank) => tank.id === id)) continue;
const current = currentTankDefinitions.tanks[id];
const preview = previewTankDefinitions.tanks[id];
if (isEqual(current, preview)) continue;
changedTanks.push([current, preview]);
}
changedTanks.sort((a, b) => b[1].tier - a[1].tier);
2025-11-12 14:18:54 -06:00
import.meta.env.PUBLIC_ASSET_BASE = "https://blitzkit.github.io/assets";
2025-11-12 13:50:17 -06:00
if (changedTanks.length > 0) {
notes += "## Changed Tanks\n\n";
for (const [current, preview] of changedTanks) {
const currentTurret = current.turrets.at(-1)!;
const previewTurret = preview.turrets.at(-1)!;
const currentGun = currentTurret.guns.at(-1)!;
const previewGun = previewTurret.guns.at(-1)!;
2025-11-12 14:10:02 -06:00
const currentShell = currentGun.shells[0];
const previewShell = previewGun.shells[0];
const currentEngine = current.engines.at(-1)!;
const previewEngine = preview.engines.at(-1)!;
const currentTracks = current.tracks.at(-1)!;
const previewTracks = preview.tracks.at(-1)!;
const currentTankModel = currentModelDefinitions.models[current.id];
const previewTankModel = previewModelDefinitions.models[preview.id];
2025-11-12 13:50:17 -06:00
const currentConsumables = Object.values(
2026-03-31 14:11:45 -05:00
currentConsumableDefinitions.consumables,
2025-11-12 13:50:17 -06:00
).filter((consumable) =>
2026-03-31 14:11:45 -05:00
checkConsumableProvisionInclusivity(consumable, current, currentGun),
2025-11-12 13:50:17 -06:00
);
const previewConsumables = Object.values(
2026-03-31 14:11:45 -05:00
previewConsumableDefinitions.consumables,
2025-11-12 13:50:17 -06:00
).filter((consumable) =>
2026-03-31 14:11:45 -05:00
checkConsumableProvisionInclusivity(consumable, preview, previewGun),
2025-11-12 13:50:17 -06:00
);
const addedConsumables = previewConsumables.filter(
(previewConsumable) =>
!currentConsumables.some(
2026-03-31 14:11:45 -05:00
(currentConsumable) => currentConsumable.id === previewConsumable.id,
),
2025-11-12 13:50:17 -06:00
);
const removedConsumables = currentConsumables.filter(
(currentConsumable) =>
!previewConsumables.some(
2026-03-31 14:11:45 -05:00
(previewConsumable) => previewConsumable.id === currentConsumable.id,
),
2025-11-12 13:50:17 -06:00
);
const currentProvisions = availableProvisions(
current,
currentGun,
2026-03-31 14:11:45 -05:00
currentProvisionDefinitions,
2025-11-12 13:50:17 -06:00
);
const previewProvisions = availableProvisions(
preview,
previewGun,
2026-03-31 14:11:45 -05:00
previewProvisionDefinitions,
2025-11-12 13:50:17 -06:00
);
const addedProvisions = previewProvisions.filter(
(previewProvision) =>
!currentProvisions.some(
2026-03-31 14:11:45 -05:00
(currentProvision) => currentProvision.id === previewProvision.id,
),
2025-11-12 13:50:17 -06:00
);
const removedProvisions = currentProvisions.filter(
(currentProvision) =>
!previewProvisions.some(
2026-03-31 14:11:45 -05:00
(previewProvision) => previewProvision.id === currentProvision.id,
),
2025-11-12 13:50:17 -06:00
);
const currentEquipment = currentEquipmentDefinitions.presets[
current.equipment_preset
].slots
.map(({ left, right }) => [left, right])
.flat();
const previewEquipment = previewEquipmentDefinitions.presets[
preview.equipment_preset
].slots
.map(({ left, right }) => [left, right])
.flat();
const addedEquipment = previewEquipment
.filter(
(previewEquipment) =>
!currentEquipment.some(
2026-03-31 14:11:45 -05:00
(currentEquipment) => currentEquipment === previewEquipment,
),
2025-11-12 13:50:17 -06:00
)
.map((id) => previewEquipmentDefinitions.equipments[id]);
const removedEquipment = currentEquipment
.filter(
(currentEquipment) =>
!previewEquipment.some(
2026-03-31 14:11:45 -05:00
(previewEquipment) => previewEquipment === currentEquipment,
),
2025-11-12 13:50:17 -06:00
)
.map((id) => currentEquipmentDefinitions.equipments[id]);
2026-04-03 12:08:47 -05:00
const equalize = false;
2025-11-12 14:10:02 -06:00
const currentCharacteristics = tankCharacteristics(
{
tank: current,
gun: currentGun,
shell: currentShell,
applyDynamicArmor: false,
applyReactiveArmor: false,
applySpallLiner: false,
assaultDistance: 0,
crewSkills: createDefaultSkills(currentSkillDefinitions),
camouflage: true,
consumables: [],
engine: currentEngine,
provisions: createDefaultProvisions(
current,
currentGun,
2026-03-31 14:11:45 -05:00
currentProvisionDefinitions,
2025-11-12 14:10:02 -06:00
),
equipmentMatrix: genericDefaultEquipmentMatrix,
stockEngine: current.engines[0],
stockGun: current.turrets[0].guns[0],
stockTrack: current.tracks[0],
stockTurret: current.turrets[0],
track: currentTracks,
turret: currentTurret,
2026-04-03 12:08:47 -05:00
equalize,
2025-11-12 14:10:02 -06:00
},
{
equipmentDefinitions: currentEquipmentDefinitions,
provisionDefinitions: currentProvisionDefinitions,
tankModelDefinition: currentTankModel,
2026-03-31 14:11:45 -05:00
},
2025-11-12 14:10:02 -06:00
);
const previewCharacteristics = tankCharacteristics(
{
tank: preview,
gun: previewGun,
shell: previewShell,
applyDynamicArmor: false,
applyReactiveArmor: false,
applySpallLiner: false,
assaultDistance: 0,
crewSkills: createDefaultSkills(previewSkillDefinitions),
camouflage: true,
consumables: [],
engine: previewEngine,
provisions: createDefaultProvisions(
preview,
previewGun,
2026-03-31 14:11:45 -05:00
previewProvisionDefinitions,
2025-11-12 14:10:02 -06:00
),
equipmentMatrix: genericDefaultEquipmentMatrix,
stockEngine: preview.engines[0],
stockGun: preview.turrets[0].guns[0],
stockTrack: preview.tracks[0],
stockTurret: preview.turrets[0],
track: previewTracks,
turret: previewTurret,
2026-04-03 12:08:47 -05:00
equalize,
2025-11-12 14:10:02 -06:00
},
{
equipmentDefinitions: previewEquipmentDefinitions,
provisionDefinitions: previewProvisionDefinitions,
tankModelDefinition: previewTankModel,
2026-03-31 14:11:45 -05:00
},
2025-11-12 14:10:02 -06:00
);
const changedCharacteristics: string[] = [];
for (const key in currentCharacteristics) {
const characteristicKey = key as keyof typeof currentCharacteristics;
if (
currentCharacteristics[characteristicKey] !==
previewCharacteristics[characteristicKey]
) {
changedCharacteristics.push(characteristicKey);
}
}
2026-03-31 14:11:45 -05:00
notes += `### [${preview.name!.locales.en}](${domain}/tanks/${preview.slug})\n`;
2025-11-12 14:18:54 -06:00
notes += `![](${tankIcon(preview.id)})\n\n`;
2025-11-12 13:50:17 -06:00
if (addedConsumables.length + removedConsumables.length > 0) {
2025-11-12 14:18:54 -06:00
notes += `Consumables: `;
2025-11-12 13:50:17 -06:00
notes += [
...addedConsumables.map(
2026-03-31 14:11:45 -05:00
(consumable) => `🟢 ${consumable.name!.locales.en}`,
2025-11-12 13:50:17 -06:00
),
...removedConsumables.map(
2026-03-31 14:11:45 -05:00
(consumable) => `🔴 ${consumable.name!.locales.en}`,
2025-11-12 13:50:17 -06:00
),
].join(", ");
notes += `\n`;
}
if (addedProvisions.length + removedProvisions.length > 0) {
2025-11-12 14:18:54 -06:00
notes += `Provisions: `;
2025-11-12 13:50:17 -06:00
notes += [
...addedProvisions.map(
2026-03-31 14:11:45 -05:00
(provision) => `🟢 ${provision.name!.locales.en}`,
2025-11-12 13:50:17 -06:00
),
...removedProvisions.map(
2026-03-31 14:11:45 -05:00
(provision) => `🔴 ${provision.name!.locales.en}`,
2025-11-12 13:50:17 -06:00
),
].join(", ");
notes += `\n`;
}
if (addedEquipment.length + removedEquipment.length > 0) {
2025-11-12 14:18:54 -06:00
notes += `-Equipment: `;
2025-11-12 13:50:17 -06:00
notes += [
2026-03-31 14:11:45 -05:00
...addedEquipment.map(
(equipment) => `🟢 ${equipment.name!.locales.en}`,
),
2025-11-12 13:50:17 -06:00
...removedEquipment.map(
2026-03-31 14:11:45 -05:00
(equipment) => `🔴 ${equipment.name!.locales.en}`,
2025-11-12 13:50:17 -06:00
),
].join(", ");
notes += `\n`;
}
2025-11-12 14:10:02 -06:00
if (changedCharacteristics.length > 0) {
2025-11-12 14:18:54 -06:00
notes += `Characteristics:\n`;
2025-11-12 14:10:02 -06:00
for (const characteristicUntyped of changedCharacteristics) {
const characteristic =
characteristicUntyped as keyof typeof currentCharacteristics;
const name =
strings.website.tools.tankopedia.characteristics.values[
characteristic
];
const before = currentCharacteristics[characteristic];
const after = previewCharacteristics[characteristic];
2025-11-12 14:18:54 -06:00
notes += `- ${
2025-11-12 14:10:02 -06:00
typeof before === "number" && typeof after === "number"
? after > before
? "⬆️"
: "🔻"
: "✏️"
} ${name}: \`${
typeof before === "number" ? before.toFixed(2) : before
}\` → \`${typeof after === "number" ? after.toFixed(2) : after}\`\n`;
}
}
2025-11-12 13:50:17 -06:00
}
}
await writeFile("../../temp/patch-notes.md", notes);