diff --git a/.github/workflows/website.yaml b/.github/workflows/website.yaml index cbd3bf04c..dba93a9d8 100644 --- a/.github/workflows/website.yaml +++ b/.github/workflows/website.yaml @@ -2,6 +2,9 @@ name: Website on: push: + branches: + - main + - production pull_request: @@ -125,9 +128,14 @@ jobs: - name: Install dependencies run: bun install - - name: Download Client + - name: Download client run: bun run download-client + - name: Download SmartDLC + if: ${{ env.CLIENT_PROVIDER == 'steam' }} + + run: bun run download-smart-dlc + - name: Build run: bun run --bun build env: diff --git a/docs/about/credits.md b/docs/about/credits.md deleted file mode 100644 index ae2ac076a..000000000 --- a/docs/about/credits.md +++ /dev/null @@ -1,47 +0,0 @@ -# BlitzKit Credits - -BlitzKit is a one man band **TrèsAbhi** but I am far from solo. Helpers, in the order of contribution over time: - -### S0AP - -BlitzKit Discord bot verification, testing, advertisement, and the initial encouragement to create BlitzKit. - -### Prince_NA - -BlitzKit Discord bot and website testing and general advise. - -### Vovko - -BlitzKit Discord bot and website rendering pipeline. - -### Maddox - -Game file decompression. - -### Pyogenics - -Game 3D model parsing. - -### Aeson - -Game file layout, general advise, advertisement, and Tankopedia pre-release testing. - -### Minitelrose, ChickenMan7777 - -3-caliber rule edge cases. - -### HisRoyalFatness, Synx - -Embed UX. - -### [OPTML] clan, \_34, xkdkw, Droodles Blitz - -Tankopedia pre-release testing. - -### GonnaHetzMe - -Redacted by request. - -### Mark Greene - -GitHub contributor on bug fixes and feature additions. diff --git a/docs/changelogs/1.29.10.md b/docs/changelogs/1.29.10.md index d96d78fd8..8ba65ad99 100644 --- a/docs/changelogs/1.29.10.md +++ b/docs/changelogs/1.29.10.md @@ -1,14 +1,14 @@ # BlitzKit 1.29.10 -Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions this update. +Thank you to [HitJack](https://github.com/Hitjack007) for your contributions this update. ## Features - Combined game mode passive and active abilities into a single dropdown -- Added tier filters to the Guess game [Mark Greene] +- Added tier filters to the Guess game [HitJack] - Changing tiers will break your streak ## Fixes -- module damage is now properly shown when sorting with it in the tank search [Mark Greene] +- module damage is now properly shown when sorting with it in the tank search [HitJack] - Duplicate abilities in the tank filters are now removed diff --git a/docs/changelogs/1.29.8.md b/docs/changelogs/1.29.8.md index a32e7d558..8f18b3474 100644 --- a/docs/changelogs/1.29.8.md +++ b/docs/changelogs/1.29.8.md @@ -1,6 +1,6 @@ # BlitzKit 1.29.8 -Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions this update. +Thank you to [HitJack](https://github.com/Hitjack007) for your contributions this update. ## Features @@ -15,5 +15,5 @@ Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions ## Fixes - The Tankopedia now smoothly resizes when enlarging on interaction -- Stock turrets now correctly mount the corresponding stock gun [Mark Greene] +- Stock turrets now correctly mount the corresponding stock gun [HitJack] - The consumable and provision buttons in Compare are no longer tiny diff --git a/docs/changelogs/1.29.9.md b/docs/changelogs/1.29.9.md index c426194e1..3ec9b1333 100644 --- a/docs/changelogs/1.29.9.md +++ b/docs/changelogs/1.29.9.md @@ -1,14 +1,14 @@ # BlitzKit 1.29.9 -Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions this update. +Thank you to [HitJack](https://github.com/Hitjack007) for your contributions this update. ## Features - Reworked tank search filters to be far more compact to make way for new filters -- Added the ability to filter tanks by consumables [Mark Greene] +- Added the ability to filter tanks by consumables [HitJack] - Added the ability to filter tanks by provisions and game-mode abilities and powers ## Fixes - Consumable and provision icons in Compare are now properly sized -- Provisions now properly affect terrain resistances [Mark Greene] +- Provisions now properly affect terrain resistances [HitJack] diff --git a/docs/changelogs/1.30.7.md b/docs/changelogs/1.30.7.md index c42589bff..c045cf5a5 100644 --- a/docs/changelogs/1.30.7.md +++ b/docs/changelogs/1.30.7.md @@ -1,6 +1,6 @@ # BlitzKit 1.30.7 -Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions this update. +Thank you to [HitJack](https://github.com/Hitjack007) for your contributions this update. ## Features @@ -8,13 +8,13 @@ Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions ## Fixes -- Clicking on the armor multiple times with HE no longer crashes BlitzKit [Mark Greene] -- Ricochets that later intersect with external modules no longer falsely claim a successful damaging penetration [Mark Greene] +- Clicking on the armor multiple times with HE no longer crashes BlitzKit [HitJack] +- Ricochets that later intersect with external modules no longer falsely claim a successful damaging penetration [HitJack] - The lighting animation no longer stops prematurely when BlitzKit is unfocused - The spot light angle has been increased to more evenly light up larger tanks - BlitzKit once again uses soft shadows, reducing the pixelated shadows - Fixed the weird patterns that formed on the tracks of tanks under self-shadows - Increased the floor size and light decay to create the illusion that the floor is infinite -- Safari no longer crashes when unloading textures for unloaded tanks [Mark Greene] +- Safari no longer crashes when unloading textures for unloaded tanks [HitJack] - The gun depression transition between two constraints (like often behind tanks) now uses a gentler zoned and can never be 0 -- Armor plate names in Static Armor are now properly capitalized in English and translated to other languages [Mark Greene] +- Armor plate names in Static Armor are now properly capitalized in English and translated to other languages [HitJack] diff --git a/docs/changelogs/1.32.0.md b/docs/changelogs/1.32.0.md index ce86475ee..9ffbce4ef 100644 --- a/docs/changelogs/1.32.0.md +++ b/docs/changelogs/1.32.0.md @@ -1,75 +1,75 @@ # BlitzKit 1.32.0 -Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions this update. +Thank you to [HitJack](https://github.com/Hitjack007) for your contributions this update. ## Features ### Tankopedia & Armor -- Added a spall liner button to the Tankopedia beside the other equipment [Mark Greene] -- Listed track repair times in the Tankopedia [Mark Greene] -- The penetration chance is now displayed when penetration testing armor [Mark Greene] -- Added a new setting to disable automatically loading tanks in Tankopedia [Mark Greene] +- Added a spall liner button to the Tankopedia beside the other equipment [HitJack] +- Listed track repair times in the Tankopedia [HitJack] +- The penetration chance is now displayed when penetration testing armor [HitJack] +- Added a new setting to disable automatically loading tanks in Tankopedia [HitJack] ### Tank Performance & Mechanics -- Added Peekaboo DPM [Mark Greene] +- Added Peekaboo DPM [HitJack] - Your Peekaboo DPM is lower than your normal DPM if your reload is faster than 10s as you'll have to wait for the remaining 10s for you to get unspotted before you can poke and shoot ### Tank Filters -- The test and owned tank filters are now more intuitive as clicking on them now turns the clicked option on instead of off [Mark Greene] +- The test and owned tank filters are now more intuitive as clicking on them now turns the clicked option on instead of off [HitJack] ### Game Compatibility -- Added compatibility for tier XI tanks [Mark Greene] +- Added compatibility for tier XI tanks [HitJack] ## Fixes ### Tankopedia & Armor -- The armor no longer disappears when you turn on Dynamic Armor System [Mark Greene] -- Camouflage values in Tankopedia are now more descriptive when shooting [Mark Greene] -- The penetration chance is now displayed when penetration testing armor [Mark Greene] -- Listed track repair times in the Tankopedia [Mark Greene] -- Added a spall liner button to the Tankopedia beside the other equipment [Mark Greene] -- The flags in the Tankopedia tech tree are no longer offset to the top left [Mark Greene] -- The loading bar below the name of the tanks in Tankopedia is now sufficiently spaced below [Mark Greene] +- The armor no longer disappears when you turn on Dynamic Armor System [HitJack] +- Camouflage values in Tankopedia are now more descriptive when shooting [HitJack] +- The penetration chance is now displayed when penetration testing armor [HitJack] +- Listed track repair times in the Tankopedia [HitJack] +- Added a spall liner button to the Tankopedia beside the other equipment [HitJack] +- The flags in the Tankopedia tech tree are no longer offset to the top left [HitJack] +- The loading bar below the name of the tanks in Tankopedia is now sufficiently spaced below [HitJack] - Removed the vertical sliver of pixels found to the right of the Equalizer toggle in Tankopedia ### Tank Search & Filters -- The search bar no longer redirects to a seemingly random tank when clicking enter when searching [Mark Greene] -- Tank search now properly handles the full names of tanks like the Super Pershing [Mark Greene] -- The tank search now remains consistent in order even when an added filter does not add/remove tanks from the list [Mark Greene] -- The test and owned tank filters are now more intuitive as clicking on them now turns the clicked option on instead of off [Mark Greene] +- The search bar no longer redirects to a seemingly random tank when clicking enter when searching [HitJack] +- Tank search now properly handles the full names of tanks like the Super Pershing [HitJack] +- The tank search now remains consistent in order even when an added filter does not add/remove tanks from the list [HitJack] +- The test and owned tank filters are now more intuitive as clicking on them now turns the clicked option on instead of off [HitJack] ### Visuals & UI -- Removed the Beta badge from the Equalizer button [Mark Greene] +- Removed the Beta badge from the Equalizer button [HitJack] - Updated the background image for the Equalizer button to the actual banner of the new game mode -- The contact shadows on the ground no longer grow & darken when switching between tabs [Mark Greene] -- Additionally, the contact shadows stays visible at low angles [Mark Greene] +- The contact shadows on the ground no longer grow & darken when switching between tabs [HitJack] +- Additionally, the contact shadows stays visible at low angles [HitJack] - The "Help Translate BlitzKit" text on the home page is now properly centered vertically -- The footer now says "Branch" instead of "CDN" [Mark Greene] -- The game version in the footer now displays a shorthand version instead of the entire version number [Mark Greene] -- The reload visualizer now displays just 1 decimal place [Mark Greene] -- Plot controls for the Static armor tab no longer pokes in from the right on non-Static armor tabs in some languages [Mark Greene] -- Mixer's controllers now scale better on smaller screens [Mark Greene] -- The list of available tanks in the Playlist is no longer excessively wide [Mark Greene] +- The footer now says "Branch" instead of "CDN" [HitJack] +- The game version in the footer now displays a shorthand version instead of the entire version number [HitJack] +- The reload visualizer now displays just 1 decimal place [HitJack] +- Plot controls for the Static armor tab no longer pokes in from the right on non-Static armor tabs in some languages [HitJack] +- Mixer's controllers now scale better on smaller screens [HitJack] +- The list of available tanks in the Playlist is no longer excessively wide [HitJack] ### Tank Mechanics & Models -- The gun depression visualizer now properly handles the inherent tilt of tanks like the Minotauro [Mark Greene] -- When moving the tracks of tanks, the textures no longer move at different rates [Mark Greene] +- The gun depression visualizer now properly handles the inherent tilt of tanks like the Minotauro [HitJack] +- When moving the tracks of tanks, the textures no longer move at different rates [HitJack] ### Localization -- Users with a preference on a language are once again redirected to the correct localized pages [Mark Greene] +- Users with a preference on a language are once again redirected to the correct localized pages [HitJack] ### Session & Game Compatibility -- BlitzKit Session now properly handles tanks removed from the game [Mark Greene] +- BlitzKit Session now properly handles tanks removed from the game [HitJack] ## Technical Fixes @@ -78,7 +78,7 @@ Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions - This was the last bug standing in the way of BlitzKit Previews - Welcome back, BlitzKit Previews! - Removed some dead code from the BlitzKit model mangler -- The player discovery loop now persists for longer than 1 iteration [Mark Greene] +- The player discovery loop now persists for longer than 1 iteration [HitJack] - Bun is now forced to run scripts with the `--bun` flag ## Technical Features @@ -94,5 +94,5 @@ Thank you to [Mark Greene](https://github.com/Hitjack007) for your contributions - This was the last bug standing in the way of BlitzKit Previews - Welcome back, BlitzKit Previews! - Removed some dead code from the BlitzKit model mangler -- The player discovery loop now persists for longer than 1 iteration [Mark Greene] +- The player discovery loop now persists for longer than 1 iteration [HitJack] - Bun is now forced to run scripts with the `--bun` flag diff --git a/package.json b/package.json index 59e8eaf3d..399d17fd9 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,12 @@ "private": true, "scripts": { "dev": "cd packages/website && bun --bun run dev", - "build": "cd packages/website && bun run build", + "build": "cd packages/website && bun --bun run build", "discover-ids": "cd packages/scripts && bun run discover-ids", "build-protos": "cd packages/scripts && bun run build-protos", "record-performance": "cd packages/scripts && bun run record-performance", "download-client": "cd packages/scripts && bun run download-client", + "download-smart-dlc": "cd packages/scripts && bun run download-smart-dlc", "clean-astro": "rm -rf packages/website/.astro packages/website/node_modules/.astro packages/website/node_modules/.vite", "vfs": "cd packages/scripts && bun run vfs" }, diff --git a/packages/core/src/blitzkit/api/server/0_base.ts b/packages/core/src/blitzkit/api/server/0_base.ts index fd522a898..034122e00 100644 --- a/packages/core/src/blitzkit/api/server/0_base.ts +++ b/packages/core/src/blitzkit/api/server/0_base.ts @@ -285,6 +285,8 @@ export abstract class ServerBlitzKitAPI0 extends BlitzKitAPI { collection[locale] = localizedString; } + collection[locales.default] = collection[locales.default] ?? name; + return { locales: collection } satisfies I18nString; } } diff --git a/packages/core/src/blitzkit/api/server/2_camouflageDefinitions.ts b/packages/core/src/blitzkit/api/server/2_camouflageDefinitions.ts index c5a63405c..e2b81e3f9 100644 --- a/packages/core/src/blitzkit/api/server/2_camouflageDefinitions.ts +++ b/packages/core/src/blitzkit/api/server/2_camouflageDefinitions.ts @@ -15,7 +15,9 @@ export abstract class ServerBlitzKitAPI2 extends ServerBlitzKitAPI1 { ); const sc2 = new Sc2ReadStream( ( - await this.vfs.file(`Data/3d/${parameters.resourcesPath.blitzModelPath}`) + await this.vfs.file( + `Data/3d/${parameters.resourcesPath.blitzModelPath}`, + ) ).buffer as ArrayBuffer, ).sc2(); const presets = new Set(); @@ -100,9 +102,11 @@ export abstract class ServerBlitzKitAPI2 extends ServerBlitzKitAPI1 { } } + const name = this.getString(camo.userString); + camouflageDefinitions.camouflages[camo.id] = { id: camo.id, - name: this.getString(camo.userString), + name, tank_name: resolvedTankName, tank_name_full: resolvedTankNameFull, tank_id: tankId, diff --git a/packages/core/src/streams/pvr.ts b/packages/core/src/streams/pvr.ts index 8703f5cd7..d55e8aaad 100644 --- a/packages/core/src/streams/pvr.ts +++ b/packages/core/src/streams/pvr.ts @@ -88,6 +88,7 @@ enum PvrChannelType { enum ResolvedBitRatePixelFormat { R4G4B4A4, + R8G8B8A8, R5G6B5A0, } @@ -137,6 +138,27 @@ export class PvrReadStream extends ReadStream { }; } + case ResolvedBitRatePixelFormat.R8G8B8A8: { + const data = Buffer.alloc(pixelCount * 4); + + times(pixelCount, (index) => { + const buffer = this.consumeUint8Array(4); + const bufferIndex = index * 4; + + data[bufferIndex] = buffer[0]; // R + data[bufferIndex + 1] = buffer[1]; // G + data[bufferIndex + 2] = buffer[2]; // B + data[bufferIndex + 3] = buffer[3]; // A + }); + + return { + data, + width: header.width, + height: header.height, + channels: 4 as const, + }; + } + case ResolvedBitRatePixelFormat.R5G6B5A0: { const data = Buffer.alloc(pixelCount * 3); @@ -208,10 +230,13 @@ export class PvrReadStream extends ReadStream { if (pixelFormat.order === "rgba") { if (isEqual(pixelFormat.bitRates, [4, 4, 4, 4])) { return ResolvedBitRatePixelFormat.R4G4B4A4; - } else + } else if (isEqual(pixelFormat.bitRates, [8, 8, 8, 8])) { + return ResolvedBitRatePixelFormat.R8G8B8A8; + } else { throw new TypeError( `Unhandled rgba bit rate ${pixelFormat.bitRates.join(", ")}`, ); + } } else if (pixelFormat.order === "rgb\0") { if (isEqual(pixelFormat.bitRates, [5, 6, 5, 0])) { return ResolvedBitRatePixelFormat.R5G6B5A0; diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index c708e45c5..5bed66678 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -1,10 +1,4 @@ { - "test": { - "default": "test", - "long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is {fruit} because it has the color of {color}. I like it so much that I will say its name 3 times! {fruit}! {fruit}! {fruit}! Once again, it's {color}, not {not_color}.", - "fox": "The quick brown fox jumps over the lazy dog." - }, - "common": { "name": "BlitzKit", @@ -338,6 +332,13 @@ }, "tools": { + "credits": { + "name": "Credits", + "button": "View people", + "description": "Contributors of BlitzKit", + "seo_description": "BlitzKit is the work of many" + }, + "playlist": { "reset": "Reset", "shuffle": "Shuffle", @@ -996,7 +997,6 @@ "about": { "title": "About", - "credits": "Credits", "discord": "Discord", "github": "GitHub", "patches": "Patches" diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 55077bcb2..4afa98947 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -6,6 +6,7 @@ "build-protos": "bun src/protos.ts", "record-performance": "bun src/recordPerformance/index.ts", "download-client": "bun src/downloadClient/index.ts", + "download-smart-dlc": "bun src/downloadSmartDLC/index.ts", "vfs": "bun src/vfs/index.ts" }, "dependencies": { diff --git a/packages/scripts/src/downloadClient/index.ts b/packages/scripts/src/downloadClient/index.ts index e3412bffe..c9eb68b61 100644 --- a/packages/scripts/src/downloadClient/index.ts +++ b/packages/scripts/src/downloadClient/index.ts @@ -9,6 +9,8 @@ import { } from "./constants"; import { QuickGitHubRelease } from "./types"; +const DEPOT_DOWNLOADER_RETRY_TIME = 30_000; + const provider = assertSecret(import.meta.env.CLIENT_PROVIDER); const source = assertSecret(import.meta.env.CLIENT_SOURCE); const dir = assertSecret(import.meta.env.CLIENT_DIR); @@ -43,11 +45,27 @@ if (provider === "steam") { const username = assertSecret(import.meta.env.STEAM_USERNAME); const password = assertSecret(import.meta.env.STEAM_PASSWORD); - await $`${DEPOT_DOWNLOADER_EXECUTABLE} -os ${ - platform - } -app ${id} -username ${username} -password ${ - password - } -dir ${dir} -max-downloads ${DEPOT_DOWNLOADER_MAX_DOWNLOADS}`; + while (true) { + const result = await $`${ + DEPOT_DOWNLOADER_EXECUTABLE + } -os ${platform} -app ${id} -username ${ + username + } -password ${password} -dir ${dir} -max-downloads ${ + DEPOT_DOWNLOADER_MAX_DOWNLOADS + }`.nothrow(); + + if (result.exitCode === 0) { + console.log("Client downloaded successfully!"); + break; + } + + console.error( + `DepotDownloader failed (exit ${result.exitCode}). Retrying in ${DEPOT_DOWNLOADER_RETRY_TIME / 1000} seconds...`, + ); + await new Promise((resolve) => + setTimeout(resolve, DEPOT_DOWNLOADER_RETRY_TIME), + ); + } } else if (provider === "zip") { const url = assertSecret(import.meta.env.CLIENT_SOURCE); diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/downloadSmartDLC/index.ts similarity index 60% rename from packages/scripts/src/applyPatches.ts rename to packages/scripts/src/downloadSmartDLC/index.ts index 18aaf6ba3..24b13f068 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/downloadSmartDLC/index.ts @@ -2,9 +2,16 @@ import { dvp } from "@blitzkit/closed"; import { assertSecret } from "@blitzkit/core"; import { mkdir, writeFile } from "fs/promises"; import { parse as parsePath } from "path"; -import ProgressBar from "progress"; import { parse as parseYaml, stringify as stringifyYaml } from "yaml"; -import { PATCHES_ROOT, vfs } from "./buildAssets/constants"; +import { RegionsPublish } from "../types/regionsPublish"; +import { vfs } from "../vfs/vfs"; + +const CLIENT_DIR = assertSecret(import.meta.env.CLIENT_DIR); + +const regionsPublish = await vfs.yaml( + "Data/regions_publish.yaml", +); +const [smartDlcUrl] = regionsPublish.Common.smartDlcUrls; const versionTextFile = await vfs.text(`Data/version.txt`); const currentVersion = versionTextFile @@ -18,9 +25,7 @@ console.log(`Installing patches for ${currentVersion}...`); let patchIndex = 1; while (true) { const response = await fetch( - `${assertSecret( - import.meta.env.WOTB_DLC_CDN, - )}/dlc/s${currentVersion}_${patchIndex}.yaml`, + `${smartDlcUrl}/s${currentVersion}_${patchIndex}.yaml`, ); console.log(patchIndex, response.status); @@ -30,51 +35,34 @@ while (true) { console.log(`Applying patch ${patchIndex}...`); const data = parseYaml(await response.text()); - const dvpm = await fetch( - `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11}`, - ).then((response) => response.arrayBuffer()); + const dvpm = await fetch(`${smartDlcUrl}/${data.dx11}`).then((response) => + response.arrayBuffer(), + ); const dvpd = await fetch( - `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11.replace( - ".dvpm", - ".dvpd", - )}`, + `${smartDlcUrl}/${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, - ); for (const { path, data } of files) { console.log(`Patching "${path}"...`); const { dir } = parsePath(path); - try { - await mkdir(`${PATCHES_ROOT}/Data/${dir}`, { recursive: true }); - } catch (error) { - console.warn(`Failed to make directory "${dir}"`); - } + await mkdir(`${CLIENT_DIR}/Data/${dir}`, { recursive: true }); const buffer = Buffer.from(data); - await writeFile(`${PATCHES_ROOT}/Data/${path}`, new Uint8Array(buffer)); - - bar.tick(); + await writeFile(`${CLIENT_DIR}/Data/${path}`, new Uint8Array(buffer)); } console.log("patches done for patch"); if ("dynamicContentLocalizationsDir" in data) { console.log( - `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${ - data.dynamicContentLocalizationsDir - }/en.yaml`, + `${smartDlcUrl}/${data.dynamicContentLocalizationsDir}/en.yaml`, ); const localizationsResponse = await fetch( - `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${ - data.dynamicContentLocalizationsDir - }/en.yaml`, + `${smartDlcUrl}/${data.dynamicContentLocalizationsDir}/en.yaml`, ); console.log("fetched"); const newStrings = parseYaml(await localizationsResponse.text()); @@ -86,10 +74,10 @@ while (true) { const patchedContent = stringifyYaml(patchedStrings); console.log("stringified"); - await mkdir(`${PATCHES_ROOT}/Data/Strings`, { recursive: true }); + await mkdir(`${CLIENT_DIR}/Data/Strings`, { recursive: true }); console.log("mkdir"); await writeFile( - `${PATCHES_ROOT}/Data/Strings/en.yaml`, + `${CLIENT_DIR}/Data/Strings/en.yaml`, new Uint8Array(Buffer.from(patchedContent)), ); console.log("file"); diff --git a/packages/scripts/src/types/regionsPublish.ts b/packages/scripts/src/types/regionsPublish.ts new file mode 100644 index 000000000..728de0f14 --- /dev/null +++ b/packages/scripts/src/types/regionsPublish.ts @@ -0,0 +1,7 @@ +export interface RegionsPublish { + Common: Common; +} + +interface Common { + smartDlcUrls: string[]; +} diff --git a/packages/scripts/src/vfs/index.ts b/packages/scripts/src/vfs/index.ts index dd0358c0d..cdf8b1fe8 100644 --- a/packages/scripts/src/vfs/index.ts +++ b/packages/scripts/src/vfs/index.ts @@ -1,7 +1,4 @@ -import { assertSecret } from "@blitzkit/core"; -import { LocalVFS } from "@blitzkit/core/src/blitzkit/vfs/local"; - -export const vfs = new LocalVFS(assertSecret(import.meta.env.CLIENT_DIR)); +import { vfs } from "./vfs"; const command = Bun.argv[2]; const path = Bun.argv[3]; @@ -20,4 +17,7 @@ if (command === "cat") { for (const file of files) { console.log(file); } +} else if (command === "yaml") { + const content = await vfs.yaml(path); + await Bun.write(Bun.stdout, JSON.stringify(content, null, 2)); } diff --git a/packages/scripts/src/vfs/vfs.ts b/packages/scripts/src/vfs/vfs.ts new file mode 100644 index 000000000..a94b39bae --- /dev/null +++ b/packages/scripts/src/vfs/vfs.ts @@ -0,0 +1,4 @@ +import { assertSecret } from "@blitzkit/core"; +import { LocalVFS } from "@blitzkit/core/src/blitzkit/vfs/local"; + +export const vfs = new LocalVFS(assertSecret(import.meta.env.CLIENT_DIR)); diff --git a/packages/website/public/assets/images/tools/credits.webp b/packages/website/public/assets/images/tools/credits.webp new file mode 100644 index 000000000..59a61c284 Binary files /dev/null and b/packages/website/public/assets/images/tools/credits.webp differ diff --git a/packages/website/public/media/users/34wotb.jpg b/packages/website/public/media/users/34wotb.jpg new file mode 100644 index 000000000..216cad339 Binary files /dev/null and b/packages/website/public/media/users/34wotb.jpg differ diff --git a/packages/website/public/media/users/aeson000.png b/packages/website/public/media/users/aeson000.png new file mode 100644 index 000000000..a003dc074 Binary files /dev/null and b/packages/website/public/media/users/aeson000.png differ diff --git a/packages/website/public/media/users/avenir.webp b/packages/website/public/media/users/avenir.webp new file mode 100644 index 000000000..146130324 Binary files /dev/null and b/packages/website/public/media/users/avenir.webp differ diff --git a/packages/website/public/media/users/chickenman7777.webp b/packages/website/public/media/users/chickenman7777.webp new file mode 100644 index 000000000..0cbf54d78 Binary files /dev/null and b/packages/website/public/media/users/chickenman7777.webp differ diff --git a/packages/website/public/media/users/droodles-blitz.jpg b/packages/website/public/media/users/droodles-blitz.jpg new file mode 100644 index 000000000..f5793cb80 Binary files /dev/null and b/packages/website/public/media/users/droodles-blitz.jpg differ diff --git a/packages/website/public/media/users/hisroyalfatness.jpg b/packages/website/public/media/users/hisroyalfatness.jpg new file mode 100644 index 000000000..411a5808c Binary files /dev/null and b/packages/website/public/media/users/hisroyalfatness.jpg differ diff --git a/packages/website/public/media/users/minitelrose.webp b/packages/website/public/media/users/minitelrose.webp new file mode 100644 index 000000000..208a82c15 Binary files /dev/null and b/packages/website/public/media/users/minitelrose.webp differ diff --git a/packages/website/public/media/users/prince-na.webp b/packages/website/public/media/users/prince-na.webp new file mode 100644 index 000000000..2f515e76f Binary files /dev/null and b/packages/website/public/media/users/prince-na.webp differ diff --git a/packages/website/public/media/users/s0ap.webp b/packages/website/public/media/users/s0ap.webp new file mode 100644 index 000000000..4717c29ef Binary files /dev/null and b/packages/website/public/media/users/s0ap.webp differ diff --git a/packages/website/public/media/users/synx.webp b/packages/website/public/media/users/synx.webp new file mode 100644 index 000000000..5b6a506df Binary files /dev/null and b/packages/website/public/media/users/synx.webp differ diff --git a/packages/website/public/media/users/tj-duff.jpg b/packages/website/public/media/users/tj-duff.jpg new file mode 100644 index 000000000..9dbf4fb5c Binary files /dev/null and b/packages/website/public/media/users/tj-duff.jpg differ diff --git a/packages/website/public/media/users/xkdkw.webp b/packages/website/public/media/users/xkdkw.webp new file mode 100644 index 000000000..7d7998c59 Binary files /dev/null and b/packages/website/public/media/users/xkdkw.webp differ diff --git a/packages/website/src/components/CreditsPromo.astro b/packages/website/src/components/CreditsPromo.astro new file mode 100644 index 000000000..65f2186d3 --- /dev/null +++ b/packages/website/src/components/CreditsPromo.astro @@ -0,0 +1,135 @@ +--- +import { Grid, Text } from "@radix-ui/themes"; +import { credits } from "../config/credits"; +import { getStrings } from "../core/i18n/getStrings"; + +interface Props { + locale: string; +} + +const { locale } = Astro.props; + +const strings = getStrings(locale); +--- + + + +
+
+ + { + credits.map((person) => ( + + +
diff --git a/packages/website/src/components/Footer.astro b/packages/website/src/components/Footer.astro index 17b204b9b..fb8d1d170 100644 --- a/packages/website/src/components/Footer.astro +++ b/packages/website/src/components/Footer.astro @@ -84,9 +84,6 @@ const strings = getStrings(locale); sm: "start", }} > - - {strings.website.footer.about.credits} - = { href: "https://discord.gg/nDt7AjGJQH", button: "plum", }, + credits: { + id: "credits", + button: "bronze", + }, }; diff --git a/packages/website/src/pages/[...chunk_api]/tanks/[id]/skins/[skin].glb.ts b/packages/website/src/pages/[...chunk_api]/tanks/[id]/skins/[skin].glb.ts deleted file mode 100644 index 9dde609df..000000000 --- a/packages/website/src/pages/[...chunk_api]/tanks/[id]/skins/[skin].glb.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { - parseHierarchies, - Sc2ReadStream, - type CamouflagesXml, - type CamouflagesYaml, - type TankParameters, -} from "@blitzkit/core"; -import { - Document, - Node, - NodeIO, - PropertyType, - Scene, -} from "@gltf-transform/core"; -import { ALL_EXTENSIONS } from "@gltf-transform/extensions"; -import { dedup, mergeDocuments, unpartition } from "@gltf-transform/functions"; -import type { APIContext } from "astro"; -import type { Vector3Tuple, Vector4Tuple } from "three"; -import { SKIN_NUMBER } from "../../../../../constants/skinNumber"; -import { api } from "../../../../../core/blitzkit/api"; -import { mixStaticPaths } from "../../../../../core/blitzkit/mixStaticPaths"; -import { vfs } from "../../../../../core/blitzkit/vfs"; -import { - extractMaterials, - extractModel, -} from "../../../../[...chunk_models_tanks]/[id]/model.glb"; -import { getStaticPaths as _getStaticPaths } from "../_index"; - -const SKIN_NUMBER_SLOTS = 5; -const DIGIT_COLUMNS = 5; -const DIGIT_ROWS = 2; - -export const getStaticPaths = mixStaticPaths(_getStaticPaths, async () => { - const camouflages = await api.camouflageDefinitions(); - - return Object.values(camouflages.camouflages) - .filter((camouflage) => camouflage.tank_id) - .map((camouflage) => ({ - params: { id: camouflage.tank_id!, skin: camouflage.id }, - props: { skin: camouflage.id }, - })); -}); - -const camouflagesXml = await vfs.xml<{ root: CamouflagesXml }>( - "Data/XML/item_defs/vehicles/common/camouflages.xml", -); -const camouflagesYaml = await vfs.yaml( - "Data/camouflages.yaml", -); -const customization = await vfs.yaml< - Record ->("Data/3d/Customization.yaml"); - -export async function GET({ props }: APIContext<{ skin: number }>) { - const nodeIO = new NodeIO().registerExtensions(ALL_EXTENSIONS); - - const items = new Map( - Object.values(customization).map(({ Name, Path }) => [ - Name, - Path.replace("~res:/3d/", "").replace(/\.sc2$/, ""), - ]), - ); - const key = Object.keys(camouflagesXml.root.camouflages).find( - (key) => camouflagesXml.root.camouflages[key].id === props.skin, - )!; - const include = camouflagesXml.root.camouflages[key].vehicleFilter.include; - const [nation, tankKey] = ( - include as { vehicle: { name: string } } - ).vehicle.name.split(":"); - const { preset, customEntities } = camouflagesYaml[key]; - const skinNumber = Number(preset?.match(/(\d+)$/)?.[1] ?? 1); - const parameters = await vfs.yaml( - `Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`, - ); - const basePath = parameters.resourcesPath.blitzModelPath.replace( - /\.sc2$/, - "", - ); - const sc2 = new Sc2ReadStream( - (await vfs.file(`Data/3d/${basePath}.sc2`)).buffer as ArrayBuffer, - ).sc2(); - const slots: Record< - string, - { - target: string; - position: Vector3Tuple; - rotation: Vector4Tuple; - scale: Vector3Tuple; - } - > = {}; - const states: Record = {}; - - parseHierarchies(sc2["#hierarchy"], null, (hierarchy, components) => { - for (const component of components) { - if (component["comp.typename"] === "NewSlotComponent") { - for (const slot of Object.values(component.slots)) { - slots[slot.name] = { - target: hierarchy.name, - position: slot.transform.position, - rotation: slot.transform.rotation, - scale: slot.transform.scale, - }; - } - } - - if (component["comp.typename"] === "SlotComponent") { - slots[component["sc.slotName"]] = { - target: hierarchy.name, - position: component["sc.attachmentTranslation"] as Vector3Tuple, - rotation: component["sc.attachmentRotation"] as Vector4Tuple, - scale: component["sc.attachmentScale"] as Vector3Tuple, - }; - } - - if (component["comp.typename"] !== "StateSwitcherComponent") continue; - - const active = component[`ssc.state${component["ssc.activeState"]}`]; - // camos without their own variant keep the default piece, but groups - // of elements to hide stay hidden - let state: string | null = - active && !/skin\d*/.test(active) && !active.includes("hide") - ? active - : null; - - for (let index = 0; index < component["ssc.statesCount"]; index++) { - const name = component[`ssc.state${index}`]; - const match = name.match(/skin(\d*)/); - - if ( - match && - !name.includes("hide") && - Number(match[1] || 1) === skinNumber - ) { - state = name; - } - } - - states[hierarchy.name] = state; - } - - return null; - }); - - const document = new Document(); - const scene = document.createScene().setExtras({ states }); - const targets = new Map(); - - document.createBuffer(); - - if (preset) await extractMaterials(document, sc2, basePath, preset); - - for (const name in customEntities) { - const slot = slots[name]; - const path = items.get(customEntities[name].item); - - if ( - !slot || - !path || - !(await vfs.resolve(`Data/3d/${path}.sc2`)) || - !(await vfs.resolve(`Data/3d/${path}.scg`)) - ) { - continue; - } - - const part = await extractModel(vfs, path, true); - const map = mergeDocuments(document, part); - const partScene = map.get(part.getRoot().listScenes()[0]) as Scene; - const node = document - .createNode(name) - .setTranslation(slot.position) - .setRotation(slot.rotation) - .setScale(slot.scale); - let target = targets.get(slot.target); - - if (!target) { - target = document.createNode(slot.target); - targets.set(slot.target, target); - scene.addChild(target); - } - - for (const child of partScene.listChildren()) { - node.addChild(child as Node); - } - - partScene.dispose(); - target.addChild(node); - } - - applySkinNumber(document, SKIN_NUMBER); - - await document.transform( - dedup({ propertyTypes: [PropertyType.ACCESSOR, PropertyType.TEXTURE] }), - unpartition(), - ); - - return new Response(await nodeIO.writeBinary(document)); -} - -function applySkinNumber(document: Document, number: string) { - const start = Math.ceil((SKIN_NUMBER_SLOTS - number.length) / 2) + 1; - - for (const node of document.getRoot().listNodes()) { - const match = node.getName().match(/_number_\d+_(\d+)$/); - - if (!match) continue; - - const digit = number[Number(match[1]) - start]; - - if (digit === undefined) { - node.dispose(); - continue; - } - - const cell = (Number(digit) + 9) % 10; - const column = cell % DIGIT_COLUMNS; - const row = Math.floor(cell / DIGIT_COLUMNS); - - node.traverse((child) => { - for (const primitive of child.getMesh()?.listPrimitives() ?? []) { - const uvs = primitive.getAttribute("TEXCOORD_0")?.clone(); - - if (!uvs) continue; - - for (let index = 0; index < uvs.getCount(); index++) { - const [u, v] = uvs.getElement(index, [0, 0]) as [number, number]; - - uvs.setElement(index, [ - (column + u) / DIGIT_COLUMNS, - (row + v) / DIGIT_ROWS, - ]); - } - - primitive.setAttribute("TEXCOORD_0", uvs); - } - }); - } -} diff --git a/packages/website/src/pages/[...chunk_default]/[...locale]/credits/index.astro b/packages/website/src/pages/[...chunk_default]/[...locale]/credits/index.astro new file mode 100644 index 000000000..0193b018b --- /dev/null +++ b/packages/website/src/pages/[...chunk_default]/[...locale]/credits/index.astro @@ -0,0 +1,13 @@ +--- +import CreditsPromo from "../../../../components/CreditsPromo.astro"; +import { tools } from "../../../../constants/tools"; +import ToolLayout from "../../../../layouts/ToolLayout.astro"; + +export { getStaticPaths } from "../index.astro"; + +const { locale } = Astro.props; +--- + + + +