From 267bb271c9aa992c64beadc69a207f2500c36929 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Tue, 22 Sep 2026 11:52:39 -0500 Subject: [PATCH] some notes --- .../src/blitzkit/api/server/7_provisions.ts | 34 +++++++------ packages/protos/src/blitzkit/script.proto | 49 +++++++++++++++++++ .../definitions/consumables.pb.ts | 47 +++++++++++++++++- 3 files changed, 114 insertions(+), 16 deletions(-) create mode 100644 packages/protos/src/blitzkit/script.proto diff --git a/packages/core/src/blitzkit/api/server/7_provisions.ts b/packages/core/src/blitzkit/api/server/7_provisions.ts index afd270e99..afcc09018 100644 --- a/packages/core/src/blitzkit/api/server/7_provisions.ts +++ b/packages/core/src/blitzkit/api/server/7_provisions.ts @@ -127,11 +127,15 @@ export abstract class ServerBlitzKitAPI7 extends ServerBlitzKitAPI6 { switch (provision.script["#text"]) { case "Stimulator": - applyCanonicalBonuses({ crew_level_increase: "crewLevelIncrease" }); + applyCanonicalBonuses({ + crew_level_increase: "crewLevelIncrease", + }); break; case "AntiHighExplosive": - applyCanonicalBonuses({ anti_high_explosive_factor: "factor" }); + applyCanonicalBonuses({ + anti_high_explosive_factor: "factor", + }); break; case "Fuel": @@ -150,7 +154,9 @@ export abstract class ServerBlitzKitAPI7 extends ServerBlitzKitAPI6 { break; case "SmallHPStock": - applyRootBonuses({ hp_stock_percent: "hpStockPercent" }); + applyRootBonuses({ + hp_stock_percent: "hpStockPercent", + }); break; case "GearOil": @@ -244,6 +250,7 @@ export abstract class ServerBlitzKitAPI7 extends ServerBlitzKitAPI6 { break; case "EnemyReloadTime": + // bonusValues is empty in the observed data. break; case "Duplet": @@ -282,13 +289,6 @@ export abstract class ServerBlitzKitAPI7 extends ServerBlitzKitAPI6 { }); break; - case "EngineAndSpeedBoost": - applyCanonicalBonuses({ - engine_power_ability_factor: "enginePowerAbilityFactor", - speed_limit_ability_bonus: "speedLimitAbilityBonus", - }); - break; - case "BigBoss": applyCanonicalBonuses({ gun_reload_factor: "gunReloadFactor", @@ -298,13 +298,9 @@ export abstract class ServerBlitzKitAPI7 extends ServerBlitzKitAPI6 { max_health_percent_bonus: "maxHealthPercentBonus", max_statics_damage_percent: "maxStaticsDamagePercent", }); - - // These are nested structures and need their own handling - // rather than a simple key -> key mapping. break; case "VampiricBoost": - // Nested `respawns` structure; needs dedicated handling. break; case "ZombieMark": @@ -315,8 +311,16 @@ export abstract class ServerBlitzKitAPI7 extends ServerBlitzKitAPI6 { speed_limits_factor: "speedLimitsFactor", common_damage_factor: "commonDamageFactor", }); + break; - // Nested respawnBoost structure. + case "HumanMark": + applyRootBonuses({ + opt_device_ramming_damage_override: + "optDeviceRammingDamageOverride", + }); + + // `bonusValues.item` is a nested array and therefore isn't + // appropriate for applyCanonicalBonuses(). break; default: diff --git a/packages/protos/src/blitzkit/script.proto b/packages/protos/src/blitzkit/script.proto new file mode 100644 index 000000000..3b7b0e278 --- /dev/null +++ b/packages/protos/src/blitzkit/script.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; + +package blitzkit; + +import "tank_definitions.proto"; + +/** + * Wargaming's script system for provisions, consumables, and equipment is + * genuinely the most repulsive and inconsistent XML schema I have ever seen. + * Here are my notes on how I normalize the data into BlitzKit. I can totally + * see why they want to move to Unreal Engine. This is unhealthy. + */ +message Script { + /** + * If #text is "StaticFactorDevice", type will be script.attribute, otherwise + * type will assume the value of #text. + */ + string type = 1; + + /** + * Bonus values enjoys Record entries from + * script.bonusValues. + * + * I also augment Record values from the root of the + * script object. That is, if an entry on the root script object isn't + * "attribute", "bonusValues", "#text", etc., it goes in here. Empty strings + * values get omitted. + */ + map bonus_values = 2; + + /** + * I thought piercing_factors distinct enough from bonus_values to separate + * them since the keys here are no longer properties of the tank, but + * specific shell types. The keys will be mapped to BlitzKit's ShellType. + */ + map piercing_factors = 3; + + /** + * Same story here, the keys are different. But this time, the values are + * stored deep in script.modulesHealthFactors.modules. Also, all keys end + * with "Health" for no reason like "leftTrackHealth". That will be trimmed. + */ + map module_health_factors = 4; + + /** + * + */ + map chances_to_hit = 5; +} \ No newline at end of file diff --git a/packages/website/src/pages/[...chunk_api]/definitions/consumables.pb.ts b/packages/website/src/pages/[...chunk_api]/definitions/consumables.pb.ts index c384c12c3..dedb3f8f6 100644 --- a/packages/website/src/pages/[...chunk_api]/definitions/consumables.pb.ts +++ b/packages/website/src/pages/[...chunk_api]/definitions/consumables.pb.ts @@ -1,9 +1,54 @@ -import { ConsumableDefinitions } from "@blitzkit/core"; +import { + ConsumableDefinitions, + type ConsumablesCommon, + type OptionalDevices, +} from "@blitzkit/core"; import { api } from "../../../blitzkit/api"; +import { vfs } from "../../../core/blitzkit/vfs"; export { getStaticPaths } from "../_index"; export async function GET() { + const samples: Record = {}; + + const optionalDevices = await vfs.xml<{ + root: OptionalDevices; + }>("Data/XML/item_defs/vehicles/common/optional_devices.xml"); + + for (const key in optionalDevices.root) { + samples[key] = optionalDevices.root[key].script; + } + + const consumablesRoot = "Data/XML/item_defs/vehicles/common/consumables"; + const consumablesList = await vfs.text(`${consumablesRoot}/list.xml`); + const consumablesListEntryPattern = //gm; + + for (const match of consumablesList.matchAll(consumablesListEntryPattern)) { + const group = match[1]; + const path = `${consumablesRoot}/${group}.xml`; + const consumables = await vfs.xml<{ root: ConsumablesCommon }>(path); + + for (const key in consumables.root) { + samples[key] = consumables.root[key].script; + } + } + + const provisionsRoot = "Data/XML/item_defs/vehicles/common/provisions"; + const provisionsList = await vfs.text(`${provisionsRoot}/list.xml`); + const provisionsListEntryPattern = //gm; + + for (const match of provisionsList.matchAll(provisionsListEntryPattern)) { + const group = match[1]; + const path = `${provisionsRoot}/${group}.xml`; + const provisions = await vfs.xml<{ root: ConsumablesCommon }>(path); + + for (const key in provisions.root) { + samples[key] = provisions.root[key].script; + } + } + + return Response.json(samples); + const definitions = await api.consumables(); const bytes = ConsumableDefinitions.encode(definitions).finish();