From e3db886923088359d5d20d5bedf65ad6d7e063e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 29 Apr 2026 10:17:53 -0500 Subject: [PATCH] feat: game strings in characteristics Co-authored-by: Copilot --- packages/closed | 2 +- .../components/TankopediaCharacteristic.tsx | 2 +- .../core/tankopedia/characteristicsOrder.ts | 3 +- .../core/tankopedia/renderCharacteristic.ts | 29 --------- .../src/hooks/useCharacteristicRenderer.ts | 59 +++++++++++++++++++ .../website-ue/src/hooks/useGameStrings.ts | 19 +++++- .../pages/[...locale]/tanks/[slug]/_index.tsx | 28 ++++++++- 7 files changed, 105 insertions(+), 37 deletions(-) delete mode 100644 packages/website-ue/src/core/tankopedia/renderCharacteristic.ts create mode 100644 packages/website-ue/src/hooks/useCharacteristicRenderer.ts diff --git a/packages/closed b/packages/closed index 852d7a629..69c368890 160000 --- a/packages/closed +++ b/packages/closed @@ -1 +1 @@ -Subproject commit 852d7a6290cc1f155bffa8ab8a2540c2090b962b +Subproject commit 69c36889061a539efc15f046f698bb2c927b5a6b diff --git a/packages/website-ue/src/components/TankopediaCharacteristic.tsx b/packages/website-ue/src/components/TankopediaCharacteristic.tsx index de911c2a8..d40ea3099 100644 --- a/packages/website-ue/src/components/TankopediaCharacteristic.tsx +++ b/packages/website-ue/src/components/TankopediaCharacteristic.tsx @@ -1,6 +1,6 @@ import type { CharacteristicOutput } from "../core/tankopedia/characteristics"; import type { CharacteristicRenderConfig } from "../core/tankopedia/characteristicsOrder"; -import { renderCharacteristic } from "../core/tankopedia/renderCharacteristic"; +import { renderCharacteristic } from "../hooks/useCharacteristicRenderer"; interface Props { characteristic: CharacteristicOutput; diff --git a/packages/website-ue/src/core/tankopedia/characteristicsOrder.ts b/packages/website-ue/src/core/tankopedia/characteristicsOrder.ts index 1cb2b46d8..0777fc64c 100644 --- a/packages/website-ue/src/core/tankopedia/characteristicsOrder.ts +++ b/packages/website-ue/src/core/tankopedia/characteristicsOrder.ts @@ -18,6 +18,7 @@ export interface CharacteristicRenderConfig { name: CharacteristicName; decimals?: number; units?: string; + strings?: string; render?: (output: CharacteristicOutput) => string; } @@ -35,7 +36,7 @@ export const characteristicsOrder: CharacteristicsOrder = [ { group: "meta", order: [ - { name: "name" }, + { name: "name", strings: "TankEntity" }, { name: "tier" }, { name: "nation", diff --git a/packages/website-ue/src/core/tankopedia/renderCharacteristic.ts b/packages/website-ue/src/core/tankopedia/renderCharacteristic.ts deleted file mode 100644 index 1cdaf5887..000000000 --- a/packages/website-ue/src/core/tankopedia/renderCharacteristic.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { CharacteristicOutput } from "./characteristics"; -import type { CharacteristicRenderConfig } from "./characteristicsOrder"; - -export function renderCharacteristic( - characteristic: CharacteristicOutput, - config: CharacteristicRenderConfig -): string | null { - if (characteristic === null) return null; - - if (config.render) return config.render(characteristic); - - if (typeof characteristic === "number") { - if (Number.isFinite(characteristic)) { - if (config.decimals === undefined) { - return characteristic.toString(); - } - - return characteristic.toFixed(config.decimals); - } - - return `${characteristic < 0 ? "-" : ""}∞`; - } - - if (typeof characteristic === "string") { - return characteristic; - } - - return characteristic.map((c) => renderCharacteristic(c, config)).join(", "); -} diff --git a/packages/website-ue/src/hooks/useCharacteristicRenderer.ts b/packages/website-ue/src/hooks/useCharacteristicRenderer.ts new file mode 100644 index 000000000..0658dfd5b --- /dev/null +++ b/packages/website-ue/src/hooks/useCharacteristicRenderer.ts @@ -0,0 +1,59 @@ +import { useMemo } from "react"; +import type { CharacteristicOutput } from "../core/tankopedia/characteristics"; +import { + characteristicsOrder, + type CharacteristicRenderConfig, +} from "../core/tankopedia/characteristicsOrder"; +import { useGameStrings } from "./useGameStrings"; + +export function useCharacteristicRenderer() { + const groups = useMemo(() => { + const groups: string[] = []; + + for (const group of characteristicsOrder) { + for (const item of group.order) { + if ("strings" in item && item.strings) { + groups.push(item.strings); + } + } + } + + return groups; + }, []); + const tankEntityStrings = useGameStrings(groups); + + function renderCharacteristic( + characteristic: CharacteristicOutput, + config: CharacteristicRenderConfig, + ): string | null { + if (characteristic === null) return null; + + if (config.render) return config.render(characteristic); + + if (typeof characteristic === "number") { + if (Number.isFinite(characteristic)) { + if (config.decimals === undefined) { + return characteristic.toString(); + } + + return characteristic.toFixed(config.decimals); + } + + return `${characteristic < 0 ? "-" : ""}∞`; + } + + if (typeof characteristic === "string") { + if (config.strings) { + return tankEntityStrings[characteristic]; + } + + return characteristic; + } + + return characteristic + .map((c) => renderCharacteristic(c, config)) + .join(", "); + } + + return renderCharacteristic; +} diff --git a/packages/website-ue/src/hooks/useGameStrings.ts b/packages/website-ue/src/hooks/useGameStrings.ts index c6690b176..b17f7d61b 100644 --- a/packages/website-ue/src/hooks/useGameStrings.ts +++ b/packages/website-ue/src/hooks/useGameStrings.ts @@ -2,11 +2,24 @@ import { api } from "../core/api/dynamic"; import { useAwait } from "./useAwait"; import { useLocale } from "./useLocale"; -export function useGameStrings(group: string) { +export function useGameStrings(groups: string | string[]) { + const resolved = typeof groups === "string" ? [groups] : groups; const locale = useLocale(); const strings = useAwait( - () => api.groupedGameStrings(locale, group, true), - `game-strings-${locale}-${group}`, + async () => { + const accumulated: Record = {}; + + await Promise.all( + resolved.map(async (group) => { + const strings = await api.groupedGameStrings(locale, group, true); + Object.assign(accumulated, strings); + }), + ); + + return accumulated; + }, + `game-strings-${locale}-${resolved.sort().join("-")}`, ); + return strings; } diff --git a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx index 9f336f628..23c05944d 100644 --- a/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx +++ b/packages/website-ue/src/pages/[...locale]/tanks/[slug]/_index.tsx @@ -2,8 +2,10 @@ import { Grade } from "@blitzkit/closed/protos/game/proto/legacy/blitz_static_st import { StageParameters_StageType } from "@blitzkit/closed/protos/game/proto/legacy/blitz_static_tank_upgrade_single_stage"; import { useMemo } from "react"; import { api } from "../../../../core/api/dynamic"; +import { characteristicsOrder } from "../../../../core/tankopedia/characteristicsOrder"; import { computeCharacteristics } from "../../../../core/tankopedia/computeCharacteristics"; import { useAwait } from "../../../../hooks/useAwait"; +import { useCharacteristicRenderer } from "../../../../hooks/useCharacteristicRenderer"; import { useGameStrings } from "../../../../hooks/useGameStrings"; import { LocaleProvider } from "../../../../hooks/useLocale"; import { Tankopedia } from "../../../../stores/tankopedia"; @@ -27,6 +29,7 @@ export function Page({ id, locale }: PageProps) { function Content() { const tankEntityGameStrings = useGameStrings("TankEntity"); + const renderCharacteristic = useCharacteristicRenderer(); const protagonist = Tankopedia.use((state) => state.protagonist); const protagonistTank = useAwait( @@ -146,11 +149,32 @@ function Content() {

characteristics

- {Object.entries(characteristics).map(([key, value]) => ( + {/* {Object.entries(characteristics).map(([key, value]) => (

{key}: {value}

- ))} + ))} */} + + {characteristicsOrder.map((group) => { + return ( + <> +

{group.group}

+ + {group.order.map((item) => { + if ("toy" in item) { + return toy: {item.toy}; + } + + return ( + + {item.name}:{" "} + {renderCharacteristic(characteristics[item.name], item)} + + ); + })} + + ); + })} );