From 6303fbb96145534409e0957836eed2a06ddaf723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 10:32:54 -0500 Subject: [PATCH 001/120] Update index.ts --- scripts/buildAssets/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index e8d91bdc3..26610d2a1 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -41,9 +41,9 @@ const methods = [ consumableProvisionIcons, camouflageIcons, boosterIcons, - tankArmors, - tankModels, tankIcons, + tankModels, + tankArmors, ]; for (const method of methods) { From 2b08ecad7f699a5cb1e334e875730b3e4809ca48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:23:24 -0500 Subject: [PATCH 002/120] Update index.ts --- scripts/buildAssets/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index 26610d2a1..b4b34d9f0 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -41,7 +41,7 @@ const methods = [ consumableProvisionIcons, camouflageIcons, boosterIcons, - tankIcons, + // tankIcons, tankModels, tankArmors, ]; From 400c6ebfe1c3f9413082ba64f8ab5566009872e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:12:02 -0500 Subject: [PATCH 003/120] Update index.ts --- scripts/buildAssets/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index b4b34d9f0..2a9f8085c 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -30,6 +30,7 @@ if (!targets && !allTargets) throw new Error('No target(s) specified'); const methods = [ definitions, + tankIcons, videos, scratchedFlags, currencies, @@ -41,7 +42,6 @@ const methods = [ consumableProvisionIcons, camouflageIcons, boosterIcons, - // tankIcons, tankModels, tankArmors, ]; From 35db670f5c3002b21e28eb16eb4bf57575bada7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:31:06 -0500 Subject: [PATCH 004/120] feat: dynamicContentLocalizationsDir --- scripts/applyPatches.ts | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/scripts/applyPatches.ts b/scripts/applyPatches.ts index c56aaadbe..7af27c4e4 100644 --- a/scripts/applyPatches.ts +++ b/scripts/applyPatches.ts @@ -1,18 +1,21 @@ import { mkdir, writeFile } from 'fs/promises'; import { parse as parsePath } from 'path'; -import { parse as parseYaml } from 'yaml'; +import ProgressBar from 'progress'; +import { parse as parseYaml, stringify as stringifyYaml } from 'yaml'; import { readStringDVPL } from '../src/core/blitz/readStringDVPL'; +import { readYAMLDVPL } from '../src/core/blitz/readYAMLDVPL'; import { writeDVPL } from '../src/core/blitz/writeDVPL'; import { secrets } from '../src/core/blitzkit/secrets'; import { dvp } from '../submodules/blitzkit-closed/src/dvp'; import { DATA } from './buildAssets/constants'; const versionTextFile = await readStringDVPL(`${DATA}/version.txt.dvpl`); -const currentVersion = versionTextFile - .split(' ')[0] - .split('.') - .slice(0, 3) - .join('.'); +// const currentVersion = versionTextFile +// .split(' ')[0] +// .split('.') +// .slice(0, 3) +// .join('.'); +const currentVersion = '11.1.0'; console.log(`Installing patches for ${currentVersion}...`); @@ -33,6 +36,10 @@ while (true) { `${secrets.WOTB_DLC_CDN}/dlc/${data.dx11.replace('.dvpm', '.dvpd')}`, ).then((response) => response.arrayBuffer()); const files = await dvp(dvpm, dvpd); + const bar = new ProgressBar( + `Patching ${files.length} files :bar`, + files.length, + ); await Promise.all( files.map(async ({ path, data }) => { @@ -40,9 +47,30 @@ while (true) { await mkdir(`${DATA}/${dir}`, { recursive: true }); await writeFile(`${DATA}/${path}.dvpl`, writeDVPL(Buffer.from(data))); + + bar.tick(); }), ); + if ('dynamicContentLocalizationsDir' in data) { + console.log('Found dynamic content localizations; patching...'); + + const localizationsResponse = await fetch( + `${secrets.WOTB_DLC_CDN}/dlc/${data.dynamicContentLocalizationsDir}/en.yaml`, + ); + const newStrings = parseYaml(await localizationsResponse.text()); + const oldStrings = await readYAMLDVPL>( + `${DATA}/Strings/en.yaml.dvpl`, + ); + const patchedStrings = { ...oldStrings, ...newStrings }; + const patchedContent = stringifyYaml(patchedStrings); + + await writeFile( + `${DATA}/Strings/en.yaml.dvpl`, + writeDVPL(Buffer.from(patchedContent)), + ); + } + patchIndex++; } else break; } From d1a4b0d1d11c7a57aebae0563dd75cd477122e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:31:33 -0500 Subject: [PATCH 005/120] fix: currentVersion --- scripts/applyPatches.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/applyPatches.ts b/scripts/applyPatches.ts index 7af27c4e4..471331661 100644 --- a/scripts/applyPatches.ts +++ b/scripts/applyPatches.ts @@ -10,12 +10,11 @@ import { dvp } from '../submodules/blitzkit-closed/src/dvp'; import { DATA } from './buildAssets/constants'; const versionTextFile = await readStringDVPL(`${DATA}/version.txt.dvpl`); -// const currentVersion = versionTextFile -// .split(' ')[0] -// .split('.') -// .slice(0, 3) -// .join('.'); -const currentVersion = '11.1.0'; +const currentVersion = versionTextFile + .split(' ')[0] + .split('.') + .slice(0, 3) + .join('.'); console.log(`Installing patches for ${currentVersion}...`); From 79a01da317425ffbd8405767c3530e9e97a1ab54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 19:23:22 -0500 Subject: [PATCH 006/120] fix: tankopedia search name alignemtn --- src/app/tools/tankopedia/components/TankCard.css.ts | 2 ++ src/app/tools/tankopedia/components/TankCard.tsx | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/components/TankCard.css.ts b/src/app/tools/tankopedia/components/TankCard.css.ts index 66079b886..47d4cc6cb 100644 --- a/src/app/tools/tankopedia/components/TankCard.css.ts +++ b/src/app/tools/tankopedia/components/TankCard.css.ts @@ -9,6 +9,7 @@ export const card = style({ alignItems: 'center', gap: 'var(--space-2)', background: cardBackgroundVar, + overflow: 'hidden', }); export const image = style({ @@ -34,6 +35,7 @@ export const name = style({ export const link = style({ color: 'inherit', textDecoration: 'none', + width: '100%', ':hover': { textDecoration: 'underline', diff --git a/src/app/tools/tankopedia/components/TankCard.tsx b/src/app/tools/tankopedia/components/TankCard.tsx index 2a508e7d8..596a9cd5d 100644 --- a/src/app/tools/tankopedia/components/TankCard.tsx +++ b/src/app/tools/tankopedia/components/TankCard.tsx @@ -162,7 +162,6 @@ export function TankCard({ tank, onSelect }: TankCardProps) { align="center" overflow="hidden" width="100%" - maxWidth="100%" > From 820c1259120e54cd1840075fff83d8a370ba226e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 19:47:35 -0500 Subject: [PATCH 007/120] fix: stricter search --- .../tools/tankopedia/components/TankSearch/index.tsx | 3 +-- src/core/blitz/resolveTankId.ts | 2 +- src/core/blitzkit/tankDefinitions/index.ts | 6 ++++-- src/core/discord/autocompleteTanks.ts | 10 ++++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/app/tools/tankopedia/components/TankSearch/index.tsx b/src/app/tools/tankopedia/components/TankSearch/index.tsx index afb42af69..cc7f2c0ec 100644 --- a/src/app/tools/tankopedia/components/TankSearch/index.tsx +++ b/src/app/tools/tankopedia/components/TankSearch/index.tsx @@ -375,8 +375,7 @@ export const TankSearch = memo( return sort.direction === 'ascending' ? sorted : sorted.reverse(); } else { const searchedRaw = go(filters.search, awaitedTankNames, { - key: 'combined', - limit: 25, + keys: ['searchableName', 'searchableNameDeburr'], }); const searchedTanks = searchedRaw.map( (result) => awaitedTankDefinitions[result.obj.id], diff --git a/src/core/blitz/resolveTankId.ts b/src/core/blitz/resolveTankId.ts index 17bfa184a..3855e0c23 100644 --- a/src/core/blitz/resolveTankId.ts +++ b/src/core/blitz/resolveTankId.ts @@ -19,7 +19,7 @@ export default async function resolveTankId( `${tank}`, await (techTreeOnly ? tankNamesTechTreeOnly : tankNames), { - keys: ['combined'], + keys: ['searchableName', 'searchableNameDeburr'], limit: 1, }, ); diff --git a/src/core/blitzkit/tankDefinitions/index.ts b/src/core/blitzkit/tankDefinitions/index.ts index f46f7e6cb..c345dc972 100644 --- a/src/core/blitzkit/tankDefinitions/index.ts +++ b/src/core/blitzkit/tankDefinitions/index.ts @@ -187,8 +187,10 @@ export const tankNames = tanksDefinitionsArray.then((tanks) => return { id, - original: tank.name, - combined: `${tank.name}${deburr(tank.name)}${tank.nameFull ? `${tank.nameFull}${deburr(tank.nameFull)}` : ''}`, + name: tank.name, + nameFull: tank.nameFull, + searchableName: tank.nameFull ?? tank.name, + searchableNameDeburr: deburr(tank.nameFull ?? tank.name), treeType: tank.treeType, }; }), diff --git a/src/core/discord/autocompleteTanks.ts b/src/core/discord/autocompleteTanks.ts index acbc7cc1d..5b4a2ce71 100644 --- a/src/core/discord/autocompleteTanks.ts +++ b/src/core/discord/autocompleteTanks.ts @@ -29,18 +29,20 @@ export default async function autocompleteTanks( focusedOption.value, await (techTreeOnly ? tankNamesTechTreeOnly : tankNames), { - keys: ['combined'], + keys: ['searchableName', 'searchableNameDeburr'], limit: 10, }, ).map(async (item) => { - let name = item.obj.original; + let name = item.obj.searchableName; if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) { const overSize = name.length - DISCORD_CHOICES_MAX_NAME_SIZE; - name = `${item.obj.original.slice( + name = `${item.obj.searchableName.slice( 0, - item.obj.original.length - overSize - OVERFLOW_SUFFIX.length, + item.obj.searchableName.length - + overSize - + OVERFLOW_SUFFIX.length, )}${OVERFLOW_SUFFIX}`; } From 8d32c7ce23ca80e58e562d9d16aa5eaaae26e12e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 19:53:47 -0500 Subject: [PATCH 008/120] fix: most optimal shell index --- .../tankopedia/[id]/components/Characteristics/index.tsx | 2 +- src/core/blitzkit/tankCharacteristics.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index b67b819cd..918faa699 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -206,7 +206,7 @@ export function Characteristics() { )} {gun.type === 'autoReloader' ? ( <> - + {stats.mostOptimalShellIndex} diff --git a/src/core/blitzkit/tankCharacteristics.ts b/src/core/blitzkit/tankCharacteristics.ts index 6180572e4..e2c9a14a3 100644 --- a/src/core/blitzkit/tankCharacteristics.ts +++ b/src/core/blitzkit/tankCharacteristics.ts @@ -343,11 +343,12 @@ export function tankCharacteristics( damageCoefficient * shell.damage.armor * gun.reload.slice(1).length : undefined; const shells = gun.type === 'regular' ? 1 : gun.count; + console.log(gun.reload); const mostOptimalShellIndex = gun.type === 'autoReloader' - ? gun.reload.at(-1)! < gun.reload.at(-2)! - ? gun.reload.length - : 1 + ? gun.reload[0] + gun.intraClip < gun.reload[1] + ? 1 + : gun.reload.length : undefined; const shellReloads = gun.type === 'autoReloader' From 7f796c5ec149ae2df5b5fa0f3ac05af318358ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 21:12:07 -0500 Subject: [PATCH 009/120] fix: stat parity with game --- .../[id]/components/Characteristics/index.tsx | 43 +++++++--------- src/core/blitzkit/resolveDpm.ts | 29 ++++++----- src/core/blitzkit/tankCharacteristics.ts | 50 ++++++++----------- 3 files changed, 55 insertions(+), 67 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index 918faa699..77eb8e3f5 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -12,7 +12,6 @@ import { debounce } from 'lodash'; import { Fragment, use, useEffect, useRef, useState } from 'react'; import { lerp } from 'three/src/math/MathUtils'; import { Ad, AdType } from '../../../../../../components/Ad'; -import { Link } from '../../../../../../components/Link'; import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawLimits'; import { isExplosive } from '../../../../../../core/blitz/isExplosive'; import { resolvePenetrationCoefficient } from '../../../../../../core/blitz/resolvePenetrationCoefficient'; @@ -179,27 +178,14 @@ export function Characteristics() { {stats.dpm} {gun.type === 'autoReloader' && ( - <> - - {stats.dpmMaximum!} - - - {stats.dpmEffective!} - - - What's the difference? - - } - /> - + + {stats.dpmEffective!} + )} {gun.type !== 'regular' && ( {stats.shells} @@ -477,15 +463,18 @@ export function Characteristics() { > {(member.type === 'commander' ? commanderMastery - : crewMemberMastery) * 100} + : commanderMastery * 1.1) * 100} + {member.substitute && ( - - + {member.substitute .map((sub, index) => @@ -495,7 +484,9 @@ export function Characteristics() { } - /> + > + {commanderMastery * 1.05 * 100} + )} ); diff --git a/src/core/blitzkit/resolveDpm.ts b/src/core/blitzkit/resolveDpm.ts index 028602fac..c9956f5c3 100644 --- a/src/core/blitzkit/resolveDpm.ts +++ b/src/core/blitzkit/resolveDpm.ts @@ -8,21 +8,26 @@ export function resolveDpm( intraClipCoefficient = 1, ) { const alpha = shell.damage.armor * damageCoefficient; + let dps: number; if (gun.type === 'regular') { - return (alpha / (reloadCoefficient * gun.reload)) * 60; + dps = alpha / (reloadCoefficient * gun.reload); } else if (gun.type === 'autoLoader') { - return ( - ((alpha * gun.count) / - (gun.reload + (gun.count - 1) * gun.intraClip * intraClipCoefficient)) * - 60 - ); + dps = + (alpha * gun.count) / + (gun.reload * reloadCoefficient + + (gun.count - 1) * gun.intraClip * intraClipCoefficient); } else { - return ( - ((alpha * gun.count) / - (reloadCoefficient * gun.reload.reduce((a, b) => a + b, 0) + - (gun.count - 1) * gun.intraClip * intraClipCoefficient)) * - 60 - ); + if (gun.reload[0] < gun.reload[1] + gun.intraClip) { + // first shell's the best + dps = alpha / (gun.reload[0] * reloadCoefficient); + } else { + dps = + alpha / + (gun.reload.at(-1)! * reloadCoefficient + + gun.intraClip * intraClipCoefficient); + } } + + return dps * 60; } diff --git a/src/core/blitzkit/tankCharacteristics.ts b/src/core/blitzkit/tankCharacteristics.ts index e2c9a14a3..71a14e018 100644 --- a/src/core/blitzkit/tankCharacteristics.ts +++ b/src/core/blitzkit/tankCharacteristics.ts @@ -75,6 +75,8 @@ export function tankCharacteristics( provisionDefinitions: ProvisionDefinitions; }, ) { + console.log(tank.crew); + const presetRows = equipmentDefinitions.presets[tank.equipment]; const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const gunModelDefinition = turretModelDefinition.guns[gun.id]; @@ -138,8 +140,15 @@ export function tankCharacteristics( 0, ) + (hasImprovedVentilation ? 0.08 : 0); const commanderMastery = crewMastery + provisionCrewBonus; - const crewMemberMastery = commanderMastery * 1.1; - + const loaderMastery = + commanderMastery * + (tank.crew.some(({ type }) => type === 'loader') ? 1.1 : 1.05); + const gunnerMastery = + commanderMastery * + (tank.crew.some(({ type }) => type === 'gunner') ? 1.1 : 1.05); + const driverMastery = + commanderMastery * + (tank.crew.some(({ type }) => type === 'driver') ? 1.1 : 1.05); const intraClipCoefficient = coefficient([hasShellReloadBoost, -0.3]); const damageCoefficient = coefficient([hasTungsten, 0.15]) * @@ -150,7 +159,7 @@ export function tankCharacteristics( ); const reloadCoefficient = (coefficient([hasGunRammer, -0.05]) * - coefficient([true, degressiveStat(crewMemberMastery)])) / + coefficient([true, degressiveStat(loaderMastery)])) / coefficient([hasAdrenaline && gun.type === 'regular', 0.17]); const penetrationCoefficient = coefficient([ hasCalibratedShells, @@ -173,10 +182,10 @@ export function tankCharacteristics( coefficient( [hasEnhancedGunLayingDrive, -0.15], [hasReticleCalibration, -0.3], - ) * coefficient([true, degressiveStat(crewMemberMastery)]); + ) * coefficient([true, degressiveStat(gunnerMastery)]); const dispersionStillCoefficient = coefficient([hasRefinedGun, -0.15], [hasReticleCalibration, -0.3]) * - coefficient([true, degressiveStat(crewMemberMastery)]); + coefficient([true, degressiveStat(gunnerMastery)]); const dispersionDamagedCoefficient = coefficient([ hasVerticalStabilizer, -0.12, @@ -212,13 +221,13 @@ export function tankCharacteristics( ); const turretTraverseCoefficient = coefficient([hasStandardFuel, 0.03], [hasImprovedFuel, 0.1]) * - coefficient([true, progressiveStat(crewMemberMastery)]); + coefficient([true, progressiveStat(gunnerMastery)]); const hullTraverseCoefficient = coefficient( [hasImprovedControl, 0.11], [hasImprovedEnginePowerBoost, 0.01], [true, crewSkills.virtuoso / 100], - ) * coefficient([true, progressiveStat(crewMemberMastery)]); + ) * coefficient([true, progressiveStat(driverMastery)]); const resistanceHardCoefficient = coefficient([hasImprovedSuspension, -0.2]); const resistanceMediumCoefficient = coefficient([ hasImprovedSuspension, @@ -305,21 +314,13 @@ export function tankCharacteristics( reloadCoefficient, intraClipCoefficient, ); - const dpmMaximum = + const mostOptimalShellIndex = gun.type === 'autoReloader' - ? ( - gun.count > 2 - ? gun.reload.at(-1)! < gun.reload.at(-2)! - : gun.reload.at(-1)! + gun.intraClip < gun.reload.at(-2)! - ) - ? ((damageCoefficient * shell.damage.armor) / - (gun.reload.at(-1)! * reloadCoefficient + - gun.intraClip * intraClipCoefficient)) * - 60 - : ((damageCoefficient * shell.damage.armor) / - (gun.reload[0] * reloadCoefficient)) * - 60 + ? gun.reload[0] + gun.intraClip < gun.reload[1] + ? 1 + : gun.reload.length : undefined; + const damage = shell.damage.armor * damageCoefficient; const dpmEffective = gun.type === 'autoReloader' ? gun.reload.at(-1)! < gun.reload.at(-2)! @@ -343,13 +344,6 @@ export function tankCharacteristics( damageCoefficient * shell.damage.armor * gun.reload.slice(1).length : undefined; const shells = gun.type === 'regular' ? 1 : gun.count; - console.log(gun.reload); - const mostOptimalShellIndex = - gun.type === 'autoReloader' - ? gun.reload[0] + gun.intraClip < gun.reload[1] - ? 1 - : gun.reload.length - : undefined; const shellReloads = gun.type === 'autoReloader' ? gun.reload.map((reload) => reload * reloadCoefficient) @@ -361,7 +355,6 @@ export function tankCharacteristics( const caliber = shell.caliber; const penetration = resolveNearPenetration(shell.penetration) * penetrationCoefficient; - const damage = shell.damage.armor * damageCoefficient; const clipDamage = gun.type === 'regular' ? undefined : gun.count * damage; const moduleDamage = shell.damage.module * damageCoefficient; const explosionRadius = shell.explosionRadius; @@ -471,7 +464,6 @@ export function tankCharacteristics( shellNormalization, shellRicochet, dpm, - dpmMaximum, dpmEffective, shells, mostOptimalShellIndex, From d43391e62541f4d74159110066195b4e1eea5ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 12 Aug 2024 21:14:05 -0500 Subject: [PATCH 010/120] fix: effective dom --- src/core/blitzkit/tankCharacteristics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/blitzkit/tankCharacteristics.ts b/src/core/blitzkit/tankCharacteristics.ts index 71a14e018..d263ec194 100644 --- a/src/core/blitzkit/tankCharacteristics.ts +++ b/src/core/blitzkit/tankCharacteristics.ts @@ -323,7 +323,7 @@ export function tankCharacteristics( const damage = shell.damage.armor * damageCoefficient; const dpmEffective = gun.type === 'autoReloader' - ? gun.reload.at(-1)! < gun.reload.at(-2)! + ? gun.reload[0] > gun.reload[1] + gun.intraClip ? ((damageCoefficient * shell.damage.armor) / (gun.reload.at(-1)! * reloadCoefficient + gun.intraClip * intraClipCoefficient)) * From 6cfa3b9c70ebfff5c10c18c8c3b28363a6484252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:00:36 -0500 Subject: [PATCH 011/120] fix: disabled turret rotation through other objects --- src/components/StaticArmor/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/StaticArmor/index.tsx b/src/components/StaticArmor/index.tsx index ed64e548a..0dab33d50 100644 --- a/src/components/StaticArmor/index.tsx +++ b/src/components/StaticArmor/index.tsx @@ -95,6 +95,7 @@ export const StaticArmor = memo(({ thicknessRange }) => { type={spaced ? ArmorType.Spaced : ArmorType.Primary} thickness={thickness} node={node} + onPointerDown={(event) => event.stopPropagation()} /> ); })} @@ -116,6 +117,7 @@ export const StaticArmor = memo(({ thicknessRange }) => { thickness={trackModelDefinition.thickness} variant="track" node={node} + onPointerDown={(event) => event.stopPropagation()} /> ); })} From 3058756346912e0b48944519c121968d63b6338a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:38:05 -0500 Subject: [PATCH 012/120] feat: camouflage definitiosn --- scripts/buildAssets/definitions.ts | 103 ++++++++++++++++++++- src/core/blitzkit/camouflageDefinitions.ts | 16 ++++ src/core/blitzkit/tankDefinitions/index.ts | 1 + 3 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/core/blitzkit/camouflageDefinitions.ts diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 83f4f83f3..2f5023037 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -8,6 +8,7 @@ import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; +import { CamouflageDefinitions } from '../../src/core/blitzkit/camouflageDefinitions'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { ConsumableDefinitions, @@ -323,6 +324,48 @@ export interface ProvisionsCommon { }; } +type CamouflagesInclude = + | { + nations?: string; + } + | { + vehicle?: { name?: string; minLevel?: number; maxLevel?: number }; + }; + +interface CamouflagesXML { + camouflages: Record< + string, + { + id: number; + userString: string; + description: string; + category: string; + group: string; + kind: string; + notInShop: boolean; + unlockCostCategory?: string; + vehicleFilter: { + include?: CamouflagesInclude | CamouflagesInclude[]; + }; + script: string[] | string; + icon?: string; + unlockPremium?: string; + unlockQuest?: string; + unlockClanLevel?: number; + unlockShopBundle?: string; + unlockTankRank?: number; + } + >; +} + +type CamouflagesYaml = Record< + string, + { + userString?: string; + shortUserString?: string; + } +>; + type ConsumablesVehicleFilter = | { minLevel: number; maxLevel: number } | { name: string } @@ -389,6 +432,7 @@ export async function definitions(production: boolean) { ).available_nations, }; const tankDefinitions: TankDefinitions = {}; + const camouflageDefinitions: CamouflageDefinitions = {}; const modelDefinitions: ModelDefinitions = {}; const mapDefinitions: MapDefinitions = {}; const equipmentDefinitions: EquipmentDefinitions = { @@ -431,6 +475,33 @@ export async function definitions(production: boolean) { ); const maps = await readYAMLDVPL(`${DATA}/maps.yaml.dvpl`); const tankXps = new Map(); + const camouflagesXml = await readXMLDVPL<{ root: CamouflagesXML }>( + `${DATA}/XML/item_defs/vehicles/common/camouflages.xml.dvpl`, + ); + const camouflagesYaml = await readYAMLDVPL( + `${DATA}/camouflages.yaml.dvpl`, + ); + const camouflagesXmlEntries = Object.entries(camouflagesXml.root.camouflages); + + camouflagesXmlEntries.forEach(([camoKey, camo]) => { + const yamlEntry = camouflagesYaml[camoKey]; + const fullName = yamlEntry.userString + ? strings[yamlEntry.userString] + : undefined; + const shortName = yamlEntry.shortUserString + ? strings[yamlEntry.shortUserString] + : undefined; + const resolvedTankName = shortName ?? fullName; + const resolvedTankNameFull = + resolvedTankName === fullName ? undefined : fullName; + + camouflageDefinitions[camo.id] = { + id: camo.id, + name: strings[camo.userString], + tankName: resolvedTankName, + tankNameFull: resolvedTankNameFull, + }; + }); await Promise.all( nations.map(async (nation) => { @@ -554,11 +625,11 @@ export async function definitions(production: boolean) { const fixedCamouflage = tankTags.includes('eventCamouflage_user'); const totalUnlocks: UnlocksListing[] = []; - Object.entries(tankDefinition.root.crew).forEach(([key, value]) => { + Object.entries(tankDefinition.root.crew).forEach(([crewKey, value]) => { let entry: Crew; - const index = crew.findIndex(({ type }) => type === key); + const index = crew.findIndex(({ type }) => type === crewKey); if (index === -1) { - entry = { type: key as CrewMember }; + entry = { type: crewKey as CrewMember }; crew.push(entry); } else { entry = crew[index]; @@ -589,8 +660,29 @@ export async function definitions(production: boolean) { } }); + const camouflages = camouflagesXmlEntries + .filter(([, camo]) => { + if (!camo.vehicleFilter.include) return false; + if (camo.unlockCostCategory !== 'legendary-skins-gold') + return false; + + const includeArray = Array.isArray(camo.vehicleFilter.include) + ? camo.vehicleFilter.include + : [camo.vehicleFilter.include]; + + return includeArray.some((filter) => { + if ('vehicle' in filter && filter.vehicle?.name) { + return filter.vehicle.name === `${nation}:${tankKey}`; + } + + return false; + }); + }) + .map(([, camo]) => camo.id); + tankDefinitions[tankId] = { id: tankId, + camouflages: camouflages.length === 0 ? undefined : camouflages, description: wargamingTankopedia.data[tankId]?.description ?? undefined, fixedCamouflage: fixedCamouflage ? true : undefined, @@ -1262,6 +1354,11 @@ export async function definitions(production: boolean) { encoding: 'base64', path: 'definitions/maps.cdon.lz4', }, + { + content: superCompress(camouflageDefinitions), + encoding: 'base64', + path: 'definitions/camouflages.cdon.lz4', + }, ], production, ); diff --git a/src/core/blitzkit/camouflageDefinitions.ts b/src/core/blitzkit/camouflageDefinitions.ts new file mode 100644 index 000000000..53c9bc3d0 --- /dev/null +++ b/src/core/blitzkit/camouflageDefinitions.ts @@ -0,0 +1,16 @@ +import { asset } from './asset'; +import { fetchCdonLz4 } from './fetchCdonLz4'; + +export type CamouflageDefinitions = Record< + number, + { + id: number; + name: string; + tankName?: string; + tankNameFull?: string; + } +>; + +export const camouflageDefinitions = fetchCdonLz4( + asset('definitions/camouflages.cdon.lz4'), +); diff --git a/src/core/blitzkit/tankDefinitions/index.ts b/src/core/blitzkit/tankDefinitions/index.ts index c345dc972..dccd7789a 100644 --- a/src/core/blitzkit/tankDefinitions/index.ts +++ b/src/core/blitzkit/tankDefinitions/index.ts @@ -43,6 +43,7 @@ export interface TankDefinition { id: number; description?: string; fixedCamouflage?: boolean; + camouflages?: number[]; ancestors?: number[]; successors?: number[]; crew: Crew[]; From ea7d822420c2128720f6943d77e9f55378c6a928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:44:35 -0500 Subject: [PATCH 013/120] feat: legendary camo names in search --- .../components/TankSearch/index.tsx | 4 +-- src/core/blitz/resolveTankId.ts | 5 ++-- src/core/blitzkit/tankDefinitions/index.ts | 18 ------------- .../blitzkit/tankDefinitions/tankNames.ts | 26 +++++++++++++++++++ src/core/discord/autocompleteTanks.ts | 4 +-- 5 files changed, 33 insertions(+), 24 deletions(-) create mode 100644 src/core/blitzkit/tankDefinitions/tankNames.ts diff --git a/src/app/tools/tankopedia/components/TankSearch/index.tsx b/src/app/tools/tankopedia/components/TankSearch/index.tsx index cc7f2c0ec..1ff8903bd 100644 --- a/src/app/tools/tankopedia/components/TankSearch/index.tsx +++ b/src/app/tools/tankopedia/components/TankSearch/index.tsx @@ -17,9 +17,9 @@ import { resolveReload } from '../../../../../core/blitzkit/resolveReload'; import { TankDefinition, tankDefinitions, - tankNames, tanksDefinitionsArray, } from '../../../../../core/blitzkit/tankDefinitions'; +import { tankNames } from '../../../../../core/blitzkit/tankDefinitions/tankNames'; import { unionBoundingBox } from '../../../../../core/blitzkit/unionBoundingBox'; import { useAdExempt } from '../../../../../hooks/useAdExempt'; import * as TankFilters from '../../../../../stores/tankFilters'; @@ -375,7 +375,7 @@ export const TankSearch = memo( return sort.direction === 'ascending' ? sorted : sorted.reverse(); } else { const searchedRaw = go(filters.search, awaitedTankNames, { - keys: ['searchableName', 'searchableNameDeburr'], + keys: ['searchableName', 'searchableNameDeburr', 'camouflages'], }); const searchedTanks = searchedRaw.map( (result) => awaitedTankDefinitions[result.obj.id], diff --git a/src/core/blitz/resolveTankId.ts b/src/core/blitz/resolveTankId.ts index 3855e0c23..125ed93f2 100644 --- a/src/core/blitz/resolveTankId.ts +++ b/src/core/blitz/resolveTankId.ts @@ -2,7 +2,8 @@ import { Locale } from 'discord.js'; import { go } from 'fuzzysort'; import markdownEscape from 'markdown-escape'; import { UserError } from '../../hooks/userError'; -import { tankDefinitions, tankNames } from '../blitzkit/tankDefinitions'; +import { tankDefinitions } from '../blitzkit/tankDefinitions'; +import { tankNames } from '../blitzkit/tankDefinitions/tankNames'; import { tankNamesTechTreeOnly } from '../discord/autocompleteTanks'; import { translator } from '../localization/translator'; @@ -19,7 +20,7 @@ export default async function resolveTankId( `${tank}`, await (techTreeOnly ? tankNamesTechTreeOnly : tankNames), { - keys: ['searchableName', 'searchableNameDeburr'], + keys: ['searchableName', 'searchableNameDeburr', 'camouflages'], limit: 1, }, ); diff --git a/src/core/blitzkit/tankDefinitions/index.ts b/src/core/blitzkit/tankDefinitions/index.ts index dccd7789a..04dbfec42 100644 --- a/src/core/blitzkit/tankDefinitions/index.ts +++ b/src/core/blitzkit/tankDefinitions/index.ts @@ -1,4 +1,3 @@ -import { deburr } from 'lodash'; import { Vector2Tuple } from 'three'; import { TankClass, TreeType } from '../../../components/Tanks'; import { asset } from '../asset'; @@ -181,23 +180,6 @@ export const tanksDefinitionsArray = new Promise( resolve((await entries).map((entry) => entry)); // TODO: wtf? }, ); -export const tankNames = tanksDefinitionsArray.then((tanks) => - Promise.all( - tanks.map(async (tank, index) => { - const { id } = (await tanksDefinitionsArray)[index]; - - return { - id, - name: tank.name, - nameFull: tank.nameFull, - searchableName: tank.nameFull ?? tank.name, - searchableNameDeburr: deburr(tank.nameFull ?? tank.name), - treeType: tank.treeType, - }; - }), - ), -); - export type Tier = (typeof TIERS)[number]; export const flags: Record = { diff --git a/src/core/blitzkit/tankDefinitions/tankNames.ts b/src/core/blitzkit/tankDefinitions/tankNames.ts new file mode 100644 index 000000000..11af3afb8 --- /dev/null +++ b/src/core/blitzkit/tankDefinitions/tankNames.ts @@ -0,0 +1,26 @@ +import { deburr } from 'lodash'; +import { tanksDefinitionsArray } from '.'; +import { camouflageDefinitions } from '../camouflageDefinitions'; + +export const tankNames = Promise.all([ + tanksDefinitionsArray, + camouflageDefinitions, +]).then(([tanks, camouflages]) => + Promise.all( + tanks.map(async (tank, index) => { + const { id } = (await tanksDefinitionsArray)[index]; + + return { + id, + name: tank.name, + nameFull: tank.nameFull, + searchableName: tank.nameFull ?? tank.name, + searchableNameDeburr: deburr(tank.nameFull ?? tank.name), + camouflages: tank.camouflages + ?.map((id) => camouflages[id].name) + .join(' '), + treeType: tank.treeType, + }; + }), + ), +); diff --git a/src/core/discord/autocompleteTanks.ts b/src/core/discord/autocompleteTanks.ts index 5b4a2ce71..39e2fd27e 100644 --- a/src/core/discord/autocompleteTanks.ts +++ b/src/core/discord/autocompleteTanks.ts @@ -4,7 +4,7 @@ import { CacheType, } from 'discord.js'; import { go } from 'fuzzysort'; -import { tankNames } from '../blitzkit/tankDefinitions'; +import { tankNames } from '../blitzkit/tankDefinitions/tankNames'; import { DISCORD_CHOICES_MAX_NAME_SIZE, OVERFLOW_SUFFIX, @@ -29,7 +29,7 @@ export default async function autocompleteTanks( focusedOption.value, await (techTreeOnly ? tankNamesTechTreeOnly : tankNames), { - keys: ['searchableName', 'searchableNameDeburr'], + keys: ['searchableName', 'searchableNameDeburr', 'camouflages'], limit: 10, }, ).map(async (item) => { From 9d346082eaf94ab2b1b38e658dc4c66b3f8ce848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:48:47 -0500 Subject: [PATCH 014/120] fix: post ricochet penetration --- .../Armor/components/SpacedArmorSceneComponent/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx index be6ab51db..0b5076ee5 100644 --- a/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx +++ b/src/components/Armor/components/SpacedArmorSceneComponent/index.tsx @@ -140,8 +140,8 @@ export function SpacedArmorSceneComponent({ if ( !allowRicochet && - !noDuplicateIntersections.some((intersection) => { - intersection.object.userData.type === ArmorType.Primary; + noDuplicateIntersections.every((intersection) => { + intersection.object.userData.type !== ArmorType.Primary; }) ) { return null; From 94db2c9159e8dc565d2e4727f6966cdeedfb0ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 13 Aug 2024 19:52:33 -0500 Subject: [PATCH 015/120] fix: additive camouflage values (Synx, you better be right!) --- src/core/blitzkit/tankCharacteristics.ts | 38 +++++++++++++++++------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/core/blitzkit/tankCharacteristics.ts b/src/core/blitzkit/tankCharacteristics.ts index d263ec194..314366b21 100644 --- a/src/core/blitzkit/tankCharacteristics.ts +++ b/src/core/blitzkit/tankCharacteristics.ts @@ -257,7 +257,18 @@ export function tankCharacteristics( [hasGearOil, 2], [hasImprovedGearOil, 4], ); - const camouflageCoefficientMoving = coefficient( + const camouflageCoefficientMoving = sum( + [ + true, + coefficient([ + camouflage, + tank.class === 'AT-SPG' + ? 0.04 + : tank.class === 'heavyTank' + ? 0.03 + : 0.02, + ]), + ], [ hasCamouflageNet, tank.class === 'heavyTank' @@ -268,12 +279,22 @@ export function tankCharacteristics( ? 0.07 : 0.1, ], - [ - camouflage, - tank.class === 'AT-SPG' ? 0.04 : tank.class === 'heavyTank' ? 0.03 : 0.02, - ], ); - const camouflageCoefficientStill = coefficient( + const camouflageCoefficientStill = sum( + [ + true, + coefficient( + [ + camouflage, + tank.class === 'AT-SPG' + ? 0.04 + : tank.class === 'heavyTank' + ? 0.03 + : 0.02, + ], + [true, crewSkills.camouflage * (3 / 100)], + ), + ], [ hasCamouflageNet, tank.class === 'heavyTank' @@ -284,11 +305,6 @@ export function tankCharacteristics( ? 0.14 : 0.2, ], - [ - camouflage, - tank.class === 'AT-SPG' ? 0.04 : tank.class === 'heavyTank' ? 0.03 : 0.02, - ], - [true, crewSkills.camouflage * (3 / 100)], ); const size = normalizeBoundingBox( From 97b251e3a3287d2b618a98bc4107cb73122f5edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:04:06 -0500 Subject: [PATCH 016/120] feat: gamemode consumable and provisions --- scripts/buildAssets/boosterIcons.ts | 8 +- scripts/buildAssets/camouflageIcons.ts | 4 +- scripts/buildAssets/circleFlags.ts | 8 +- scripts/buildAssets/constants.ts | 31 +- .../buildAssets/consumableProvisionIcons.ts | 284 ++++++++++-------- scripts/buildAssets/definitions.ts | 38 ++- scripts/buildAssets/equipmentIcons.ts | 10 +- scripts/buildAssets/moduleIcons.ts | 8 +- scripts/buildAssets/scratchedFlags.ts | 6 +- scripts/buildAssets/shellIcons.ts | 10 +- scripts/buildAssets/tankArmors.ts | 6 +- scripts/buildAssets/tankIcons.ts | 8 +- scripts/buildAssets/tankModels.ts | 8 +- scripts/buildAssets/videos.ts | 12 +- 14 files changed, 225 insertions(+), 216 deletions(-) diff --git a/scripts/buildAssets/boosterIcons.ts b/scripts/buildAssets/boosterIcons.ts index 307b2c8c2..0f987a421 100644 --- a/scripts/buildAssets/boosterIcons.ts +++ b/scripts/buildAssets/boosterIcons.ts @@ -4,14 +4,14 @@ import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; export async function boosterIcons(production: boolean) { - const boosterFiles = (await readdir(`${DATA}/${POI.boosterIcons}`)).filter( + const boosterFiles = (await readdir(`${DATA}/Gfx/Shared/boosters`)).filter( (file) => !file.endsWith('@2x.txt.dvpl') && !file.startsWith('texture0'), ); const image = sharp( - await readDVPLFile(`${DATA}/${POI.boosterIcons}/texture0.packed.webp.dvpl`), + await readDVPLFile(`${DATA}/Gfx/Shared/boosters/texture0.packed.webp.dvpl`), ); const changes: FileChange[] = []; @@ -22,7 +22,7 @@ export async function boosterIcons(production: boolean) { if (name === undefined) return; const sizes = ( - await readStringDVPL(`${DATA}/${POI.boosterIcons}/${file}`) + await readStringDVPL(`${DATA}/Gfx/Shared/boosters/${file}`) ) .split('\n')[4] .split(' ') diff --git a/scripts/buildAssets/camouflageIcons.ts b/scripts/buildAssets/camouflageIcons.ts index 551b130e6..dfa5eba0c 100644 --- a/scripts/buildAssets/camouflageIcons.ts +++ b/scripts/buildAssets/camouflageIcons.ts @@ -1,12 +1,12 @@ import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; export async function camouflageIcons(production: boolean) { console.log('Building camouflage icons...'); const content = await readDVPLFile( - `${DATA}/${POI.defaultCamoIcon.replace('.webp', '.packed.webp.dvpl')}`, + `${DATA}/Gfx/UI/Hangar/IconCamouflage.packed.webp.dvpl`, ).then((content) => content.toString('base64')); const changes: FileChange[] = [ { diff --git a/scripts/buildAssets/circleFlags.ts b/scripts/buildAssets/circleFlags.ts index 8828728e8..2ce95a293 100644 --- a/scripts/buildAssets/circleFlags.ts +++ b/scripts/buildAssets/circleFlags.ts @@ -3,10 +3,10 @@ import sharp from 'sharp'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; export async function circleFlags(production: boolean) { - const flags = await readdir(`${DATA}/${POI.flags}`); + const flags = await readdir(`${DATA}/Gfx/Lobby/flags`); const changes = await Promise.all( flags .filter( @@ -15,7 +15,9 @@ export async function circleFlags(production: boolean) { !flag.endsWith('@2x.packed.webp.dvpl'), ) .map(async (flag) => { - const image = sharp(await readDVPLFile(`${DATA}/${POI.flags}/${flag}`)); + const image = sharp( + await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`), + ); const content = ( await image.trim({ threshold: 100 }).toBuffer() ).toString('base64'); diff --git a/scripts/buildAssets/constants.ts b/scripts/buildAssets/constants.ts index d7649d279..e66c10e87 100644 --- a/scripts/buildAssets/constants.ts +++ b/scripts/buildAssets/constants.ts @@ -2,39 +2,12 @@ import { readdir } from 'fs/promises'; import { argv } from 'process'; const isDepot = argv.includes('--depot'); + export const WOTB_WIN32_DEPOT = 444202; + export const DATA = isDepot ? await (async () => { const [installationVersion] = await readdir(`depots/${WOTB_WIN32_DEPOT}`); return `depots/${WOTB_WIN32_DEPOT}/${installationVersion}/Data`; })() : 'C:/Program Files (x86)/Steam/steamapps/common/World of Tanks Blitz/Data'; - -export const POI = { - vehicleDefinitions: 'XML/item_defs/vehicles', - strings: 'Strings', - cachedStrings: 'https://stufficons.wgcdn.co/localizations/en.yaml', - tankParameters: '3d/Tanks/Parameters', - smallIcons: 'Gfx/UI/BattleScreenHUD/SmallTankIcons', - bigIcons: 'Gfx/UI/BigTankIcons', - flags: 'Gfx/Lobby/flags', - '3d': '3d', - bigShellIcons: 'Gfx/Shared/tank-supply/ammunition/big', - moduleIcons: 'Gfx/UI/ModulesTechTree', - collisionMeshes: '3d/Tanks/CollisionMeshes', - optionalDevices: 'XML/item_defs/vehicles/common/optional_devices.xml', - optionalDeviceSlots: - 'XML/item_defs/vehicles/common/optional_device_slots.xml', - optionalDeviceImageMappings: - 'UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml', - optionalDevicesImage: - 'Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp', - consumablesCommon: 'XML/item_defs/vehicles/common/consumables/common.xml', - consumableIcons: 'Gfx/UI/InventoryIcons/Big/Consumables', - provisionIcons: 'Gfx/UI/InventoryIcons/Big/Provisions', - equipmentItemImageMappings: - 'UI/Screens3/Lobby/Inventory/Equipment/EquipmentItemImage.style.yaml', - provisionsCommon: 'XML/item_defs/vehicles/common/provisions/common.xml', - defaultCamoIcon: 'Gfx/UI/Hangar/IconCamouflage.webp', - boosterIcons: 'Gfx/Shared/boosters', -} as const; diff --git a/scripts/buildAssets/consumableProvisionIcons.ts b/scripts/buildAssets/consumableProvisionIcons.ts index 0f03d13c6..cb2fcdcf6 100644 --- a/scripts/buildAssets/consumableProvisionIcons.ts +++ b/scripts/buildAssets/consumableProvisionIcons.ts @@ -1,3 +1,4 @@ +import { existsSync } from 'fs'; import sharp from 'sharp'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; @@ -5,7 +6,7 @@ import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; import { ConsumablesCommon, ProvisionsCommon } from './definitions'; interface Mappings { @@ -16,149 +17,176 @@ interface Mappings { }[]; } +const listItemsPattern = //g; + export async function consumableProvisionIcons(production: boolean) { console.log('Building consumable and provision icons...'); const changes: FileChange[] = []; - const consumablesTexture = sharp( - await readDVPLFile( - `${DATA}/${POI.consumableIcons}/texture0.packed.webp.dvpl`, + + const styles = [ + 'UI/Styles/Lobby/Inventory/InventoryNormalStyles.yaml', + 'UI/Screens3/Lobby/Inventory/Equipment/EquipmentItemImage.style.yaml', + 'UI/Styles/Lobby/Inventory/Event/InventoryNormalStyles.yaml', + 'UI/Screens/Battle/Styles/BattleEquipmentStyles.yaml', + 'UI/Styles/Lobby/Inventory/Event/InventoryBigStyles.yaml', + ]; + const styleSheets = await Promise.all( + styles.map(async (path) => + Object.values( + (await readYAMLDVPL(`${DATA}/${path}.dvpl`)).StyleSheets, + ), ), - ); - const provisionsTexture = sharp( - await readDVPLFile( - `${DATA}/${POI.provisionIcons}/texture0.packed.webp.dvpl`, - ), - ); + ).then((array) => array.flat()); - const equipmentItemImageMappings = await readYAMLDVPL( - `${DATA}/${POI.equipmentItemImageMappings}.dvpl`, - ); - const consumablesCommon = await readXMLDVPL<{ - root: ConsumablesCommon; - }>(`${DATA}/${POI.consumablesCommon}.dvpl`); - const provisionsCommon = await readXMLDVPL<{ - root: ProvisionsCommon; - }>(`${DATA}/${POI.provisionsCommon}.dvpl`); - const styleSheets = Object.values(equipmentItemImageMappings.StyleSheets); + for (const match of ( + await readStringDVPL( + `${DATA}/XML/item_defs/vehicles/common/consumables/list.xml.dvpl`, + ) + ).matchAll(listItemsPattern)) { + const consumablesCommon = await readXMLDVPL<{ + root: ConsumablesCommon; + }>( + `${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml.dvpl`, + ); - await Promise.all( - Object.values(consumablesCommon.root).map(async (consumable) => { - const styleSheet = styleSheets.find((styleSheet) => - styleSheet.selectors.includes( - `.equipment_item.${consumable.icon} * .equipment-img`, - ), - ); - - if (!styleSheet) { - console.warn( - `No style sheet found for consumable ${consumable.icon}; skipping...`, + await Promise.all( + Object.values(consumablesCommon.root).map(async (consumable) => { + const styleSheet = styleSheets.find((styleSheet) => + styleSheet.selectors.some((selector) => + selector.includes(consumable.icon), + ), ); - return; - } - const configPath = styleSheet.properties['bg-sprite'] - .replace('~res:/', '') - .replace('.psd', '') - .replace('.txt', ''); + if (!styleSheet) { + console.warn( + `No style sheet found for consumable ${consumable.icon}; skipping...`, + ); + return; + } - if (configPath.startsWith('Gfx/Shared')) { - const image = sharp( - await readDVPLFile(`${DATA}/${configPath}.packed.webp.dvpl`), + const configPath = styleSheet.properties['bg-sprite'] + .replace('~res:/', '') + .replace('.psd', '') + .replace('.txt', ''); + + if (existsSync(`${DATA}/${configPath}.packed.webp.dvpl`)) { + const image = sharp( + await readDVPLFile(`${DATA}/${configPath}.packed.webp.dvpl`), + ); + const content = ( + await image.trim({ threshold: 100 }).toBuffer() + ).toString('base64'); + + changes.push({ + path: `icons/consumables/${consumable.id}.webp`, + encoding: 'base64', + content, + }); + } else { + const consumablesTexture = sharp( + await readDVPLFile( + `${`${DATA}/${configPath}`.split('/').slice(0, -1).join('/')}/texture0.packed.webp.dvpl`, + ), + ); + const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt.dvpl`)) + .split('\n')[4] + .split(' ') + .map(Number); + const content = ( + await consumablesTexture + .clone() + .extract({ + left: sizes[0], + top: sizes[1], + width: sizes[2], + height: sizes[3], + }) + .toBuffer() + ).toString('base64'); + + changes.push({ + path: `icons/consumables/${consumable.id}.webp`, + encoding: 'base64', + content, + }); + } + }), + ); + } + + for (const match of ( + await readStringDVPL( + `${DATA}/XML/item_defs/vehicles/common/provisions/list.xml.dvpl`, + ) + ).matchAll(listItemsPattern)) { + const provisionsCommon = await readXMLDVPL<{ + root: ProvisionsCommon; + }>(`${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml.dvpl`); + await Promise.all( + Object.values(provisionsCommon.root).map(async (provision) => { + const styleSheet = styleSheets.find((styleSheet) => + styleSheet.selectors.some((selector) => + selector.includes(provision.icon), + ), ); - const content = ( - await image.trim({ threshold: 100 }).toBuffer() - ).toString('base64'); - changes.push({ - path: `icons/consumables/${consumable.id}.webp`, - encoding: 'base64', - content, - }); - } else { - const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt.dvpl`)) - .split('\n')[4] - .split(' ') - .map(Number); - const content = ( - await consumablesTexture - .clone() - .extract({ - left: sizes[0], - top: sizes[1], - width: sizes[2], - height: sizes[3], - }) - .toBuffer() - ).toString('base64'); + if (!styleSheet) { + console.warn( + `No style sheet found for provision ${provision.icon}; skipping...`, + ); + return; + } - changes.push({ - path: `icons/consumables/${consumable.id}.webp`, - encoding: 'base64', - content, - }); - } - }), - ); + const configPath = styleSheet.properties['bg-sprite'] + .replace('~res:/', '') + .replace('.psd', '') + .replace('.txt', ''); - await Promise.all( - Object.values(provisionsCommon.root).map(async (provision) => { - const styleSheet = styleSheets.find((styleSheet) => - styleSheet.selectors.includes( - `.equipment_item.${provision.icon} * .equipment-img`, - ), - ); + if (existsSync(`${DATA}/${configPath}.packed.webp.dvpl`)) { + const image = sharp( + await readDVPLFile(`${DATA}/${configPath}.packed.webp.dvpl`), + ); + const content = ( + await image.trim({ threshold: 100 }).toBuffer() + ).toString('base64'); - if (!styleSheet) { - console.warn( - `No style sheet found for provision ${provision.icon}; skipping...`, - ); - return; - } + changes.push({ + path: `icons/provisions/${provision.id}.webp`, + encoding: 'base64', + content, + }); + } else { + const provisionsTexture = sharp( + await readDVPLFile( + `${`${DATA}/${configPath}`.split('/').slice(0, -1).join('/')}/texture0.packed.webp.dvpl`, + ), + ); + const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt.dvpl`)) + .split('\n')[4] + .split(' ') + .map(Number); + const content = ( + await provisionsTexture + .clone() + .extract({ + left: sizes[0], + top: sizes[1], + width: sizes[2], + height: sizes[3], + }) + .toBuffer() + ).toString('base64'); - const configPath = styleSheet.properties['bg-sprite'] - .replace('~res:/', '') - .replace('.psd', '') - .replace('.txt', ''); - - if (configPath.startsWith('Gfx/Shared')) { - const image = sharp( - await readDVPLFile(`${DATA}/${configPath}.packed.webp.dvpl`), - ); - const content = ( - await image.trim({ threshold: 100 }).toBuffer() - ).toString('base64'); - - changes.push({ - path: `icons/provisions/${provision.id}.webp`, - encoding: 'base64', - content, - }); - } else { - const sizes = (await readStringDVPL(`${DATA}/${configPath}.txt.dvpl`)) - .split('\n')[4] - .split(' ') - .map(Number); - const content = ( - await provisionsTexture - .clone() - .extract({ - left: sizes[0], - top: sizes[1], - width: sizes[2], - height: sizes[3], - }) - .toBuffer() - ).toString('base64'); - - changes.push({ - path: `icons/provisions/${provision.id}.webp`, - encoding: 'base64', - content, - }); - } - }), - ); + changes.push({ + path: `icons/provisions/${provision.id}.webp`, + encoding: 'base64', + content, + }); + } + }), + ); + } await commitAssets('consumable and provision icons', changes, production); } diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 2f5023037..959bdcc51 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -38,7 +38,7 @@ import { Tier, Unlock, } from '../../src/core/blitzkit/tankDefinitions'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; import { Avatar } from './skillIcons'; import { TankParameters } from './tankIcons'; @@ -444,18 +444,20 @@ export async function definitions(production: boolean) { const skillDefinitions: SkillDefinitions = { classes: { lightTank: [], mediumTank: [], heavyTank: [], 'AT-SPG': [] }, }; - const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then( + const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( (nations) => nations.filter((nation) => nation !== 'common'), ); const tankStringIdMap: Record = {}; const stringsPreInstalled = await readYAMLDVPL( - `${DATA}/${POI.strings}/en.yaml.dvpl`, + `${DATA}/Strings/en.yaml.dvpl`, ); - const stringsCache = await fetch(POI.cachedStrings) + const stringsCache = await fetch( + 'https://stufficons.wgcdn.co/localizations/en.yaml', + ) .then((response) => response.text()) .then((string) => parseYaml(string) as BlitzStrings); const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>( - `${DATA}/${POI.optionalDevices}.dvpl`, + `${DATA}/XML/item_defs/vehicles/common/optional_devices.xml.dvpl`, ); const strings = { ...stringsPreInstalled, @@ -463,12 +465,12 @@ export async function definitions(production: boolean) { }; const optionalDeviceSlots = await readXMLDVPL<{ root: OptionalDeviceSlots; - }>(`${DATA}/${POI.optionalDeviceSlots}.dvpl`); + }>(`${DATA}/XML/item_defs/vehicles/common/optional_device_slots.xml.dvpl`); const consumables = await readXMLDVPL<{ root: ConsumablesCommon }>( - `${DATA}/${POI.consumablesCommon}.dvpl`, + `${DATA}/XML/item_defs/vehicles/common/consumables/common.xml.dvpl`, ); const provisions = await readXMLDVPL<{ root: ProvisionsCommon }>( - `${DATA}/${POI.provisionsCommon}.dvpl`, + `${DATA}/XML/item_defs/vehicles/common/provisions/common.xml.dvpl`, ); const avatar = await readXMLDVPL<{ root: Avatar }>( `${DATA}/XML/item_defs/tankmen/avatar.xml.dvpl`, @@ -506,32 +508,28 @@ export async function definitions(production: boolean) { await Promise.all( nations.map(async (nation) => { const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`, ); const turretList = await readXMLDVPL<{ root: TurretDefinitionsList; }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/components/turrets.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/components/turrets.xml.dvpl`, ); const gunList = await readXMLDVPL<{ root: GunDefinitionsList; - }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/components/guns.xml.dvpl`, - ); + }>(`${DATA}/XML/item_defs/vehicles/${nation}/components/guns.xml.dvpl`); const shellList = await readXMLDVPL<{ root: ShellDefinitionsList; - }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/components/shells.xml.dvpl`, - ); + }>(`${DATA}/XML/item_defs/vehicles/${nation}/components/shells.xml.dvpl`); const enginesList = await readXMLDVPL<{ root: EngineDefinitionsList; }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/components/engines.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/components/engines.xml.dvpl`, ); const chassisList = await readXMLDVPL<{ root: ChassisDefinitionsList; }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/components/chassis.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/components/chassis.xml.dvpl`, ); function resolveUnlocks(unlocks?: Unlocks) { @@ -587,10 +585,10 @@ export async function definitions(production: boolean) { ? { type: 'credits', value: tank.price } : { type: 'gold', value: tank.price['#text'] }; const tankDefinition = await readXMLDVPL<{ root: VehicleDefinitions }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/${tankKey}.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/${tankKey}.xml.dvpl`, ); const tankParameters = await readYAMLDVPL( - `${DATA}/${POI.tankParameters}/${nation}/${tankKey}.yaml.dvpl`, + `${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`, ); const turretOrigin = tankDefinition.root.hull.turretPositions.turret .split(' ') diff --git a/scripts/buildAssets/equipmentIcons.ts b/scripts/buildAssets/equipmentIcons.ts index 171edc14e..795a142e9 100644 --- a/scripts/buildAssets/equipmentIcons.ts +++ b/scripts/buildAssets/equipmentIcons.ts @@ -5,7 +5,7 @@ import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; import { OptionalDevices } from './definitions'; interface Mappings { @@ -22,13 +22,15 @@ export async function equipmentIcons(production: boolean) { const changes: FileChange[] = []; const optionalDevices = await readXMLDVPL<{ root: OptionalDevices }>( - `${DATA}/${POI.optionalDevices}.dvpl`, + `${DATA}/XML/item_defs/vehicles/common/optional_devices.xml.dvpl`, ); const mappings = await readYAMLDVPL( - `${DATA}/${POI.optionalDeviceImageMappings}.dvpl`, + `${DATA}/UI/Screens3/Lobby/Inventory/OptionalDevices/OptionalDevicesItemImage.style.yaml.dvpl`, ); const image = sharp( - await readDVPLFile(`${DATA}/${POI.optionalDevicesImage}.dvpl`), + await readDVPLFile( + `${DATA}/Gfx/UI/InventoryIcons/Big/OptionalDevices/texture0.packed.webp.dvpl`, + ), ); await Promise.all( diff --git a/scripts/buildAssets/moduleIcons.ts b/scripts/buildAssets/moduleIcons.ts index fedd6e7c8..763404d39 100644 --- a/scripts/buildAssets/moduleIcons.ts +++ b/scripts/buildAssets/moduleIcons.ts @@ -3,13 +3,13 @@ import sharp from 'sharp'; import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; export async function moduleIcons(production: boolean) { console.log('Building module icons...'); const changes = await Promise.all( - (await readdir(`${DATA}/${POI.moduleIcons}`)) + (await readdir(`${DATA}/Gfx/UI/ModulesTechTree`)) .filter( (file) => !file.endsWith('@2x.packed.webp.dvpl') && file.startsWith('vehicle'), @@ -18,7 +18,9 @@ export async function moduleIcons(production: boolean) { const nameRaw = file.match(/vehicle(.+)\.packed\.webp\.dvpl/)![1]; const name = nameRaw[0].toLowerCase() + nameRaw.slice(1); const content = ( - await sharp(await readDVPLFile(`${DATA}/${POI.moduleIcons}/${file}`)) + await sharp( + await readDVPLFile(`${DATA}/Gfx/UI/ModulesTechTree/${file}`), + ) .trim() .toBuffer() ).toString('base64'); diff --git a/scripts/buildAssets/scratchedFlags.ts b/scripts/buildAssets/scratchedFlags.ts index 31fc0e562..c3cc6880d 100644 --- a/scripts/buildAssets/scratchedFlags.ts +++ b/scripts/buildAssets/scratchedFlags.ts @@ -2,12 +2,12 @@ import { readdir } from 'fs/promises'; import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; export async function scratchedFlags(production: boolean) { console.log('Building scratched flags...'); - const flags = await readdir(`${DATA}/${POI.flags}`); + const flags = await readdir(`${DATA}/Gfx/Lobby/flags`); const changes = await Promise.all( flags .filter( @@ -16,7 +16,7 @@ export async function scratchedFlags(production: boolean) { !flag.endsWith('@2x.packed.webp.dvpl'), ) .map(async (flag) => { - const content = await readBase64DVPL(`${DATA}/${POI.flags}/${flag}`); + const content = await readBase64DVPL(`${DATA}/Gfx/Lobby/flags/${flag}`); const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1]; return { diff --git a/scripts/buildAssets/shellIcons.ts b/scripts/buildAssets/shellIcons.ts index d08b271ae..60adc62a0 100644 --- a/scripts/buildAssets/shellIcons.ts +++ b/scripts/buildAssets/shellIcons.ts @@ -4,24 +4,26 @@ import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readStringDVPL } from '../../src/core/blitz/readStringDVPL'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; export async function shellIcons(production: boolean) { console.log('Building shell icons...'); const image = sharp( await readDVPLFile( - `${DATA}/${POI.bigShellIcons}/texture0.packed.webp.dvpl`, + `${DATA}/Gfx/Shared/tank-supply/ammunition/big/texture0.packed.webp.dvpl`, ), ); const changes = await Promise.all( - (await readdir(`${DATA}/${POI.bigShellIcons}`)) + (await readdir(`${DATA}/Gfx/Shared/tank-supply/ammunition/big`)) .filter((file) => file.endsWith('_l.txt.dvpl')) .map(async (file) => { const name = file.match(/(.+)_l\.txt\.dvpl/)![1]; const sizes = ( - await readStringDVPL(`${DATA}/${POI.bigShellIcons}/${file}`) + await readStringDVPL( + `${DATA}/Gfx/Shared/tank-supply/ammunition/big/${file}`, + ) ) .split('\n')[4] .split(' ') diff --git a/scripts/buildAssets/tankArmors.ts b/scripts/buildAssets/tankArmors.ts index 8c0e104d1..da233edd0 100644 --- a/scripts/buildAssets/tankArmors.ts +++ b/scripts/buildAssets/tankArmors.ts @@ -5,7 +5,7 @@ import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; import { VehicleDefinitionList } from './definitions'; export async function tankArmors(production: boolean) { @@ -13,14 +13,14 @@ export async function tankArmors(production: boolean) { const changes: FileChange[] = []; const nodeIO = new NodeIO(); - const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then( + const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( (nations) => nations.filter((nation) => nation !== 'common'), ); await Promise.all( nations.map(async (nation) => { const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`, ); await Promise.all( diff --git a/scripts/buildAssets/tankIcons.ts b/scripts/buildAssets/tankIcons.ts index ddd1ff803..ef5a00e5c 100644 --- a/scripts/buildAssets/tankIcons.ts +++ b/scripts/buildAssets/tankIcons.ts @@ -7,7 +7,7 @@ import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; import { VehicleDefinitionList } from './definitions'; export interface TankParameters { @@ -46,14 +46,14 @@ export async function tankIcons(production: boolean) { console.log('Building tank icons...'); const changes: FileChange[] = []; - const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then( + const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( (nations) => nations.filter((nation) => nation !== 'common'), ); await Promise.all( nations.map(async (nation) => { const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`, ); await Promise.all( @@ -63,7 +63,7 @@ export async function tankIcons(production: boolean) { const nationVehicleId = tank.id; const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1; const parameters = await readYAMLDVPL( - `${DATA}/${POI.tankParameters}/${nation}/${tankKey}.yaml.dvpl`, + `${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`, ); const smallPath = `${DATA}/${parameters.resourcesPath.smallIconPath .replace(/~res:\//, '') diff --git a/scripts/buildAssets/tankModels.ts b/scripts/buildAssets/tankModels.ts index 8c03b31e7..42721811c 100644 --- a/scripts/buildAssets/tankModels.ts +++ b/scripts/buildAssets/tankModels.ts @@ -6,7 +6,7 @@ import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; import { VehicleDefinitionList } from './definitions'; import { TankParameters } from './tankIcons'; @@ -14,7 +14,7 @@ export async function tankModels(production: boolean) { console.log('Building tank models...'); const nodeIO = new NodeIO(); - const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then( + const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( (nations) => nations.filter((nation) => nation !== 'common'), ); @@ -22,7 +22,7 @@ export async function tankModels(production: boolean) { const nation = nations[nationIndex]; const changes: FileChange[] = []; const tanks = await readXMLDVPL<{ root: VehicleDefinitionList }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`, ); console.log(`Building models for ${nation}`); @@ -33,7 +33,7 @@ export async function tankModels(production: boolean) { const id = toUniqueId(nation, tank.id); const parameters = await readYAMLDVPL( - `${DATA}/${POI.tankParameters}/${nation}/${tankKey}.yaml.dvpl`, + `${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml.dvpl`, ); const model = await extractModel( DATA, diff --git a/scripts/buildAssets/videos.ts b/scripts/buildAssets/videos.ts index 8868ab8ff..2bf5734c5 100644 --- a/scripts/buildAssets/videos.ts +++ b/scripts/buildAssets/videos.ts @@ -7,7 +7,7 @@ import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { VideoDefinitions } from '../../src/core/blitzkit/videos'; -import { DATA, POI } from './constants'; +import { DATA } from './constants'; import { BlitzStrings, botPattern, VehicleDefinitionList } from './definitions'; const youtubers = [ @@ -45,13 +45,15 @@ export async function videos(production: boolean) { }); const youtube = google.youtube({ version: 'v3', auth }); - const nations = await readdir(`${DATA}/${POI.vehicleDefinitions}`).then( + const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( (nations) => nations.filter((nation) => nation !== 'common'), ); const stringsPreInstalled = await readYAMLDVPL( - `${DATA}/${POI.strings}/en.yaml.dvpl`, + `${DATA}/Strings/en.yaml.dvpl`, ); - const stringsCache = await fetch(POI.cachedStrings) + const stringsCache = await fetch( + 'https://stufficons.wgcdn.co/localizations/en.yaml', + ) .then((response) => response.text()) .then((string) => parseYaml(string) as BlitzStrings); const strings = { @@ -62,7 +64,7 @@ export async function videos(production: boolean) { await Promise.all( nations.map(async (nation) => { const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>( - `${DATA}/${POI.vehicleDefinitions}/${nation}/list.xml.dvpl`, + `${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`, ); await Promise.all( From 643c7272ca9f08f32e520e13fef33c12624f2d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:17:23 -0500 Subject: [PATCH 017/120] feat: gamemode definitions --- scripts/buildAssets/definitions.ts | 1 + src/core/blitzkit/tankDefinitions/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 959bdcc51..2c04b47dc 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -680,6 +680,7 @@ export async function definitions(production: boolean) { tankDefinitions[tankId] = { id: tankId, + roles: tank.combatRole ?? {}, camouflages: camouflages.length === 0 ? undefined : camouflages, description: wargamingTankopedia.data[tankId]?.description ?? undefined, diff --git a/src/core/blitzkit/tankDefinitions/index.ts b/src/core/blitzkit/tankDefinitions/index.ts index 04dbfec42..5710b464a 100644 --- a/src/core/blitzkit/tankDefinitions/index.ts +++ b/src/core/blitzkit/tankDefinitions/index.ts @@ -40,6 +40,7 @@ export type ModuleDefinition = | GunDefinition; export interface TankDefinition { id: number; + roles: Record; description?: string; fixedCamouflage?: boolean; camouflages?: number[]; From 6ada813dd53da8a79deb0ee4881e5bad744781b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 14 Aug 2024 20:46:55 -0500 Subject: [PATCH 018/120] feat: gamemode defs --- .vscode/settings.json | 1 - scripts/buildAssets/definitions.ts | 31 ++++++++++++++++++++++++++++ src/core/blitzkit/gameDefinitions.ts | 6 ++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ad9ea3b0b..1ee34dfd5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -68,7 +68,6 @@ "Fullscreen", "fullstats", "fuzzysort", - "gamemode", "gameplay", "glsl", "GLTF", diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 2c04b47dc..4971cada2 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -419,6 +419,7 @@ export async function definitions(production: boolean) { ).then((response) => response.json())) as { data: { [key: number]: { description: null | string } }; }; + const gameDefinitions: GameDefinitions = { version: (await readStringDVPL(`${DATA}/version.txt.dvpl`)) .split(' ')[0] @@ -430,6 +431,7 @@ export async function definitions(production: boolean) { `${DATA}/available_nations.yaml.dvpl`, ) ).available_nations, + gameModes: {}, }; const tankDefinitions: TankDefinitions = {}; const camouflageDefinitions: CamouflageDefinitions = {}; @@ -485,6 +487,35 @@ export async function definitions(production: boolean) { ); const camouflagesXmlEntries = Object.entries(camouflagesXml.root.camouflages); + for (const match of ( + await readYAMLDVPL<{ + Prototypes: { + components: { + UIDataLocalBindingsComponent: { + data: string[][]; + }; + }; + }[]; + }>(`${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`) + ).Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( + /battleType\/([a-zA-Z]+)/g, + )) { + const id = match[1]; + const name = strings[`battleType/${id}`]; + const description = ( + strings[`hangar/battleType/${id}ShortDescription`] ?? + strings[ + `hangar/battleType/${id.slice(0, 1).toUpperCase() + id.slice(1)}ShortDescription` + ] ?? + strings[`hangar/battleType/${id}Description`] + ).split('\n')[0]; + + gameDefinitions.gameModes[id] = { + name, + description, + }; + } + camouflagesXmlEntries.forEach(([camoKey, camo]) => { const yamlEntry = camouflagesYaml[camoKey]; const fullName = yamlEntry.userString diff --git a/src/core/blitzkit/gameDefinitions.ts b/src/core/blitzkit/gameDefinitions.ts index dab1576fe..7697ff3cc 100644 --- a/src/core/blitzkit/gameDefinitions.ts +++ b/src/core/blitzkit/gameDefinitions.ts @@ -1,9 +1,15 @@ import { asset } from './asset'; import { fetchCdonLz4 } from './fetchCdonLz4'; +interface GameMode { + name: string; + description: string; +} + export interface GameDefinitions { version: string; nations: string[]; + gameModes: Record; } export const gameDefinitions = fetchCdonLz4( From 3e00860f7faba5493bf05c2fed27a72681b0416f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:35:09 -0500 Subject: [PATCH 019/120] feat: start of game mode icons --- scripts/buildAssets/definitions.ts | 39 ++++++++++++---------------- scripts/buildAssets/gameModeIcons.ts | 24 +++++++++++++++++ scripts/buildAssets/index.ts | 1 + src/core/blitzkit/gameDefinitions.ts | 3 +-- 4 files changed, 43 insertions(+), 24 deletions(-) create mode 100644 scripts/buildAssets/gameModeIcons.ts diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 4971cada2..596b2f17e 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -400,6 +400,16 @@ interface AvailableNationsYaml { available_nations: string[]; } +export interface SquadBattleTypeUI { + Prototypes: { + components: { + UIDataLocalBindingsComponent: { + data: [string, string, string][]; + }; + }; + }[]; +} + const blitzShellKindToBlitzkit: Record = { ARMOR_PIERCING: ShellType.AP, ARMOR_PIERCING_CR: ShellType.APCR, @@ -486,33 +496,18 @@ export async function definitions(production: boolean) { `${DATA}/camouflages.yaml.dvpl`, ); const camouflagesXmlEntries = Object.entries(camouflagesXml.root.camouflages); + const squadBattleTypeUI = await readYAMLDVPL( + `${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`, + ); - for (const match of ( - await readYAMLDVPL<{ - Prototypes: { - components: { - UIDataLocalBindingsComponent: { - data: string[][]; - }; - }; - }[]; - }>(`${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`) - ).Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( - /battleType\/([a-zA-Z]+)/g, + for (const match of squadBattleTypeUI.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( + /"(\d+)" -> "(battleType\/[a-zA-Z]+)"/g, )) { - const id = match[1]; - const name = strings[`battleType/${id}`]; - const description = ( - strings[`hangar/battleType/${id}ShortDescription`] ?? - strings[ - `hangar/battleType/${id.slice(0, 1).toUpperCase() + id.slice(1)}ShortDescription` - ] ?? - strings[`hangar/battleType/${id}Description`] - ).split('\n')[0]; + const id = Number(match[1]); + const name = strings[match[2]]; gameDefinitions.gameModes[id] = { name, - description, }; } diff --git a/scripts/buildAssets/gameModeIcons.ts b/scripts/buildAssets/gameModeIcons.ts new file mode 100644 index 000000000..31c7193c8 --- /dev/null +++ b/scripts/buildAssets/gameModeIcons.ts @@ -0,0 +1,24 @@ +import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; +import { DATA } from './constants'; +import { SquadBattleTypeUI } from './definitions'; + +// enum EGameMode { +// Rating = 7, +// Scuffle = 22, +// } + +export async function gameModeIcons(production: boolean) { + const squadBattleTypeUI = await readYAMLDVPL( + `${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`, + ); + + for (const match of squadBattleTypeUI.Prototypes[0].components.UIDataLocalBindingsComponent.data[0][2].matchAll( + /"(\d+)" -> "(battleType\/[a-zA-Z]+)"/g, + )) { + const id = Number(match[1]); + + // gameDefinitions.gameModes[id] = { + // name, + // }; + } +} diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index 2a9f8085c..7c62ac81e 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -29,6 +29,7 @@ import { videos } from './videos'; if (!targets && !allTargets) throw new Error('No target(s) specified'); const methods = [ + // gameModeIcons, definitions, tankIcons, videos, diff --git a/src/core/blitzkit/gameDefinitions.ts b/src/core/blitzkit/gameDefinitions.ts index 7697ff3cc..d167e5d46 100644 --- a/src/core/blitzkit/gameDefinitions.ts +++ b/src/core/blitzkit/gameDefinitions.ts @@ -3,13 +3,12 @@ import { fetchCdonLz4 } from './fetchCdonLz4'; interface GameMode { name: string; - description: string; } export interface GameDefinitions { version: string; nations: string[]; - gameModes: Record; + gameModes: Record; } export const gameDefinitions = fetchCdonLz4( From f07aa9a2a7ff995b9e37d7883bb9f1f71217b877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:06:57 -0500 Subject: [PATCH 020/120] fix: variable most optimal shell --- .../[id]/components/Characteristics/index.tsx | 2 +- src/core/blitzkit/resolveDpm.ts | 24 ++++++++++++------- src/core/blitzkit/tankCharacteristics.ts | 19 +++++++++++---- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index 77eb8e3f5..426af6b45 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -193,7 +193,7 @@ export function Characteristics() { {gun.type === 'autoReloader' ? ( <> - {stats.mostOptimalShellIndex} + {stats.mostOptimalShellIndex! + 1} {stats.shellReloads!.map((reload, index) => ( diff --git a/src/core/blitzkit/resolveDpm.ts b/src/core/blitzkit/resolveDpm.ts index c9956f5c3..2cf3ad9e5 100644 --- a/src/core/blitzkit/resolveDpm.ts +++ b/src/core/blitzkit/resolveDpm.ts @@ -18,15 +18,21 @@ export function resolveDpm( (gun.reload * reloadCoefficient + (gun.count - 1) * gun.intraClip * intraClipCoefficient); } else { - if (gun.reload[0] < gun.reload[1] + gun.intraClip) { - // first shell's the best - dps = alpha / (gun.reload[0] * reloadCoefficient); - } else { - dps = - alpha / - (gun.reload.at(-1)! * reloadCoefficient + - gun.intraClip * intraClipCoefficient); - } + const mostOptimalShell = gun.reload.reduce((current, reloadRaw, index) => { + const reload = + reloadRaw * reloadCoefficient + + (index > 0 ? gun.intraClip * intraClipCoefficient : 0); + + if (current === null || reload < current.reload) { + return { index, reload }; + } + return current; + }, null)!; + + dps = alpha / mostOptimalShell?.reload; } return dps * 60; diff --git a/src/core/blitzkit/tankCharacteristics.ts b/src/core/blitzkit/tankCharacteristics.ts index 314366b21..5eee4c6bf 100644 --- a/src/core/blitzkit/tankCharacteristics.ts +++ b/src/core/blitzkit/tankCharacteristics.ts @@ -330,11 +330,22 @@ export function tankCharacteristics( reloadCoefficient, intraClipCoefficient, ); + const intraClip = + gun.type === 'regular' ? undefined : gun.intraClip * intraClipCoefficient; const mostOptimalShellIndex = gun.type === 'autoReloader' - ? gun.reload[0] + gun.intraClip < gun.reload[1] - ? 1 - : gun.reload.length + ? gun.reload.reduce( + (current, reloadRaw, index) => { + const reload = + reloadRaw * reloadCoefficient + (index > 0 ? intraClip! : 0); + + if (current === null || reload < current.reload) { + return { index, reload }; + } + return current; + }, + null, + )!.index : undefined; const damage = shell.damage.armor * damageCoefficient; const dpmEffective = @@ -366,8 +377,6 @@ export function tankCharacteristics( : undefined; const shellReload = gun.type === 'autoReloader' ? undefined : gun.reload * reloadCoefficient; - const intraClip = - gun.type === 'regular' ? undefined : gun.intraClip * intraClipCoefficient; const caliber = shell.caliber; const penetration = resolveNearPenetration(shell.penetration) * penetrationCoefficient; From 1132018d16b7dbc8fa0b78cd49879e8385af1c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:32:08 -0500 Subject: [PATCH 021/120] feat: seperable buttons and remove antagonist configurer --- .../components/ConfigurationChildWrapper.tsx | 9 +- .../components/Miscellaneous.tsx | 4 - .../Model/CharacteristicsSection.tsx | 3 +- .../components/Model/components/Options.tsx | 157 ++---------------- src/components/ConsumablesManager.tsx | 12 +- src/components/CrewSkillManager.tsx | 2 - src/components/EquipmentManager.tsx | 12 +- .../ModuleButtons/ConsumableButton.tsx | 9 +- .../ModuleButtons/TankComponentButton.tsx | 11 -- src/components/ModuleManager.tsx | 12 -- src/components/ProvisionsManager.tsx | 5 +- 11 files changed, 36 insertions(+), 200 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx index 3c83a2f74..f164672eb 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx @@ -1,15 +1,16 @@ -import { Flex } from '@radix-ui/themes'; +import { Flex, FlexProps } from '@radix-ui/themes'; import { ReactNode } from 'react'; -interface ConfigurationChildWrapperProps { +type ConfigurationChildWrapperProps = FlexProps & { children: ReactNode; -} +}; export function ConfigurationChildWrapper({ children, + ...props }: ConfigurationChildWrapperProps) { return ( - + {children} ); diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx index d82594867..2713ba63d 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous.tsx @@ -47,8 +47,6 @@ export function Miscellaneous() { left: '50%', transform: 'translate(calc(-50% + 4px), calc(-50% + 4px))', }} - first - last onClick={() => { mutateDuel((draft) => { draft.protagonist.camouflage = !camouflage; @@ -59,8 +57,6 @@ export function Miscellaneous() { 0} - first - last banner={ cooldownBooster === 0 ? undefined diff --git a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx index f9a803d1f..7347b9e1b 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx @@ -36,7 +36,7 @@ export function CharacteristicsSection() { justify="center" direction={{ initial: 'column', sm: 'row' }} > - + Configuration @@ -45,7 +45,6 @@ export function CharacteristicsSection() { - - + {[...antagonistUniqueGuns] .reverse() .map(({ gun, turret }, index) => ( @@ -196,8 +190,6 @@ export function Options({ thicknessRange }: OptionsProps) { draft.antagonist.shell = gun.shells[0]; }) } - first={index === 0} - last={index === antagonistUniqueGuns.length - 1} selected={gun.id === antagonistGun.id} discriminator={TIER_ROMAN_NUMERALS[gun.tier]} /> @@ -343,136 +335,21 @@ export function Options({ thicknessRange }: OptionsProps) { onValueChange={setTab} style={{ position: 'relative' }} > - - - - - - - Search - Configure - - - - - { - mutateDuel((draft) => { - draft.antagonist.tank = tank; - draft.antagonist.engine = tank.engines.at(-1)!; - draft.antagonist.track = tank.tracks.at(-1)!; - draft.antagonist.turret = tank.turrets.at(-1)!; - draft.antagonist.gun = - draft.antagonist.turret.guns.at(-1)!; - draft.antagonist.shell = - draft.antagonist.gun.shells[0]; - }); - setAntagonistSelectorOpen(false); - }} - /> - - - - - - - - {antagonistTank.name} modules - - - - - {antagonistTank.turrets.map((turret, index) => ( - { - mutateDuel((draft) => { - draft.antagonist.turret = turret; - draft.antagonist.gun = - turret.guns.at(-1)!; - draft.antagonist.shell = - draft.antagonist.gun.shells[0]; - }); - mutateTankopediaEphemeral((draft) => { - draft.shot = undefined; - }); - }} - selected={antagonistTurret.id === turret.id} - discriminator={ - TIER_ROMAN_NUMERALS[turret.tier] - } - module="turret" - /> - ))} - - - {antagonistTurret.guns.map((gun, index) => ( - { - mutateDuel((draft) => { - draft.antagonist.gun = gun; - draft.antagonist.shell = gun.shells[0]; - }); - }} - selected={antagonistGun.id === gun.id} - discriminator={TIER_ROMAN_NUMERALS[gun.tier]} - module="gun" - /> - ))} - - - - - - Properties - -
    -
  • - Turret: {antagonistTurret.name} -
  • -
  • - Gun: {antagonistGun.name} -
  • -
  • Shells:
  • -
      - {antagonistGun.shells.map((shell) => ( -
    • - {SHELL_NAMES[shell.type]}:{' '} - - {resolveNearPenetration(shell.penetration)} - mm - - , {shell.damage.armor}HP -
    • - ))} -
    -
-
-
-
-
+ { + mutateDuel((draft) => { + draft.antagonist.tank = tank; + draft.antagonist.engine = tank.engines.at(-1)!; + draft.antagonist.track = tank.tracks.at(-1)!; + draft.antagonist.turret = tank.turrets.at(-1)!; + draft.antagonist.gun = + draft.antagonist.turret.guns.at(-1)!; + draft.antagonist.shell = draft.antagonist.gun.shells[0]; + }); + setAntagonistSelectorOpen(false); + }} + /> diff --git a/src/components/ConsumablesManager.tsx b/src/components/ConsumablesManager.tsx index a9119731e..e10c78f2b 100644 --- a/src/components/ConsumablesManager.tsx +++ b/src/components/ConsumablesManager.tsx @@ -24,14 +24,7 @@ export function ConsumablesManager({ hasHighEndConsumables, }: ConsumablesManagerProps) { return ( - + {consumables.map((consumable, index) => { const isSelected = selected.some((id) => id === consumable.id); @@ -53,9 +46,6 @@ export function ConsumablesManager({ : undefined } key={consumable.id} - first={index === 0} - last={index === consumables.length - 1} - rowChild disabled={disabled && !isSelected} consumable={consumable.id} selected={isSelected} diff --git a/src/components/CrewSkillManager.tsx b/src/components/CrewSkillManager.tsx index a3686bfef..7f3b3c64f 100644 --- a/src/components/CrewSkillManager.tsx +++ b/src/components/CrewSkillManager.tsx @@ -30,8 +30,6 @@ export function CrewSkillManager({ 0} discriminator={ level === 0 ? undefined : TIER_ROMAN_NUMERALS[level as Tier] diff --git a/src/components/EquipmentManager.tsx b/src/components/EquipmentManager.tsx index 08b3d3edc..e0fa540f8 100644 --- a/src/components/EquipmentManager.tsx +++ b/src/components/EquipmentManager.tsx @@ -23,8 +23,10 @@ export function EquipmentManager({ { const draft = cloneDeep(matrix); @@ -40,8 +42,10 @@ export function EquipmentManager({ /> { const draft = cloneDeep(matrix); diff --git a/src/components/ModuleButtons/ConsumableButton.tsx b/src/components/ModuleButtons/ConsumableButton.tsx index 950ccb8a2..370074de8 100644 --- a/src/components/ModuleButtons/ConsumableButton.tsx +++ b/src/components/ModuleButtons/ConsumableButton.tsx @@ -23,17 +23,13 @@ export function ConsumableButton({ return ( {(cooldown || duration) && ( - + {duration && ( 0 ? 'green' @@ -50,6 +46,7 @@ export function ConsumableButton({ )} {cooldown && ( { selected?: boolean; - first?: boolean; - last?: boolean; - rowChild?: boolean; children?: ReactNode; discriminator?: ReactNode; disabled?: boolean; @@ -17,9 +14,6 @@ export interface TankComponentButtonProps export function TankComponentButton({ variant, selected, - first = false, - last = false, - rowChild, discriminator, special, children, @@ -38,11 +32,6 @@ export function TankComponentButton({ minWidth: 48, height: 40, position: 'relative', - borderTopLeftRadius: first ? undefined : 0, - borderTopRightRadius: last ? undefined : 0, - borderBottomLeftRadius: first ? undefined : 0, - borderBottomRightRadius: last ? undefined : 0, - margin: rowChild ? -0.5 : 'unset', overflow: 'hidden', cursor: 'unset', pointerEvents: variant === 'ghost' ? 'none' : undefined, diff --git a/src/components/ModuleManager.tsx b/src/components/ModuleManager.tsx index e51014e1e..832925116 100644 --- a/src/components/ModuleManager.tsx +++ b/src/components/ModuleManager.tsx @@ -41,9 +41,6 @@ export function ModuleManager({ setTurretMenuOpen(true)} /> @@ -85,9 +82,6 @@ export function ModuleManager({ setGunMenuOpen(true)} /> @@ -128,9 +122,6 @@ export function ModuleManager({ setEngineMenuOpen(true)} /> @@ -170,9 +161,6 @@ export function ModuleManager({ setTrackMenuOpen(true)} /> diff --git a/src/components/ProvisionsManager.tsx b/src/components/ProvisionsManager.tsx index 689e75305..b8aafd752 100644 --- a/src/components/ProvisionsManager.tsx +++ b/src/components/ProvisionsManager.tsx @@ -15,16 +15,13 @@ export function ProvisionsManager({ disabled, }: ProvisionsManagerProps) { return ( - + {provisions.map((provision, index) => { const isSelected = selected.includes(provision); return ( Date: Thu, 15 Aug 2024 20:02:42 -0500 Subject: [PATCH 022/120] feat: logs --- docs/changelogs/1.22.1.md | 19 +++++++++++++++++++ package.json | 2 +- public/assets/versions.json | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 docs/changelogs/1.22.1.md diff --git a/docs/changelogs/1.22.1.md b/docs/changelogs/1.22.1.md new file mode 100644 index 000000000..a05562a0a --- /dev/null +++ b/docs/changelogs/1.22.1.md @@ -0,0 +1,19 @@ +# BlitzKit 1.22.1 + +## Features + +- Legendary camouflage names are now included in the Tankopedia search (for example, you can search up "Shark" and the T54E2 will show up) +- Provision and consumable buttons in the Tankopedia and Compare tools are now separate buttons + +## Fixes + +- The name and icons of tanks in the Tankopedia search page are now properly aligned and trimmed +- The Tankopedia search is now stricter; thus, filters out nonsensical results +- The most optimal shell index once again shows the correct index +- The DPM listing is now in parity with the game which is what "Max DPM" used to be previously +- The Max DPM value is now also correct since the optimal shell index has been corrected +- The mastery of crew members who play a secondary role in the tank is now handled properly +- The turret of tanks cannot be accidentally rotated when dragging over other objects (like the body of the tank) +- Penetrations are once again calculated after a ricochet +- Camouflage values are now calculated properly when the Camouflage Net equipment is applied +- Removed the redundant Configure tab when selecting an antagonist tank diff --git a/package.json b/package.json index 1e33a9889..10cbfd377 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkit", - "version": "1.22.0", + "version": "1.22.1", "description": "🎉 Tools for everything World of Tanks Blitz", "main": "src/server.ts", "type": "module", diff --git a/public/assets/versions.json b/public/assets/versions.json index 9193a276d..c9af294ec 100644 --- a/public/assets/versions.json +++ b/public/assets/versions.json @@ -1 +1 @@ -["1.10.0","1.10.1","1.10.2","1.11.0","1.12.0","1.12.1","1.12.2","1.12.3","1.12.4","1.12.5","1.12.6","1.12.7","1.12.8","1.12.9","1.13.0","1.13.1","1.13.2","1.13.3","1.14.0","1.14.1","1.14.2","1.14.3","1.14.4","1.15.0","1.15.1","1.15.10","1.15.11","1.15.12","1.15.13","1.15.2","1.15.3","1.15.4","1.15.5","1.15.6","1.15.7","1.15.8","1.15.9","1.16.0","1.16.1","1.16.2","1.16.3","1.16.4","1.17.0","1.17.1","1.17.2","1.18.0","1.18.1","1.18.2","1.18.3","1.19.0","1.19.1","1.19.2","1.19.3","1.19.4","1.19.5","1.19.6","1.20.0","1.20.1","1.20.2","1.20.3","1.20.4","1.20.5","1.21.0","1.21.1","1.21.2","1.21.3","1.22.0","1.3.0","1.3.1","1.3.2","1.3.3","1.4.0","1.4.1","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.6.0","1.7.0","1.7.1","1.7.2","1.7.3-1.7.4","1.7.5","1.7.6","1.7.7","1.8.0","1.8.1","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","1.9.5"] \ No newline at end of file +["1.10.0","1.10.1","1.10.2","1.11.0","1.12.0","1.12.1","1.12.2","1.12.3","1.12.4","1.12.5","1.12.6","1.12.7","1.12.8","1.12.9","1.13.0","1.13.1","1.13.2","1.13.3","1.14.0","1.14.1","1.14.2","1.14.3","1.14.4","1.15.0","1.15.1","1.15.10","1.15.11","1.15.12","1.15.13","1.15.2","1.15.3","1.15.4","1.15.5","1.15.6","1.15.7","1.15.8","1.15.9","1.16.0","1.16.1","1.16.2","1.16.3","1.16.4","1.17.0","1.17.1","1.17.2","1.18.0","1.18.1","1.18.2","1.18.3","1.19.0","1.19.1","1.19.2","1.19.3","1.19.4","1.19.5","1.19.6","1.20.0","1.20.1","1.20.2","1.20.3","1.20.4","1.20.5","1.21.0","1.21.1","1.21.2","1.21.3","1.22.0","1.22.1","1.3.0","1.3.1","1.3.2","1.3.3","1.4.0","1.4.1","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.6.0","1.7.0","1.7.1","1.7.2","1.7.3-1.7.4","1.7.5","1.7.6","1.7.7","1.8.0","1.8.1","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","1.9.5"] \ No newline at end of file From b25814e3991eb687daeedc5ee2b2544a0edbf88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 15 Aug 2024 21:08:02 -0500 Subject: [PATCH 023/120] fix: trim --- scripts/buildAssets/definitions.ts | 7 ++-- scripts/buildAssets/gameModeIcons.ts | 52 +++++++++++++++++++++------- scripts/buildAssets/index.ts | 3 +- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 596b2f17e..e21b2d3c2 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -400,7 +400,7 @@ interface AvailableNationsYaml { available_nations: string[]; } -export interface SquadBattleTypeUI { +export interface SquadBattleTypeStyles { Prototypes: { components: { UIDataLocalBindingsComponent: { @@ -496,11 +496,11 @@ export async function definitions(production: boolean) { `${DATA}/camouflages.yaml.dvpl`, ); const camouflagesXmlEntries = Object.entries(camouflagesXml.root.camouflages); - const squadBattleTypeUI = await readYAMLDVPL( + const squadBattleTypeStyles = await readYAMLDVPL( `${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`, ); - for (const match of squadBattleTypeUI.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( + for (const match of squadBattleTypeStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( /"(\d+)" -> "(battleType\/[a-zA-Z]+)"/g, )) { const id = Number(match[1]); @@ -1336,6 +1336,7 @@ export async function definitions(production: boolean) { }; }); + return; await commitAssets( 'definitions', [ diff --git a/scripts/buildAssets/gameModeIcons.ts b/scripts/buildAssets/gameModeIcons.ts index 31c7193c8..90e3463d4 100644 --- a/scripts/buildAssets/gameModeIcons.ts +++ b/scripts/buildAssets/gameModeIcons.ts @@ -1,24 +1,52 @@ +import sharp from 'sharp'; +import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; +import { commitAssets } from '../../src/core/blitzkit/commitAssets'; +import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; import { DATA } from './constants'; -import { SquadBattleTypeUI } from './definitions'; - -// enum EGameMode { -// Rating = 7, -// Scuffle = 22, -// } +import { SquadBattleTypeStyles } from './definitions'; export async function gameModeIcons(production: boolean) { - const squadBattleTypeUI = await readYAMLDVPL( + const changes: FileChange[] = []; + const gameTypeSelectorStyles = await readYAMLDVPL( + `${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml.dvpl`, + ); + const squadBattleTypeStyles = await readYAMLDVPL( `${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`, ); + const bannerMatches: { name: string; path: string }[] = []; - for (const match of squadBattleTypeUI.Prototypes[0].components.UIDataLocalBindingsComponent.data[0][2].matchAll( - /"(\d+)" -> "(battleType\/[a-zA-Z]+)"/g, + for (const match of gameTypeSelectorStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( + /eGameMode\.([a-zA-Z]+) -> "~res:([^"]+)"/g, + )) { + bannerMatches.push({ name: match[1], path: match[2] }); + } + + for (const match of squadBattleTypeStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( + /"(\d+)" -> "battleType\/([a-zA-Z]+)"/g, )) { const id = Number(match[1]); + const name = match[2]; + let path = bannerMatches.find( + (bannerMatch) => bannerMatch.name.toLowerCase() === name.toLowerCase(), + )?.path; - // gameDefinitions.gameModes[id] = { - // name, - // }; + if (path === undefined) { + path = `/Gfx/UI/Hangar/GameTypes/battle-type_${name.toLowerCase()}`; + } + + const content = ( + await sharp(await readDVPLFile(`${DATA}${path}.packed.webp.dvpl`)) + .trim({ background: { r: 0, g: 0, b: 0, alpha: 0 } }) + .toBuffer() + ).toString('base64'); + + changes.push({ + path: `icons/game_mode_banners/${id}.webp`, + content, + encoding: 'base64', + }); } + + await commitAssets('game mode icons', changes, production); } diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index 7c62ac81e..0bd4afe59 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -17,6 +17,7 @@ import { consumableProvisionIcons } from './consumableProvisionIcons'; import { currencies } from './currencies'; import { definitions } from './definitions'; import { equipmentIcons } from './equipmentIcons'; +import { gameModeIcons } from './gameModeIcons'; import { moduleIcons } from './moduleIcons'; import { scratchedFlags } from './scratchedFlags'; import { shellIcons } from './shellIcons'; @@ -29,7 +30,7 @@ import { videos } from './videos'; if (!targets && !allTargets) throw new Error('No target(s) specified'); const methods = [ - // gameModeIcons, + gameModeIcons, definitions, tankIcons, videos, From e9d5de7e97d108f207d6861eecb424299ccfe561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:52:29 -0500 Subject: [PATCH 024/120] feat: abilites --- scripts/buildAssets/definitions.ts | 36 +++++++++++- .../{gameModeIcons.ts => gameModeBanners.ts} | 6 +- scripts/buildAssets/index.ts | 4 +- .../[id]/components/Model/GameModeSection.tsx | 56 +++++++++++++++++++ .../[id]/components/Model/TankopediaPlug.tsx | 30 ---------- .../[id]/components/Model/TechTreeSection.tsx | 1 + src/app/tools/tankopedia/[id]/page.tsx | 2 + .../Armor/components/PrimaryArmorScene.tsx | 8 --- src/core/blitzkit/tankCharacteristics.ts | 2 - src/core/blitzkit/tankDefinitions/index.ts | 11 +--- 10 files changed, 101 insertions(+), 55 deletions(-) rename scripts/buildAssets/{gameModeIcons.ts => gameModeBanners.ts} (91%) create mode 100644 src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx delete mode 100644 src/app/tools/tankopedia/[id]/components/Model/TankopediaPlug.tsx diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index e21b2d3c2..c28b08627 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -499,18 +499,33 @@ export async function definitions(production: boolean) { const squadBattleTypeStyles = await readYAMLDVPL( `${DATA}/UI/Screens3/Lobby/Hangar/Squad/SquadBattleType.yaml.dvpl`, ); + const gameTypeSelectorStyles = await readYAMLDVPL( + `${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml.dvpl`, + ); + const gameModeNativeNames: Record = {}; for (const match of squadBattleTypeStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( - /"(\d+)" -> "(battleType\/[a-zA-Z]+)"/g, + /"(\d+)" -> "(battleType\/([a-zA-Z]+))"/g, )) { const id = Number(match[1]); const name = strings[match[2]]; + gameModeNativeNames[match[3]] = id; gameDefinitions.gameModes[id] = { name, }; } + for (const match of gameTypeSelectorStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( + /eGameMode\.([a-zA-Z]+) -> "~res:\/Gfx\/UI\/Hangar\/GameTypes\/battle-type_([^"]+)"/g, + )) { + Object.entries(gameModeNativeNames).forEach(([key, value]) => { + if (key.toLowerCase() === match[2].toLowerCase()) { + gameModeNativeNames[match[1]] = value; + } + }); + } + camouflagesXmlEntries.forEach(([camoKey, camo]) => { const yamlEntry = camouflagesYaml[camoKey]; const fullName = yamlEntry.userString @@ -706,7 +721,7 @@ export async function definitions(production: boolean) { tankDefinitions[tankId] = { id: tankId, - roles: tank.combatRole ?? {}, + roles: {}, camouflages: camouflages.length === 0 ? undefined : camouflages, description: wargamingTankopedia.data[tankId]?.description ?? undefined, @@ -747,6 +762,22 @@ export async function definitions(production: boolean) { tracks: [], }; + if (tank.combatRole) { + Object.entries(tank.combatRole).forEach(([gameMode, role]) => { + const id = Object.entries(gameModeNativeNames).find( + ([key]) => key.toLowerCase() === gameMode.toLowerCase(), + )?.[1]; + + if (id === undefined) { + throw new Error( + `Unknown game mode in tank ${tankKey}: ${gameMode}`, + ); + } + + tankDefinitions[tankId].roles[id] = role; + }); + } + if (tankDefinitions[tankId].name === tankDefinitions[tankId].nameFull) { delete tankDefinitions[tankId].nameFull; } @@ -1336,7 +1367,6 @@ export async function definitions(production: boolean) { }; }); - return; await commitAssets( 'definitions', [ diff --git a/scripts/buildAssets/gameModeIcons.ts b/scripts/buildAssets/gameModeBanners.ts similarity index 91% rename from scripts/buildAssets/gameModeIcons.ts rename to scripts/buildAssets/gameModeBanners.ts index 90e3463d4..a3fcc6d8f 100644 --- a/scripts/buildAssets/gameModeIcons.ts +++ b/scripts/buildAssets/gameModeBanners.ts @@ -6,7 +6,9 @@ import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; import { DATA } from './constants'; import { SquadBattleTypeStyles } from './definitions'; -export async function gameModeIcons(production: boolean) { +export async function gameModeBanners(production: boolean) { + console.log('Building game mode banners...'); + const changes: FileChange[] = []; const gameTypeSelectorStyles = await readYAMLDVPL( `${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml.dvpl`, @@ -48,5 +50,5 @@ export async function gameModeIcons(production: boolean) { }); } - await commitAssets('game mode icons', changes, production); + await commitAssets('game mode banners', changes, production); } diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index 0bd4afe59..6a37cf087 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -17,7 +17,7 @@ import { consumableProvisionIcons } from './consumableProvisionIcons'; import { currencies } from './currencies'; import { definitions } from './definitions'; import { equipmentIcons } from './equipmentIcons'; -import { gameModeIcons } from './gameModeIcons'; +import { gameModeBanners } from './gameModeBanners'; import { moduleIcons } from './moduleIcons'; import { scratchedFlags } from './scratchedFlags'; import { shellIcons } from './shellIcons'; @@ -30,7 +30,7 @@ import { videos } from './videos'; if (!targets && !allTargets) throw new Error('No target(s) specified'); const methods = [ - gameModeIcons, + gameModeBanners, definitions, tankIcons, videos, diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx new file mode 100644 index 000000000..cead10659 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -0,0 +1,56 @@ +import { Box, Flex, Heading } from '@radix-ui/themes'; +import { use } from 'react'; +import { asset } from '../../../../../../core/blitzkit/asset'; +import { gameDefinitions } from '../../../../../../core/blitzkit/gameDefinitions'; +import * as Duel from '../../../../../../stores/duel'; + +export function GameModeSection() { + const tank = Duel.use((state) => state.protagonist.tank); + const awaitedGameDefinitions = use(gameDefinitions); + + return ( + + Game mode abilities + + + {Object.entries(tank.roles).map(([key, value]) => { + const id = Number(key); + const gameMode = awaitedGameDefinitions.gameModes[id]; + + return ( + + + + + {gameMode.name} + + + ); + })} + + + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankopediaPlug.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankopediaPlug.tsx deleted file mode 100644 index a50ec3315..000000000 --- a/src/app/tools/tankopedia/[id]/components/Model/TankopediaPlug.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Flex, Link, Text } from '@radix-ui/themes'; -import PageWrapper from '../../../../../../components/PageWrapper'; -import { PatreonIcon } from '../../../../../../icons/Patreon'; - -export function TankopediaPlug() { - return ( - - - - Liking BlitzKit? Consider donating on{' '} - - {' '} - Patreon - - . - - - - ); -} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx index 3961388bd..8f82fac94 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx @@ -126,6 +126,7 @@ export function TechTreeSection() { return ( } {!exempt && } + diff --git a/src/components/Armor/components/PrimaryArmorScene.tsx b/src/components/Armor/components/PrimaryArmorScene.tsx index d8c2492d3..5ab77f777 100644 --- a/src/components/Armor/components/PrimaryArmorScene.tsx +++ b/src/components/Armor/components/PrimaryArmorScene.tsx @@ -7,7 +7,6 @@ import { useArmor } from '../../../hooks/useArmor'; import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition'; import { useTankTransform } from '../../../hooks/useTankTransform'; import * as Duel from '../../../stores/duel'; -import * as TankopediaPersistent from '../../../stores/tankopediaPersistent'; import { ModelTankWrapper } from './ModelTankWrapper'; import { PrimaryArmorSceneComponent } from './PrimaryArmorSceneComponent'; @@ -29,13 +28,6 @@ export const PrimaryArmorScene = memo(() => { const hullOrigin = correctZYTuple(trackModelDefinition.origin); const turretOrigin = correctZYTuple(tankModelDefinition.turretOrigin); const gunOrigin = correctZYTuple(turretModelDefinition.gunOrigin); - const tankopediaPersistentStore = TankopediaPersistent.useStore(); - - console.log( - tankModelDefinition.armor, - turretModelDefinition.armor, - gunModelDefinition.armor, - ); useTankTransform(protagonist, turretContainer, gunContainer); diff --git a/src/core/blitzkit/tankCharacteristics.ts b/src/core/blitzkit/tankCharacteristics.ts index 5eee4c6bf..884950f30 100644 --- a/src/core/blitzkit/tankCharacteristics.ts +++ b/src/core/blitzkit/tankCharacteristics.ts @@ -75,8 +75,6 @@ export function tankCharacteristics( provisionDefinitions: ProvisionDefinitions; }, ) { - console.log(tank.crew); - const presetRows = equipmentDefinitions.presets[tank.equipment]; const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const gunModelDefinition = turretModelDefinition.guns[gun.id]; diff --git a/src/core/blitzkit/tankDefinitions/index.ts b/src/core/blitzkit/tankDefinitions/index.ts index 5710b464a..ab70c86a8 100644 --- a/src/core/blitzkit/tankDefinitions/index.ts +++ b/src/core/blitzkit/tankDefinitions/index.ts @@ -40,7 +40,7 @@ export type ModuleDefinition = | GunDefinition; export interface TankDefinition { id: number; - roles: Record; + roles: Record; description?: string; fixedCamouflage?: boolean; camouflages?: number[]; @@ -173,13 +173,8 @@ export const tankDefinitions = fetchCdonLz4( asset('definitions/tanks.cdon.lz4'), ); -const entries = new Promise(async (resolve) => { - resolve(Object.entries(await tankDefinitions).map(([, entry]) => entry)); -}); -export const tanksDefinitionsArray = new Promise( - async (resolve) => { - resolve((await entries).map((entry) => entry)); // TODO: wtf? - }, +export const tanksDefinitionsArray = tankDefinitions.then((tanks) => + Object.values(tanks), ); export type Tier = (typeof TIERS)[number]; From 354be775ada903add8d7919086cab4ca477a6b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:58:17 -0500 Subject: [PATCH 025/120] feat: more styling --- .../[id]/components/Model/GameModeSection.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx index cead10659..c9e3a8cd2 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -1,4 +1,4 @@ -import { Box, Flex, Heading } from '@radix-ui/themes'; +import { Box, Flex, Heading, Text } from '@radix-ui/themes'; import { use } from 'react'; import { asset } from '../../../../../../core/blitzkit/asset'; import { gameDefinitions } from '../../../../../../core/blitzkit/gameDefinitions'; @@ -12,17 +12,17 @@ export function GameModeSection() { Game mode abilities - + {Object.entries(tank.roles).map(([key, value]) => { const id = Number(key); const gameMode = awaitedGameDefinitions.gameModes[id]; return ( - {gameMode.name} + {gameMode.name} ); From 4811668832c93bfaee8d4590330942397463890c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:05:27 -0500 Subject: [PATCH 026/120] feat: numerical role ids --- scripts/buildAssets/definitions.ts | 16 +++++++++++++++- src/core/blitzkit/tankDefinitions/index.ts | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index c28b08627..a040c3839 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -410,6 +410,14 @@ export interface SquadBattleTypeStyles { }[]; } +type CombatRolesYaml = Record< + string, + { + id: number; + default_abilities: string[]; + } +>; + const blitzShellKindToBlitzkit: Record = { ARMOR_PIERCING: ShellType.AP, ARMOR_PIERCING_CR: ShellType.APCR, @@ -503,6 +511,9 @@ export async function definitions(production: boolean) { `${DATA}/UI/Screens/Lobby/Hangar/GameTypeSelector.yaml.dvpl`, ); const gameModeNativeNames: Record = {}; + const combatRoles = await readYAMLDVPL( + `${DATA}/XML/item_defs/vehicles/common/combat_roles.yaml.dvpl`, + ); for (const match of squadBattleTypeStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( /"(\d+)" -> "(battleType\/([a-zA-Z]+))"/g, @@ -774,7 +785,9 @@ export async function definitions(production: boolean) { ); } - tankDefinitions[tankId].roles[id] = role; + console.log(combatRoles[role].id); + + tankDefinitions[tankId].roles[id] = combatRoles[role].id; }); } @@ -1367,6 +1380,7 @@ export async function definitions(production: boolean) { }; }); + return; await commitAssets( 'definitions', [ diff --git a/src/core/blitzkit/tankDefinitions/index.ts b/src/core/blitzkit/tankDefinitions/index.ts index ab70c86a8..a411f02b6 100644 --- a/src/core/blitzkit/tankDefinitions/index.ts +++ b/src/core/blitzkit/tankDefinitions/index.ts @@ -40,7 +40,7 @@ export type ModuleDefinition = | GunDefinition; export interface TankDefinition { id: number; - roles: Record; + roles: Record; description?: string; fixedCamouflage?: boolean; camouflages?: number[]; From d9c2f53c6a122b460079295b875f9774a6a00d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:48:23 -0500 Subject: [PATCH 027/120] feat: ability defs --- scripts/buildAssets/definitions.ts | 257 +++++++++++++-------- src/core/blitzkit/consumableDefinitions.ts | 15 +- src/core/blitzkit/gameDefinitions.ts | 7 + src/core/blitzkit/provisionDefinitions.ts | 15 +- 4 files changed, 190 insertions(+), 104 deletions(-) diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index a040c3839..5aa659b0e 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -12,6 +12,7 @@ import { CamouflageDefinitions } from '../../src/core/blitzkit/camouflageDefinit import { commitAssets } from '../../src/core/blitzkit/commitAssets'; import { ConsumableDefinitions, + ConsumableEntry, TankFilterDefinitionCategory, } from '../../src/core/blitzkit/consumableDefinitions'; import { @@ -25,7 +26,10 @@ import { ModelArmor, ModelDefinitions, } from '../../src/core/blitzkit/modelDefinitions'; -import { ProvisionDefinitions } from '../../src/core/blitzkit/provisionDefinitions'; +import { + ProvisionDefinitions, + ProvisionEntry, +} from '../../src/core/blitzkit/provisionDefinitions'; import { SkillDefinitions } from '../../src/core/blitzkit/skillDefinitions'; import { superCompress } from '../../src/core/blitzkit/superCompress'; import { @@ -450,6 +454,7 @@ export async function definitions(production: boolean) { ) ).available_nations, gameModes: {}, + roles: {}, }; const tankDefinitions: TankDefinitions = {}; const camouflageDefinitions: CamouflageDefinitions = {}; @@ -486,12 +491,43 @@ export async function definitions(production: boolean) { const optionalDeviceSlots = await readXMLDVPL<{ root: OptionalDeviceSlots; }>(`${DATA}/XML/item_defs/vehicles/common/optional_device_slots.xml.dvpl`); - const consumables = await readXMLDVPL<{ root: ConsumablesCommon }>( - `${DATA}/XML/item_defs/vehicles/common/consumables/common.xml.dvpl`, - ); - const provisions = await readXMLDVPL<{ root: ProvisionsCommon }>( - `${DATA}/XML/item_defs/vehicles/common/provisions/common.xml.dvpl`, - ); + const consumables: ConsumablesCommon = {}; + const provisions: ProvisionsCommon = {}; + + for (const match of ( + await readStringDVPL( + `${DATA}/XML/item_defs/vehicles/common/consumables/list.xml.dvpl`, + ) + ).matchAll(//g)) { + if (match[1] === 'prototypes') continue; + + Object.assign( + consumables, + ( + await readXMLDVPL<{ root: ConsumablesCommon }>( + `${DATA}/XML/item_defs/vehicles/common/consumables/${match[1]}.xml.dvpl`, + ) + ).root, + ); + } + + for (const match of ( + await readStringDVPL( + `${DATA}/XML/item_defs/vehicles/common/provisions/list.xml.dvpl`, + ) + ).matchAll(//g)) { + if (match[1] === 'prototypes') continue; + + Object.assign( + provisions, + ( + await readXMLDVPL<{ root: ConsumablesCommon }>( + `${DATA}/XML/item_defs/vehicles/common/provisions/${match[1]}.xml.dvpl`, + ) + ).root, + ); + } + const avatar = await readXMLDVPL<{ root: Avatar }>( `${DATA}/XML/item_defs/tankmen/avatar.xml.dvpl`, ); @@ -514,6 +550,8 @@ export async function definitions(production: boolean) { const combatRoles = await readYAMLDVPL( `${DATA}/XML/item_defs/vehicles/common/combat_roles.yaml.dvpl`, ); + const consumableNativeNames: Record = {}; + const provisionNativeNames: Record = {}; for (const match of squadBattleTypeStyles.Prototypes[0].components.UIDataLocalBindingsComponent.data[1][2].matchAll( /"(\d+)" -> "(battleType\/([a-zA-Z]+))"/g, @@ -785,8 +823,6 @@ export async function definitions(production: boolean) { ); } - console.log(combatRoles[role].id); - tankDefinitions[tankId].roles[id] = combatRoles[role].id; }); } @@ -1240,126 +1276,140 @@ export async function definitions(production: boolean) { }, ); - Object.values(consumables.root).forEach((consumable) => { - consumableDefinitions[consumable.id] = { + Object.entries(consumables).forEach(([key, consumable]) => { + consumableNativeNames[key] = consumable.id; + + const entry = { id: consumable.id, + gameMode: 'gameModeFilter' in consumable, cooldown: consumable.script.cooldown, duration: consumable.script.duration, name: strings[consumable.userString] ?? missingStrings[consumable.userString] ?? `Unknown ${consumable.id}`, - include: [], - }; + } as ConsumableEntry; + consumableDefinitions[consumable.id] = entry; const includeRaw = consumable.vehicleFilter?.include.vehicle; const excludeRaw = consumable.vehicleFilter?.exclude?.vehicle; - if (includeRaw) { - if ('minLevel' in includeRaw) { - consumableDefinitions[consumable.id].include.push({ - type: 'tier', - min: includeRaw.minLevel, - max: includeRaw.maxLevel, - }); - } else if ('name' in includeRaw) { - consumableDefinitions[consumable.id].include.push({ - type: 'ids', - ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]), - }); - } else throw new SyntaxError('Unhandled include type'); + if (!entry.gameMode) { + if (includeRaw) { + entry.include = []; - if (consumable.vehicleFilter?.include.nations) { - consumableDefinitions[consumable.id].include.push({ - type: 'nation', - nations: consumable.vehicleFilter.include.nations.split(' '), - }); + if ('minLevel' in includeRaw) { + entry.include.push({ + type: 'tier', + min: includeRaw.minLevel, + max: includeRaw.maxLevel, + }); + } else if ('name' in includeRaw) { + entry.include.push({ + type: 'ids', + ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else throw new SyntaxError('Unhandled include type'); + + if (consumable.vehicleFilter?.include.nations) { + entry.include.push({ + type: 'nation', + nations: consumable.vehicleFilter.include.nations.split(' '), + }); + } } - } - if (excludeRaw) { - consumableDefinitions[consumable.id].exclude = []; + if (excludeRaw) { + entry.exclude = []; - if ('name' in excludeRaw) { - consumableDefinitions[consumable.id].exclude!.push({ - type: 'ids', - ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]), - }); - } else if ('extendedTags' in excludeRaw) { - consumableDefinitions[consumable.id].exclude!.push({ - type: 'category', - categories: excludeRaw.extendedTags.split( - ' ', - ) as TankFilterDefinitionCategory[], - }); - } else throw new SyntaxError('Unhandled exclude type'); + if ('name' in excludeRaw) { + entry.exclude!.push({ + type: 'ids', + ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else if ('extendedTags' in excludeRaw) { + entry.exclude!.push({ + type: 'category', + categories: excludeRaw.extendedTags.split( + ' ', + ) as TankFilterDefinitionCategory[], + }); + } else throw new SyntaxError('Unhandled exclude type'); - if (consumable.vehicleFilter?.exclude?.nations) { - consumableDefinitions[consumable.id].exclude!.push({ - type: 'nation', - nations: consumable.vehicleFilter.exclude.nations.split(' '), - }); + if (consumable.vehicleFilter?.exclude?.nations) { + entry.exclude!.push({ + type: 'nation', + nations: consumable.vehicleFilter.exclude.nations.split(' '), + }); + } } } }); - Object.values(provisions.root).forEach((provision) => { - provisionDefinitions[provision.id] = { + Object.entries(provisions).forEach(([key, provision]) => { + provisionNativeNames[key] = provision.id; + + const entry = { id: provision.id, + gameMode: 'gameModeFilter' in provision, name: strings[provision.userString] ?? missingStrings[provision.userString] ?? `Unknown ${provision.id}`, - include: [], - }; + } as ProvisionEntry; + provisionDefinitions[provision.id] = entry; const includeRaw = provision.vehicleFilter?.include.vehicle; const excludeRaw = provision.vehicleFilter?.exclude?.vehicle; - if (includeRaw) { - if ('minLevel' in includeRaw) { - provisionDefinitions[provision.id].include.push({ - type: 'tier', - min: includeRaw.minLevel, - max: includeRaw.maxLevel, - }); - } else if ('name' in includeRaw) { - provisionDefinitions[provision.id].include.push({ - type: 'ids', - ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]), - }); - } else throw new SyntaxError('Unhandled include type'); + if (!entry.gameMode) { + if (includeRaw) { + entry.include = []; - if (provision.vehicleFilter?.include.nations) { - provisionDefinitions[provision.id].include.push({ - type: 'nation', - nations: provision.vehicleFilter.include.nations.split(' '), - }); + if ('minLevel' in includeRaw) { + entry.include.push({ + type: 'tier', + min: includeRaw.minLevel, + max: includeRaw.maxLevel, + }); + } else if ('name' in includeRaw) { + entry.include.push({ + type: 'ids', + ids: includeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else throw new SyntaxError('Unhandled include type'); + + if (provision.vehicleFilter?.include.nations) { + entry.include.push({ + type: 'nation', + nations: provision.vehicleFilter.include.nations.split(' '), + }); + } } - } - if (excludeRaw) { - provisionDefinitions[provision.id].exclude = []; + if (excludeRaw) { + entry.exclude = []; - if ('name' in excludeRaw) { - provisionDefinitions[provision.id].exclude!.push({ - type: 'ids', - ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]), - }); - } else if ('extendedTags' in excludeRaw) { - provisionDefinitions[provision.id].exclude!.push({ - type: 'category', - categories: excludeRaw.extendedTags.split( - ' ', - ) as TankFilterDefinitionCategory[], - }); - } else throw new SyntaxError('Unhandled exclude type'); + if ('name' in excludeRaw) { + entry.exclude!.push({ + type: 'ids', + ids: excludeRaw.name.split(' ').map((key) => tankStringIdMap[key]), + }); + } else if ('extendedTags' in excludeRaw) { + entry.exclude!.push({ + type: 'category', + categories: excludeRaw.extendedTags.split( + ' ', + ) as TankFilterDefinitionCategory[], + }); + } else throw new SyntaxError('Unhandled exclude type'); - if (provision.vehicleFilter?.exclude?.nations) { - provisionDefinitions[provision.id].exclude!.push({ - type: 'nation', - nations: provision.vehicleFilter.exclude.nations.split(' '), - }); + if (provision.vehicleFilter?.exclude?.nations) { + entry.exclude!.push({ + type: 'nation', + nations: provision.vehicleFilter.exclude.nations.split(' '), + }); + } } } @@ -1369,6 +1419,22 @@ export async function definitions(production: boolean) { } }); + Object.entries(combatRoles).forEach(([, value]) => { + gameDefinitions.roles[value.id] = { provisions: [], consumables: [] }; + + value.default_abilities.forEach((ability) => { + if (ability in consumableNativeNames) { + gameDefinitions.roles[value.id].consumables.push( + consumableNativeNames[ability], + ); + } else if (ability in provisionNativeNames) { + gameDefinitions.roles[value.id].provisions.push( + provisionNativeNames[ability], + ); + } else throw new Error(`Unknown ability ${ability}`); + }); + }); + Object.entries(avatar.root.skillsByClasses).forEach(([tankClass, skills]) => { skillDefinitions.classes[tankClass as TankClass] = skills.split(' '); }); @@ -1380,7 +1446,6 @@ export async function definitions(production: boolean) { }; }); - return; await commitAssets( 'definitions', [ diff --git a/src/core/blitzkit/consumableDefinitions.ts b/src/core/blitzkit/consumableDefinitions.ts index 76a417488..d56d2a570 100644 --- a/src/core/blitzkit/consumableDefinitions.ts +++ b/src/core/blitzkit/consumableDefinitions.ts @@ -22,14 +22,21 @@ export type TankFilterDefinition = nations: string[]; }; -export interface ConsumableEntry { +export type ConsumableEntry = { id: number; name: string; cooldown: number; duration?: number; - include: TankFilterDefinition[]; - exclude?: TankFilterDefinition[]; -} +} & ( + | { + gameMode: false; + include: TankFilterDefinition[]; + exclude?: TankFilterDefinition[]; + } + | { + gameMode: true; + } +); export interface ConsumableDefinitions { [key: string]: ConsumableEntry; diff --git a/src/core/blitzkit/gameDefinitions.ts b/src/core/blitzkit/gameDefinitions.ts index d167e5d46..4270a07dd 100644 --- a/src/core/blitzkit/gameDefinitions.ts +++ b/src/core/blitzkit/gameDefinitions.ts @@ -9,6 +9,13 @@ export interface GameDefinitions { version: string; nations: string[]; gameModes: Record; + roles: Record< + number, + { + provisions: number[]; + consumables: number[]; + } + >; } export const gameDefinitions = fetchCdonLz4( diff --git a/src/core/blitzkit/provisionDefinitions.ts b/src/core/blitzkit/provisionDefinitions.ts index 9f70f90af..6d8451427 100644 --- a/src/core/blitzkit/provisionDefinitions.ts +++ b/src/core/blitzkit/provisionDefinitions.ts @@ -2,13 +2,20 @@ import { asset } from './asset'; import { TankFilterDefinition } from './consumableDefinitions'; import { fetchCdonLz4 } from './fetchCdonLz4'; -export interface ProvisionEntry { +export type ProvisionEntry = { id: number; name: string; - include: TankFilterDefinition[]; - exclude?: TankFilterDefinition[]; crew?: number; -} +} & ( + | { + gameMode: false; + include: TankFilterDefinition[]; + exclude?: TankFilterDefinition[]; + } + | { + gameMode: true; + } +); export interface ProvisionDefinitions { [key: string]: ProvisionEntry; From 987a14b68d871127a02f6de5c9eaa41c1f9af2b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 14:09:58 -0500 Subject: [PATCH 028/120] feat: looks --- .../[id]/components/Model/GameModeSection.tsx | 57 ++++++++++++++- .../checkConsumableProvisionInclusivity.ts | 69 +++++++++++-------- 2 files changed, 93 insertions(+), 33 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx index c9e3a8cd2..727dd2ca5 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -1,12 +1,16 @@ import { Box, Flex, Heading, Text } from '@radix-ui/themes'; import { use } from 'react'; import { asset } from '../../../../../../core/blitzkit/asset'; +import { consumableDefinitions } from '../../../../../../core/blitzkit/consumableDefinitions'; import { gameDefinitions } from '../../../../../../core/blitzkit/gameDefinitions'; +import { provisionDefinitions } from '../../../../../../core/blitzkit/provisionDefinitions'; import * as Duel from '../../../../../../stores/duel'; export function GameModeSection() { const tank = Duel.use((state) => state.protagonist.tank); const awaitedGameDefinitions = use(gameDefinitions); + const awaitedConsumableDefinitions = use(consumableDefinitions); + const awaitedProvisionDefinitions = use(provisionDefinitions); return ( @@ -19,10 +23,9 @@ export function GameModeSection() { return ( - {gameMode.name} + + {gameMode.name} + + + + {awaitedGameDefinitions.roles[value].provisions.map((id) => { + const provisions = awaitedProvisionDefinitions[id]; + + return ( + + + {provisions.name} + {provisions.name} + + + ); + })} + {awaitedGameDefinitions.roles[value].consumables.map((id) => { + const consumable = awaitedConsumableDefinitions[id]; + + return ( + + + {consumable.name} + {consumable.name} + + + ); + })} + ); diff --git a/src/core/blitzkit/checkConsumableProvisionInclusivity.ts b/src/core/blitzkit/checkConsumableProvisionInclusivity.ts index 27083a6f0..1f72f81f7 100644 --- a/src/core/blitzkit/checkConsumableProvisionInclusivity.ts +++ b/src/core/blitzkit/checkConsumableProvisionInclusivity.ts @@ -7,41 +7,50 @@ export function checkConsumableProvisionInclusivity( tank: TankDefinition, gun: GunDefinition, ) { - const included = consumableProvision.include.every((rule) => { - switch (rule.type) { - case 'tier': - return rule.min <= tank.tier && tank.tier <= rule.max; + const included = + !consumableProvision.gameMode && + consumableProvision.include?.every((rule) => { + switch (rule.type) { + case 'tier': + return rule.min <= tank.tier && tank.tier <= rule.max; - case 'ids': - return rule.ids.includes(tank.id); + case 'ids': + return rule.ids.includes(tank.id); - case 'nation': - return rule.nations.includes(tank.nation); + case 'nation': + return rule.nations.includes(tank.nation); - case 'category': - throw new SyntaxError('Category filtering found in include rule'); - } - }); - const excluded = consumableProvision.exclude?.some((rule) => { - switch (rule.type) { - case 'tier': - return rule.min <= tank.tier && tank.tier <= rule.max; + case 'category': + throw new SyntaxError('Category filtering found in include rule'); + } + }); + const excluded = + consumableProvision.gameMode || + consumableProvision.exclude?.some((rule) => { + switch (rule.type) { + case 'tier': + return rule.min <= tank.tier && tank.tier <= rule.max; - case 'ids': - return rule.ids.includes(tank.id); + case 'ids': + return rule.ids.includes(tank.id); - case 'nation': - return rule.nations.includes(tank.nation); + case 'nation': + return rule.nations.includes(tank.nation); - case 'category': - return rule.categories.some((category) => { - switch (category) { - case 'clip': - return gun.type !== 'regular'; - } - }); - } - }); + case 'category': + return rule.categories.some((category) => { + switch (category) { + case 'clip': + return gun.type !== 'regular'; + } + }); + } + }); - return consumableProvision.include.length > 0 && included && !excluded; + return ( + !consumableProvision.gameMode && + consumableProvision.include?.length > 0 && + included && + !excluded + ); } From 7e6e480788d9b507901a11edcab0611b539ced3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 19:41:03 -0500 Subject: [PATCH 029/120] feat: better cards --- .../[id]/components/Model/GameModeSection.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx index 727dd2ca5..22f698644 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -23,8 +23,10 @@ export function GameModeSection() { return ( {gameMode.name} @@ -66,8 +67,8 @@ export function GameModeSection() { Date: Fri, 16 Aug 2024 20:05:25 -0500 Subject: [PATCH 030/120] feat: start of better tech tree --- .../[id]/components/Model/TechTreeSection.tsx | 268 +++++++++--------- 1 file changed, 133 insertions(+), 135 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx index 8f82fac94..ba181b169 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx @@ -1,9 +1,18 @@ -import { ChevronRightIcon } from '@radix-ui/react-icons'; -import { Box, ChevronDownIcon, Flex, Heading, Text } from '@radix-ui/themes'; +import { CaretRightIcon, ChevronRightIcon } from '@radix-ui/react-icons'; +import { + ChevronDownIcon, + Flex, + Heading, + ScrollArea, + Text, +} from '@radix-ui/themes'; import Link from 'next/link'; -import { ComponentProps, use } from 'react'; +import { ComponentProps, use, useMemo } from 'react'; import { asset } from '../../../../../../core/blitzkit/asset'; -import { tankDefinitions } from '../../../../../../core/blitzkit/tankDefinitions'; +import { + TankDefinition, + tankDefinitions, +} from '../../../../../../core/blitzkit/tankDefinitions'; import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants'; import { formatCompact } from '../../../../../../core/math/formatCompact'; import * as Duel from '../../../../../../stores/duel'; @@ -49,158 +58,147 @@ export function TreeArrow({ ); } -export function TechTreeSection() { +function Card({ id }: { id: number }) { const awaitedTankDefinitions = use(tankDefinitions); - const tank = Duel.use((state) => state.protagonist.tank); + const ancestor = awaitedTankDefinitions[id]; - if (tank.treeType !== 'researchable') return null; + return ( + + + {ancestor.name} - function Card({ id }: { id: number }) { - const ancestor = awaitedTankDefinitions[id]; - - return ( - - {ancestor.name} + + + {TIER_ROMAN_NUMERALS[ancestor.tier]} + + {ancestor.name} + - - - - {TIER_ROMAN_NUMERALS[ancestor.tier]} + + + XP + + {ancestor.xp === undefined ? 0 : formatCompact(ancestor.xp!)} - {ancestor.name} - - - XP - - {formatCompact(ancestor.xp!)} - - - - - Silver - - {formatCompact(ancestor.price.value)} - - + + Silver + + {formatCompact(ancestor.price.value)} + - - ); + + + ); +} + +export function TechTreeSection() { + const tank = Duel.use((state) => state.protagonist.tank); + const awaitedTankDefinitions = use(tankDefinitions); + + if ( + tank.treeType !== 'researchable' || + tank.ancestors === undefined || + tank.ancestors.length === 0 + ) { + return null; } + const ancestors = useMemo(() => { + const treeBackwards: number[] = []; + let ancestor: TankDefinition | undefined = tank; + + while (ancestor !== undefined) { + if (ancestor.ancestors === undefined || ancestor.ancestors.length === 0) { + ancestor = undefined; + break; + } else if (ancestor.ancestors.length === 1) { + ancestor = awaitedTankDefinitions[ancestor.ancestors[0]]; + } else { + let bestAncestor = awaitedTankDefinitions[ancestor.ancestors[0]]; + + ancestor.ancestors.forEach((thisAncestorId) => { + const possibleAncestor = awaitedTankDefinitions[thisAncestorId]; + + if (possibleAncestor.xp! < bestAncestor.xp!) { + bestAncestor = possibleAncestor; + } + }); + + ancestor = bestAncestor as TankDefinition; + } + + treeBackwards.push(ancestor.id); + } + + return treeBackwards.reverse(); + }, []); + + console.log(ancestors); + return ( - + Tech tree - Tech tree - - - {tank.ancestors && ( - <> - - {tank.ancestors.map((id) => ( - - ))} - - - - - - - - - - )} - - - - {tank.successors && ( - <> - - - - - - - - - {tank.successors.map((id) => ( - - ))} - - - )} - + + + {ancestors.map((id, index) => ( + <> + {index > 0 && ( + + + + )} + + + ))} + + ); } From 5d603cc2463f76c14770407e011864df0e1a4a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 20:06:37 -0500 Subject: [PATCH 031/120] fix: hide game mode section on no tanks --- .../tankopedia/[id]/components/Model/GameModeSection.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx index 22f698644..0b0320e16 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -11,13 +11,16 @@ export function GameModeSection() { const awaitedGameDefinitions = use(gameDefinitions); const awaitedConsumableDefinitions = use(consumableDefinitions); const awaitedProvisionDefinitions = use(provisionDefinitions); + const roles = Object.entries(tank.roles); + + if (roles.length === 0) return null; return ( Game mode abilities - {Object.entries(tank.roles).map(([key, value]) => { + {roles.map(([key, value]) => { const id = Number(key); const gameMode = awaitedGameDefinitions.gameModes[id]; From 1cf31c67f857b114381030219d2bbd97dd4c9852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 20:38:09 -0500 Subject: [PATCH 032/120] feat: better highlighting --- .../[id]/components/Model/TechTreeSection.tsx | 184 +++++++++--------- 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx index ba181b169..4fa1834f7 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx @@ -1,13 +1,7 @@ -import { CaretRightIcon, ChevronRightIcon } from '@radix-ui/react-icons'; -import { - ChevronDownIcon, - Flex, - Heading, - ScrollArea, - Text, -} from '@radix-ui/themes'; +import { CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; +import { Flex, Heading, ScrollArea, Text } from '@radix-ui/themes'; import Link from 'next/link'; -import { ComponentProps, use, useMemo } from 'react'; +import { use, useEffect, useMemo, useRef } from 'react'; import { asset } from '../../../../../../core/blitzkit/asset'; import { TankDefinition, @@ -17,48 +11,7 @@ import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinit import { formatCompact } from '../../../../../../core/math/formatCompact'; import * as Duel from '../../../../../../stores/duel'; -export function TreeArrow({ - style, - down = false, - ...props -}: ComponentProps & { down?: boolean }) { - const Icon = down ? ChevronDownIcon : ChevronRightIcon; - - return ( - - - - - - ); -} - -function Card({ id }: { id: number }) { +function Card({ id, highlight }: { id: number; highlight?: boolean }) { const awaitedTankDefinitions = use(tankDefinitions); const ancestor = awaitedTankDefinitions[id]; @@ -72,7 +25,20 @@ function Card({ id }: { id: number }) { position: 'relative', }} > - + {ancestor.name} - - XP - - {ancestor.xp === undefined ? 0 : formatCompact(ancestor.xp!)} - - + + + XP + {ancestor.xp === undefined || ancestor.tier === 1 + ? 0 + : formatCompact(ancestor.xp!)} + + - - Silver - + + + Silver {formatCompact(ancestor.price.value)} - - + + @@ -128,9 +98,18 @@ function Card({ id }: { id: number }) { ); } +function Arrow() { + return ( + + + + ); +} + export function TechTreeSection() { const tank = Duel.use((state) => state.protagonist.tank); const awaitedTankDefinitions = use(tankDefinitions); + const container = useRef(null); if ( tank.treeType !== 'researchable' || @@ -145,7 +124,11 @@ export function TechTreeSection() { let ancestor: TankDefinition | undefined = tank; while (ancestor !== undefined) { - if (ancestor.ancestors === undefined || ancestor.ancestors.length === 0) { + if ( + ancestor.tier === 1 || + ancestor.ancestors === undefined || + ancestor.ancestors.length === 0 + ) { ancestor = undefined; break; } else if (ancestor.ancestors.length === 1) { @@ -170,33 +153,54 @@ export function TechTreeSection() { return treeBackwards.reverse(); }, []); - console.log(ancestors); + useEffect(() => { + if (!container.current) return; + + container.current.scrollLeft = container.current.scrollWidth; + }); return ( - Tech tree + + Tech tree + - - + + {ancestors.map((id, index) => ( <> - {index > 0 && ( - - - - )} + {index > 0 && } ))} + + + + + {tank.tier < 10 && ( + <> + + {tank.successors!.map((id, index) => ( + <> + {index > 0 && ( + + + + )} + + + ))} + + )} From b329152dc3fc62ec82a98ca996bc2916145f5794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 20:49:29 -0500 Subject: [PATCH 033/120] feat: flag in highlight --- .../[id]/components/Model/TechTreeSection.tsx | 124 ++++++++++-------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx index 4fa1834f7..59c0d654a 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx @@ -1,5 +1,5 @@ import { CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; -import { Flex, Heading, ScrollArea, Text } from '@radix-ui/themes'; +import { Box, Flex, Heading, ScrollArea, Text } from '@radix-ui/themes'; import Link from 'next/link'; import { use, useEffect, useMemo, useRef } from 'react'; import { asset } from '../../../../../../core/blitzkit/asset'; @@ -13,7 +13,7 @@ import * as Duel from '../../../../../../stores/duel'; function Card({ id, highlight }: { id: number; highlight?: boolean }) { const awaitedTankDefinitions = use(tankDefinitions); - const ancestor = awaitedTankDefinitions[id]; + const tank = awaitedTankDefinitions[id]; return ( - - {ancestor.name} + > + {tank.name} - - - - {TIER_ROMAN_NUMERALS[ancestor.tier]} - - {ancestor.name} - + + + + {TIER_ROMAN_NUMERALS[tank.tier]} + + {tank.name} + - - - - XP - {ancestor.xp === undefined || ancestor.tier === 1 - ? 0 - : formatCompact(ancestor.xp!)} - - + + + + XP + {tank.xp === undefined || tank.tier === 1 + ? 0 + : formatCompact(tank.xp!)} + + - - - Silver - {formatCompact(ancestor.price.value)} - - + + + Silver + {formatCompact(tank.price.value)} + + + - + ); } From 6a3fefd51351c9e36e5750e492811c93486a2514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:08:50 -0500 Subject: [PATCH 034/120] feat: better flags --- scripts/buildAssets/circleFlags.ts | 35 ----------- scripts/buildAssets/flags.ts | 86 +++++++++++++++++++++++++++ scripts/buildAssets/index.ts | 6 +- scripts/buildAssets/scratchedFlags.ts | 31 ---------- 4 files changed, 88 insertions(+), 70 deletions(-) delete mode 100644 scripts/buildAssets/circleFlags.ts create mode 100644 scripts/buildAssets/flags.ts delete mode 100644 scripts/buildAssets/scratchedFlags.ts diff --git a/scripts/buildAssets/circleFlags.ts b/scripts/buildAssets/circleFlags.ts deleted file mode 100644 index 2ce95a293..000000000 --- a/scripts/buildAssets/circleFlags.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { readdir } from 'fs/promises'; -import sharp from 'sharp'; -import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; -import { commitAssets } from '../../src/core/blitzkit/commitAssets'; -import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA } from './constants'; - -export async function circleFlags(production: boolean) { - const flags = await readdir(`${DATA}/Gfx/Lobby/flags`); - const changes = await Promise.all( - flags - .filter( - (flag) => - flag.startsWith('flag_profile-stat_') && - !flag.endsWith('@2x.packed.webp.dvpl'), - ) - .map(async (flag) => { - const image = sharp( - await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`), - ); - const content = ( - await image.trim({ threshold: 100 }).toBuffer() - ).toString('base64'); - const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1]; - - return { - content, - encoding: 'base64', - path: `flags/circle/${name}.webp`, - } satisfies FileChange; - }), - ); - - await commitAssets('circle flags', changes, production); -} diff --git a/scripts/buildAssets/flags.ts b/scripts/buildAssets/flags.ts new file mode 100644 index 000000000..21ca7f41c --- /dev/null +++ b/scripts/buildAssets/flags.ts @@ -0,0 +1,86 @@ +import { readdir, writeFile } from 'fs/promises'; +import sharp from 'sharp'; +import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL'; +import { readDVPLFile } from '../../src/core/blitz/readDVPLFile'; +import { commitAssets } from '../../src/core/blitzkit/commitAssets'; +import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; +import { DATA } from './constants'; + +export async function flags(production: boolean) { + console.log('Building flags...'); + + const changes = [ + ...(await Promise.all( + (await readdir(`${DATA}/Gfx/Lobby/flags`)) + .filter( + (flag) => + flag.startsWith('flag_profile-stat_') && + !flag.endsWith('@2x.packed.webp.dvpl'), + ) + .map(async (flag) => { + const image = sharp( + await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`), + ); + const content = ( + await image.trim({ threshold: 100 }).toBuffer() + ).toString('base64'); + const name = flag.match(/flag_profile-stat_(.+)\.packed\.webp/)![1]; + + return { + content, + encoding: 'base64', + path: `flags/circle/${name}.webp`, + } satisfies FileChange; + }), + )), + ...(await Promise.all( + (await readdir(`${DATA}/Gfx/Lobby/flags`)) + .filter( + (flag) => + flag.startsWith('flag_tutor-tank_') && + !flag.endsWith('@2x.packed.webp.dvpl'), + ) + .map(async (flag) => { + const content = await readBase64DVPL( + `${DATA}/Gfx/Lobby/flags/${flag}`, + ); + const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1]; + + return { + content, + encoding: 'base64', + path: `flags/scratched/${name}.webp`, + } satisfies FileChange; + }), + )), + ...(await Promise.all( + (await readdir(`${DATA}/Gfx/Lobby/flags`)) + .filter( + (flag) => + flag.startsWith('flag_filter_') && + flag.endsWith('@2x.packed.webp.dvpl'), + ) + .map(async (flag) => { + const content = ( + await sharp(await readDVPLFile(`${DATA}/Gfx/Lobby/flags/${flag}`)) + .trim({ + threshold: 100, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toBuffer() + ).toString('base64'); + const name = flag.match(/flag_filter_(.+)@2x\.packed\.webp/)![1]; + + writeFile(`temp/icons/${name}.webp`, content, { encoding: 'base64' }); + + return { + content, + encoding: 'base64', + path: `flags/fade_small/${name}.webp`, + } satisfies FileChange; + }), + )), + ]; + + await commitAssets('flags', changes, production); +} diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index 6a37cf087..4d6b5abae 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -12,14 +12,13 @@ const production = argv.includes('--production'); import { boosterIcons } from './boosterIcons'; import { camouflageIcons } from './camouflageIcons'; -import { circleFlags } from './circleFlags'; import { consumableProvisionIcons } from './consumableProvisionIcons'; import { currencies } from './currencies'; import { definitions } from './definitions'; import { equipmentIcons } from './equipmentIcons'; +import { flags } from './flags'; import { gameModeBanners } from './gameModeBanners'; import { moduleIcons } from './moduleIcons'; -import { scratchedFlags } from './scratchedFlags'; import { shellIcons } from './shellIcons'; import { skillIcons } from './skillIcons'; import { tankArmors } from './tankArmors'; @@ -34,10 +33,9 @@ const methods = [ definitions, tankIcons, videos, - scratchedFlags, currencies, skillIcons, - circleFlags, + flags, shellIcons, moduleIcons, equipmentIcons, diff --git a/scripts/buildAssets/scratchedFlags.ts b/scripts/buildAssets/scratchedFlags.ts deleted file mode 100644 index c3cc6880d..000000000 --- a/scripts/buildAssets/scratchedFlags.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { readdir } from 'fs/promises'; -import { readBase64DVPL } from '../../src/core/blitz/readBase64DVPL'; -import { commitAssets } from '../../src/core/blitzkit/commitAssets'; -import { FileChange } from '../../src/core/blitzkit/commitMultipleFiles'; -import { DATA } from './constants'; - -export async function scratchedFlags(production: boolean) { - console.log('Building scratched flags...'); - - const flags = await readdir(`${DATA}/Gfx/Lobby/flags`); - const changes = await Promise.all( - flags - .filter( - (flag) => - flag.startsWith('flag_tutor-tank_') && - !flag.endsWith('@2x.packed.webp.dvpl'), - ) - .map(async (flag) => { - const content = await readBase64DVPL(`${DATA}/Gfx/Lobby/flags/${flag}`); - const name = flag.match(/flag_tutor-tank_(.+)\.packed\.webp/)![1]; - - return { - content, - encoding: 'base64', - path: `flags/scratched/${name}.webp`, - } satisfies FileChange; - }), - ); - - await commitAssets('scratched flags', changes, production); -} From 7fcd4a1e9413c111ea81e282e0f4f1740988b0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:10:14 -0500 Subject: [PATCH 035/120] feat: better flags --- .../tankopedia/[id]/components/Model/TechTreeSection.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx index 59c0d654a..adee7b1f0 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx @@ -29,11 +29,10 @@ function Card({ id, highlight }: { id: number; highlight?: boolean }) { mx={highlight ? '2' : '0'} style={{ background: highlight - ? `url(${asset(`flags/scratched/${tank.nation}.webp`)})` + ? `url(${asset(`flags/fade_small/${tank.nation}.webp`)})` : undefined, - backgroundPosition: '25% center', + backgroundPosition: 'center', backgroundSize: 'cover', - backgroundRepeat: 'no-repeat', boxShadow: highlight ? 'var(--shadow-4)' : undefined, borderRadius: 'var(--radius-4)', overflow: 'hidden', From ca7c01bbc80efc53592d896b3458dbb539b09419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 16 Aug 2024 21:17:50 -0500 Subject: [PATCH 036/120] feat: better history and video sections --- scripts/buildAssets/videos.ts | 9 ++------- .../[id]/components/HistorySection.tsx | 2 +- .../tankopedia/[id]/components/VideoSection.tsx | 17 +++++++++++++---- src/app/tools/tankopedia/[id]/page.tsx | 2 +- src/constants/youtubers.ts | 5 +++++ 5 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 src/constants/youtubers.ts diff --git a/scripts/buildAssets/videos.ts b/scripts/buildAssets/videos.ts index 2bf5734c5..6f4ab1fd2 100644 --- a/scripts/buildAssets/videos.ts +++ b/scripts/buildAssets/videos.ts @@ -2,6 +2,7 @@ import { readdir } from 'fs/promises'; import { google } from 'googleapis'; import { cloneDeep, uniqBy } from 'lodash'; import { parse as parseYaml } from 'yaml'; +import { youtubers } from '../../src/constants/youtubers'; import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; import { toUniqueId } from '../../src/core/blitz/toUniqueId'; @@ -10,12 +11,6 @@ import { VideoDefinitions } from '../../src/core/blitzkit/videos'; import { DATA } from './constants'; import { BlitzStrings, botPattern, VehicleDefinitionList } from './definitions'; -const youtubers = [ - 'UCKBYXp4Xn2I2tL1UL4fpbhw', // droodles - 'UCrQ-Dy8lVsm11u8pCJ8W7Tw', // fatness - 'UCxRpZqMElssTdPYDK3x7wyg', // n90 -]; - export async function videos(production: boolean) { console.log('Building videos...'); @@ -108,7 +103,7 @@ export async function videos(production: boolean) { (item) => item.snippet?.channelId && item.id?.videoId && - youtubers.includes(item.snippet.channelId), + youtubers.some(({ id }) => id === item.snippet?.channelId), ), (item) => item.snippet!.channelId, ); diff --git a/src/app/tools/tankopedia/[id]/components/HistorySection.tsx b/src/app/tools/tankopedia/[id]/components/HistorySection.tsx index 56ac43ba3..c37b9c2f1 100644 --- a/src/app/tools/tankopedia/[id]/components/HistorySection.tsx +++ b/src/app/tools/tankopedia/[id]/components/HistorySection.tsx @@ -8,7 +8,7 @@ export function HistorySection() { if (!tank.description) return null; return ( - + History of the {tank.name} {tank.description} diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index 59edbfb3e..ac826ae28 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -1,4 +1,5 @@ -import { Flex, Heading, Link, Text } from '@radix-ui/themes'; +import { InfoCircledIcon } from '@radix-ui/react-icons'; +import { Callout, Flex, Heading, Link } from '@radix-ui/themes'; import { use } from 'react'; import PageWrapper from '../../../../../components/PageWrapper'; import { videoDefinitions } from '../../../../../core/blitzkit/videos'; @@ -11,10 +12,18 @@ export function VideoSection() { return ( - - + + Review videos - BlitzKit does not endorse any review videos. + + + + + + + BlitzKit does not endorse any review videos. + + diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index caf960c75..a5a06d49e 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -84,7 +84,7 @@ export default function Page({ params }: { params: { id: string } }) { - {!exempt && } + {!exempt && } ); } diff --git a/src/constants/youtubers.ts b/src/constants/youtubers.ts new file mode 100644 index 000000000..65d19d8dd --- /dev/null +++ b/src/constants/youtubers.ts @@ -0,0 +1,5 @@ +export const youtubers = [ + { id: 'UCKBYXp4Xn2I2tL1UL4fpbhw', name: 'Droodles' }, + { id: 'UCrQ-Dy8lVsm11u8pCJ8W7Tw', name: 'HisRoyalFatness' }, + { id: 'UCxRpZqMElssTdPYDK3x7wyg', name: 'N90' }, +]; From 4b88a52fcfded022028a4b3875ba3b2f68ce57cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 17 Aug 2024 14:47:47 -0500 Subject: [PATCH 037/120] feat: start of new navbar --- src/app/layout.tsx | 4 +- .../Navbar/components/EverythingSearch.tsx | 42 --- src/components/Navbar/index.css.ts | 53 +-- src/components/Navbar/index.tsx | 346 ++++-------------- src/constants/tools.tsx | 2 - 5 files changed, 87 insertions(+), 360 deletions(-) delete mode 100644 src/components/Navbar/components/EverythingSearch.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index bb5b82e8a..3dc18c167 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -7,7 +7,7 @@ import { Roboto_Flex } from 'next/font/google'; import { usePathname } from 'next/navigation'; import { ReactNode, Suspense } from 'react'; import { Footer } from '../components/Footer'; -import Navbar, { NAVBAR_HEIGHT } from '../components/Navbar'; +import Navbar from '../components/Navbar'; import { Party3 } from '../components/Party3'; import * as App from '../stores/app'; import { Checks } from './components/Checks'; @@ -68,7 +68,7 @@ export default function RootLayout({ children }: RootLayoutProps) { direction="column" style={{ minHeight: '100vh', - paddingTop: isEmbed ? undefined : NAVBAR_HEIGHT, + // paddingTop: isEmbed ? undefined : NAVBAR_HEIGHT, }} > {!isEmbed && } diff --git a/src/components/Navbar/components/EverythingSearch.tsx b/src/components/Navbar/components/EverythingSearch.tsx deleted file mode 100644 index 8640bc2df..000000000 --- a/src/components/Navbar/components/EverythingSearch.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { MagnifyingGlassIcon } from '@radix-ui/react-icons'; -import { Card, TextField } from '@radix-ui/themes'; -import { ComponentProps, useState } from 'react'; - -export function EverythingSearch({ - style, - ...props -}: ComponentProps) { - const [search, setSearch] = useState(''); - - return ( - <> - { - setSearch(event.target.value.trim()); - }} - {...props} - > - - - - - {search.length > 0 && ( - - - - )} - - - ); -} diff --git a/src/components/Navbar/index.css.ts b/src/components/Navbar/index.css.ts index 20a1d37e6..c3f7b51d1 100644 --- a/src/components/Navbar/index.css.ts +++ b/src/components/Navbar/index.css.ts @@ -1,56 +1,23 @@ -import { style, styleVariants } from '@vanilla-extract/css'; +import { style } from '@vanilla-extract/css'; -const MIN_EXPANDED_TOOLS = 752; +const MIN_WIDTH = 640 + 64; + +export const hamburger = style({ + display: 'inline-flex', -export const hamburgerButton = style({ '@media': { - [`screen and (min-width: ${MIN_EXPANDED_TOOLS}px)`]: { + [`screen and (min-width: ${MIN_WIDTH}px)`]: { display: 'none', }, }, }); -const navbarBase = style({ - position: 'fixed', - top: 0, - left: 0, - width: '100%', - zIndex: 2, - padding: '1rem', - backgroundColor: 'var(--color-panel-translucent)', - backdropFilter: 'blur(4rem)', - WebkitBackdropFilter: 'blur(4rem)', - boxSizing: 'border-box', - transition: 'max-height 0.2s ease-in-out', - overflow: 'hidden', -}); -export const navbar = styleVariants({ - expanded: [ - navbarBase, - { - maxHeight: '100%', - }, - ], - collapsed: [ - navbarBase, - { - maxHeight: 65, - }, - ], -}); +export const tools = style({ + display: 'none', -export const toolCard = style({ - boxShadow: `inset 0 -200px 128px -128px var(--color-overlay)`, - - ':hover': { - boxShadow: `inset 0 -160px 128px -128px #ffffff00`, - }, -}); - -export const toolTexts = style({ '@media': { - [`screen and (max-width: ${MIN_EXPANDED_TOOLS}px)`]: { - display: 'none', + [`screen and (min-width: ${MIN_WIDTH}px)`]: { + display: 'flex', }, }, }); diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 9d3f6913f..82a913ea9 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -1,311 +1,115 @@ 'use client'; import { - Cross1Icon, DiscordLogoIcon, GearIcon, HamburgerMenuIcon, PersonIcon, } from '@radix-ui/react-icons'; -import { - Box, - Button, - Dialog, - Flex, - IconButton, - Inset, - Popover, - Separator, - Text, -} from '@radix-ui/themes'; +import { Box, Flex, IconButton, Separator } from '@radix-ui/themes'; import { usePathname } from 'next/navigation'; import { useState } from 'react'; -import { REGIONS } from '../../constants/regions'; import { TOOLS } from '../../constants/tools'; -import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; -import { imgur, ImgurSize } from '../../core/blitzkit/imgur'; -import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl'; import { PatreonIcon } from '../../icons/Patreon'; -import { WargamingIcon } from '../../icons/Wargaming'; -import strings from '../../lang/en-US.json'; -import { theme } from '../../stitches.config'; import * as App from '../../stores/app'; import { Link } from '../Link'; import * as styles from './index.css'; -export const NAVBAR_HEIGHT = 64; - export default function Navbar() { const [showHamburgerMenu, setShowHamburgerMenu] = useState(false); const pathname = usePathname(); const logins = App.use((state) => state.logins); - const filteredTools = TOOLS.filter((tool) => !tool.href); const mutateApp = App.useMutation(); return ( - - - - - setShowHamburgerMenu((state) => !state)} - > - {showHamburgerMenu ? : } - + + + + + - setShowHamburgerMenu(false)} - href="/" - style={{ - color: 'inherit', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }} - weight="bold" - > - BlitzKit - - + + BlitzKit + + - - {filteredTools.map((tool) => { - const selected = pathname.startsWith(`/tools/${tool.id}`); + - return ( + + {TOOLS.map((tool, index) => { + const selected = pathname.startsWith(`/tools/${tool.id}`); + + return ( + <> + {index > 0 && } {tool.title} - ); - })} - - - - setShowHamburgerMenu(false)} - href="https://discord.gg/nDt7AjGJQH" - target="_blank" - style={{ - color: 'inherit', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }} - > - - - - setShowHamburgerMenu(false)} - href="https://www.patreon.com/tresabhi" - target="_blank" - style={{ - color: 'inherit', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }} - > - - - - setShowHamburgerMenu(false)} - color="gray" - highContrast - > - - - - - - - - - - - event.preventDefault()} - > - {(logins.patreon || logins.wargaming) && ( - - - Logged in accounts - - - {logins.patreon && ( - - - Patreon - - - )} - - {logins.wargaming && ( - - - Wargaming - - - )} - - )} - - {!logins.patreon !== !logins.wargaming && ( - - - - )} - - {(!logins.patreon || !logins.wargaming) && ( - - - Log in with... - - - {!logins.patreon && ( - - - - )} - - {!logins.wargaming && ( - - - - - - - - Choose your region - - - {REGIONS.map((region) => ( - - - - - - ))} - - - - - )} - - )} - - - + + ); + })} - - {filteredTools.map((tool) => ( - setShowHamburgerMenu(false)} - > - - {tool.title} - - - ))} + + + + + + + + + + + + + + + - + ); } diff --git a/src/constants/tools.tsx b/src/constants/tools.tsx index bbfb3cbe5..666eb3c1d 100644 --- a/src/constants/tools.tsx +++ b/src/constants/tools.tsx @@ -126,6 +126,4 @@ export const TOOLS: Tool[] = [ playerStatsTool, sessionTool, ratingTool, - discordTool, - moreTool, ]; From bc9e1c3007fb31429acb64f8fc9c1295df04c0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 17 Aug 2024 20:00:01 -0500 Subject: [PATCH 038/120] feat: more things --- src/components/Navbar/index.css.ts | 35 ++++- src/components/Navbar/index.tsx | 243 ++++++++++++++++++++--------- 2 files changed, 198 insertions(+), 80 deletions(-) diff --git a/src/components/Navbar/index.css.ts b/src/components/Navbar/index.css.ts index c3f7b51d1..db966b91f 100644 --- a/src/components/Navbar/index.css.ts +++ b/src/components/Navbar/index.css.ts @@ -1,6 +1,7 @@ -import { style } from '@vanilla-extract/css'; +import { style, styleVariants } from '@vanilla-extract/css'; -const MIN_WIDTH = 640 + 64; +const MIN_WIDTH = 640 + 128; +const HEIGHT = 48; export const hamburger = style({ display: 'inline-flex', @@ -21,3 +22,33 @@ export const tools = style({ }, }, }); + +const navbarBase = style({ + // 1px overlap with content to bleed color + marginBottom: -1, + backdropFilter: 'blur(4rem) brightness(0.75)', + WebkitBackdropFilter: 'blur(4rem) brightness(0.75)', + zIndex: 1, + transitionDuration: '250ms', + + '@media': { + [`screen and (min-width: ${MIN_WIDTH}px)`]: { + maxHeight: HEIGHT, + }, + }, +}); + +export const navbar = styleVariants({ + false: [ + navbarBase, + { + maxHeight: HEIGHT, + }, + ], + true: [ + navbarBase, + { + maxHeight: '100vh', + }, + ], +}); diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 82a913ea9..22b1c1121 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -1,15 +1,25 @@ 'use client'; import { + Cross1Icon, DiscordLogoIcon, GearIcon, HamburgerMenuIcon, PersonIcon, } from '@radix-ui/react-icons'; -import { Box, Flex, IconButton, Separator } from '@radix-ui/themes'; +import { + Box, + Flex, + Grid, + IconButton, + ScrollArea, + Separator, + Text, +} from '@radix-ui/themes'; import { usePathname } from 'next/navigation'; import { useState } from 'react'; import { TOOLS } from '../../constants/tools'; +import { imgur, ImgurSize } from '../../core/blitzkit/imgur'; import { PatreonIcon } from '../../icons/Patreon'; import * as App from '../../stores/app'; import { Link } from '../Link'; @@ -23,93 +33,170 @@ export default function Navbar() { return ( - - - - - + + + + setShowHamburgerMenu((state) => !state)} + > + {showHamburgerMenu ? : } + - setShowHamburgerMenu(false)} + > + BlitzKit + + + + + + - BlitzKit - - + {TOOLS.map((tool, index) => { + const selected = pathname.startsWith(`/tools/${tool.id}`); - + return ( + <> + {index > 0 && } + + {tool.title} + + + ); + })} + - - {TOOLS.map((tool, index) => { - const selected = pathname.startsWith(`/tools/${tool.id}`); + - return ( - <> - {index > 0 && } - - {tool.title} - - - ); - })} - - - - - - - - - - - - - - - - - + + setShowHamburgerMenu(false)} + > + + + setShowHamburgerMenu(false)} + > + + + setShowHamburgerMenu(false)} + > + + + + + + + + + + + {TOOLS.map((tool) => ( + setShowHamburgerMenu(false)} + > + + + + + {tool.title} + + + + ))} + + + ); } From afd99a1dfe869611d159305873792d9e4a42e585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 17 Aug 2024 20:01:27 -0500 Subject: [PATCH 039/120] feat: accounts --- src/components/Navbar/index.tsx | 127 +++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 22b1c1121..35bc1b8a9 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -9,18 +9,27 @@ import { } from '@radix-ui/react-icons'; import { Box, + Button, + Dialog, Flex, Grid, IconButton, + Inset, + Popover, ScrollArea, Separator, Text, } from '@radix-ui/themes'; import { usePathname } from 'next/navigation'; import { useState } from 'react'; +import { REGIONS } from '../../constants/regions'; import { TOOLS } from '../../constants/tools'; +import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; import { imgur, ImgurSize } from '../../core/blitzkit/imgur'; +import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl'; import { PatreonIcon } from '../../icons/Patreon'; +import { WargamingIcon } from '../../icons/Wargaming'; +import strings from '../../lang/en-US.json'; import * as App from '../../stores/app'; import { Link } from '../Link'; import * as styles from './index.css'; @@ -125,9 +134,121 @@ export default function Navbar() { > - - - + + + + + + + + event.preventDefault()} + > + {(logins.patreon || logins.wargaming) && ( + + + Logged in accounts + + + {logins.patreon && ( + + + Patreon + + + )} + + {logins.wargaming && ( + + + Wargaming + + + )} + + )} + + {!logins.patreon !== !logins.wargaming && ( + + + + )} + + {(!logins.patreon || !logins.wargaming) && ( + + + Log in with... + + + {!logins.patreon && ( + + + + )} + + {!logins.wargaming && ( + + + + + + + + Choose your region + + + {REGIONS.map((region) => ( + + + + + + ))} + + + + + )} + + )} + + From 207b9ae36c0f25398a9f56de3d04153d92a84fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 17 Aug 2024 20:03:00 -0500 Subject: [PATCH 040/120] fix: manage errors extensions --- src/app/components/Checks.tsx | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/app/components/Checks.tsx b/src/app/components/Checks.tsx index 314d9657d..98fe9334c 100644 --- a/src/app/components/Checks.tsx +++ b/src/app/components/Checks.tsx @@ -9,13 +9,18 @@ import * as App from '../../stores/app'; import { CURRENT_POLICIES_AGREEMENT_INDEX } from '../../stores/app/constants'; import { PatreonAuthResponse } from '../auth/[provider]/page'; -interface Extension { - data: { - access_token: string; - account_id: number; - expires_at: number; - }; -} +type Extension = + | { + status: 'ok'; + data: { + access_token: string; + account_id: number; + expires_at: number; + }; + } + | { + status: 'error'; + }; /** * Wargaming: 14 (refresh: 7) @@ -80,11 +85,15 @@ export function Checks() { .then((response) => response.json() as Promise) .then((json) => { mutateApp((draft) => { - draft.logins.wargaming = { - id: wargaming.id, - token: json.data.access_token, - expires: json.data.expires_at * 1000, - }; + if (json.status === 'error') { + draft.logins.wargaming = undefined; + } else { + draft.logins.wargaming = { + id: wargaming.id, + token: json.data.access_token, + expires: json.data.expires_at * 1000, + }; + } }); }); } From 5f3a1b1311b5f611a3866bd892e33a3397d88cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 17 Aug 2024 20:09:52 -0500 Subject: [PATCH 041/120] feat: home link --- src/components/Navbar/index.tsx | 14 ++++++++------ src/constants/tools.tsx | 9 ++++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 35bc1b8a9..fc40a4122 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -23,7 +23,7 @@ import { import { usePathname } from 'next/navigation'; import { useState } from 'react'; import { REGIONS } from '../../constants/regions'; -import { TOOLS } from '../../constants/tools'; +import { homeTool, TOOLS } from '../../constants/tools'; import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; import { imgur, ImgurSize } from '../../core/blitzkit/imgur'; import { patreonLoginUrl } from '../../core/blitzkit/patreonLoginUrl'; @@ -39,6 +39,7 @@ export default function Navbar() { const pathname = usePathname(); const logins = App.use((state) => state.logins); const mutateApp = App.useMutation(); + const tools = [homeTool, ...TOOLS]; return ( setShowHamburgerMenu((state) => !state)} + onBlur={() => setShowHamburgerMenu(false)} > {showHamburgerMenu ? : } @@ -256,14 +258,14 @@ export default function Navbar() { - {TOOLS.map((tool) => ( + {tools.map((tool) => ( setShowHamburgerMenu(false)} > Date: Sat, 17 Aug 2024 20:12:21 -0500 Subject: [PATCH 042/120] fix: no center align between xs and sm --- src/app/components/ToolCard.tsx | 4 ++-- src/components/Navbar/index.tsx | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/app/components/ToolCard.tsx b/src/app/components/ToolCard.tsx index 5991c70b7..a228dc823 100644 --- a/src/app/components/ToolCard.tsx +++ b/src/app/components/ToolCard.tsx @@ -78,7 +78,7 @@ export function ToolCard({ tool, style, ...props }: ToolCardProps) { width="100%" direction={{ initial: 'column', - sm: 'row', + xs: 'row', }} style={{ backgroundColor: 'var(--color-panel-translucent)', @@ -91,7 +91,7 @@ export function ToolCard({ tool, style, ...props }: ToolCardProps) { justify="center" align={{ initial: 'center', - sm: 'start', + xs: 'start', }} > Date: Sat, 17 Aug 2024 20:13:36 -0500 Subject: [PATCH 043/120] feat: smaller images for navbar --- src/components/Navbar/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 821cec214..384e4deda 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -271,7 +271,7 @@ export default function Navbar() { position: 'relative', borderRadius: 'var(--radius-2)', overflow: 'hidden', - backgroundImage: `url(${imgur(tool.image, { format: 'jpeg', size: ImgurSize.LargeThumbnail })})`, + backgroundImage: `url(${imgur(tool.image, { format: 'jpeg', size: ImgurSize.MediumThumbnail })})`, backgroundSize: 'cover', backgroundPosition: 'center', aspectRatio: '2 / 1', @@ -292,7 +292,7 @@ export default function Navbar() { Date: Mon, 19 Aug 2024 13:28:46 -0500 Subject: [PATCH 044/120] feat: no push content --- src/components/Navbar/index.css.ts | 30 +- src/components/Navbar/index.tsx | 547 +++++++++++++++-------------- 2 files changed, 305 insertions(+), 272 deletions(-) diff --git a/src/components/Navbar/index.css.ts b/src/components/Navbar/index.css.ts index db966b91f..02385d6b3 100644 --- a/src/components/Navbar/index.css.ts +++ b/src/components/Navbar/index.css.ts @@ -23,13 +23,22 @@ export const tools = style({ }, }); -const navbarBase = style({ - // 1px overlap with content to bleed color - marginBottom: -1, +export const navbar = style({ + height: HEIGHT, + marginBottom: -1, // 1px overlap with content to bleed color + position: 'sticky', + top: 0, + zIndex: 1, +}); + +const navbarExpanderBase = style({ + transitionDuration: '250ms', + height: '1000px', + width: '100%', + overflow: 'hidden', + backdropFilter: 'blur(4rem) brightness(0.75)', WebkitBackdropFilter: 'blur(4rem) brightness(0.75)', - zIndex: 1, - transitionDuration: '250ms', '@media': { [`screen and (min-width: ${MIN_WIDTH}px)`]: { @@ -38,17 +47,22 @@ const navbarBase = style({ }, }); -export const navbar = styleVariants({ +export const navbarExpander = styleVariants({ false: [ - navbarBase, + navbarExpanderBase, { maxHeight: HEIGHT, }, ], true: [ - navbarBase, + navbarExpanderBase, { maxHeight: '100vh', }, ], }); + +export const navbarContent = style({ + width: '100%', + maxHeight: '100vh', +}); diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 384e4deda..d47486016 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -42,280 +42,299 @@ export default function Navbar() { const tools = [homeTool, ...TOOLS]; return ( - - - - - setShowHamburgerMenu((state) => !state)} - onBlur={() => setShowHamburgerMenu(false)} - > - {showHamburgerMenu ? : } - - - setShowHamburgerMenu(false)} - > - BlitzKit - - - - - - - {TOOLS.map((tool, index) => { - const selected = pathname.startsWith(`/tools/${tool.id}`); - - return ( - <> - {index > 0 && } - - {tool.title} - - - ); - })} - - - - - - setShowHamburgerMenu(false)} - > - - - setShowHamburgerMenu(false)} - > - - - setShowHamburgerMenu(false)} - > - - - - - - - - - - event.preventDefault()} - > - {(logins.patreon || logins.wargaming) && ( - - - Logged in accounts - - - {logins.patreon && ( - - - Patreon - - - )} - - {logins.wargaming && ( - - - Wargaming - - - )} - - )} - - {!logins.patreon !== !logins.wargaming && ( - - - - )} - - {(!logins.patreon || !logins.wargaming) && ( - - - Log in with... - - - {!logins.patreon && ( - - - - )} - - {!logins.wargaming && ( - - - - - - - - Choose your region - - - {REGIONS.map((region) => ( - - - - - - ))} - - - - - )} - - )} - - - - - - - - - - {tools.map((tool) => ( - setShowHamburgerMenu(false)} - > - + setShowHamburgerMenu((state) => !state)} + > + event.stopPropagation()} + > + + + + { + event.stopPropagation(); + setShowHamburgerMenu((state) => !state); }} > - : } + + + setShowHamburgerMenu(false)} + > + BlitzKit + + + + + + + {TOOLS.map((tool, index) => { + const selected = pathname.startsWith(`/tools/${tool.id}`); + + return ( + <> + {index > 0 && ( + + )} + setShowHamburgerMenu(false)} + color="gray" + highContrast={selected} + size="2" + href={`tools/${tool.id}`} + key={tool.title} + underline={selected ? 'always' : 'hover'} + > + {tool.title} + + + ); + })} + + + + + + setShowHamburgerMenu(false)} + > + + + setShowHamburgerMenu(false)} + > + + + setShowHamburgerMenu(false)} + > + + + + + + + + + + event.preventDefault()} + > + {(logins.patreon || logins.wargaming) && ( + + + Logged in accounts + + + {logins.patreon && ( + + + Patreon + + + )} + + {logins.wargaming && ( + + + Wargaming + + + )} + + )} + + {!logins.patreon !== !logins.wargaming && ( + + + + )} + + {(!logins.patreon || !logins.wargaming) && ( + + + Log in with... + + + {!logins.patreon && ( + + + + )} + + {!logins.wargaming && ( + + + + + + + + Choose your region + + + {REGIONS.map((region) => ( + + + + + + ))} + + + + + )} + + )} + + + + + + + + + + {tools.map((tool) => ( + setShowHamburgerMenu(false)} style={{ + position: 'relative', + borderRadius: 'var(--radius-2)', + overflow: 'hidden', backgroundImage: `url(${imgur(tool.image, { format: 'jpeg', size: ImgurSize.MediumThumbnail })})`, backgroundSize: 'cover', backgroundPosition: 'center', - }} - /> - - - {tool.title} + + + + + {tool.title} + + - - - ))} - + ))} + + + - + ); } From ec547af49e5d8682199669ea95f18aa4311fb97e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:35:19 -0500 Subject: [PATCH 045/120] feat: simplified --- src/components/Navbar/index.css.ts | 1 + src/components/Navbar/index.tsx | 516 ++++++++++++++--------------- 2 files changed, 252 insertions(+), 265 deletions(-) diff --git a/src/components/Navbar/index.css.ts b/src/components/Navbar/index.css.ts index 02385d6b3..bdfd45529 100644 --- a/src/components/Navbar/index.css.ts +++ b/src/components/Navbar/index.css.ts @@ -58,6 +58,7 @@ export const navbarExpander = styleVariants({ navbarExpanderBase, { maxHeight: '100vh', + overscrollBehavior: 'contain', }, ], }); diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index d47486016..192e53200 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -45,295 +45,281 @@ export default function Navbar() { setShowHamburgerMenu((state) => !state)} + direction="column" + gap="2" > - event.stopPropagation()} - > - - - - { - event.stopPropagation(); - setShowHamburgerMenu((state) => !state); - }} - > - {showHamburgerMenu ? : } - - - setShowHamburgerMenu(false)} - > - BlitzKit - - - - - - + + + { + event.stopPropagation(); + setShowHamburgerMenu((state) => !state); + }} > - {TOOLS.map((tool, index) => { - const selected = pathname.startsWith(`/tools/${tool.id}`); + {showHamburgerMenu ? : } + - return ( - <> - {index > 0 && ( - - )} - setShowHamburgerMenu(false)} - color="gray" - highContrast={selected} - size="2" - href={`tools/${tool.id}`} - key={tool.title} - underline={selected ? 'always' : 'hover'} - > - {tool.title} - - - ); - })} - + setShowHamburgerMenu(false)} + > + BlitzKit + + - + - - setShowHamburgerMenu(false)} + + {TOOLS.map((tool, index) => { + const selected = pathname.startsWith(`/tools/${tool.id}`); + + return ( + <> + {index > 0 && } + setShowHamburgerMenu(false)} + color="gray" + highContrast={selected} + size="2" + href={`tools/${tool.id}`} + key={tool.title} + underline={selected ? 'always' : 'hover'} + > + {tool.title} + + + ); + })} + + + + + + setShowHamburgerMenu(false)} + > + + + setShowHamburgerMenu(false)} + > + + + setShowHamburgerMenu(false)} + > + + + + + + + + + + event.preventDefault()} > - - - setShowHamburgerMenu(false)} - > - - - setShowHamburgerMenu(false)} - > - - - - - - - - + {(logins.patreon || logins.wargaming) && ( + + + Logged in accounts + - event.preventDefault()} - > - {(logins.patreon || logins.wargaming) && ( - - - Logged in accounts - - - {logins.patreon && ( - - - Patreon - - - )} - - {logins.wargaming && ( - - - Wargaming - - - )} - - )} - - {!logins.patreon !== !logins.wargaming && ( - - - - )} - - {(!logins.patreon || !logins.wargaming) && ( - - - Log in with... - - - {!logins.patreon && ( - + + Patreon + + + )} + + {logins.wargaming && ( + + + Wargaming + + + )} + + )} + + {!logins.patreon !== !logins.wargaming && ( + + + + )} + + {(!logins.patreon || !logins.wargaming) && ( + + + Log in with... + + + {!logins.patreon && ( + + + + )} + + {!logins.wargaming && ( + + + - - )} + - {!logins.wargaming && ( - - - - + + + Choose your region - - - Choose your region - - - {REGIONS.map((region) => ( - - - - - - ))} - + + {REGIONS.map((region) => ( + + + + + + ))} - - - )} - - )} - - - + + + + )} + + )} +
+
+
- - - + + {tools.map((tool) => ( + setShowHamburgerMenu(false)} + style={{ + position: 'relative', + borderRadius: 'var(--radius-2)', + overflow: 'hidden', + backgroundImage: `url(${imgur(tool.image, { format: 'jpeg', size: ImgurSize.MediumThumbnail })})`, + backgroundSize: 'cover', + backgroundPosition: 'center', + aspectRatio: '2 / 1', + }} > - {tools.map((tool) => ( - setShowHamburgerMenu(false)} + + + + - - - - - {tool.title} - - + {tool.title} - ))} - - - -
+ + + ))} + + ); From 7268e5fc11c49aa04355a4d079de589bc63db30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:36:13 -0500 Subject: [PATCH 046/120] fix: no toggle on miss --- src/components/Navbar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index 192e53200..0e251cdd7 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -45,7 +45,7 @@ export default function Navbar() { setShowHamburgerMenu((state) => !state)} + onClick={() => setShowHamburgerMenu(false)} direction="column" gap="2" > From 72769fbcb00e93aa3413dcdee66c820e61a2c735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:40:17 -0500 Subject: [PATCH 047/120] feat: plum more tools --- src/constants/tools.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/tools.tsx b/src/constants/tools.tsx index 46828232f..338b24ed3 100644 --- a/src/constants/tools.tsx +++ b/src/constants/tools.tsx @@ -90,7 +90,7 @@ export const moreTool: Tool = { image: '1nPm6VI', button: { text: 'Join Discord', - color: 'indigo', + color: 'plum', }, }; From d67b0ef5abf289e013b9d1361b1ef0804b75a008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 19 Aug 2024 13:45:12 -0500 Subject: [PATCH 048/120] fix: slimmer and correct banners --- .../tankopedia/[id]/components/Model/GameModeSection.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx index 0b0320e16..fa64bdbcb 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -26,8 +26,8 @@ export function GameModeSection() { return ( Date: Mon, 19 Aug 2024 13:45:47 -0500 Subject: [PATCH 049/120] fix: webkit you asshole --- .../tools/tankopedia/[id]/components/Model/TechTreeSection.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx index adee7b1f0..4ad1352df 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx @@ -45,6 +45,7 @@ function Card({ id, highlight }: { id: number; highlight?: boolean }) { px={highlight ? '4' : '2'} style={{ backdropFilter: highlight ? 'brightness(0.25)' : undefined, + WebkitBackdropFilter: highlight ? 'brightness(0.25)' : undefined, }} > Date: Mon, 19 Aug 2024 13:50:41 -0500 Subject: [PATCH 050/120] fix: wrap modules --- .../[id]/components/Characteristics/components/Modules.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx index 2e8b82ef3..c39d86a8c 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx @@ -310,6 +310,7 @@ export function Modules() { Modules + {hasUpgrades && ( <> - - - - - - - BkNI - - - A next generation performance metric - - - - {BKNI_PERCENTILES.map(({ percentile, min }, index) => ( - - ))} - - - - } - /> - - - {(winrate * 100).toFixed(0)} - - % - - - } - color="green" - fill={0.5 * (Math.cbrt(2 * winrate - 1) + 1)} - label={Winrate} - /> - - - - {stats.map((stat) => ( - - {stat[1]} - - {stat[0]} - - - ))} - - - - - - {/* - - - - */} - {/* - - - */} - - {/* - { - setPeriod(value === 'custom' ? 'custom' : Number(value)); - }} - > - - Today - 30 days - Career - Custom - - - - - - - - - - - - - - - We haven't tracked long enough to provide statistics. Please check - back after a few days. - - - - - {isTracking && } */} - - ); -} diff --git a/src/app/tools/player-stats/page.tsx b/src/app/tools/player-stats/page.tsx deleted file mode 100644 index 2ad419791..000000000 --- a/src/app/tools/player-stats/page.tsx +++ /dev/null @@ -1,110 +0,0 @@ -'use client'; - -import { ArrowDownIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons'; -import { Button, Card, Flex, Text, TextField } from '@radix-ui/themes'; -import { useRef, useState } from 'react'; -import { Link } from '../../../components/Link'; -import PageWrapper from '../../../components/PageWrapper'; -import { UNLOCALIZED_REGION_NAMES_SHORT } from '../../../constants/regions'; -import searchPlayersAcrossRegions, { - AccountListWithServer, -} from '../../../core/blitz/searchPlayersAcrossRegions'; - -export default function Page() { - const input = useRef(null); - const [showSearch, setShowSearch] = useState(false); - const [searching, setSearching] = useState(false); - const [searchResults, setSearchResults] = useState([]); - - async function search() { - if (!input.current) return; - - setSearchResults(await searchPlayersAcrossRegions(input.current.value, 9)); - setSearching(false); - } - - return ( - - - - Look up a player to get started - - - - { - if (!input.current) return; - - const sanitized = input.current.value.trim(); - - if (sanitized.length > 0) { - setShowSearch(true); - setSearching(true); - search(); - } else { - setShowSearch(false); - } - }} - > - - - - - {showSearch && ( - - {searching && ( - - Searching... - - )} - - {!searching && searchResults.length === 0 && ( - - No players found - - )} - - {!searching && searchResults.length > 0 && ( - - {searchResults.map((player) => ( - - - - ))} - - )} - - )} - - - - ); -} From 5b3723322e382c0d5aee749697dc3cfe88237728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:12:22 -0500 Subject: [PATCH 065/120] fix: navbar links --- src/components/Link.tsx | 4 ++-- src/components/Navbar/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 05aa574e3..576727433 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -5,7 +5,7 @@ import { useRouter } from 'next/navigation'; import { forwardRef } from 'react'; export const Link = forwardRef( - ({ href, onClick, ...props }, ref) => { + ({ href, onClick, target, ...props }, ref) => { const router = useRouter(); return ( @@ -15,7 +15,7 @@ export const Link = forwardRef( onClick={(event) => { event.preventDefault(); if (href) { - if (event.ctrlKey || event.metaKey) { + if (event.ctrlKey || event.metaKey || target === '_blank') { window.open(href); } else { router.push(href); diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx index c69c07863..46b317aa4 100644 --- a/src/components/Navbar/index.tsx +++ b/src/components/Navbar/index.tsx @@ -95,7 +95,7 @@ export default function Navbar() { color="gray" highContrast={selected} size="2" - href={`tools/${tool.id}`} + href={`/tools/${tool.id}`} underline={selected ? 'always' : 'hover'} > {tool.title} @@ -121,7 +121,7 @@ export default function Navbar() { setShowHamburgerMenu(false)} From e6a1a98fd39cd7cbf7b8085db019cedd8acd83ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:17:03 -0500 Subject: [PATCH 066/120] fix: homepage links --- src/app/components/ToolCard.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/components/ToolCard.tsx b/src/app/components/ToolCard.tsx index a228dc823..09f4aecbb 100644 --- a/src/app/components/ToolCard.tsx +++ b/src/app/components/ToolCard.tsx @@ -44,7 +44,8 @@ export function ToolCard({ tool, style, ...props }: ToolCardProps) { {...props} > Date: Tue, 20 Aug 2024 11:17:56 -0500 Subject: [PATCH 067/120] feat: game name in descs --- src/app/tools/tankopedia/[id]/layout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/layout.tsx b/src/app/tools/tankopedia/[id]/layout.tsx index 43e426434..e2ea7fb52 100644 --- a/src/app/tools/tankopedia/[id]/layout.tsx +++ b/src/app/tools/tankopedia/[id]/layout.tsx @@ -25,7 +25,7 @@ export default async function Layout({ const title = `${tank.name} - Tier ${TIER_ROMAN_NUMERALS[tank.tier]} ${ (strings.common.nations_adjectives as Record)[tank.nation] } ${strings.common.tank_class_short[tank.class]}`; - const description = `Statistics, armor, and equipment for ${tank.name}`; + const description = `Statistics, armor, and equipment for ${tank.name} in World of Tanks Blitz | WoTB`; return ( From cfe0060121b06b675f9b819353a6172ea15f4811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 20 Aug 2024 11:51:05 -0500 Subject: [PATCH 068/120] fix: correct currencies --- scripts/buildAssets/definitions.ts | 24 ++++++-- .../[id]/components/Model/MetaSection.tsx | 56 ++++++------------- src/core/blitzkit/tankDefinitions/index.ts | 4 +- 3 files changed, 38 insertions(+), 46 deletions(-) diff --git a/scripts/buildAssets/definitions.ts b/scripts/buildAssets/definitions.ts index 5aa659b0e..8d96b3985 100644 --- a/scripts/buildAssets/definitions.ts +++ b/scripts/buildAssets/definitions.ts @@ -37,8 +37,8 @@ import { CrewMember, GunDefinition, ShellType, - TankDefinitionPrice, TankDefinitions, + TankPrice, Tier, Unlock, } from '../../src/core/blitzkit/tankDefinitions'; @@ -670,10 +670,7 @@ export async function definitions(production: boolean) { const engineXps = new Map(); const trackXps = new Map(); const tank = tankList.root[tankKey]; - const tankPrice: TankDefinitionPrice = - typeof tank.price === 'number' - ? { type: 'credits', value: tank.price } - : { type: 'gold', value: tank.price['#text'] }; + let tankPrice: TankPrice; const tankDefinition = await readXMLDVPL<{ root: VehicleDefinitions }>( `${DATA}/XML/item_defs/vehicles/${nation}/${tankKey}.xml.dvpl`, ); @@ -689,6 +686,23 @@ export async function definitions(production: boolean) { const equipment = tankDefinition.root.optDevicePreset; tankStringIdMap[`${nation}:${tankKey}`] = tankId; + if (tank.sellPrice) { + tankPrice = { + type: 'gold', + value: tank.sellPrice['#text'] * 2, + }; + } else if (typeof tank.price === 'number') { + tankPrice = { + type: 'credits', + value: tank.price, + }; + } else { + tankPrice = { + type: 'credits', + value: tank.price['#text'] * 400, + }; + } + Object.keys(tankDefinition.root.hull.armor) .filter((name) => name.startsWith('armor_')) .forEach((name) => { diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx index 4523c3190..4f45720c6 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx @@ -1,4 +1,3 @@ -import { CheckIcon, Cross1Icon } from '@radix-ui/react-icons'; import { Code, Flex, Heading, Text } from '@radix-ui/themes'; import { classIcons } from '../../../../../../components/ClassIcon'; import { asset } from '../../../../../../core/blitzkit/asset'; @@ -10,20 +9,7 @@ import * as Duel from '../../../../../../stores/duel'; export function MetaSection() { const developerMode = App.useDeferred(false, (state) => state.developerMode); const tank = Duel.use((state) => state.protagonist.tank); - const rawPrice = - typeof tank.price === 'number' ? tank.price : tank.price.value; - const priceType = - typeof tank.price === 'number' ? 'credits' : tank.price.type; - const salePrice = 0.5 * rawPrice; - const purchasePrice = rawPrice; const ClassIcon = classIcons[tank.class]; - let worthSelling: boolean; - - if (priceType === 'gold') { - worthSelling = tank.tier <= 6 || purchasePrice - salePrice <= 500; - } else { - worthSelling = tank.tier <= 7; - } return ( @@ -95,21 +81,32 @@ export function MetaSection() { - {priceType === 'credits' ? 'Purchase' : 'Restoration'} price + {tank.price.type === 'credits' ? 'Purchase' : 'Restoration'}{' '} + price - {tank.xp && Research XP} Sale price - Worth selling + {tank.xp && Research XP} - {purchasePrice.toLocaleString()} + {tank.price.value.toLocaleString()} {priceType} + + + + {(tank.price.value / 2).toLocaleString()} + {tank.price.type} @@ -124,25 +121,6 @@ export function MetaSection() { /> )} - - - {salePrice.toLocaleString()} - {priceType} - - - - - {worthSelling ? 'Yes' : 'No'} - {worthSelling && } - {!worthSelling && } - - diff --git a/src/core/blitzkit/tankDefinitions/index.ts b/src/core/blitzkit/tankDefinitions/index.ts index a411f02b6..c92d25e1c 100644 --- a/src/core/blitzkit/tankDefinitions/index.ts +++ b/src/core/blitzkit/tankDefinitions/index.ts @@ -60,7 +60,7 @@ export interface TankDefinition { turrets: TurretDefinition[]; engines: EngineDefinition[]; tracks: TrackDefinition[]; - price: TankDefinitionPrice; + price: TankPrice; xp?: number; speed: { forwards: number; @@ -102,7 +102,7 @@ export interface EngineDefinition { weight: number; unlocks?: Unlock[]; } -export type TankDefinitionPrice = +export type TankPrice = | { type: 'credits'; value: number } | { type: 'gold'; value: number }; export interface TurretDefinition { From 781d2da9335e9d029db5dd67dd433980e7993097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:49:14 -0500 Subject: [PATCH 069/120] feat: multiple lines --- .../[id]/components/Model/TechTreeSection.tsx | 218 ------------------ .../TechTreeSection/components/Arrow.tsx | 10 + .../Model/TechTreeSection/components/Node.tsx | 104 +++++++++ .../Model/TechTreeSection/index.tsx | 145 ++++++++++++ 4 files changed, 259 insertions(+), 218 deletions(-) delete mode 100644 src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx create mode 100644 src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Arrow.tsx create mode 100644 src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx create mode 100644 src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx deleted file mode 100644 index 4ad1352df..000000000 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import { CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; -import { Box, Flex, Heading, ScrollArea, Text } from '@radix-ui/themes'; -import Link from 'next/link'; -import { use, useEffect, useMemo, useRef } from 'react'; -import { asset } from '../../../../../../core/blitzkit/asset'; -import { - TankDefinition, - tankDefinitions, -} from '../../../../../../core/blitzkit/tankDefinitions'; -import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants'; -import { formatCompact } from '../../../../../../core/math/formatCompact'; -import * as Duel from '../../../../../../stores/duel'; - -function Card({ id, highlight }: { id: number; highlight?: boolean }) { - const awaitedTankDefinitions = use(tankDefinitions); - const tank = awaitedTankDefinitions[id]; - - return ( - - - - {tank.name} - - - - - {TIER_ROMAN_NUMERALS[tank.tier]} - - {tank.name} - - - - - - XP - {tank.xp === undefined || tank.tier === 1 - ? 0 - : formatCompact(tank.xp!)} - - - - - - Silver - {formatCompact(tank.price.value)} - - - - - - - - ); -} - -function Arrow() { - return ( - - - - ); -} - -export function TechTreeSection() { - const tank = Duel.use((state) => state.protagonist.tank); - const awaitedTankDefinitions = use(tankDefinitions); - const container = useRef(null); - - if ( - tank.treeType !== 'researchable' || - tank.ancestors === undefined || - tank.ancestors.length === 0 - ) { - return null; - } - - const ancestors = useMemo(() => { - const treeBackwards: number[] = []; - let ancestor: TankDefinition | undefined = tank; - - while (ancestor !== undefined) { - if ( - ancestor.tier === 1 || - ancestor.ancestors === undefined || - ancestor.ancestors.length === 0 - ) { - ancestor = undefined; - break; - } else if (ancestor.ancestors.length === 1) { - ancestor = awaitedTankDefinitions[ancestor.ancestors[0]]; - } else { - let bestAncestor = awaitedTankDefinitions[ancestor.ancestors[0]]; - - ancestor.ancestors.forEach((thisAncestorId) => { - const possibleAncestor = awaitedTankDefinitions[thisAncestorId]; - - if (possibleAncestor.xp! < bestAncestor.xp!) { - bestAncestor = possibleAncestor; - } - }); - - ancestor = bestAncestor as TankDefinition; - } - - treeBackwards.push(ancestor.id); - } - - return treeBackwards.reverse(); - }, []); - - useEffect(() => { - if (!container.current) return; - - container.current.scrollLeft = container.current.scrollWidth; - }); - - return ( - - - Tech tree - - - - - {ancestors.map((id, index) => ( - <> - {index > 0 && } - - - ))} - - - - - {tank.tier < 10 && ( - <> - - {tank.successors!.map((id, index) => ( - <> - {index > 0 && ( - - - - )} - - - ))} - - )} - - - - ); -} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Arrow.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Arrow.tsx new file mode 100644 index 000000000..79acdf3f3 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Arrow.tsx @@ -0,0 +1,10 @@ +import { CaretRightIcon } from '@radix-ui/react-icons'; +import { Text } from '@radix-ui/themes'; + +export function Arrow() { + return ( + + + + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx new file mode 100644 index 000000000..be6df1460 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx @@ -0,0 +1,104 @@ +import { Box, Flex, Text } from '@radix-ui/themes'; +import Link from 'next/link'; +import { use } from 'react'; +import { asset } from '../../../../../../../../core/blitzkit/asset'; +import { tankDefinitions } from '../../../../../../../../core/blitzkit/tankDefinitions'; +import { TIER_ROMAN_NUMERALS } from '../../../../../../../../core/blitzkit/tankDefinitions/constants'; +import { formatCompact } from '../../../../../../../../core/math/formatCompact'; + +export function Node({ id, highlight }: { id: number; highlight?: boolean }) { + const awaitedTankDefinitions = use(tankDefinitions); + const tank = awaitedTankDefinitions[id]; + + return ( + + + + {tank.name} + + + + + {TIER_ROMAN_NUMERALS[tank.tier]} + + {tank.name} + + + + + + XP + {tank.xp === undefined || tank.tier === 1 + ? 0 + : formatCompact(tank.xp!)} + + + + + + Silver + {formatCompact(tank.price.value)} + + + + + + + + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx new file mode 100644 index 000000000..23796023c --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -0,0 +1,145 @@ +import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; +import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes'; +import { use, useEffect, useMemo, useRef, useState } from 'react'; +import { tankDefinitions } from '../../../../../../../core/blitzkit/tankDefinitions'; +import * as Duel from '../../../../../../../stores/duel'; +import { Arrow } from './components/Arrow'; +import { Node } from './components/Node'; + +// function Ancestry({ line }: { line: Line }) { +// return ( +// +// +// {line.map((node) => { +// if (typeof node === 'number') { +// return ; +// } else { +// return ( +// +// {node.map((line) => ( +// +// ))} +// +// ); +// } +// })} +// +// +// ); +// } + +type Line = number[]; + +export function TechTreeSection() { + const master = Duel.use((state) => state.protagonist.tank); + const awaitedTankDefinitions = use(tankDefinitions); + const container = useRef(null); + const lines = useMemo(() => { + function extend(line: Line): Line[] { + const root = awaitedTankDefinitions[line.at(-1)!]; + + if (root.ancestors === undefined || root.tier === 1) { + return [line]; + } else { + if (root.ancestors.length === 1 || root.tier === 2) { + line.push(root.ancestors[0]); + return extend(line); + } else { + return root.ancestors + .map((ancestor) => { + const newLine = [...line, ancestor]; + return extend(newLine); + }) + .flat(); + } + } + } + + return extend([master.id]); + }, [master]); + const [lineIndex, setLineIndex] = useState(0); + const line = useMemo( + () => [...lines[lineIndex]].toReversed(), + [master, lineIndex], + ); + + if ( + master.treeType !== 'researchable' || + master.ancestors === undefined || + master.ancestors.length === 0 + ) { + return null; + } + + useEffect(() => { + if (!container.current) return; + + container.current.scrollLeft = container.current.scrollWidth; + }); + + return ( + + + Tech tree + + {lines.length > 1 && ( + + + setLineIndex((lines.length + lineIndex - 1) % lines.length) + } + > + + + + Route {lineIndex + 1} of {lines.length} + + setLineIndex((lineIndex + 1) % lines.length)} + > + + + + )} + + + + + {line.map((id, index) => ( + <> + {index > 0 && } + + + ))} + + {master.tier < 10 && ( + <> + + {master.successors!.map((id, index) => ( + <> + {index > 0 && ( + + + + )} + + + ))} + + )} + + + + ); +} From c2abc94241383d92bf3f9b166a10d90aebf0dd72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:57:22 -0500 Subject: [PATCH 070/120] feat: totals --- .../Model/TechTreeSection/index.tsx | 93 ++++++++++++++----- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx index 23796023c..8c44cfa3d 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -1,6 +1,7 @@ import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes'; import { use, useEffect, useMemo, useRef, useState } from 'react'; +import { asset } from '../../../../../../../core/blitzkit/asset'; import { tankDefinitions } from '../../../../../../../core/blitzkit/tankDefinitions'; import * as Duel from '../../../../../../../stores/duel'; import { Arrow } from './components/Arrow'; @@ -62,6 +63,14 @@ export function TechTreeSection() { () => [...lines[lineIndex]].toReversed(), [master, lineIndex], ); + const totalXp = line.reduce( + (xp, id) => xp + (awaitedTankDefinitions[id].xp ?? 0), + 0, + ); + const totalCredits = line.reduce( + (credits, id) => credits + awaitedTankDefinitions[id].price.value, + 0, + ); if ( master.treeType !== 'researchable' || @@ -82,36 +91,48 @@ export function TechTreeSection() { my="6" direction="column" align="center" - gap="4" + gap="0" style={{ backgroundColor: 'var(--color-surface)', }} py="6" > - + Tech tree - {lines.length > 1 && ( - - - setLineIndex((lines.length + lineIndex - 1) % lines.length) - } - > - - - - Route {lineIndex + 1} of {lines.length} - - setLineIndex((lineIndex + 1) % lines.length)} - > - - - - )} + + + + XP + {totalXp.toLocaleString()} + + + + + + Silver + {totalCredits.toLocaleString()} + + + @@ -140,6 +161,32 @@ export function TechTreeSection() { )} + + + {lines.length > 1 && ( + + + setLineIndex((lines.length + lineIndex - 1) % lines.length) + } + > + + + + Route {lineIndex + 1} of {lines.length} + + setLineIndex((lineIndex + 1) % lines.length)} + > + + + + )} + ); } From 09848c7b211a7e4e67fd742b53ffff403c4b771d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:08:02 -0500 Subject: [PATCH 071/120] feat: more robust xp --- .../Model/TechTreeSection/index.tsx | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx index 8c44cfa3d..3d8d88a61 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -64,7 +64,12 @@ export function TechTreeSection() { [master, lineIndex], ); const totalXp = line.reduce( - (xp, id) => xp + (awaitedTankDefinitions[id].xp ?? 0), + (xp, id) => + xp + + (awaitedTankDefinitions[id].xp === undefined || + awaitedTankDefinitions[id].tier === 1 + ? 0 + : awaitedTankDefinitions[id].xp), 0, ); const totalCredits = line.reduce( @@ -100,39 +105,41 @@ export function TechTreeSection() { Tech tree - - - - XP - {totalXp.toLocaleString()} - - + {master.tier > 1 && ( + + + + XP + {totalXp.toLocaleString()} + + - - - Silver - {totalCredits.toLocaleString()} - - - + + + Silver + {totalCredits.toLocaleString()} + + + + )} From 263740dd302a0c3f8406c8566bb4fa1ea5f832b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:11:08 -0500 Subject: [PATCH 072/120] fix: invalidate frame on model transform --- src/core/blitzkit/modelTransform.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/blitzkit/modelTransform.ts b/src/core/blitzkit/modelTransform.ts index 1b5487d7f..3908802cb 100644 --- a/src/core/blitzkit/modelTransform.ts +++ b/src/core/blitzkit/modelTransform.ts @@ -1,3 +1,4 @@ +import { invalidate } from '@react-three/fiber'; import { EventManager } from './eventManager'; export interface ModelTransformEventData { @@ -6,3 +7,4 @@ export interface ModelTransformEventData { } export const modelTransformEvent = new EventManager(); +modelTransformEvent.on(() => invalidate()); From 876dee187097c042d677474f09ce7ff34222e127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:28:15 -0500 Subject: [PATCH 073/120] feat: responsive meta --- .../[id]/components/Model/MetaSection.tsx | 131 ------------------ .../Model/MetaSection/components/Listing.tsx | 14 ++ .../components/Model/MetaSection/index.tsx | 127 +++++++++++++++++ 3 files changed, 141 insertions(+), 131 deletions(-) delete mode 100644 src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx create mode 100644 src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx create mode 100644 src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx deleted file mode 100644 index 4f45720c6..000000000 --- a/src/app/tools/tankopedia/[id]/components/Model/MetaSection.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import { Code, Flex, Heading, Text } from '@radix-ui/themes'; -import { classIcons } from '../../../../../../components/ClassIcon'; -import { asset } from '../../../../../../core/blitzkit/asset'; -import { tankIcon } from '../../../../../../core/blitzkit/tankIcon'; -import strings from '../../../../../../lang/en-US.json'; -import * as App from '../../../../../../stores/app'; -import * as Duel from '../../../../../../stores/duel'; - -export function MetaSection() { - const developerMode = App.useDeferred(false, (state) => state.developerMode); - const tank = Duel.use((state) => state.protagonist.tank); - const ClassIcon = classIcons[tank.class]; - - return ( - - - Economics - - - - Overview - - - - Name - {tank.nameFull && Full-name} - Nation - Tier - Class - Type - {developerMode && ( - - DEV: ID - - )} - - - - {tank.name} - {tank.nameFull && {tank.nameFull}} - - - {tank.nation} - { - strings.common.nations[ - tank.nation as keyof typeof strings.common.nations - ] - } - - - {tank.tier} - - - - {strings.common.tank_class_short[tank.class]} - - - - {strings.common.tree_type[tank.treeType]} - - {developerMode && {tank.id}} - - - - - - Economics - - - - - {tank.price.type === 'credits' ? 'Purchase' : 'Restoration'}{' '} - price - - Sale price - {tank.xp && Research XP} - - - - - {tank.price.value.toLocaleString()} - {tank.price.type} - - - - {(tank.price.value / 2).toLocaleString()} - {tank.price.type} - - - {tank.xp && ( - - {tank.xp.toLocaleString()} - xp - - )} - - - - - - - ); -} diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx new file mode 100644 index 000000000..688dc1cd4 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx @@ -0,0 +1,14 @@ +import { Flex, Text, TextProps } from '@radix-ui/themes'; + +type ListingProps = TextProps & { + label: string; +}; + +export function Listing({ label, ...props }: ListingProps) { + return ( + + {label} + + + ); +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx new file mode 100644 index 000000000..25bc5d4a1 --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx @@ -0,0 +1,127 @@ +import { Code, Flex, Heading } from '@radix-ui/themes'; +import { classIcons } from '../../../../../../../components/ClassIcon'; +import { asset } from '../../../../../../../core/blitzkit/asset'; +import { tankIcon } from '../../../../../../../core/blitzkit/tankIcon'; +import strings from '../../../../../../../lang/en-US.json'; +import * as App from '../../../../../../../stores/app'; +import * as Duel from '../../../../../../../stores/duel'; +import { Listing } from './components/Listing'; + +export function MetaSection() { + const developerMode = App.useDeferred(false, (state) => state.developerMode); + const tank = Duel.use((state) => state.protagonist.tank); + const ClassIcon = classIcons[tank.class]; + + return ( + + + Economics + + + + + Overview + + + {tank.name} + {tank.nameFull && ( + {tank.nameFull} + )} + + + {tank.nation} + { + strings.common.nations[ + tank.nation as keyof typeof strings.common.nations + ] + } + + + {tank.tier} + + + + {strings.common.tank_class_short[tank.class]} + + + + {strings.common.tree_type[tank.treeType]} + + {developerMode && ( + + {tank.id} + + )} + + + + + Economics + + + + + {tank.price.value.toLocaleString()} + {tank.price.type} + + + + + {(tank.price.value / 2).toLocaleString()} + {tank.price.type} + + + {tank.xp && ( + + + {tank.xp.toLocaleString()} + xp + + + )} + + + + + ); +} From d45637a40773811192934788ea073e040f008284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 19:45:33 -0500 Subject: [PATCH 074/120] feat: characteristics section --- .../tools/compare/components/CompareTable.tsx | 2 +- .../components/ConfigurationChildWrapper.tsx | 7 +++++- .../components/Consumables.tsx | 3 ++- .../Characteristics/components/Modules.tsx | 4 +--- .../Model/CharacteristicsSection.tsx | 22 ++++++++++++------- .../[id]/components/Model/GameModeSection.tsx | 2 +- .../components/Model/MetaSection/index.tsx | 2 +- src/components/ConsumablesManager.tsx | 17 +++++++------- .../ModuleButtons/ConsumableButton.tsx | 1 + 9 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/app/tools/compare/components/CompareTable.tsx b/src/app/tools/compare/components/CompareTable.tsx index 2f4bd3180..18b986247 100644 --- a/src/app/tools/compare/components/CompareTable.tsx +++ b/src/app/tools/compare/components/CompareTable.tsx @@ -509,7 +509,7 @@ export function CompareTable({ stats }: CompareTableProps) { { + onConsumablesChange={(consumables) => { mutateCompareEphemeral((draft) => { draft.members[index].consumables = consumables; }); diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx index f164672eb..ed5fe5977 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/ConfigurationChildWrapper.tsx @@ -10,7 +10,12 @@ export function ConfigurationChildWrapper({ ...props }: ConfigurationChildWrapperProps) { return ( - + {children} ); diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx index dfdb633b6..52e63878c 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables.tsx @@ -77,11 +77,12 @@ export function Consumables() { hasConsumableDeliverySystem={hasConsumableDeliverySystem} hasHighEndConsumables={hasHighEndConsumables} timers - onChange={(consumables) => { + onConsumablesChange={(consumables) => { mutateDuel((draft) => { draft.protagonist.consumables = consumables; }); }} + justify={{ initial: 'center', sm: 'start' }} /> ); diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx index c39d86a8c..3d566aa11 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules.tsx @@ -214,9 +214,7 @@ export function Modules() { align="center" direction="column" gap="2" - style={{ - position: 'relative', - }} + position="relative" > {unlock.cost.value > 0 && ( <> diff --git a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx index 14389122e..f7a2be54e 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/CharacteristicsSection.tsx @@ -12,11 +12,17 @@ export function CharacteristicsSection() { - + Configuration @@ -27,14 +33,14 @@ export function CharacteristicsSection() { - Characteristics + + Characteristics + diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx index 974bd17d4..46b1a60fc 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -27,7 +27,7 @@ export function GameModeSection() { return ( - + Overview diff --git a/src/components/ConsumablesManager.tsx b/src/components/ConsumablesManager.tsx index e10c78f2b..1448b1c31 100644 --- a/src/components/ConsumablesManager.tsx +++ b/src/components/ConsumablesManager.tsx @@ -1,30 +1,31 @@ -import { Flex } from '@radix-ui/themes'; +import { Flex, FlexProps } from '@radix-ui/themes'; import { ConsumableEntry } from '../core/blitzkit/consumableDefinitions'; import { ConsumableButton } from './ModuleButtons/ConsumableButton'; -interface ConsumablesManagerProps { +type ConsumablesManagerProps = FlexProps & { consumables: ConsumableEntry[]; selected: number[]; - onChange?: (consumables: number[]) => void; + onConsumablesChange?: (consumables: number[]) => void; disabled?: boolean; timers?: boolean; hasHighEndConsumables?: boolean; hasConsumableDeliverySystem?: boolean; cooldownBooster?: number; -} +}; export function ConsumablesManager({ consumables, selected, - onChange, + onConsumablesChange, disabled, timers, hasConsumableDeliverySystem, cooldownBooster, hasHighEndConsumables, + ...props }: ConsumablesManagerProps) { return ( - + {consumables.map((consumable, index) => { const isSelected = selected.some((id) => id === consumable.id); @@ -50,7 +51,7 @@ export function ConsumablesManager({ consumable={consumable.id} selected={isSelected} onClick={() => { - if (!onChange) return; + if (!onConsumablesChange) return; const draft = [...selected]; @@ -60,7 +61,7 @@ export function ConsumablesManager({ draft.push(consumable.id); } - onChange(draft); + onConsumablesChange(draft); }} /> ); diff --git a/src/components/ModuleButtons/ConsumableButton.tsx b/src/components/ModuleButtons/ConsumableButton.tsx index 58749eb64..8cc8295ba 100644 --- a/src/components/ModuleButtons/ConsumableButton.tsx +++ b/src/components/ModuleButtons/ConsumableButton.tsx @@ -25,6 +25,7 @@ export function ConsumableButton({ return ( Date: Wed, 21 Aug 2024 20:01:20 -0500 Subject: [PATCH 075/120] fix: persistent tank filters --- src/app/tools/tankopedia/[id]/layout.tsx | 29 +++++++++++------------- src/app/tools/tankopedia/layout.tsx | 7 ++++-- src/app/tools/tankopedia/page.tsx | 3 --- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/layout.tsx b/src/app/tools/tankopedia/[id]/layout.tsx index e2ea7fb52..d4d7e7542 100644 --- a/src/app/tools/tankopedia/[id]/layout.tsx +++ b/src/app/tools/tankopedia/[id]/layout.tsx @@ -6,7 +6,6 @@ import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/c import { tankIcon } from '../../../../core/blitzkit/tankIcon'; import strings from '../../../../lang/en-US.json'; import * as Duel from '../../../../stores/duel'; -import * as TankFilters from '../../../../stores/tankFilters'; import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral'; export default async function Layout({ @@ -29,22 +28,20 @@ export default async function Layout({ return ( - - - {title} - - - - + + {title} + + + + - {children} - - + {children} + ); } diff --git a/src/app/tools/tankopedia/layout.tsx b/src/app/tools/tankopedia/layout.tsx index 90aa0fa5b..f4cc51323 100644 --- a/src/app/tools/tankopedia/layout.tsx +++ b/src/app/tools/tankopedia/layout.tsx @@ -1,10 +1,13 @@ +import * as TankFilters from '../../../stores/tankFilters'; import * as TankopediaPersistent from '../../../stores/tankopediaPersistent'; import * as TankopediaSort from '../../../stores/tankopediaSort'; export default function Layout({ children }: { children: React.ReactNode }) { return ( - + + {children} - + + ); } diff --git a/src/app/tools/tankopedia/page.tsx b/src/app/tools/tankopedia/page.tsx index 92158b251..72190e2c5 100644 --- a/src/app/tools/tankopedia/page.tsx +++ b/src/app/tools/tankopedia/page.tsx @@ -1,13 +1,10 @@ import PageWrapper from '../../../components/PageWrapper'; -import * as TankFilters from '../../../stores/tankFilters'; import { TankSearch } from './components/TankSearch'; export default function Page() { return ( - - ); } From 679bd2956baf5b91bae8c1ed8401da3819712dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:04:27 -0500 Subject: [PATCH 076/120] fix: invalidate frame on shell switch --- .../tankopedia/[id]/components/Model/components/Options.tsx | 2 ++ src/app/tools/tankopedia/[id]/page.tsx | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx index 0cda66b87..7773cf731 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx @@ -17,6 +17,7 @@ import { Tabs, Text, } from '@radix-ui/themes'; +import { invalidate } from '@react-three/fiber'; import { useEffect, useState } from 'react'; import { ModuleButton } from '../../../../../../../components/ModuleButtons/ModuleButton'; import { SmallTankIcon } from '../../../../../../../components/SmallTankIcon'; @@ -216,6 +217,7 @@ export function Options({ thicknessRange }: OptionsProps) { marginTop: shellIndex === 0 ? 0 : -1, }} onClick={() => { + invalidate(); mutateDuel((draft) => { draft.antagonist.shell = thisShell; }); diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index b221b086c..dbf1911fa 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -1,5 +1,6 @@ 'use client'; +import { invalidate } from '@react-three/fiber'; import { useEffect } from 'react'; import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive'; import PageWrapper from '../../../../components/PageWrapper'; @@ -8,9 +9,9 @@ import * as Duel from '../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral'; import { HistorySection } from './components/HistorySection'; import { CharacteristicsSection } from './components/Model/CharacteristicsSection'; -import { MetaSection } from './components/Model/MetaSection'; import { GameModeSection } from './components/Model/GameModeSection'; import { HeroSection } from './components/Model/HeroSection'; +import { MetaSection } from './components/Model/MetaSection'; import { TechTreeSection } from './components/Model/TechTreeSection'; import { ShotDisplaySection } from './components/ShotDisplaySection'; import { TestingSection } from './components/TestingSection'; @@ -34,11 +35,13 @@ export default function Page({ params }: { params: { id: string } }) { } if (event.key === '1') { + invalidate(); wipeShot(); mutateDuel((draft) => { draft.antagonist.shell = draft.antagonist.gun.shells[0]; }); } else if (event.key === '2') { + invalidate(); wipeShot(); mutateDuel((draft) => { if (draft.antagonist.gun.shells[1]) { @@ -46,6 +49,7 @@ export default function Page({ params }: { params: { id: string } }) { } }); } else if (event.key === '3') { + invalidate(); wipeShot(); mutateDuel((draft) => { if (draft.antagonist.gun.shells[2]) { From 575fdbbcc37aa58ae43597dccc0814acd096cd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:23:39 -0500 Subject: [PATCH 077/120] feat: currency icons --- scripts/buildAssets/currencies.ts | 45 ++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/scripts/buildAssets/currencies.ts b/scripts/buildAssets/currencies.ts index 74a7923a3..1b2b658ba 100644 --- a/scripts/buildAssets/currencies.ts +++ b/scripts/buildAssets/currencies.ts @@ -14,10 +14,19 @@ const ICONS = [ ['currency_battle-xp_xl.packed.webp', 'xp'], ]; +type BlitzGlossary = Record< + string, + { + image_url: null | string; + } +>; + export async function currencies(production: boolean) { console.log('Building currency icons...'); - const changes = await Promise.all( + const changes: FileChange[] = []; + + await Promise.all( ICONS.map(async ([file, name]) => { const content = ( await sharp( @@ -27,13 +36,43 @@ export async function currencies(production: boolean) { .toBuffer() ).toString('base64'); - return { + changes.push({ content, encoding: 'base64', path: `icons/currencies/${name}.webp`, - } satisfies FileChange; + }); }), ); + const glossary = await fetch(process.env.WOTB_GLOSSARY!).then( + (response) => response.json() as Promise, + ); + + await Promise.all( + Object.entries(glossary) + .filter(([key]) => /^prx_season_\d+$/.test(key)) + .map(async ([key, item]) => { + if (item.image_url === null) throw new Error(`No image_url for ${key}`); + + const imageRaw = await fetch(item.image_url).then((response) => + response.arrayBuffer(), + ); + const content = ( + await sharp(imageRaw) + .trim({ + threshold: 100, + background: { r: 0, g: 0, b: 0, alpha: 0 }, + }) + .toBuffer() + ).toString('base64'); + + changes.push({ + content, + encoding: 'base64', + path: `icons/currencies/${key}.webp`, + }); + }), + ); + await commitAssets('currency icons', changes, production); } From c19eeb01e1ea1c58499513cca9d163312008020b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:25:22 -0500 Subject: [PATCH 078/120] fix: restorateion price for prems --- .../tankopedia/[id]/components/Model/MetaSection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx index cdd0455d6..c23dd2539 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx @@ -82,7 +82,7 @@ export function MetaSection() { {tank.price.value.toLocaleString()} From 17526ca59c424bdbaf4afae9699c9af9c29f38ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Wed, 21 Aug 2024 20:25:51 -0500 Subject: [PATCH 079/120] feat: remove name --- .../tools/tankopedia/[id]/components/Model/MetaSection/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx index c23dd2539..0e045d338 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx @@ -32,7 +32,6 @@ export function MetaSection() { Overview - {tank.name} {tank.nameFull && ( {tank.nameFull} )} From aeed328c187740daa604ba586e6cbe551c185cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 22 Aug 2024 19:09:05 -0500 Subject: [PATCH 080/120] Update credits.md --- docs/about/credits.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/about/credits.md b/docs/about/credits.md index a87b5d11a..801f272d8 100644 --- a/docs/about/credits.md +++ b/docs/about/credits.md @@ -12,7 +12,7 @@ BlitzKit is a one man band **TrèsAbhi** but I am far from solo. | Game file layout | Aeson | | 3-caliber rule edge cases | Minitelrose, ChickenMan7777 | | Embed UX | \_34, HisRoyalFatness, Synx | -| Tankopedia pre-release testing | [OPTML], Aeson, \_34, Droodles | -| Website advertisement platform | Aeson, Droodles | -| Compare pre-release testing | [OPTML], Droodles | +| Tankopedia pre-release testing | [OPTML], Aeson, \_34 | +| Website advertisement platform | Aeson | +| Compare pre-release testing | [OPTML] | | Redacted | GonnaHetzMe | From 912f134eb6c3869d02959ba4971fef6299b1af9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Thu, 22 Aug 2024 19:44:52 -0500 Subject: [PATCH 081/120] Update settings.json --- .vscode/settings.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1ee34dfd5..784528977 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -55,7 +55,6 @@ "DIDS", "donotremove", "drei", - "Droodles", "dvpd", "dvpl", "DVPLCRC", From 5dc55914ed25c291850490eebc9569cfd4120b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:50:48 -0500 Subject: [PATCH 082/120] feat: linux assets --- .github/workflows/cd-assets.yml | 4 ++-- scripts/setupDepotDownloader.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index d6bd41a6d..644f89645 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -13,7 +13,7 @@ concurrency: jobs: build: - runs-on: windows-latest + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -29,7 +29,7 @@ jobs: run: bun scripts/setupDepotDownloader.ts - name: Run DepotDownloader - run: ./temp/depotDownloader/DepotDownloader.exe -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" + run: ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" - name: Apply patches run: | diff --git a/scripts/setupDepotDownloader.ts b/scripts/setupDepotDownloader.ts index 37aa6858c..01ead4510 100644 --- a/scripts/setupDepotDownloader.ts +++ b/scripts/setupDepotDownloader.ts @@ -18,13 +18,13 @@ await fetch( }>, ) .then(({ assets }) => { - const asset = assets.find(({ name }) => name.includes('windows-x64')); + const asset = assets.find(({ name }) => name.includes('linux-x64')); if (!asset) throw new Error('No asset found'); return fetch(asset.browser_download_url); }) .then((response) => response.arrayBuffer()) .then((arrayBuffer) => - writeFile('temp/depotDownloader.zip', Buffer.from(arrayBuffer)), + writeFile('temp/depotDownloader.zip', new Uint8Array(arrayBuffer)), ); console.log('Unzipping...'); From 59d837bbb2d0831683636b3ffd0e3ea32aa30540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:52:17 -0500 Subject: [PATCH 083/120] fix: format --- .github/workflows/cd-assets.yml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index 644f89645..cb917f63a 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -32,20 +32,8 @@ jobs: run: ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" - name: Apply patches - run: | - $env:DISCORD_CLIENT_ID = "${{ secrets.DISCORD_CLIENT_ID }}" - $env:GH_TOKEN = "${{ secrets.GH_TOKEN }}" - $env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}" - $env:DATABASE_URL = "${{ secrets.DATABASE_URL }}" - $env:WOTB_DLC_CDN = "${{ secrets.WOTB_DLC_CDN }}" - bun scripts/applyPatches.ts --depot + run: DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} WOTB_DLC_CDN=${{ secrets.WOTB_DLC_CDN }} bun scripts/applyPatches.ts --depot - name: Build assets run: | - $env:DISCORD_CLIENT_ID = "${{ secrets.DISCORD_CLIENT_ID }}" - $env:GH_TOKEN = "${{ secrets.GH_TOKEN }}" - $env:DISCORD_TOKEN = "${{ secrets.DISCORD_TOKEN }}" - $env:DATABASE_URL = "${{ secrets.DATABASE_URL }}" - $env:VIDEOS_SHEET = "${{ secrets.VIDEOS_SHEET }}" - $env:GOOGLE_APPLICATION_CREDENTIALS = "${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}" - bun build:assets --all-targets --depot --production + DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} VIDEOS_SHEET=${{ secrets.VIDEOS_SHEET }} GOOGLE_APPLICATION_CREDENTIALS=${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} bun build:assets --all-targets --depot --production From 66e65587bdfc2f8a3780afeb54bdfd441e1cc97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:54:36 -0500 Subject: [PATCH 084/120] fix: update index --- .github/workflows/cd-assets.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index cb917f63a..dee09f85d 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -29,11 +29,12 @@ jobs: run: bun scripts/setupDepotDownloader.ts - name: Run DepotDownloader - run: ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" + run: | + git update-index --chmod=+x ./temp/depotDownloader/DepotDownloader + ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" - name: Apply patches run: DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} WOTB_DLC_CDN=${{ secrets.WOTB_DLC_CDN }} bun scripts/applyPatches.ts --depot - name: Build assets - run: | - DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} VIDEOS_SHEET=${{ secrets.VIDEOS_SHEET }} GOOGLE_APPLICATION_CREDENTIALS=${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} bun build:assets --all-targets --depot --production + run: DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} VIDEOS_SHEET=${{ secrets.VIDEOS_SHEET }} GOOGLE_APPLICATION_CREDENTIALS=${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} bun build:assets --all-targets --depot --production From f7e1b08788fe35426b219a6b4d193ebcbfc9b4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:55:45 -0500 Subject: [PATCH 085/120] fix: add --- .github/workflows/cd-assets.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index dee09f85d..9a7349479 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -30,6 +30,7 @@ jobs: - name: Run DepotDownloader run: | + git add temp git update-index --chmod=+x ./temp/depotDownloader/DepotDownloader ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" From ed283d4d2e094cd172314f8be73dbd715fd10655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:56:24 -0500 Subject: [PATCH 086/120] fix: f --- .github/workflows/cd-assets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index 9a7349479..d61b4affb 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -30,7 +30,7 @@ jobs: - name: Run DepotDownloader run: | - git add temp + git add temp -f git update-index --chmod=+x ./temp/depotDownloader/DepotDownloader ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" From 69676da446d2774954f64bd1fe59ee41382ee838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:57:58 -0500 Subject: [PATCH 087/120] fix: guess the pokemon! --- .github/workflows/cd-assets.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index d61b4affb..4aa8ae3a0 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -30,8 +30,7 @@ jobs: - name: Run DepotDownloader run: | - git add temp -f - git update-index --chmod=+x ./temp/depotDownloader/DepotDownloader + chmod +x ./temp/depotDownloader/DepotDownloader ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" - name: Apply patches From 2f5e1eeadcadf51d1bb1a7eeffec72c308e284f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 23 Aug 2024 19:58:58 -0500 Subject: [PATCH 088/120] fix: spaces --- .github/workflows/cd-assets.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd-assets.yml b/.github/workflows/cd-assets.yml index 4aa8ae3a0..1f4f3d92a 100644 --- a/.github/workflows/cd-assets.yml +++ b/.github/workflows/cd-assets.yml @@ -34,7 +34,7 @@ jobs: ./temp/depotDownloader/DepotDownloader -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}" - name: Apply patches - run: DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} WOTB_DLC_CDN=${{ secrets.WOTB_DLC_CDN }} bun scripts/applyPatches.ts --depot + run: DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} WOTB_DLC_CDN=${{ secrets.WOTB_DLC_CDN }} bun scripts/applyPatches.ts --depot - name: Build assets - run: DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} VIDEOS_SHEET=${{ secrets.VIDEOS_SHEET }} GOOGLE_APPLICATION_CREDENTIALS=${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} bun build:assets --all-targets --depot --production + run: DISCORD_CLIENT_ID=${{ secrets.DISCORD_CLIENT_ID }} GH_TOKEN=${{ secrets.GH_TOKEN }} DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} VIDEOS_SHEET=${{ secrets.VIDEOS_SHEET }} GOOGLE_APPLICATION_CREDENTIALS=${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} bun build:assets --all-targets --depot --production From cae2bcc3ea106c0c9d260b63f176e4d82bc40cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 24 Aug 2024 20:23:58 -0500 Subject: [PATCH 089/120] fix: it didn't have to end this way --- src/constants/youtubers.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/constants/youtubers.ts b/src/constants/youtubers.ts index 65d19d8dd..369770389 100644 --- a/src/constants/youtubers.ts +++ b/src/constants/youtubers.ts @@ -1,5 +1,4 @@ export const youtubers = [ - { id: 'UCKBYXp4Xn2I2tL1UL4fpbhw', name: 'Droodles' }, { id: 'UCrQ-Dy8lVsm11u8pCJ8W7Tw', name: 'HisRoyalFatness' }, { id: 'UCxRpZqMElssTdPYDK3x7wyg', name: 'N90' }, ]; From 474846e9c2213f3ae9b93e13a9e74735dd9169b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 24 Aug 2024 20:26:12 -0500 Subject: [PATCH 090/120] feat: add wotb official to whitelist --- src/constants/youtubers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/constants/youtubers.ts b/src/constants/youtubers.ts index 369770389..6585e0527 100644 --- a/src/constants/youtubers.ts +++ b/src/constants/youtubers.ts @@ -1,4 +1,5 @@ export const youtubers = [ + { id: 'UC9lE09jxmMgMoG13WrNHPmA', name: 'World of Tanks Blitz' }, { id: 'UCrQ-Dy8lVsm11u8pCJ8W7Tw', name: 'HisRoyalFatness' }, { id: 'UCxRpZqMElssTdPYDK3x7wyg', name: 'N90' }, ]; From f91dd1e2c05bea990cf7c7d7815254fa1dc9e706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 09:21:17 -0500 Subject: [PATCH 091/120] stash: averages proto --- public/protos/reviews.proto | 16 ++++++++++++++++ scripts/averages.ts | 2 +- src/core/blitzkit/averageDefinitions/index.ts | 2 +- src/core/protobuf/lookup.ts | 8 ++++---- src/test.ts | 7 +++++++ 5 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 public/protos/reviews.proto create mode 100644 src/test.ts diff --git a/public/protos/reviews.proto b/public/protos/reviews.proto new file mode 100644 index 000000000..ba4f3391f --- /dev/null +++ b/public/protos/reviews.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package blitzkit; + +message Reviews { + map reviews = 1; +} + +message Review { + repeated Video video = 1; +} + +message Video { + string id = 1; + string author = 2; +} \ No newline at end of file diff --git a/scripts/averages.ts b/scripts/averages.ts index adf3576ea..ae17683d3 100644 --- a/scripts/averages.ts +++ b/scripts/averages.ts @@ -229,7 +229,7 @@ async function postWork() { { path: `averages/${latest}.pb`, content: await encodeToBase64( - 'blitzkit.AverageDefinitions', + 'blitzkit/blitzkit.AverageDefinitions', averageDefinitions, ), encoding: 'base64', diff --git a/src/core/blitzkit/averageDefinitions/index.ts b/src/core/blitzkit/averageDefinitions/index.ts index 535e54d65..adea8dca6 100644 --- a/src/core/blitzkit/averageDefinitions/index.ts +++ b/src/core/blitzkit/averageDefinitions/index.ts @@ -56,7 +56,7 @@ export const averageDefinitions = fetch(asset('averages/manifest.json'), { .then((response) => response.arrayBuffer()) .then((buffer) => decode( - 'blitzkit.AverageDefinitions', + 'blitzkit/blitzkit.AverageDefinitions', new Uint8Array(buffer), ), ); diff --git a/src/core/protobuf/lookup.ts b/src/core/protobuf/lookup.ts index 1aaf82ff8..fd0ce752a 100644 --- a/src/core/protobuf/lookup.ts +++ b/src/core/protobuf/lookup.ts @@ -2,13 +2,13 @@ import { Root } from 'protobufjs'; import { context } from '../blitzkit/context'; export async function lookup(proto: string) { - const name = proto.split('.')[0]; + const [file, message] = proto.split('/')[0]; const root = await new Root().load( context === 'server' - ? `public/protos/${name}.proto` - : `/protos/${name}.proto`, + ? `public/protos/${file}.proto` + : `/protos/${file}.proto`, { keepCase: true }, ); - return root.lookupType(proto); + return root.lookupType(message); } diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 000000000..266ce6616 --- /dev/null +++ b/src/test.ts @@ -0,0 +1,7 @@ +import { youtubers } from './constants/youtubers'; +import { decodeYouTubeId } from './core/youtube/decodeYouTubeId'; +import { encodeYouTubeId } from './core/youtube/encodeYouTubeId'; + +youtubers.forEach((yt) => { + console.log(yt.id, decodeYouTubeId(encodeYouTubeId(yt.id))); +}); From d9521ce1e5d0c4ab4d2bf0af232c6c2f57607194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 18:10:56 -0500 Subject: [PATCH 092/120] feat: new reviews --- .github/workflows/reviews.yml | 24 +++ public/protos/reviews.proto | 3 +- scripts/buildAssets/index.ts | 2 - scripts/buildAssets/videos.ts | 139 ------------------ scripts/reviews.ts | 135 +++++++++++++++++ .../[id]/components/VideoSection.tsx | 14 +- src/core/blitzkit/reviews.ts | 22 +++ src/core/blitzkit/videos.ts | 32 ---- src/core/protobuf/encode.ts | 4 + src/core/protobuf/lookup.ts | 2 +- src/test.ts | 7 - 11 files changed, 196 insertions(+), 188 deletions(-) create mode 100644 .github/workflows/reviews.yml delete mode 100644 scripts/buildAssets/videos.ts create mode 100644 scripts/reviews.ts create mode 100644 src/core/blitzkit/reviews.ts delete mode 100644 src/core/blitzkit/videos.ts delete mode 100644 src/test.ts diff --git a/.github/workflows/reviews.yml b/.github/workflows/reviews.yml new file mode 100644 index 000000000..c9d0a1f6e --- /dev/null +++ b/.github/workflows/reviews.yml @@ -0,0 +1,24 @@ +name: Reviews + +on: + workflow_dispatch: + schedule: + - cron: 0 0 * * 2 + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v1 + + - name: Install dependencies + run: bun install + + - name: Find reviews + run: DISCORD_TOKEN=${{ secrets.DISCORD_TOKEN }} GH_TOKEN=${{ secrets.GH_TOKEN }} DATABASE_URL=${{ secrets.DATABASE_URL }} bun scripts/reviews.ts diff --git a/public/protos/reviews.proto b/public/protos/reviews.proto index ba4f3391f..482daeb75 100644 --- a/public/protos/reviews.proto +++ b/public/protos/reviews.proto @@ -7,7 +7,8 @@ message Reviews { } message Review { - repeated Video video = 1; + float last_updated = 1; + repeated Video videos = 2; } message Video { diff --git a/scripts/buildAssets/index.ts b/scripts/buildAssets/index.ts index 4d6b5abae..32a886455 100644 --- a/scripts/buildAssets/index.ts +++ b/scripts/buildAssets/index.ts @@ -24,7 +24,6 @@ import { skillIcons } from './skillIcons'; import { tankArmors } from './tankArmors'; import { tankIcons } from './tankIcons'; import { tankModels } from './tankModels'; -import { videos } from './videos'; if (!targets && !allTargets) throw new Error('No target(s) specified'); @@ -32,7 +31,6 @@ const methods = [ gameModeBanners, definitions, tankIcons, - videos, currencies, skillIcons, flags, diff --git a/scripts/buildAssets/videos.ts b/scripts/buildAssets/videos.ts deleted file mode 100644 index 6f4ab1fd2..000000000 --- a/scripts/buildAssets/videos.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { readdir } from 'fs/promises'; -import { google } from 'googleapis'; -import { cloneDeep, uniqBy } from 'lodash'; -import { parse as parseYaml } from 'yaml'; -import { youtubers } from '../../src/constants/youtubers'; -import { readXMLDVPL } from '../../src/core/blitz/readXMLDVPL'; -import { readYAMLDVPL } from '../../src/core/blitz/readYAMLDVPL'; -import { toUniqueId } from '../../src/core/blitz/toUniqueId'; -import { commitAssets } from '../../src/core/blitzkit/commitAssets'; -import { VideoDefinitions } from '../../src/core/blitzkit/videos'; -import { DATA } from './constants'; -import { BlitzStrings, botPattern, VehicleDefinitionList } from './definitions'; - -export async function videos(production: boolean) { - console.log('Building videos...'); - - const currentVideos = await fetch( - 'https://raw.githubusercontent.com/tresabhi/blitzkit-assets/main/definitions/videos.csv', - ) - .then((response) => response.text()) - .then((lines) => { - return lines - .split('\n') - .map((line) => { - const [idString, lastUpdatedString, ...videos] = line.split(','); - const id = Number(idString); - const lastUpdated = Number(lastUpdatedString); - return { id, lastUpdated, videos }; - }) - .reduce( - (accumulator, { id, lastUpdated, videos }) => { - accumulator[id] = { lastUpdated, videos }; - return accumulator; - }, - {}, - ); - }); - const auth = await google.auth.getClient({ - scopes: ['https://www.googleapis.com/auth/youtube.readonly'], - }); - const youtube = google.youtube({ version: 'v3', auth }); - - const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( - (nations) => nations.filter((nation) => nation !== 'common'), - ); - const stringsPreInstalled = await readYAMLDVPL( - `${DATA}/Strings/en.yaml.dvpl`, - ); - const stringsCache = await fetch( - 'https://stufficons.wgcdn.co/localizations/en.yaml', - ) - .then((response) => response.text()) - .then((string) => parseYaml(string) as BlitzStrings); - const strings = { - ...stringsPreInstalled, - ...stringsCache, - }; - const tanks: { id: number; name: string; tier: number }[] = []; - await Promise.all( - nations.map(async (nation) => { - const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>( - `${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`, - ); - - await Promise.all( - Object.entries(tankList.root).map(async ([tankKey, tank]) => { - if (botPattern.test(tankKey)) return null; - - const id = toUniqueId(nation, tank.id); - const name = - (tank.shortUserString - ? strings[tank.shortUserString] - : undefined) ?? strings[tank.userString]; - const tier = tank.level; - - tanks.push({ id, name, tier }); - }), - ); - }), - ); - - const tanksSanitized = tanks - .sort((a, b) => b.tier - a.tier) - .sort((a, b) => { - const lastUpdatedA = currentVideos[a.id]?.lastUpdated ?? 0; - const lastUpdatedB = currentVideos[b.id]?.lastUpdated ?? 0; - return lastUpdatedA - lastUpdatedB; - }); - const videos: VideoDefinitions = cloneDeep(currentVideos); - - let done = 0; - for (const tank of tanksSanitized) { - try { - const results = await youtube.search.list({ - part: ['snippet'], - q: `World of Tanks Blitz ${tank.name}`, - }); - - if (!results.data.items || results.data.items.length === 0) continue; - - const items = uniqBy( - results.data.items.filter( - (item) => - item.snippet?.channelId && - item.id?.videoId && - youtubers.some(({ id }) => id === item.snippet?.channelId), - ), - (item) => item.snippet!.channelId, - ); - - videos[tank.id] = { - lastUpdated: Math.round(Date.now() / 1000), - videos: items.map((item) => item.id!.videoId!), - }; - - console.log( - `${++done} / ${tanks.length} (${Math.round(100 * (done / tanks.length))}%) done; found ${items.length} for ${tank.name}`, - ); - - await new Promise((resolve) => setTimeout(resolve, 1000 / 5)); - } catch (error) { - console.warn('An error occurred, safely exiting prematurely...', error); - break; - } - } - - const content = Object.entries(videos) - .map( - ([id, { videos, lastUpdated }]) => - `${id},${lastUpdated},${videos.join(',')}`, - ) - .join('\n'); - - await commitAssets( - 'videos', - [{ content, encoding: 'utf-8', path: 'definitions/videos.csv' }], - production, - ); -} diff --git a/scripts/reviews.ts b/scripts/reviews.ts new file mode 100644 index 000000000..d3a232644 --- /dev/null +++ b/scripts/reviews.ts @@ -0,0 +1,135 @@ +import { readdir } from 'fs/promises'; +import { google } from 'googleapis'; +import { cloneDeep, uniqBy } from 'lodash'; +import { parse as parseYaml } from 'yaml'; +import { youtubers } from '../src/constants/youtubers'; +import { readXMLDVPL } from '../src/core/blitz/readXMLDVPL'; +import { readYAMLDVPL } from '../src/core/blitz/readYAMLDVPL'; +import { toUniqueId } from '../src/core/blitz/toUniqueId'; +import { asset } from '../src/core/blitzkit/asset'; +import { commitAssets } from '../src/core/blitzkit/commitAssets'; +import { Reviews, Video } from '../src/core/blitzkit/reviews'; +import { decode } from '../src/core/protobuf/decode'; +import { encode } from '../src/core/protobuf/encode'; +import { DATA } from './buildAssets/constants'; +import { + BlitzStrings, + botPattern, + VehicleDefinitionList, +} from './buildAssets/definitions'; + +const MAX_QUERIES = 128; + +console.log('Finding reviews...'); + +const currentReviews = await fetch(asset('definitions/reviews.pb', false)) + .then((response) => response.arrayBuffer()) + .then((buffer) => + decode('reviews/blitzkit.Reviews', new Uint8Array(buffer)), + ); +const auth = await google.auth.getClient({ + scopes: ['https://www.googleapis.com/auth/youtube.readonly'], +}); +const youtube = google.youtube({ version: 'v3', auth }); + +const nations = await readdir(`${DATA}/XML/item_defs/vehicles`).then( + (nations) => nations.filter((nation) => nation !== 'common'), +); +const stringsPreInstalled = await readYAMLDVPL( + `${DATA}/Strings/en.yaml.dvpl`, +); +const stringsCache = await fetch( + 'https://stufficons.wgcdn.co/localizations/en.yaml', +) + .then((response) => response.text()) + .then((string) => parseYaml(string) as BlitzStrings); +const strings = { + ...stringsPreInstalled, + ...stringsCache, +}; +const tanks: { id: number; name: string; tier: number }[] = []; +await Promise.all( + nations.map(async (nation) => { + const tankList = await readXMLDVPL<{ root: VehicleDefinitionList }>( + `${DATA}/XML/item_defs/vehicles/${nation}/list.xml.dvpl`, + ); + + await Promise.all( + Object.entries(tankList.root).map(async ([tankKey, tank]) => { + if (botPattern.test(tankKey)) return null; + + const id = toUniqueId(nation, tank.id); + const name = + (tank.shortUserString ? strings[tank.shortUserString] : undefined) ?? + strings[tank.userString]; + const tier = tank.level; + + tanks.push({ id, name, tier }); + }), + ); + }), +); + +const tanksSanitized = tanks + .sort((a, b) => b.tier - a.tier) + .sort((a, b) => { + const lastUpdatedA = currentReviews.reviews[a.id]?.last_updated ?? 0; + const lastUpdatedB = currentReviews.reviews[b.id]?.last_updated ?? 0; + return lastUpdatedA - lastUpdatedB; + }); +const reviews: Reviews = cloneDeep(currentReviews); + +let done = 0; +for (const tank of tanksSanitized) { + if (done >= MAX_QUERIES) { + console.log(`Limit reached with ${done} queries; stopping...`); + break; + } + + try { + const results = await youtube.search.list({ + part: ['snippet'], + q: `World of Tanks Blitz ${tank.name}`, + }); + + if (!results.data.items || results.data.items.length === 0) continue; + + const items = uniqBy( + results.data.items.filter( + (item) => + item.snippet?.channelId && + item.id?.videoId && + youtubers.some(({ id }) => id === item.snippet?.channelId), + ), + (item) => item.snippet!.channelId, + ); + + reviews.reviews[tank.id] = { + last_updated: Date.now(), + videos: items.map( + (item) => + ({ + id: item.id!.videoId!, + author: item.snippet!.channelId!, + }) satisfies Video, + ), + }; + + console.log(`${++done} done; found ${items.length} for ${tank.name}`); + + await new Promise((resolve) => setTimeout(resolve, 1000 / 5)); + } catch (error) { + console.warn(`Limit reached with ${done} queries`); + break; + } +} + +const content = await encode('reviews/blitzkit.Reviews', reviews).then( + (array) => Buffer.from(array).toString('base64'), +); + +await commitAssets( + 'reviews', + [{ content, encoding: 'base64', path: 'definitions/reviews.pb' }], + true, +); diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index ac826ae28..19d3f0527 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -2,13 +2,15 @@ import { InfoCircledIcon } from '@radix-ui/react-icons'; import { Callout, Flex, Heading, Link } from '@radix-ui/themes'; import { use } from 'react'; import PageWrapper from '../../../../../components/PageWrapper'; -import { videoDefinitions } from '../../../../../core/blitzkit/videos'; +import { reviews } from '../../../../../core/blitzkit/reviews'; import * as Duel from '../../../../../stores/duel'; export function VideoSection() { const tank = Duel.use((state) => state.protagonist.tank); - const awaitedVideoDefinitions = use(videoDefinitions); - const videos = awaitedVideoDefinitions[tank.id]?.videos ?? []; + const awaitedReviews = use(reviews); + const videos = awaitedReviews.reviews[tank.id]?.videos; + + if (!videos) return null; return ( @@ -29,13 +31,13 @@ export function VideoSection() { {videos.map((video) => ( Video thumbnail; +} + +interface Review { + last_updated: number; + videos?: Video[]; +} + +export interface Video { + id: string; + author: string; +} + +export const reviews = fetch(asset('definitions/reviews.pb')) + .then((response) => response.arrayBuffer()) + .then((buffer) => + decode('reviews/blitzkit.Reviews', new Uint8Array(buffer)), + ); diff --git a/src/core/blitzkit/videos.ts b/src/core/blitzkit/videos.ts deleted file mode 100644 index 69c3e2508..000000000 --- a/src/core/blitzkit/videos.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { asset } from './asset'; - -export interface VideoDefinitions { - [id: number]: { - videos: string[]; - lastUpdated: number; - }; -} - -export const videoDefinitions = fetch(asset('definitions/videos.csv')) - .then((response) => response.text()) - .then((text) => - text - .split('\n') - .map((line) => { - const [idString, lastUpdatedString, ...videos] = line - .split(',') - .filter(Boolean); - const id = Number(idString); - const lastUpdated = Number(lastUpdatedString); - return { id, videos, lastUpdated }; - }) - .filter(({ videos }) => videos.length > 0) - .reduce((accumulator, { id, videos, lastUpdated }) => { - accumulator[id] = { - videos, - lastUpdated, - }; - - return accumulator; - }, {}), - ); diff --git a/src/core/protobuf/encode.ts b/src/core/protobuf/encode.ts index a7c3034c6..7ff1b18d1 100644 --- a/src/core/protobuf/encode.ts +++ b/src/core/protobuf/encode.ts @@ -2,5 +2,9 @@ import { lookup } from './lookup'; export async function encode(proto: string, data: any) { const Message = await lookup(proto); + const verification = Message.verify(data); + + if (verification !== null) throw new Error(verification); + return Message.encode(Message.create(data)).finish(); } diff --git a/src/core/protobuf/lookup.ts b/src/core/protobuf/lookup.ts index fd0ce752a..388ed29da 100644 --- a/src/core/protobuf/lookup.ts +++ b/src/core/protobuf/lookup.ts @@ -2,7 +2,7 @@ import { Root } from 'protobufjs'; import { context } from '../blitzkit/context'; export async function lookup(proto: string) { - const [file, message] = proto.split('/')[0]; + const [file, message] = proto.split('/'); const root = await new Root().load( context === 'server' ? `public/protos/${file}.proto` diff --git a/src/test.ts b/src/test.ts deleted file mode 100644 index 266ce6616..000000000 --- a/src/test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { youtubers } from './constants/youtubers'; -import { decodeYouTubeId } from './core/youtube/decodeYouTubeId'; -import { encodeYouTubeId } from './core/youtube/encodeYouTubeId'; - -youtubers.forEach((yt) => { - console.log(yt.id, decodeYouTubeId(encodeYouTubeId(yt.id))); -}); From 8ebd604cde1b80d7f66fb84e73ae8e650e9f5e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 18:33:04 -0500 Subject: [PATCH 093/120] feat: display videos --- .vscode/settings.json | 1 + .../[id]/components/VideoSection.tsx | 106 +++++++++++++----- src/app/tools/tankopedia/[id]/page.tsx | 2 +- src/components/VerifiedIcon.tsx | 16 +++ src/core/blitzkit/var.ts | 7 ++ 5 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 src/components/VerifiedIcon.tsx create mode 100644 src/core/blitzkit/var.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 784528977..db1baa6b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -188,6 +188,7 @@ "XMLDVPL", "YAMLDVPL", "yolo", + "youtuber", "youtubers", "zustand" ], diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index 19d3f0527..70f54fb9c 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -1,8 +1,12 @@ -import { InfoCircledIcon } from '@radix-ui/react-icons'; -import { Callout, Flex, Heading, Link } from '@radix-ui/themes'; +import { PlusIcon } from '@radix-ui/react-icons'; +import { Box, Flex, Heading, Text } from '@radix-ui/themes'; import { use } from 'react'; +import { Link } from '../../../../../components/Link'; import PageWrapper from '../../../../../components/PageWrapper'; +import { VerifiedIcon } from '../../../../../components/VerifiedIcon'; +import { youtubers } from '../../../../../constants/youtubers'; import { reviews } from '../../../../../core/blitzkit/reviews'; +import { Var } from '../../../../../core/blitzkit/var'; import * as Duel from '../../../../../stores/duel'; export function VideoSection() { @@ -15,38 +19,84 @@ export function VideoSection() { return ( - + Review videos - - - - - - BlitzKit does not endorse any review videos. - - + BlitzKit does not endorse any review videos. - {videos.map((video) => ( - { + const image = `https://i.ytimg.com/vi/${video.id}/hqdefault.jpg`; + const youtuber = youtubers.find( + (youtuber) => youtuber.id === video.author, + ); + + if (!youtuber) return null; + + return ( + + + + + {youtuber.name} + + + + + ); + })} + + + - Video thumbnail - - ))} + + Apply to feature your video + + diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index dbf1911fa..446db40e6 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -80,7 +80,7 @@ export default function Page({ params }: { params: { id: string } }) { }, []); return ( - + diff --git a/src/components/VerifiedIcon.tsx b/src/components/VerifiedIcon.tsx new file mode 100644 index 000000000..278a1bcf2 --- /dev/null +++ b/src/components/VerifiedIcon.tsx @@ -0,0 +1,16 @@ +import { ComponentProps } from 'react'; + +export function VerifiedIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} diff --git a/src/core/blitzkit/var.ts b/src/core/blitzkit/var.ts new file mode 100644 index 000000000..417008b2d --- /dev/null +++ b/src/core/blitzkit/var.ts @@ -0,0 +1,7 @@ +type Name = + | `color-${'background' | `panel-${'solid' | 'translucent'}` | 'surface' | 'overlay'}` + | `radius-${1 | 2 | 3 | 4 | 5 | 6 | 'full'}`; + +export function Var(name: Name) { + return `var(--${name})`; +} From 1a1b8c3a65d257ffa4c906d2133ffeaea7084e2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 18:36:57 -0500 Subject: [PATCH 094/120] feat: premium purchase price --- .../[id]/components/Model/MetaSection/index.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx index 0e045d338..8b6083599 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx @@ -13,7 +13,7 @@ export function MetaSection() { const ClassIcon = classIcons[tank.class]; return ( - + + {tank.treeType === 'premium' && ( + + + {tank.price.value / 400} + gold + + + )} From da6691928e3ea5fba200753b8435f5e5bc8607be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 18:38:28 -0500 Subject: [PATCH 095/120] feat: mode tooltips --- .../components/Model/components/Options.tsx | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx index 7773cf731..05ef3bd11 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx @@ -16,6 +16,7 @@ import { Strong, Tabs, Text, + Tooltip, } from '@radix-ui/themes'; import { invalidate } from '@react-three/fiber'; import { useEffect, useState } from 'react'; @@ -366,21 +367,29 @@ export function Options({ thicknessRange }: OptionsProps) { }); }} > - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + From 2e97ccd40d5488141d0618f4a4519690134047ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 18:45:01 -0500 Subject: [PATCH 096/120] feat: filter tooltips --- .../tankopedia/components/FilterControl.tsx | 442 ++++++++++-------- src/lang/en-US.json | 7 + 2 files changed, 248 insertions(+), 201 deletions(-) diff --git a/src/app/tools/tankopedia/components/FilterControl.tsx b/src/app/tools/tankopedia/components/FilterControl.tsx index d2be97bf1..0ab1e2e8e 100644 --- a/src/app/tools/tankopedia/components/FilterControl.tsx +++ b/src/app/tools/tankopedia/components/FilterControl.tsx @@ -1,7 +1,7 @@ 'use client'; import { ReloadIcon } from '@radix-ui/react-icons'; -import { Box, Flex, IconButton, Text } from '@radix-ui/themes'; +import { Box, Flex, IconButton, Text, Tooltip } from '@radix-ui/themes'; import { times } from 'lodash'; import { use } from 'react'; import { classIcons } from '../../../../components/ClassIcon'; @@ -14,6 +14,7 @@ import { asset } from '../../../../core/blitzkit/asset'; import { gameDefinitions } from '../../../../core/blitzkit/gameDefinitions'; import { Tier } from '../../../../core/blitzkit/tankDefinitions'; import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants'; +import strings from '../../../../lang/en-US.json'; import * as TankFilters from '../../../../stores/tankFilters'; interface FilterControlProps { @@ -39,24 +40,26 @@ export function FilterControl({ compact }: FilterControlProps) { const selected = filters.tiers?.includes(tier); return ( - - mutateTankFilters((draft) => { - if (draft.tiers?.includes(tier)) { - draft.tiers = draft.tiers?.filter((t) => t !== tier); - } else { - draft.tiers = [...(draft.tiers ?? []), tier]; - } - }) - } - > - {TIER_ROMAN_NUMERALS[tier]} - + + + mutateTankFilters((draft) => { + if (draft.tiers?.includes(tier)) { + draft.tiers = draft.tiers?.filter((t) => t !== tier); + } else { + draft.tiers = [...(draft.tiers ?? []), tier]; + } + }) + } + > + {TIER_ROMAN_NUMERALS[tier]} + + ); })} @@ -66,24 +69,26 @@ export function FilterControl({ compact }: FilterControlProps) { const selected = filters.tiers?.includes(tier); return ( - - mutateTankFilters((draft) => { - if (draft.tiers?.includes(tier)) { - draft.tiers = draft.tiers?.filter((t) => t !== tier); - } else { - draft.tiers = [...(draft.tiers ?? []), tier]; - } - }) - } - > - {TIER_ROMAN_NUMERALS[tier]} - + + + mutateTankFilters((draft) => { + if (draft.tiers?.includes(tier)) { + draft.tiers = draft.tiers?.filter((t) => t !== tier); + } else { + draft.tiers = [...(draft.tiers ?? []), tier]; + } + }) + } + > + {TIER_ROMAN_NUMERALS[tier]} + + ); })} @@ -101,29 +106,37 @@ export function FilterControl({ compact }: FilterControlProps) { const selected = filters.nations?.includes(nation); return ( - - mutateTankFilters((draft) => { - if (draft.nations?.includes(nation)) { - draft.nations = draft.nations?.filter( - (n) => n !== nation, - ); - } else { - draft.nations = [...(draft.nations ?? []), nation]; - } - }) + - - + + mutateTankFilters((draft) => { + if (draft.nations?.includes(nation)) { + draft.nations = draft.nations?.filter( + (n) => n !== nation, + ); + } else { + draft.nations = [...(draft.nations ?? []), nation]; + } + }) + } + > + + + ); })} @@ -134,30 +147,39 @@ export function FilterControl({ compact }: FilterControlProps) { const selected = filters.nations?.includes(nation); return ( - - mutateTankFilters((draft) => { - if (draft.nations?.includes(nation)) { - draft.nations = draft.nations?.filter( - (n) => n !== nation, - ); - } else { - draft.nations = [...(draft.nations ?? []), nation]; - } - }) + - - + + mutateTankFilters((draft) => { + if (draft.nations?.includes(nation)) { + draft.nations = draft.nations?.filter( + (n) => n !== nation, + ); + } else { + draft.nations = [...(draft.nations ?? []), nation]; + } + }) + } + > + + + ); })} @@ -173,26 +195,30 @@ export function FilterControl({ compact }: FilterControlProps) { const selected = filters.classes?.includes(tankClass); return ( - - mutateTankFilters((draft) => { - if (draft.classes?.includes(tankClass)) { - draft.classes = draft.classes?.filter( - (c) => c !== tankClass, - ); - } else { - draft.classes = [...(draft.classes ?? []), tankClass]; - } - }) - } > - - + + mutateTankFilters((draft) => { + if (draft.classes?.includes(tankClass)) { + draft.classes = draft.classes?.filter( + (c) => c !== tankClass, + ); + } else { + draft.classes = [...(draft.classes ?? []), tankClass]; + } + }) + } + > + + + ); })} @@ -202,67 +228,75 @@ export function FilterControl({ compact }: FilterControlProps) { style={{ borderRadius: 'var(--radius-full)' }} direction={compact ? 'column' : { sm: 'row', initial: 'column' }} > - - mutateTankFilters((draft) => { - if (draft.types?.includes('researchable')) { - draft.types = draft.types?.filter((t) => t !== 'researchable'); - } else { - draft.types = [...(draft.types ?? []), 'researchable']; - } - }) - } - > - - - - mutateTankFilters((draft) => { - if (draft.types?.includes('premium')) { - draft.types = draft.types?.filter((t) => t !== 'premium'); - } else { - draft.types = [...(draft.types ?? []), 'premium']; - } - }) - } - > - + + mutateTankFilters((draft) => { + if (draft.types?.includes('researchable')) { + draft.types = draft.types?.filter( + (t) => t !== 'researchable', + ); + } else { + draft.types = [...(draft.types ?? []), 'researchable']; + } + }) + } > - - - - mutateTankFilters((draft) => { - if (draft.types?.includes('collector')) { - draft.types = draft.types?.filter((t) => t !== 'collector'); - } else { - draft.types = [...(draft.types ?? []), 'collector']; - } - }) - } - > - + + + + mutateTankFilters((draft) => { + if (draft.types?.includes('premium')) { + draft.types = draft.types?.filter((t) => t !== 'premium'); + } else { + draft.types = [...(draft.types ?? []), 'premium']; + } + }) + } > - - - + + + + + + + + mutateTankFilters((draft) => { + if (draft.types?.includes('collector')) { + draft.types = draft.types?.filter((t) => t !== 'collector'); + } else { + draft.types = [...(draft.types ?? []), 'collector']; + } + }) + } + > + + + + + - - mutateTankFilters((draft) => { - draft.testing = 'include'; - }) - } - > - - - - mutateTankFilters((draft) => { - draft.testing = 'exclude'; - }) - } - > - - - - mutateTankFilters((draft) => { - draft.testing = 'only'; - }) - } - > - - + + + mutateTankFilters((draft) => { + draft.testing = 'include'; + }) + } + > + + + + + + mutateTankFilters((draft) => { + draft.testing = 'exclude'; + }) + } + > + + + + + + mutateTankFilters((draft) => { + draft.testing = 'only'; + }) + } + > + + + diff --git a/src/lang/en-US.json b/src/lang/en-US.json index a170b1a2f..63390b39b 100644 --- a/src/lang/en-US.json +++ b/src/lang/en-US.json @@ -58,6 +58,13 @@ "AT-SPG": "TD" }, + "tank_class_medium": { + "lightTank": "Light", + "mediumTank": "Medium", + "heavyTank": "Heavy", + "AT-SPG": "Tank destroyer" + }, + "tree_type": { "researchable": "Tech tree", "premium": "Premium", From 2b02158e19cb984880d822a82f2fb3d758a1ddaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 18:48:57 -0500 Subject: [PATCH 097/120] feat: move tech tree section up --- .../Model/TechTreeSection/index.tsx | 27 +------------------ .../[id]/components/ShotDisplaySection.tsx | 8 +----- src/app/tools/tankopedia/[id]/page.tsx | 4 +-- 3 files changed, 4 insertions(+), 35 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx index 3d8d88a61..c7eeaabf6 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -7,28 +7,6 @@ import * as Duel from '../../../../../../../stores/duel'; import { Arrow } from './components/Arrow'; import { Node } from './components/Node'; -// function Ancestry({ line }: { line: Line }) { -// return ( -// -// -// {line.map((node) => { -// if (typeof node === 'number') { -// return ; -// } else { -// return ( -// -// {node.map((line) => ( -// -// ))} -// -// ); -// } -// })} -// -// -// ); -// } - type Line = number[]; export function TechTreeSection() { @@ -93,13 +71,10 @@ export function TechTreeSection() { return ( diff --git a/src/app/tools/tankopedia/[id]/components/ShotDisplaySection.tsx b/src/app/tools/tankopedia/[id]/components/ShotDisplaySection.tsx index 142d4dba4..07418e0f6 100644 --- a/src/app/tools/tankopedia/[id]/components/ShotDisplaySection.tsx +++ b/src/app/tools/tankopedia/[id]/components/ShotDisplaySection.tsx @@ -8,13 +8,7 @@ export function ShotDisplaySection() { if (!shot) return null; return ( - + ); diff --git a/src/app/tools/tankopedia/[id]/page.tsx b/src/app/tools/tankopedia/[id]/page.tsx index 446db40e6..1aa3d8b14 100644 --- a/src/app/tools/tankopedia/[id]/page.tsx +++ b/src/app/tools/tankopedia/[id]/page.tsx @@ -82,14 +82,14 @@ export default function Page({ params }: { params: { id: string } }) { return ( - + {!exempt && } + {!exempt && } - {!exempt && } From bb0b39fabb82dbf88317297cac60a3b31ad934a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 18:52:30 -0500 Subject: [PATCH 098/120] fix: background accent color image alignment --- src/app/tools/tankopedia/[id]/components/VideoSection.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index 70f54fb9c..6b0d73b13 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -49,6 +49,7 @@ export function VideoSection() { borderRadius: 'var(--radius-3)', overflow: 'hidden', background: `url(${image})`, + backgroundPosition: '0 18px', backgroundSize: 'cover', }} > @@ -63,6 +64,7 @@ export function VideoSection() { /> Date: Sun, 25 Aug 2024 18:52:58 -0500 Subject: [PATCH 099/120] fix: discord application link --- src/app/tools/tankopedia/[id]/components/VideoSection.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index 6b0d73b13..8d729619b 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -81,7 +81,11 @@ export function VideoSection() { ); })} - + Date: Sun, 25 Aug 2024 19:11:30 -0500 Subject: [PATCH 100/120] feat: screenshot button --- .../[id]/components/Model/HeroSection.tsx | 7 +- .../[id]/components/Model/TankSandbox.tsx | 280 +++++++++--------- .../components/Model/components/Options.tsx | 34 ++- 3 files changed, 177 insertions(+), 144 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx index f415d4186..1be32e2f1 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx @@ -1,7 +1,7 @@ import { ChevronLeftIcon, MixIcon } from '@radix-ui/react-icons'; import { Box, Button, Flex, Heading, Text } from '@radix-ui/themes'; import Link from 'next/link'; -import { Suspense, use, useEffect, useMemo, useState } from 'react'; +import { Suspense, use, useEffect, useMemo, useRef, useState } from 'react'; import { classIcons } from '../../../../../../components/ClassIcon'; import { ScienceIcon } from '../../../../../../components/ScienceIcon'; import { ThicknessRange } from '../../../../../../components/StaticArmor'; @@ -20,6 +20,7 @@ interface HeroSectionProps { } export function HeroSection({ id }: HeroSectionProps) { + const canvas = useRef(null); const protagonist = Duel.use((state) => state.protagonist.tank); const antagonist = Duel.use((state) => state.antagonist.tank); const compareTanks = @@ -169,11 +170,11 @@ export function HeroSection({ id }: HeroSectionProps) { /> } > - + - + diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx index 2d6876969..773d18806 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx @@ -1,5 +1,11 @@ import { Canvas } from '@react-three/fiber'; -import { Suspense, useEffect, useRef } from 'react'; +import { + forwardRef, + Suspense, + useEffect, + useImperativeHandle, + useRef, +} from 'react'; import { Armor } from '../../../../../../components/Armor'; import { ArmorPlateDisplay } from '../../../../../../components/Armor/components/ArmorPlateDisplay'; import { ShotDisplay } from '../../../../../../components/Armor/components/ShotDisplay'; @@ -26,154 +32,162 @@ interface TankSandboxProps { thicknessRange: ThicknessRange; } -export function TankSandbox({ thicknessRange }: TankSandboxProps) { - const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); - const canvas = useRef(null); - const hasImprovedVerticalStabilizer = useEquipment(122); - const protagonist = Duel.use((state) => state.protagonist); - const mutateDuel = Duel.useMutation(); - const tankModelDefinition = useTankModelDefinition(); - const turretModelDefinition = - tankModelDefinition.turrets[protagonist.turret.id]; - const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; - const display = TankopediaPersistent.use((state) => state.display); +export const TankSandbox = forwardRef( + ({ thicknessRange }, ref) => { + const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); + const canvas = useRef(null); + const hasImprovedVerticalStabilizer = useEquipment(122); + const protagonist = Duel.use((state) => state.protagonist); + const mutateDuel = Duel.useMutation(); + const tankModelDefinition = useTankModelDefinition(); + const turretModelDefinition = + tankModelDefinition.turrets[protagonist.turret.id]; + const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; + const display = TankopediaPersistent.use((state) => state.display); - function handlePointerDown() { - window.addEventListener('pointermove', handlePointerMove); - window.addEventListener('pointerup', handlePointerUp); - } - function handlePointerMove(event: PointerEvent) { - event.preventDefault(); - } - function handlePointerUp(event: PointerEvent) { - event.preventDefault(); + useImperativeHandle(ref, () => canvas.current!, []); - window.removeEventListener('pointermove', handlePointerMove); - window.removeEventListener('pointerup', handlePointerUp); - } + function handlePointerDown() { + window.addEventListener('pointermove', handlePointerMove); + window.addEventListener('pointerup', handlePointerUp); + } + function handlePointerMove(event: PointerEvent) { + event.preventDefault(); + } + function handlePointerUp(event: PointerEvent) { + event.preventDefault(); - useEffect(() => { - function handlePoseEvent(pose: Pose) { - switch (pose) { - case Pose.HullDown: { - mutateDuel((draft) => { - const [pitch, yaw] = applyPitchYawLimits( - -Infinity, - 0, - gunModelDefinition.pitch, - turretModelDefinition.yaw, - hasImprovedVerticalStabilizer, - ); + window.removeEventListener('pointermove', handlePointerMove); + window.removeEventListener('pointerup', handlePointerUp); + } - modelTransformEvent.emit({ pitch, yaw }); - draft.protagonist.pitch = pitch; - draft.protagonist.yaw = yaw; - }); + useEffect(() => { + function handlePoseEvent(pose: Pose) { + switch (pose) { + case Pose.HullDown: { + mutateDuel((draft) => { + const [pitch, yaw] = applyPitchYawLimits( + -Infinity, + 0, + gunModelDefinition.pitch, + turretModelDefinition.yaw, + hasImprovedVerticalStabilizer, + ); - break; + modelTransformEvent.emit({ pitch, yaw }); + draft.protagonist.pitch = pitch; + draft.protagonist.yaw = yaw; + }); + + break; + } + + case Pose.FaceHug: { + mutateDuel((draft) => { + const [pitch, yaw] = applyPitchYawLimits( + Infinity, + 0, + gunModelDefinition.pitch, + turretModelDefinition.yaw, + hasImprovedVerticalStabilizer, + ); + + modelTransformEvent.emit({ pitch, yaw }); + draft.protagonist.pitch = pitch; + draft.protagonist.yaw = yaw; + }); + + break; + } + + case Pose.Default: + mutateDuel((draft) => { + const [pitch, yaw] = applyPitchYawLimits( + 0, + 0, + gunModelDefinition.pitch, + turretModelDefinition.yaw, + hasImprovedVerticalStabilizer, + ); + + modelTransformEvent.emit({ pitch, yaw }); + draft.protagonist.pitch = pitch; + draft.protagonist.yaw = yaw; + }); + + break; } - - case Pose.FaceHug: { - mutateDuel((draft) => { - const [pitch, yaw] = applyPitchYawLimits( - Infinity, - 0, - gunModelDefinition.pitch, - turretModelDefinition.yaw, - hasImprovedVerticalStabilizer, - ); - - modelTransformEvent.emit({ pitch, yaw }); - draft.protagonist.pitch = pitch; - draft.protagonist.yaw = yaw; - }); - - break; - } - - case Pose.Default: - mutateDuel((draft) => { - const [pitch, yaw] = applyPitchYawLimits( - 0, - 0, - gunModelDefinition.pitch, - turretModelDefinition.yaw, - hasImprovedVerticalStabilizer, - ); - - modelTransformEvent.emit({ pitch, yaw }); - draft.protagonist.pitch = pitch; - draft.protagonist.yaw = yaw; - }); - - break; } - } - poseEvent.on(handlePoseEvent); + poseEvent.on(handlePoseEvent); - return () => { - poseEvent.off(handlePoseEvent); - }; - }); - - useEffect(() => { - mutateDuel((draft) => { - [draft.protagonist.pitch, draft.protagonist.yaw] = applyPitchYawLimits( - draft.protagonist.pitch, - draft.protagonist.yaw, - gunModelDefinition.pitch, - turretModelDefinition.yaw, - hasImprovedVerticalStabilizer, - ); + return () => { + poseEvent.off(handlePoseEvent); + }; }); - }, [protagonist.gun, protagonist.turret]); - useEffect(() => { - if (display !== TankopediaDisplay.DynamicArmor) { - mutateTankopediaEphemeral((draft) => { - draft.shot = undefined; + useEffect(() => { + mutateDuel((draft) => { + [draft.protagonist.pitch, draft.protagonist.yaw] = applyPitchYawLimits( + draft.protagonist.pitch, + draft.protagonist.yaw, + gunModelDefinition.pitch, + turretModelDefinition.yaw, + hasImprovedVerticalStabilizer, + ); }); - } + }, [protagonist.gun, protagonist.turret]); - if (display !== TankopediaDisplay.StaticArmor) { - mutateTankopediaEphemeral((draft) => { - draft.highlightArmor = undefined; - }); - } - }, [display]); - - return ( - { + useEffect(() => { + if (display !== TankopediaDisplay.DynamicArmor) { mutateTankopediaEphemeral((draft) => { draft.shot = undefined; + }); + } + + if (display !== TankopediaDisplay.StaticArmor) { + mutateTankopediaEphemeral((draft) => { draft.highlightArmor = undefined; }); - }} - style={{ userSelect: 'none' }} - camera={{ fov: 25, far: 32 }} - > - - - {display !== TankopediaDisplay.StaticArmor && } + } + }, [display]); - - + return ( + { + mutateTankopediaEphemeral((draft) => { + draft.shot = undefined; + draft.highlightArmor = undefined; + }); + }} + style={{ userSelect: 'none' }} + camera={{ fov: 25, far: 32 }} + > + + + {display !== TankopediaDisplay.StaticArmor && } - {/* idk why the shot display doesn't work without suspense here lol */} - }> - {display === TankopediaDisplay.DynamicArmor && } - {display === TankopediaDisplay.StaticArmor && ( - - )} - - - - ); -} + + + + {/* idk why the shot display doesn't work without suspense here lol */} + }> + {display === TankopediaDisplay.DynamicArmor && } + {display === TankopediaDisplay.StaticArmor && ( + + )} + + + + ); + }, +); diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx index 05ef3bd11..1f5c2c38a 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx @@ -1,4 +1,5 @@ import { + CameraIcon, EnterFullScreenIcon, ExitFullScreenIcon, EyeOpenIcon, @@ -19,7 +20,7 @@ import { Tooltip, } from '@radix-ui/themes'; import { invalidate } from '@react-three/fiber'; -import { useEffect, useState } from 'react'; +import { RefObject, useEffect, useState } from 'react'; import { ModuleButton } from '../../../../../../../components/ModuleButtons/ModuleButton'; import { SmallTankIcon } from '../../../../../../../components/SmallTankIcon'; import { ThicknessRange } from '../../../../../../../components/StaticArmor'; @@ -45,9 +46,10 @@ import { Thicknesses } from '../../Thicknesses'; interface OptionsProps { thicknessRange: ThicknessRange; + canvas: RefObject; } -export function Options({ thicknessRange }: OptionsProps) { +export function Options({ thicknessRange, canvas }: OptionsProps) { const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); const mutateTankopediaPersistent = TankopediaPersistent.useMutation(); const displayRaw = TankopediaPersistent.use((state) => state.display); @@ -73,6 +75,7 @@ export function Options({ thicknessRange }: OptionsProps) { (state) => state.model.visual.environment, ); const developerMode = App.useDeferred(false, (state) => state.developerMode); + const protagonist = Duel.use((state) => state.protagonist.tank); const antagonistGun = Duel.use((state) => state.antagonist.gun); const antagonistShell = Duel.use((state) => state.antagonist.shell); const [antagonistSelectorOpen, setAntagonistSelectorOpen] = useState(false); @@ -122,12 +125,9 @@ export function Options({ thicknessRange }: OptionsProps) { @@ -302,6 +302,24 @@ export function Options({ thicknessRange }: OptionsProps) { )} + + { + if (!canvas.current) return; + + const anchor = document.createElement('a'); + + anchor.setAttribute('download', `${protagonist.name}.png`); + anchor.setAttribute('href', canvas.current.toDataURL('image/png')); + anchor.click(); + }} + > + + + + Date: Sun, 25 Aug 2024 19:23:13 -0500 Subject: [PATCH 101/120] fix: auto clear --- .../tools/tankopedia/[id]/components/Model/AutoClear.tsx | 9 +++++++++ .../tankopedia/[id]/components/Model/TankSandbox.tsx | 2 ++ 2 files changed, 11 insertions(+) create mode 100644 src/app/tools/tankopedia/[id]/components/Model/AutoClear.tsx diff --git a/src/app/tools/tankopedia/[id]/components/Model/AutoClear.tsx b/src/app/tools/tankopedia/[id]/components/Model/AutoClear.tsx new file mode 100644 index 000000000..7c095b7cd --- /dev/null +++ b/src/app/tools/tankopedia/[id]/components/Model/AutoClear.tsx @@ -0,0 +1,9 @@ +import { useFrame } from '@react-three/fiber'; + +export function AutoClear() { + useFrame(({ gl }) => { + gl.clear(); + }, 0); + + return null; +} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx index 773d18806..0760202a2 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx @@ -25,6 +25,7 @@ import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent import { Controls } from '../Control'; import { Lighting } from '../Lighting'; import { SceneProps } from '../SceneProps'; +import { AutoClear } from './AutoClear'; import { ModelLoader } from './components/ModelLoader'; import { TankModel } from './components/TankModel'; @@ -178,6 +179,7 @@ export const TankSandbox = forwardRef( + {/* idk why the shot display doesn't work without suspense here lol */} }> From 2f183896ebfcf101ab5e502b8314e8e82ab3ca63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 19:30:47 -0500 Subject: [PATCH 102/120] feat: crew in compare --- .../tools/compare/components/CompareTable.tsx | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/app/tools/compare/components/CompareTable.tsx b/src/app/tools/compare/components/CompareTable.tsx index 18b986247..b481f0fee 100644 --- a/src/app/tools/compare/components/CompareTable.tsx +++ b/src/app/tools/compare/components/CompareTable.tsx @@ -1,6 +1,6 @@ import { ComponentPlaceholderIcon } from '@radix-ui/react-icons'; -import { Button, Flex, Popover, Table } from '@radix-ui/themes'; -import { times } from 'lodash'; +import { Button, Flex, Popover, Slider, Table, Text } from '@radix-ui/themes'; +import { debounce, times } from 'lodash'; import { use } from 'react'; import { ConsumablesManager } from '../../../../components/ConsumablesManager'; import { CrewSkillManager } from '../../../../components/CrewSkillManager'; @@ -167,6 +167,7 @@ export function CompareTable({ stats }: CompareTableProps) { engine, track, consumables, + crewMastery, }, index, ) => { @@ -532,6 +533,23 @@ export function CompareTable({ stats }: CompareTableProps) { + + + {Math.round(crewMastery * 100)}% + + { + mutateCompareEphemeral((draft) => { + draft.members[index].crewMastery = value; + }); + }, 500)} + /> + + ); From 22831cc26846451b6302bf85f00845ddd3c71c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 19:32:28 -0500 Subject: [PATCH 103/120] fix: selector --- .../components/Model/components/Options.tsx | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx index 1f5c2c38a..35924e2d8 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx @@ -385,29 +385,27 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { }); }} > - - + + - - - - + + + + - - - - + + + + - - + + From 9a686230c6cc558f512f230840d2f683521d78c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:06:56 -0500 Subject: [PATCH 104/120] feat: battle count --- .../Model/TechTreeSection/components/Node.tsx | 37 +++++++++-- .../Model/TechTreeSection/index.tsx | 62 ++++++++++++++++--- src/stores/tankopediaEphemeral.ts | 3 + 3 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx index be6df1460..8dade4fd4 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/components/Node.tsx @@ -2,13 +2,36 @@ import { Box, Flex, Text } from '@radix-ui/themes'; import Link from 'next/link'; import { use } from 'react'; import { asset } from '../../../../../../../../core/blitzkit/asset'; +import { averageDefinitions } from '../../../../../../../../core/blitzkit/averageDefinitions'; import { tankDefinitions } from '../../../../../../../../core/blitzkit/tankDefinitions'; import { TIER_ROMAN_NUMERALS } from '../../../../../../../../core/blitzkit/tankDefinitions/constants'; import { formatCompact } from '../../../../../../../../core/math/formatCompact'; +import * as TankopediaEphemeral from '../../../../../../../../stores/tankopediaEphemeral'; -export function Node({ id, highlight }: { id: number; highlight?: boolean }) { +interface NodeProps { + id: number; + nextIds?: number[]; + highlight?: boolean; +} + +export function Node({ id, highlight, nextIds }: NodeProps) { + const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier); const awaitedTankDefinitions = use(tankDefinitions); const tank = awaitedTankDefinitions[id]; + const nextTanks = nextIds?.map((id) => awaitedTankDefinitions[id]); + const awaitedAverageDefinitions = use(averageDefinitions); + const thisTankXp = + tank.xp === undefined || tank.tier === 1 ? 0 : tank.xp! / xpMultiplier; + const nextTanksXp = nextTanks?.reduce( + (xp, tank) => + xp + + (tank.xp === undefined || tank.tier === 1 ? 0 : tank.xp! / xpMultiplier), + 0, + ); + const averages = awaitedAverageDefinitions.averages[tank.id]?.mu; + const averageXp = averages ? averages.xp / averages.battles : undefined; + const games = + averages && nextTanks ? Math.round(nextTanksXp! / averageXp!) : undefined; return ( {tank.name} - @@ -74,12 +96,9 @@ export function Node({ id, highlight }: { id: number; highlight?: boolean }) { objectPosition: 'center', }} /> - {tank.xp === undefined || tank.tier === 1 - ? 0 - : formatCompact(tank.xp!)} + {formatCompact(thisTankXp)} - + + {averages && nextTanks && ( + + {games!} {games === 1 ? 'battle' : 'battles'} + + )} diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx index c7eeaabf6..18c467b8b 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -2,14 +2,20 @@ import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons'; import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes'; import { use, useEffect, useMemo, useRef, useState } from 'react'; import { asset } from '../../../../../../../core/blitzkit/asset'; +import { imgur } from '../../../../../../../core/blitzkit/imgur'; import { tankDefinitions } from '../../../../../../../core/blitzkit/tankDefinitions'; import * as Duel from '../../../../../../../stores/duel'; +import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral'; import { Arrow } from './components/Arrow'; import { Node } from './components/Node'; type Line = number[]; +export const XP_MULTIPLIERS = [1, 2, 3, 4, 5, 10]; + export function TechTreeSection() { + const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier); + const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); const master = Duel.use((state) => state.protagonist.tank); const awaitedTankDefinitions = use(tankDefinitions); const container = useRef(null); @@ -94,7 +100,7 @@ export function TechTreeSection() { objectPosition: 'center', }} /> - {totalXp.toLocaleString()} + {Math.round(totalXp / xpMultiplier).toLocaleString()} @@ -115,16 +121,58 @@ export function TechTreeSection() { )} + + + {XP_MULTIPLIERS.map((multiplier) => { + const selected = xpMultiplier === multiplier; + + return ( + { + mutateTankopediaEphemeral((draft) => { + draft.xpMultiplier = multiplier; + }); + }} + key={multiplier} + width="2.5rem" + justify="center" + align="center" + pt="1" + pl="1" + > + x{multiplier} + + ); + })} + - {line.map((id, index) => ( - <> - {index > 0 && } - - - ))} + {line.map((id, index) => { + const last = index === line.length - 1; + const tank = awaitedTankDefinitions[id]; + + return ( + <> + {index > 0 && } + + + ); + })} {master.tier < 10 && ( <> diff --git a/src/stores/tankopediaEphemeral.ts b/src/stores/tankopediaEphemeral.ts index f91d435c2..02de4153b 100644 --- a/src/stores/tankopediaEphemeral.ts +++ b/src/stores/tankopediaEphemeral.ts @@ -3,6 +3,7 @@ import { Vector3 } from 'three'; import { create } from 'zustand'; import { subscribeWithSelector } from 'zustand/middleware'; +import { XP_MULTIPLIERS } from '../app/tools/tankopedia/[id]/components/Model/TechTreeSection'; import { ArmorType } from '../components/Armor/components/SpacedArmorScene'; import { ExternalModuleVariant } from '../components/Armor/components/SpacedArmorSceneComponent'; import { ModelDefinition } from '../core/blitzkit/modelDefinitions'; @@ -28,6 +29,7 @@ interface TankopediaEphemeral { } | { type: ArmorType.External } ); + xpMultiplier: (typeof XP_MULTIPLIERS)[number]; } export interface ShotLayerBase { @@ -97,6 +99,7 @@ export const { Provider, use, useMutation, useStore } = createNextSafeStore( skills: {}, model, controlsEnabled: true, + xpMultiplier: 1, })), ), ); From 6cc616d993690e454e2baab9d8a7edeaff5caec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:08:41 -0500 Subject: [PATCH 105/120] feat: xp multipler bold --- .../[id]/components/Model/TechTreeSection/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx index 18c467b8b..c51689aa6 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -148,7 +148,9 @@ export function TechTreeSection() { pt="1" pl="1" > - x{multiplier} + + x{multiplier} + ); })} From 3d5b8e31c8152923e60e19ed4ac2ce7b081d8020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:09:07 -0500 Subject: [PATCH 106/120] feat: xp multipler bold --- .../[id]/components/Model/TechTreeSection/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx index c51689aa6..0ac640b39 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TechTreeSection/index.tsx @@ -148,8 +148,8 @@ export function TechTreeSection() { pt="1" pl="1" > - - x{multiplier} + + x{multiplier} ); From 7391937070c2b574b4016e0e8cf3cbbee65c5155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:12:21 -0500 Subject: [PATCH 107/120] fix: align videos --- src/app/tools/tankopedia/[id]/components/VideoSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index 8d729619b..0ca769d25 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -25,7 +25,7 @@ export function VideoSection() { BlitzKit does not endorse any review videos. - + {videos.map((video) => { const image = `https://i.ytimg.com/vi/${video.id}/hqdefault.jpg`; const youtuber = youtubers.find( From 5bcfa88f48a86eec348e0ab7f37a09a015d4bc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:15:16 -0500 Subject: [PATCH 108/120] fix: persistent search --- src/app/tools/tankopedia/components/SearchBar.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/tools/tankopedia/components/SearchBar.tsx b/src/app/tools/tankopedia/components/SearchBar.tsx index c65f33f22..b7c4a2d2d 100644 --- a/src/app/tools/tankopedia/components/SearchBar.tsx +++ b/src/app/tools/tankopedia/components/SearchBar.tsx @@ -15,6 +15,7 @@ interface SearchBarProps { export function SearchBar({ topResult, onSelect }: SearchBarProps) { const tankFiltersStore = TankFilters.useStore(); + const lastSearch = tankFiltersStore.getState().search; const router = useRouter(); const input = useRef(null); const searching = TankFilters.use((state) => state.searching); @@ -58,6 +59,7 @@ export function SearchBar({ topResult, onSelect }: SearchBarProps) { Date: Sun, 25 Aug 2024 21:32:35 -0500 Subject: [PATCH 109/120] fix: icon check order --- scripts/buildAssets/consumableProvisionIcons.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/buildAssets/consumableProvisionIcons.ts b/scripts/buildAssets/consumableProvisionIcons.ts index cb2fcdcf6..d22f91b0b 100644 --- a/scripts/buildAssets/consumableProvisionIcons.ts +++ b/scripts/buildAssets/consumableProvisionIcons.ts @@ -25,11 +25,11 @@ export async function consumableProvisionIcons(production: boolean) { const changes: FileChange[] = []; const styles = [ + 'UI/Styles/Lobby/Inventory/Event/InventoryBigStyles.yaml', + 'UI/Styles/Lobby/Inventory/Event/InventoryNormalStyles.yaml', 'UI/Styles/Lobby/Inventory/InventoryNormalStyles.yaml', 'UI/Screens3/Lobby/Inventory/Equipment/EquipmentItemImage.style.yaml', - 'UI/Styles/Lobby/Inventory/Event/InventoryNormalStyles.yaml', 'UI/Screens/Battle/Styles/BattleEquipmentStyles.yaml', - 'UI/Styles/Lobby/Inventory/Event/InventoryBigStyles.yaml', ]; const styleSheets = await Promise.all( styles.map(async (path) => @@ -54,7 +54,7 @@ export async function consumableProvisionIcons(production: boolean) { Object.values(consumablesCommon.root).map(async (consumable) => { const styleSheet = styleSheets.find((styleSheet) => styleSheet.selectors.some((selector) => - selector.includes(consumable.icon), + selector.includes(`${consumable.icon} `), ), ); @@ -127,7 +127,7 @@ export async function consumableProvisionIcons(production: boolean) { Object.values(provisionsCommon.root).map(async (provision) => { const styleSheet = styleSheets.find((styleSheet) => styleSheet.selectors.some((selector) => - selector.includes(provision.icon), + selector.includes(`${provision.icon} `), ), ); From 5be9c94641f9993a4c5f874691d6d821678d3bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sun, 25 Aug 2024 21:48:26 -0500 Subject: [PATCH 110/120] feat: logs --- docs/changelogs/1.22.2.md | 38 ++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 docs/changelogs/1.22.2.md diff --git a/docs/changelogs/1.22.2.md b/docs/changelogs/1.22.2.md new file mode 100644 index 000000000..7c54d927d --- /dev/null +++ b/docs/changelogs/1.22.2.md @@ -0,0 +1,38 @@ +# BlitzKit 1.22.2 + +This update packs a punch. + +## Features + +- Added "Game mode abilities" section to the tankopedia pages + - Shows the game mode provisions and consumables underneath the corresponding mode's banner +- Reworked the tech tree section + - Now shows the whole line and if multiple paths exist, they are can be selected + - The selected tank is now highlighted with the flag of the corresponding country + - This section now also shows the total required XP and credits required + - Added a battle count which indicates the number of games required to reach the next tank (not including module upgrades) based on average xp earnings of players + - XP multipliers can also be applied to get a sense of how many battles you will really have to play +- Reworked the "Review videos" section + - Removed all previews videos; we will be starting from scratch + - Added names of content creators under their corresponding videos + - Added a way for YouTubers to apply to be a part of the review videos section +- Reworked the navbar + - This are a lot more compact and contrastive + - Tool names are now separated with vertical lines now + - The hamburger menu now looks more like the homepage cards +- Added a warning for test tanks +- Switched to on-demand rendering + - This makes it so that the canvas only renders upon interaction and not the continuously synced with the screen's refresh rate +- Added the meta information section to the tankopedia pages + - Lists the full name, nation, tier, class, type, restoration, purchase, and sale prices +- Added tooltips to a lot of places +- Reduced ads on the tankopedia pages +- Added a screenshot button to take screenshots of the tank +- Added crew training slider to the compare tool + +## Fixes + +- Invalid Wargaming logins are now handled properly +- Season currencies are now displayed properly +- Tank filters are now persistent but will be reset on refresh +- The search for a tank now populates the search bar when navigating back to the search page diff --git a/package.json b/package.json index 10cbfd377..3b75026a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkit", - "version": "1.22.1", + "version": "1.22.2", "description": "🎉 Tools for everything World of Tanks Blitz", "main": "src/server.ts", "type": "module", From aef020c744373fac4785013c81727e2196311b55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:16:14 -0500 Subject: [PATCH 111/120] feat: better hero sectio alighment --- public/assets/versions.json | 2 +- .../tools/tankopedia/[id]/components/Model/HeroSection.tsx | 3 ++- .../tankopedia/[id]/components/Model/components/Options.tsx | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/public/assets/versions.json b/public/assets/versions.json index c9af294ec..3d2b3168c 100644 --- a/public/assets/versions.json +++ b/public/assets/versions.json @@ -1 +1 @@ -["1.10.0","1.10.1","1.10.2","1.11.0","1.12.0","1.12.1","1.12.2","1.12.3","1.12.4","1.12.5","1.12.6","1.12.7","1.12.8","1.12.9","1.13.0","1.13.1","1.13.2","1.13.3","1.14.0","1.14.1","1.14.2","1.14.3","1.14.4","1.15.0","1.15.1","1.15.10","1.15.11","1.15.12","1.15.13","1.15.2","1.15.3","1.15.4","1.15.5","1.15.6","1.15.7","1.15.8","1.15.9","1.16.0","1.16.1","1.16.2","1.16.3","1.16.4","1.17.0","1.17.1","1.17.2","1.18.0","1.18.1","1.18.2","1.18.3","1.19.0","1.19.1","1.19.2","1.19.3","1.19.4","1.19.5","1.19.6","1.20.0","1.20.1","1.20.2","1.20.3","1.20.4","1.20.5","1.21.0","1.21.1","1.21.2","1.21.3","1.22.0","1.22.1","1.3.0","1.3.1","1.3.2","1.3.3","1.4.0","1.4.1","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.6.0","1.7.0","1.7.1","1.7.2","1.7.3-1.7.4","1.7.5","1.7.6","1.7.7","1.8.0","1.8.1","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","1.9.5"] \ No newline at end of file +["1.10.0","1.10.1","1.10.2","1.11.0","1.12.0","1.12.1","1.12.2","1.12.3","1.12.4","1.12.5","1.12.6","1.12.7","1.12.8","1.12.9","1.13.0","1.13.1","1.13.2","1.13.3","1.14.0","1.14.1","1.14.2","1.14.3","1.14.4","1.15.0","1.15.1","1.15.10","1.15.11","1.15.12","1.15.13","1.15.2","1.15.3","1.15.4","1.15.5","1.15.6","1.15.7","1.15.8","1.15.9","1.16.0","1.16.1","1.16.2","1.16.3","1.16.4","1.17.0","1.17.1","1.17.2","1.18.0","1.18.1","1.18.2","1.18.3","1.19.0","1.19.1","1.19.2","1.19.3","1.19.4","1.19.5","1.19.6","1.20.0","1.20.1","1.20.2","1.20.3","1.20.4","1.20.5","1.21.0","1.21.1","1.21.2","1.21.3","1.22.0","1.22.1","1.22.2","1.3.0","1.3.1","1.3.2","1.3.3","1.4.0","1.4.1","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.6.0","1.7.0","1.7.1","1.7.2","1.7.3-1.7.4","1.7.5","1.7.6","1.7.7","1.8.0","1.8.1","1.9.0","1.9.1","1.9.2","1.9.3","1.9.4","1.9.5"] \ No newline at end of file diff --git a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx index 1be32e2f1..b48e2a5e1 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx @@ -65,7 +65,8 @@ export function HeroSection({ id }: HeroSectionProps) { justify="center" pt={{ initial: '6', md: '0' }} style={{ background: 'var(--color-surface)', position: 'relative' }} - height={{ initial: 'calc(75vh - 64px)', md: undefined }} + height={{ initial: 'calc(75vh - 4rem)', md: undefined }} + minHeight="30rem" gap="4" > )} - + { if (!canvas.current) return; From 62fd98e075eee323052fd5e4161e39f8eea49fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:18:33 -0500 Subject: [PATCH 112/120] feat: responsive shell distance input --- .../[id]/components/Characteristics/index.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx index 9904a5b7c..1d70a14f6 100644 --- a/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Characteristics/index.tsx @@ -44,6 +44,9 @@ export function Characteristics() { const hasImprovedVentilation = useEquipment(102); const crewMastery = Duel.use((state) => state.protagonist.crewMastery); const [penetrationDistance, setPenetrationDistance] = useState(250); + const setPenetrationDistanceDebounced = debounce((value: number) => { + setPenetrationDistance(value); + }, 500); const provisions = Duel.use((state) => state.protagonist.provisions); const provisionCrewBonus = @@ -257,9 +260,13 @@ export function Characteristics() { max={500} style={{ flex: 1 }} defaultValue={[penetrationDistance]} - onValueChange={debounce(([value]) => { - setPenetrationDistance(value); - }, 500)} + onValueChange={([value]) => { + setPenetrationDistanceDebounced(value); + + if (!penetrationDistanceInput.current) return; + + penetrationDistanceInput.current.value = value.toString(); + }} /> Date: Mon, 26 Aug 2024 10:21:03 -0500 Subject: [PATCH 113/120] fix: game mode banner visiblity --- .../tools/tankopedia/[id]/components/Model/GameModeSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx index 46b1a60fc..5ac66a431 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/GameModeSection.tsx @@ -39,8 +39,8 @@ export function GameModeSection() { }} > Date: Mon, 26 Aug 2024 10:49:10 -0500 Subject: [PATCH 114/120] feat: incoporate meta section in hero --- .../[id]/components/Model/HeroSection.tsx | 71 ++---- .../Model/MetaSection/components/Listing.tsx | 2 +- .../components/Model/MetaSection/index.tsx | 235 +++++++++--------- 3 files changed, 139 insertions(+), 169 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx index b48e2a5e1..24bdec2b8 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/HeroSection.tsx @@ -1,17 +1,16 @@ import { ChevronLeftIcon, MixIcon } from '@radix-ui/react-icons'; -import { Box, Button, Flex, Heading, Text } from '@radix-ui/themes'; +import { Box, Button, Flex, Heading } from '@radix-ui/themes'; import Link from 'next/link'; import { Suspense, use, useEffect, useMemo, useRef, useState } from 'react'; import { classIcons } from '../../../../../../components/ClassIcon'; -import { ScienceIcon } from '../../../../../../components/ScienceIcon'; import { ThicknessRange } from '../../../../../../components/StaticArmor'; import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration'; import { tankDefinitions } from '../../../../../../core/blitzkit/tankDefinitions'; -import { TIER_ROMAN_NUMERALS } from '../../../../../../core/blitzkit/tankDefinitions/constants'; import { useFullScreen } from '../../../../../../hooks/useFullScreen'; -import strings from '../../../../../../lang/en-US.json'; +import * as App from '../../../../../../stores/app'; import * as Duel from '../../../../../../stores/duel'; import { Options } from './components/Options'; +import { MetaSection } from './MetaSection'; import { TankSandbox } from './TankSandbox'; import { TankSandboxLoader } from './TankSandboxLoader'; @@ -20,6 +19,7 @@ interface HeroSectionProps { } export function HeroSection({ id }: HeroSectionProps) { + const developerMode = App.useDeferred(false, (state) => state.developerMode); const canvas = useRef(null); const protagonist = Duel.use((state) => state.protagonist.tank); const antagonist = Duel.use((state) => state.antagonist.tank); @@ -38,6 +38,7 @@ export function HeroSection({ id }: HeroSectionProps) { : undefined; const awaitedTankDefinitions = use(tankDefinitions); const tank = awaitedTankDefinitions[id]; + const ClassIcon = classIcons[tank.class]; const thicknessRange = useMemo(() => { const entries = Object.values(awaitedTankDefinitions); const filtered = entries.filter((thisTank) => thisTank.tier === tank.tier); @@ -66,12 +67,13 @@ export function HeroSection({ id }: HeroSectionProps) { pt={{ initial: '6', md: '0' }} style={{ background: 'var(--color-surface)', position: 'relative' }} height={{ initial: 'calc(75vh - 4rem)', md: undefined }} - minHeight="30rem" + minHeight={{ initial: '30rem' }} gap="4" > - - {' '} - - - {protagonist.name} - - - - - {tank.testing && ( - - - Tank in testing - - - - )} - - - Tier {TIER_ROMAN_NUMERALS[protagonist.tier]}{' '} - { - (strings.common.nations_adjectives as Record)[ - protagonist.nation - ] - }{' '} - {strings.common.tank_class_short[protagonist.class]} - - - - + + + + {' '} + + + + {protagonist.name} + + + + diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx index 688dc1cd4..bab7f34c8 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/components/Listing.tsx @@ -6,7 +6,7 @@ type ListingProps = TextProps & { export function Listing({ label, ...props }: ListingProps) { return ( - + {label} diff --git a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx index 8b6083599..793b0212b 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/MetaSection/index.tsx @@ -1,138 +1,127 @@ -import { Code, Flex, Heading } from '@radix-ui/themes'; +import { Code, Flex } from '@radix-ui/themes'; import { classIcons } from '../../../../../../../components/ClassIcon'; import { asset } from '../../../../../../../core/blitzkit/asset'; -import { tankIcon } from '../../../../../../../core/blitzkit/tankIcon'; import strings from '../../../../../../../lang/en-US.json'; import * as App from '../../../../../../../stores/app'; import * as Duel from '../../../../../../../stores/duel'; import { Listing } from './components/Listing'; -export function MetaSection() { +interface MetaSectionProps { + naked?: boolean; +} + +export function MetaSection({ naked }: MetaSectionProps) { const developerMode = App.useDeferred(false, (state) => state.developerMode); const tank = Duel.use((state) => state.protagonist.tank); const ClassIcon = classIcons[tank.class]; + const content = ( + + {tank.nameFull && {tank.nameFull}} + + + {tank.nation} + { + strings.common.nations[ + tank.nation as keyof typeof strings.common.nations + ] + } + + + {tank.tier} + + + + {strings.common.tank_class_short[tank.class]} + + + + {strings.common.tree_type[tank.treeType]} + + {developerMode && ( + + {tank.id} + + )} + {tank.treeType === 'premium' && ( + + + {tank.price.value / 400} + gold + + + )} + + + {tank.price.value.toLocaleString()} + {tank.price.type} + + + + + {(tank.price.value / 2).toLocaleString()} + {tank.price.type} + + + {tank.xp && ( + + + {tank.xp.toLocaleString()} + xp + + + )} + + ); + + if (naked) return content; return ( - - - Economics - - - - - Overview - - - {tank.nameFull && ( - {tank.nameFull} - )} - - - {tank.nation} - { - strings.common.nations[ - tank.nation as keyof typeof strings.common.nations - ] - } - - - {tank.tier} - - - - {strings.common.tank_class_short[tank.class]} - - - - {strings.common.tree_type[tank.treeType]} - - {developerMode && ( - - {tank.id} - - )} - - - - - Economics - - - {tank.treeType === 'premium' && ( - - - {tank.price.value / 400} - gold - - - )} - - - {tank.price.value.toLocaleString()} - {tank.price.type} - - - - - {(tank.price.value / 2).toLocaleString()} - {tank.price.type} - - - {tank.xp && ( - - - {tank.xp.toLocaleString()} - xp - - - )} - - - + + {content} ); } From 51f28b5936682931cd28d44524d9b6e290578ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:18:07 -0500 Subject: [PATCH 115/120] feat: copy to clipbioard screenshot --- .../components/Model/components/Options.tsx | 63 +++++++++++++++---- src/app/tools/tankopedia/[id]/layout.tsx | 2 +- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx index 2f098a7bb..709e665f6 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/Options.tsx @@ -1,5 +1,7 @@ import { CameraIcon, + CopyIcon, + DownloadIcon, EnterFullScreenIcon, ExitFullScreenIcon, EyeOpenIcon, @@ -303,21 +305,56 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { )} - { - if (!canvas.current) return; + + + + + + - const anchor = document.createElement('a'); + + + + + + + + + + + )[tank.nation] } ${strings.common.tank_class_short[tank.class]}`; - const description = `Statistics, armor, and equipment for ${tank.name} in World of Tanks Blitz | WoTB`; + const description = `Statistics, armor, and equipment for ${tank.name} in World of Tanks Blitz (WoTB)`; return ( From 49b4810a7822f4edd95a1c93b38a06c292d3c9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:20:45 -0500 Subject: [PATCH 116/120] feat: better program --- .../tankopedia/[id]/components/VideoSection.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index 0ca769d25..bbf8750c7 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -1,4 +1,4 @@ -import { PlusIcon } from '@radix-ui/react-icons'; +import { ClipboardIcon } from '@radix-ui/react-icons'; import { Box, Flex, Heading, Text } from '@radix-ui/themes'; import { use } from 'react'; import { Link } from '../../../../../components/Link'; @@ -85,6 +85,7 @@ export function VideoSection() { href="https://discord.gg/nDt7AjGJQH" target="_blank" color="gray" + highContrast > - - Apply to feature your video + + + Apply to BlitzKit YouTuber program + From 579f604b9f6744a6b6e2530fbc393aa88e34930b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:25:20 -0500 Subject: [PATCH 117/120] feat: new blitzkit logos --- public/favicon.ico | Bin 4286 -> 0 bytes public/favicon.png | Bin 0 -> 692 bytes src/app/layout.tsx | 2 +- .../tools/compare/components/CompareTable.tsx | 4 +- src/icons/Blitzkit.tsx | 180 ------------------ src/icons/BlitzkitButtonGray.tsx | 40 ++++ src/icons/BlitzkitButtonWatermark.tsx | 44 ----- src/icons/BlitzkitWide.tsx | 19 -- 8 files changed, 43 insertions(+), 246 deletions(-) delete mode 100644 public/favicon.ico create mode 100644 public/favicon.png delete mode 100644 src/icons/Blitzkit.tsx create mode 100644 src/icons/BlitzkitButtonGray.tsx delete mode 100644 src/icons/BlitzkitButtonWatermark.tsx delete mode 100644 src/icons/BlitzkitWide.tsx diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index 18906c604c9f24d8c9c3a370d178c50315a4a301..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmeHLZBUfg6~4sG*ckS`FQPFS`Hmfk2<*Zx%Pz2hbtcv*h~fuSKtvJbD~dotNI`^2 zTATWj)JTPnu_FyJ8KpKKljvwlZLB61V`gll6-lb8fnu~qP~_=zU(k|Fn2eqHqcge8 zv-jQm-h0k-o^$Tm8H8}-pP!#lpW?T=5Dy6K)fZ_+2P`8^huwg~dnzp2b^c5FaVOk-ic$zOUnnARV)a zA576<_85D87IKL3?Ew8C~U5`p6KBi+{u#UM?btLgQiSrKw zbwvB?;9jV`>df$25kdX#W>|ftu=?s_IM1YwW6Gx8Phuv0q)gMXfSCK3MDjFG%nO}> z*@4pFFo#^GQwyb!;;PPCedJ7PqilU61)HBPxR=m9IoI$^4}mzwtl~`#)v+i<`PPsf z>yI}#X5$af=Ob@MAf5=+3@wxa4P%Y!Ty?ZL6Qh*Yb$;lfv$=3C=e1f1P^= zqWmTEE0GqaBi*cHafmeHuS;{_?4D}i{q4YsMqGHU9vib0kQ6+gxuGuPs&b^XP`W8w zwEMcU?eNpx?2L2di1OD3F^=oG+<%_?5I03)0sSov*O6&q?9)uha(bin={#ILz66JXJMNGgD4`rLkjq=mSMKNAA909s;`0G>X ze<#t$??%j-7Ks%RI3U*mK+Qo z--aVE6kti@BbZMO6ja`n775gXen3t8lrQDe5#S-50eT9bJJh>)?pYKnvC<}yYol)q zV~%_XO||*x?mP+f{|kdxy3l{I13Rj+u#mN|FxVZ*LE}&|YbvfDeinnrwqbKl0_Fyp zj5;xRuwGS8RQ<+0I>dufWN=GC~~z6CqiCK~rOC7AU@{|YK6N(&dY zSYeeYaZ0QqRy)XnC?4jqKE;fqdmC}{>IIy6?*QtTJ&p|4Vp@nhnriZZFaC+{v&Yf4 zxfCxq?w_w zSWA4BM^U5+C9X+$sbLj*KR$(jUpkBSz0EkhrxBlDI1Svqj8pII!&2KslqTEo?kmsX zCTsK7>3taN*oD8n{1iUeRf?{CwYbPT+FF%@Ec+uy4>4*dMDO`=j7%km4+(rNk0=dA zb`3wvh{3V89k_b&GzPDIivHd%{PoE1@bkPmXs*q}XXiRF@cDWC`IW8s)8vPlhF2D1#WzN6b=`D!^h`0Xbah~TTC{P8vyDEYW2r^|guSeYz0^I!tc#@l^bien$fj`B2A%nl|W#Yx`c-F|ynxbDa_ z>uy<=FZbWuBr08+Smz=Smz-GXk`3h1OCIBz}hTLcoJH!TA9+?2 z@{B$rdvmO^fgC3Ct_k+k+wMl4tH^=4pF9$Y6Xb#0Jj$Xq)Fn?vQ%Mr`*Db=csbNFC z!=c~lA0v32pdN|2R(XG(?VEppM-r-zr516z;t@bJlgD+%qdeLjzb=`J15NAE-c*U7 zE(peph4Cnhn}9XU$#4(3&b%~{M?kSd3g%^`>AQNailY{B@_}lXTuvV6$OF~WCt!1? z9WCp#(Yj$dTFPc)ty3e69&(Nxma~^Wz#6$LU!!fVCWqQMO>hn;_E)*Ifyx*YHZBUm zo(t4^P!EQe9kK#dz9 u1O|kN>l4EFvJhhr2{EQd{X1clq23+ho=)ynXVh6`!?2}nD%;A(i18mC$xS~1 diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7b326ae1e07a383eb837d1e3cc2679136727cc25 GIT binary patch literal 692 zcmV;l0!#ggP);)pcsy?smV^H|xR3qCa%tz&YPJzweyiIS2ShasDdE!xwZ# z>rk@BjQK|&@bDmaYi*YySe%jQQ>qWLY;taTvs|_bSSPaM5JD$m!vTWy0TKoyYB%Sv z8yoW-8y#QU#Xhq03D^ali2@iE0Fg)0-rroSk!`)r_zhE-ncD{><6L#YC(huZ%^U zz7#`c`8EWDd$4ow0n9#rhV*9(5ANK?qx<(zuyT@`%^|EV#_KzXcs&?%p|Z?_;h_Pz zy<0Idp1@FS6ub2xI**^k)q%5enDlk-B!EIjY8p<(r#@wwr4T{z)tn1scW05K5~xkB zDDimFdbk6lH?LtOot9O_H}DF`GEFALiS;#dEu_gv6poTEl-5WS*cS?+wxJP|!*N)a zC2MV^wH%$HTkS_bl~CL=`5 literal 0 HcmV?d00001 diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 3dc18c167..1a4fb8388 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -45,7 +45,7 @@ export default function RootLayout({ children }: RootLayoutProps) { )} - + diff --git a/src/app/tools/compare/components/CompareTable.tsx b/src/app/tools/compare/components/CompareTable.tsx index b481f0fee..155f76003 100644 --- a/src/app/tools/compare/components/CompareTable.tsx +++ b/src/app/tools/compare/components/CompareTable.tsx @@ -17,7 +17,7 @@ import { equipmentDefinitions } from '../../../../core/blitzkit/equipmentDefinit import { provisionDefinitions } from '../../../../core/blitzkit/provisionDefinitions'; import { skillDefinitions } from '../../../../core/blitzkit/skillDefinitions'; import { TankCharacteristics } from '../../../../core/blitzkit/tankCharacteristics'; -import { BlitzkitButtonWatermark } from '../../../../icons/BlitzkitButtonWatermark'; +import { BlitzkitButtonGray } from '../../../../icons/BlitzkitButtonGray'; import { theme } from '../../../../stitches.config'; import * as CompareEphemeral from '../../../../stores/compareEphemeral'; import { EquipmentMatrix } from '../../../../stores/duel'; @@ -56,7 +56,7 @@ export function CompareTable({ stats }: CompareTableProps) { align="center" justify="center" > - + diff --git a/src/icons/Blitzkit.tsx b/src/icons/Blitzkit.tsx deleted file mode 100644 index afc98baa4..000000000 --- a/src/icons/Blitzkit.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { ComponentProps } from 'react'; - -export function Blitzkit(props: ComponentProps<'svg'>) { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/src/icons/BlitzkitButtonGray.tsx b/src/icons/BlitzkitButtonGray.tsx new file mode 100644 index 000000000..2a6e5aa09 --- /dev/null +++ b/src/icons/BlitzkitButtonGray.tsx @@ -0,0 +1,40 @@ +import { ComponentProps } from 'react'; + +export function BlitzkitButtonGray(props: ComponentProps<'svg'>) { + return ( + + + + + + + + + + + + + + ); +} diff --git a/src/icons/BlitzkitButtonWatermark.tsx b/src/icons/BlitzkitButtonWatermark.tsx deleted file mode 100644 index 5a9e7d4b5..000000000 --- a/src/icons/BlitzkitButtonWatermark.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { ComponentProps } from 'react'; - -export function BlitzkitButtonWatermark(props: ComponentProps<'svg'>) { - return ( - - - - - - - - - - - - - - - ); -} diff --git a/src/icons/BlitzkitWide.tsx b/src/icons/BlitzkitWide.tsx deleted file mode 100644 index da286875b..000000000 --- a/src/icons/BlitzkitWide.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { ComponentProps } from 'react'; - -export function BlitzkitWide(props: ComponentProps<'svg'>) { - return ( - - - - ); -} From f58b6dcd17093ea916e9091db28160612665b867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:34:57 -0500 Subject: [PATCH 118/120] feat: ah --- src/app/tools/tankopedia/[id]/components/VideoSection.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx index bbf8750c7..ab161213a 100644 --- a/src/app/tools/tankopedia/[id]/components/VideoSection.tsx +++ b/src/app/tools/tankopedia/[id]/components/VideoSection.tsx @@ -1,4 +1,3 @@ -import { ClipboardIcon } from '@radix-ui/react-icons'; import { Box, Flex, Heading, Text } from '@radix-ui/themes'; import { use } from 'react'; import { Link } from '../../../../../components/Link'; @@ -99,7 +98,7 @@ export function VideoSection() { borderRadius: Var('radius-3'), }} > - + Date: Mon, 26 Aug 2024 21:47:14 -0500 Subject: [PATCH 119/120] feat: never render off screen --- .../[id]/components/Model/TankSandbox.tsx | 6 ++++- src/hooks/useOnScreen.ts | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/hooks/useOnScreen.ts diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx index 0760202a2..99eccfa2c 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx @@ -17,6 +17,7 @@ import { applyPitchYawLimits } from '../../../../../../core/blitz/applyPitchYawL import { modelTransformEvent } from '../../../../../../core/blitzkit/modelTransform'; import { Pose, poseEvent } from '../../../../../../core/blitzkit/pose'; import { useEquipment } from '../../../../../../hooks/useEquipment'; +import useOnScreen from '../../../../../../hooks/useOnScreen'; import { useTankModelDefinition } from '../../../../../../hooks/useTankModelDefinition'; import * as Duel from '../../../../../../stores/duel'; import * as TankopediaEphemeral from '../../../../../../stores/tankopediaEphemeral'; @@ -45,6 +46,9 @@ export const TankSandbox = forwardRef( tankModelDefinition.turrets[protagonist.turret.id]; const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; const display = TankopediaPersistent.use((state) => state.display); + const onScreen = useOnScreen(canvas); + + console.log(onScreen); useImperativeHandle(ref, () => canvas.current!, []); @@ -155,7 +159,7 @@ export const TankSandbox = forwardRef( return ( ) { + const [isIntersecting, setIntersecting] = useState(false); + const observer = useRef(); + + useEffect(() => { + observer.current = new IntersectionObserver(([entry]) => + setIntersecting(entry.isIntersecting), + ); + }, [ref]); + + useEffect(() => { + if (!ref.current) return; + + observer.current?.observe(ref.current); + return () => observer.current?.disconnect(); + }, [ref]); + + return isIntersecting; +} From f2d40d40fd8018e2397e94bdf1922ac74a27756a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 26 Aug 2024 21:52:34 -0500 Subject: [PATCH 120/120] feat: logs --- docs/changelogs/1.22.3.md | 16 ++++++++++++++++ package.json | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 docs/changelogs/1.22.3.md diff --git a/docs/changelogs/1.22.3.md b/docs/changelogs/1.22.3.md new file mode 100644 index 000000000..db55ffae8 --- /dev/null +++ b/docs/changelogs/1.22.3.md @@ -0,0 +1,16 @@ +# BlitzKit 1.22.3 + +This should've been in the last update lol. + +## Features + +- The "meta information" section has been moved to the hero section on larger screens +- Added an option to take a screenshot directly to the clipboard +- Removed the number from the BlitzKit logo +- The tank playground now stops rendering when it is offscreen, hence fixing a lot of crashes + +## Fixes + +- The hero section of the Tankopedia is now better sized on smaller screens +- The shell penetration over distance slider now instantly updates the corresponding input instead after a delay +- The game mode banner info is now visible on Apple devices diff --git a/package.json b/package.json index 3b75026a6..26ab77bbf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkit", - "version": "1.22.2", + "version": "1.22.3", "description": "🎉 Tools for everything World of Tanks Blitz", "main": "src/server.ts", "type": "module",