Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09f5d4e3f7 | ||
|
|
0365656a0e | ||
|
|
90a46eeffa | ||
|
|
1249877a8c | ||
|
|
02df1e59d8 | ||
|
|
edce64c1bd | ||
|
|
74b821ac13 | ||
|
|
a5a72f9536 | ||
|
|
fe3d029e74 | ||
|
|
a69ea38947 | ||
|
|
bc9f7054e1 | ||
|
|
53c2f9605f | ||
|
|
95f67a04d7 | ||
|
|
1e6ee2b80d | ||
|
|
6a21c9aaac | ||
|
|
7e11c1e5ce | ||
|
|
2dc4f12246 | ||
|
|
354aca5057 | ||
|
|
c5f156eecc | ||
|
|
37b89d1f2d | ||
|
|
74c358dde5 | ||
|
|
4362746de3 | ||
|
|
d5d97e772a | ||
|
|
654c87dae7 | ||
|
|
e94f8a7cd2 | ||
|
|
d39ffecb3b | ||
|
|
6f8e12657c | ||
|
|
4a79f98f3f | ||
|
|
06de86c5a6 | ||
|
|
37ba6d37d4 | ||
|
|
636add3a18 | ||
|
|
2e13bcfee2 | ||
|
|
af53713c60 | ||
|
|
c37820d2cd | ||
|
|
d51b6bdd18 | ||
|
|
67ce4815df | ||
|
|
8c14c3d093 | ||
|
|
8373fb1b7a | ||
|
|
3aafe4d9f1 | ||
|
|
2c2c3687c7 | ||
|
|
9375f134db | ||
|
|
1eca71d28c | ||
|
|
9bf1554c30 | ||
|
|
f48c5d246d | ||
|
|
5e9aa99755 | ||
|
|
e7386ff766 | ||
|
|
4129a1964f | ||
|
|
64d12bba8b | ||
|
|
69b13fd33a | ||
|
|
bc6bb4f10e | ||
|
|
5adf90bab2 | ||
|
|
bc8cfc9897 | ||
|
|
9037e2caff |
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"indentSize": 2
|
||||||
|
}
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
name: Build Assets
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: main
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
cdn_branch:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
default: main
|
|
||||||
description: What CDN branch to write to
|
|
||||||
zip_url:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
description: ZIP URL to download instead of Steam client
|
|
||||||
zip_root:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
description: Root dir of ZIP which houses the executable and Data dir
|
|
||||||
|
|
||||||
schedule:
|
|
||||||
- cron: '0 2 * * *'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.cdn_branch }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
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 }}
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
PUBLIC_ASSET_REPO: blitzkit/assets
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: true
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
|
||||||
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
|
|
||||||
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
|
|
||||||
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
|
|
||||||
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
|
|
||||||
PUBLIC_DEBUG_MISSING_I18N: false
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_FAST_USER: blitzkit
|
|
||||||
PUBLIC_ASSET_FAST_REPO: assets
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
download_client:
|
|
||||||
name: Download client
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: (ZIP) Maximize build space
|
|
||||||
if: github.event.inputs.zip_url != ''
|
|
||||||
uses: easimon/maximize-build-space@master
|
|
||||||
with:
|
|
||||||
root-reserve-mb: 512
|
|
||||||
swap-size-mb: 1024
|
|
||||||
remove-dotnet: 'true'
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
- name: (Steam) Setup bun
|
|
||||||
uses: oven-sh/setup-bun@v1
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
|
|
||||||
- name: (Steam) Install dependencies
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: (Steam) Setup DepotDownloader
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: bun run setup:depotdownloader
|
|
||||||
|
|
||||||
- name: (Steam) Download client
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: |
|
|
||||||
chmod +x ./temp/depotDownloader/DepotDownloader
|
|
||||||
./temp/depotDownloader/DepotDownloader -q -os windows -app 444200 -username ${{ secrets.DEPOT_DOWNLOADER_USERNAME }} -password "${{ secrets.DEPOT_DOWNLOADER_PASSWORD }}"
|
|
||||||
|
|
||||||
- name: (Steam) Apply patches
|
|
||||||
if: github.event.inputs.zip_url == ''
|
|
||||||
run: bun setup:patches --depot
|
|
||||||
|
|
||||||
- name: (ZIP) Download client
|
|
||||||
if: github.event.inputs.zip_url != ''
|
|
||||||
env:
|
|
||||||
ZIP_URL: ${{ github.event.inputs.zip_url }}
|
|
||||||
ZIP_ROOT: ${{ github.event.inputs.zip_root }}
|
|
||||||
run: |
|
|
||||||
wget -q -O client.zip $ZIP_URL
|
|
||||||
unzip -q client.zip -d client
|
|
||||||
rm client.zip
|
|
||||||
mkdir -p depots/444202/0
|
|
||||||
mv client/$ZIP_ROOT/* depots/444202/0
|
|
||||||
|
|
||||||
- name: Archive depots
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: depots
|
|
||||||
path: depots
|
|
||||||
|
|
||||||
build_assets:
|
|
||||||
name: Build assets
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: download_client
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
- name: Setup bun
|
|
||||||
uses: oven-sh/setup-bun@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Lint
|
|
||||||
run: bun run lint:website
|
|
||||||
|
|
||||||
- name: Download depots
|
|
||||||
uses: actions/download-artifact@v4
|
|
||||||
with:
|
|
||||||
name: depots
|
|
||||||
path: depots
|
|
||||||
|
|
||||||
- name: AppArmor hack
|
|
||||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
|
||||||
|
|
||||||
- name: Start server and build assets
|
|
||||||
run: |
|
|
||||||
bun dev:website --verbosepa &
|
|
||||||
SERVER_PID=$!
|
|
||||||
|
|
||||||
bun run build:assets --all-targets --depot --production
|
|
||||||
|
|
||||||
kill $SERVER_PID || true
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
name: Averages
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 8 * * *'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
|
||||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: 'true'
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Build averages
|
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
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 }}
|
|
||||||
run: bun run build:averages --production
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
name: Discover IDs
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * 1'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Discover IDs
|
|
||||||
run: bun build:ids --production
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
name: Rating Asia
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 17 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
host:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Generate leaderboard
|
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
|
||||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: 'true'
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
|
||||||
run: bun build:ratingleaderboard --region=asia
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
name: Rating Europe
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 23 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
host:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Generate leaderboard
|
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
|
||||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: 'true'
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
|
||||||
run: bun build:ratingleaderboard --region=eu
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
name: Rating North America
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 5 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
host:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Generate leaderboard
|
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
|
||||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: 'true'
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
|
||||||
run: bun build:ratingleaderboard --region=com
|
|
||||||
@@ -17,33 +17,34 @@ concurrency:
|
|||||||
cancel-in-progress: ${{ github.ref == 'refs/heads/main' }}
|
cancel-in-progress: ${{ github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
AUTO_PROXY_ORIGIN: ${{ secrets.AUTO_PROXY_ORIGIN }}
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
ALLOW_ROBOTS: ${{ secrets.ALLOW_ROBOTS }}
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
|
||||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
|
||||||
SERVICING: ${{ secrets.SERVICING }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
- name: Setup Bun
|
||||||
- uses: actions/configure-pages@v5
|
uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
|
|
||||||
|
- name: Configure pages
|
||||||
|
uses: actions/configure-pages@v5
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bun install
|
run: bun install
|
||||||
@@ -57,13 +58,12 @@ jobs:
|
|||||||
path: dist/website
|
path: dist/website
|
||||||
|
|
||||||
deploy-github-pages:
|
deploy-github-pages:
|
||||||
if: ${{ github.ref == 'refs/heads/main' }}
|
|
||||||
name: Deploy to GitHub Pages
|
name: Deploy to GitHub Pages
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
environment:
|
if: >
|
||||||
name: Production
|
(github.repository == 'tresabhi/blitzkit' && github.ref == 'refs/heads/main') ||
|
||||||
url: ${{ steps.deployment.outputs.page_url }}
|
(github.repository == 'blitzkit/host-redux' && github.ref == 'refs/heads/ue4')
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
|
|||||||
@@ -22,9 +22,232 @@ depots
|
|||||||
public/sitemap*
|
public/sitemap*
|
||||||
/firebase.json
|
/firebase.json
|
||||||
target
|
target
|
||||||
# packages/core/src/protos/*.ts
|
|
||||||
/.vercel
|
/.vercel
|
||||||
/.astro
|
/.astro
|
||||||
.vercel
|
.vercel
|
||||||
/src
|
|
||||||
/packages/bot/src/prisma
|
/packages/bot/src/prisma
|
||||||
|
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
*.userprefs
|
||||||
|
mono_crash.*
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
[Aa][Rr][Mm]64[Ee][Cc]/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
.vs/
|
||||||
|
Generated\ Files/
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
StyleCopReport.xml
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.idb
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
!Directory.Build.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
_Chutzpah*
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
*.e2e
|
||||||
|
$tf/
|
||||||
|
*.gpState
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
_TeamCity*
|
||||||
|
*.dotCover
|
||||||
|
.axoCover/*
|
||||||
|
|
||||||
|
|
||||||
|
!.axoCover/settings.json
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
_NCrunch_*
|
||||||
|
.NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
.sass-cache/
|
||||||
|
[Ee]xpress/
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
publish/
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
*.nupkg
|
||||||
|
*.snupkg
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
csx/
|
||||||
|
|
||||||
|
*.build.csdef
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
*.[Cc]ache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
Generated_Code/
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
FakesAssemblies/
|
||||||
|
*.GhostDoc.xml
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
*.plg
|
||||||
|
*.opt
|
||||||
|
*.vbw
|
||||||
|
*.vbp
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
.fake/
|
||||||
|
.cr/personal
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
*.tss
|
||||||
|
*.jmconfig
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
OpenCover/
|
||||||
|
ASALocalRun/
|
||||||
|
*.binlog
|
||||||
|
.aws-sam
|
||||||
|
*.nvuser
|
||||||
|
.mfractor/
|
||||||
|
.localhistory/
|
||||||
|
.vshistory/
|
||||||
|
healthchecksdb
|
||||||
|
MigrationBackup/
|
||||||
|
.ionide/
|
||||||
|
FodyWeavers.xsd
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
.history/
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
*.sln.iml
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
"CUBEMAP",
|
"CUBEMAP",
|
||||||
"CUBETEXCOORD",
|
"CUBETEXCOORD",
|
||||||
"customperiod",
|
"customperiod",
|
||||||
|
"Datacard",
|
||||||
"datasource",
|
"datasource",
|
||||||
"Dava",
|
"Dava",
|
||||||
"dbid",
|
"dbid",
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
"DIDS",
|
"DIDS",
|
||||||
"donotremove",
|
"donotremove",
|
||||||
"drei",
|
"drei",
|
||||||
|
"dsapp",
|
||||||
"dvpd",
|
"dvpd",
|
||||||
"dvpl",
|
"dvpl",
|
||||||
"DVPLCRC",
|
"DVPLCRC",
|
||||||
@@ -86,7 +88,6 @@
|
|||||||
"gameplay",
|
"gameplay",
|
||||||
"glsl",
|
"glsl",
|
||||||
"GLTF",
|
"GLTF",
|
||||||
"gtag",
|
|
||||||
"haha",
|
"haha",
|
||||||
"highp",
|
"highp",
|
||||||
"iife",
|
"iife",
|
||||||
@@ -109,7 +110,6 @@
|
|||||||
"Maddoxkkm",
|
"Maddoxkkm",
|
||||||
"malum",
|
"malum",
|
||||||
"mantlets",
|
"mantlets",
|
||||||
"mediump",
|
|
||||||
"metallicness",
|
"metallicness",
|
||||||
"metalness",
|
"metalness",
|
||||||
"minitelrose",
|
"minitelrose",
|
||||||
@@ -129,6 +129,7 @@
|
|||||||
"noout",
|
"noout",
|
||||||
"normalmap",
|
"normalmap",
|
||||||
"oneof",
|
"oneof",
|
||||||
|
"oodle",
|
||||||
"oopsies",
|
"oopsies",
|
||||||
"Oopsy",
|
"Oopsy",
|
||||||
"opentest",
|
"opentest",
|
||||||
@@ -193,6 +194,8 @@
|
|||||||
"Turretless",
|
"Turretless",
|
||||||
"TYPELESS",
|
"TYPELESS",
|
||||||
"ubjson",
|
"ubjson",
|
||||||
|
"Uncompiled",
|
||||||
|
"undiscriminated",
|
||||||
"Unicum",
|
"Unicum",
|
||||||
"UNLOCALIZED",
|
"UNLOCALIZED",
|
||||||
"UNORM",
|
"UNORM",
|
||||||
@@ -222,12 +225,12 @@
|
|||||||
"yolo",
|
"yolo",
|
||||||
"youtuber",
|
"youtuber",
|
||||||
"youtubers",
|
"youtubers",
|
||||||
"zoomable",
|
|
||||||
"zustand"
|
"zustand"
|
||||||
],
|
],
|
||||||
"deno.enable": false,
|
"deno.enable": false,
|
||||||
"deno.unstable": false,
|
"deno.unstable": false,
|
||||||
"cSpell.enableFiletypes": ["glsl", "proto3"],
|
"cSpell.enableFiletypes": ["glsl", "proto3"],
|
||||||
"typescript.tsdk": "node_modules\\typescript\\lib",
|
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||||
"liveServer.settings.multiRootWorkspaceName": "blitzkit"
|
"liveServer.settings.multiRootWorkspaceName": "blitzkit",
|
||||||
|
"git.ignoreLimitWarning": true
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/BlitzKit.sln",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/BlitzKit.sln",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/BlitzKit.sln"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F23F76D4-C350-4BBA-9DF1-E67C5CD391B1}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlitzKit.FFI", "src\BlitzKit.FFI\BlitzKit.FFI.csproj", "{8E798C66-C863-4A67-87EA-853109EEE037}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8E798C66-C863-4A67-87EA-853109EEE037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8E798C66-C863-4A67-87EA-853109EEE037}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8E798C66-C863-4A67-87EA-853109EEE037}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8E798C66-C863-4A67-87EA-853109EEE037}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{8E798C66-C863-4A67-87EA-853109EEE037} = {F23F76D4-C350-4BBA-9DF1-E67C5CD391B1}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# BlitzKit License
|
|
||||||
|
|
||||||
Version 1.1, August 5th, 2025. Copyright (c) TrèsAbhi.
|
|
||||||
|
|
||||||
Permission is hereby granted to anyone to:
|
|
||||||
|
|
||||||
- Fork, clone, and download the contents of this repository.
|
|
||||||
- Modify the code locally in private.
|
|
||||||
- Use and run the code **only for personal, non-public testing, or educational purposes**.
|
|
||||||
|
|
||||||
The following restrictions apply:
|
|
||||||
|
|
||||||
- You may **not** deploy, host, or make this project or any derivative publicly accessible.
|
|
||||||
- You may **not** share screenshots, recordings, or any form of media from this project unless you intend to merge your changes back into BlitzKit.
|
|
||||||
- You may **not** use this project or its contents in any public or commercial product.
|
|
||||||
- You may **not** redistribute modified or unmodified versions of this project.
|
|
||||||
|
|
||||||
Contributions:
|
|
||||||
|
|
||||||
- You are encouraged to propose changes or improvements via pull requests to the original BlitzKit repository.
|
|
||||||
- Any such contributions will be considered under the same license terms unless explicitly stated otherwise.
|
|
||||||
|
|
||||||
Violations of this license may result in revocation of usage rights and takedown requests.
|
|
||||||
|
|
||||||
For questions or licensing inquiries, contact support@blitzkit.app.
|
|
||||||
|
|
||||||
## Notes on Existing Forks
|
|
||||||
|
|
||||||
All forks fall under these categories:
|
|
||||||
|
|
||||||
- If your fork was made from commit `8462901` (Apr 17, 2023) or between commits `2958124` (Jul 3, 2023) and `85e483e` (Jul 13, 2024), your fork falls under the **MIT license**.
|
|
||||||
- If your fork was made from commits between `5646093` (Jul 13, 2024) and `e3f131c` (Aug 5, 2025), your fork falls under the **AGPL-3.0 license**.
|
|
||||||
- If your fork was made between commit `f7c356d` (Apr 17, 2023) and `2958124` (Jul 3, 2023), your fork falls under **a default exclusive copyright**.
|
|
||||||
- If your fork was made from commits between `e3f131c` (Aug 5, 2025) and today, your fork falls under **this license**.
|
|
||||||
|
|
||||||
MIT and AGPL-3.0 licensed fork owners:
|
|
||||||
|
|
||||||
- You may continue to use your fork of BlitzKit under the corresponding license.
|
|
||||||
- You may upgrade your fork up to commit `5cab394` (Aug 4, 2025) and keep the AGPL-3.0 license.
|
|
||||||
- You may upgrade to commit `e3f131c` (Aug 5, 2025) or beyond but have to **switch to this license** where all rules apply.
|
|
||||||
- If you upgrade to commit `e3f131c` (Aug 5, 2025) or beyond, you must retract all public deployments of BlitzKit.
|
|
||||||
- Existing screenshots, recordings, or any form of media can remain.
|
|
||||||
|
|
||||||
Default exclusive copyright fork owners:
|
|
||||||
|
|
||||||
- You may continue to use their forks under the AGPL-3.0 license as no license was applied to BlitzKit at the time of forking.
|
|
||||||
|
|
||||||
BlitzKit licensed fork owners:
|
|
||||||
|
|
||||||
- You may continue to upgrade to the latest commits only under the conditions of this license.
|
|
||||||
@@ -11,3 +11,12 @@ Your premier source for all things Blitz.
|
|||||||
Go to [application directory for BlitzKit](https://discord.com/application-directory/1097673957865443370) and click "Add to Server." Voila! You're ready to go.
|
Go to [application directory for BlitzKit](https://discord.com/application-directory/1097673957865443370) and click "Add to Server." Voila! You're ready to go.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Naming Guide
|
||||||
|
|
||||||
|
| Type | Style | Example |
|
||||||
|
| --------- | -------------- | ---------------------------------------------------------------- |
|
||||||
|
| In-text | CamelCase | BlitzKit |
|
||||||
|
| Code | lowerCamelCase | `let blitzkit = { ... }`, `function fetchBlitzkitData() { ... }` |
|
||||||
|
| URLs | kebab-case | `https://example.com/blitzkit/` |
|
||||||
|
| Constants | SNAKE_CASE | `const BLITZKIT_VERSION = "1.0.0"` |
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"name": "blitzkit",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.27.11",
|
||||||
|
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||||
|
"type": "module",
|
||||||
|
"types": "./types.d.ts",
|
||||||
|
"workspaces": ["packages/*", "submodules/*"],
|
||||||
|
"scripts": {
|
||||||
|
"build:assets": "cd packages/scripts && bun run build:assets",
|
||||||
|
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
||||||
|
"build:bot": "cd packages/scripts && bun run build:bot",
|
||||||
|
"build:website": "bun build:prisma --no-hints && cd packages/website && bun run build",
|
||||||
|
"build:prisma": "prisma generate",
|
||||||
|
"build:sitemap": "bun scripts/sitemap.ts",
|
||||||
|
"build:docs": "vitepress build docs",
|
||||||
|
"build:ratingleaderboard": "cd packages/scripts && bun run build:ratingleaderboard",
|
||||||
|
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
||||||
|
"start:bot": "bun dist/bot/main.js",
|
||||||
|
"dev:docs": "vitepress dev docs",
|
||||||
|
"dev:website": "cd packages/website-ue && bun run dev",
|
||||||
|
"dev:api": "bun --filter=@blitzkit/api run dev",
|
||||||
|
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
||||||
|
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
||||||
|
"start:website": "bun --filter=@blitzkit/website run start",
|
||||||
|
"host:docs": "vitepress preview docs",
|
||||||
|
"lint": "tsc",
|
||||||
|
"lint:website": "cd packages/website && bun run lint",
|
||||||
|
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
||||||
|
"update": "yarn upgrade --latest",
|
||||||
|
"tunnel": "cloudflared tunnel --url http://localhost:3000",
|
||||||
|
"discoverids": "scripts/discoverIds.ts",
|
||||||
|
"build:protos": "bun packages/scripts/src/protos.ts",
|
||||||
|
"preview:website": "cd packages/website && bun run preview",
|
||||||
|
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||||
|
"build:ids": "cd packages/scripts && bun build:ids",
|
||||||
|
"prunestrings": "cd packages/scripts && bun prunestrings"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"satori": "^0.10.14",
|
||||||
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
|
"discord.js": "^14.16.3",
|
||||||
|
"bepaint": "^0.1.0-beta.3",
|
||||||
|
"markdown-escape": "^2.0.0",
|
||||||
|
"@types/markdown-escape": "^1.1.3",
|
||||||
|
"@types/adm-zip": "^0.5.5",
|
||||||
|
"@types/lz4js": "^0.2.1",
|
||||||
|
"@octokit/plugin-throttling": "^8.2.0",
|
||||||
|
"@octokit/rest": "^20.1.1",
|
||||||
|
"@prisma/client": "^6.6.0",
|
||||||
|
"adm-zip": "^0.5.16",
|
||||||
|
"crc": "^4.3.2",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"lz4js": "^0.2.0",
|
||||||
|
"yaml": "^2.5.0",
|
||||||
|
"ts-deepmerge": "^7.0.2",
|
||||||
|
"@types/decompress": "^4.2.7",
|
||||||
|
"@types/progress": "^2.0.7",
|
||||||
|
"@gltf-transform/core": "^4.0.10",
|
||||||
|
"@gltf-transform/extensions": "^4.0.10",
|
||||||
|
"@gltf-transform/functions": "^4.0.10",
|
||||||
|
"csv-parse": "^5.5.6",
|
||||||
|
"decompress": "^4.2.1",
|
||||||
|
"esbuild": "^0.19.12",
|
||||||
|
"fast-xml-parser": "^4.4.1",
|
||||||
|
"progress": "^2.0.3",
|
||||||
|
"puppeteer": "^23.10.4",
|
||||||
|
"@astrojs/check": "^0.9.4",
|
||||||
|
"@playform/compress": "^0.1.9",
|
||||||
|
"@playform/inline": "^0.1.2",
|
||||||
|
"@types/js-cookie": "^3.0.6",
|
||||||
|
"astro-compressor": "^1.0.0",
|
||||||
|
"@fontsource/inter": "^5.2.5",
|
||||||
|
"@nanostores/persistent": "^0.10.2",
|
||||||
|
"@nanostores/react": "^0.7.3",
|
||||||
|
"@nivo/bar": "^0.87.0",
|
||||||
|
"@nivo/line": "^0.88.0",
|
||||||
|
"compare-versions": "^6.1.1",
|
||||||
|
"echarts": "^5.5.1",
|
||||||
|
"js-cookie": "^3.0.5",
|
||||||
|
"markdown-to-jsx": "^7.5.0",
|
||||||
|
"nanostores": "^0.11.3",
|
||||||
|
"react-device-detect": "^2.2.3",
|
||||||
|
"react-promise-suspense": "^0.3.4",
|
||||||
|
"urlon": "^3.1.0",
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/node": "^22.14.1",
|
||||||
|
"prisma": "^6.6.0",
|
||||||
|
"typescript": "^5.8.3",
|
||||||
|
"googleapis": "^144.0.0",
|
||||||
|
"protobufjs": "^7.5.2",
|
||||||
|
"quicklime": "^1.2.0",
|
||||||
|
"sharp": "^0.33.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
{
|
||||||
|
"name": "blitzkit",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.27.11",
|
||||||
|
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||||
|
"type": "module",
|
||||||
|
"types": "./types.d.ts",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*",
|
||||||
|
"submodules/*"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build:assets": "cd packages/scripts && bun run build:assets",
|
||||||
|
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
||||||
|
"build:bot": "cd packages/scripts && bun run build:bot",
|
||||||
|
"build:website": "bun build:prisma --no-hints && cd packages/website && bun run build",
|
||||||
|
"build:prisma": "prisma generate",
|
||||||
|
"build:sitemap": "bun scripts/sitemap.ts",
|
||||||
|
"build:docs": "vitepress build docs",
|
||||||
|
"build:ratingleaderboard": "cd packages/scripts && bun run build:ratingleaderboard",
|
||||||
|
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
||||||
|
"start:bot": "bun dist/bot/main.js",
|
||||||
|
"dev:docs": "vitepress dev docs",
|
||||||
|
"dev:website": "cd packages/website-ue && bun run dev",
|
||||||
|
"dev:api": "bun --filter=@blitzkit/api run dev",
|
||||||
|
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
||||||
|
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
||||||
|
"start:website": "bun --filter=@blitzkit/website run start",
|
||||||
|
"host:docs": "vitepress preview docs",
|
||||||
|
"lint": "tsc",
|
||||||
|
"lint:website": "cd packages/website && bun run lint",
|
||||||
|
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
||||||
|
"update": "yarn upgrade --latest",
|
||||||
|
"tunnel": "cloudflared tunnel --url http://localhost:3000",
|
||||||
|
"discoverids": "scripts/discoverIds.ts",
|
||||||
|
"build:protos": "bun packages/scripts/src/protos.ts",
|
||||||
|
"preview:website": "cd packages/website && bun run preview",
|
||||||
|
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||||
|
"build:ids": "cd packages/scripts && bun build:ids",
|
||||||
|
"prunestrings": "cd packages/scripts && bun prunestrings"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"satori": "^0.10.14",
|
||||||
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
|
"discord.js": "^14.16.3",
|
||||||
|
"fuzzysort": "^2.0.4",
|
||||||
|
"bepaint": "^0.1.0-beta.3",
|
||||||
|
"markdown-escape": "^2.0.0",
|
||||||
|
"@types/markdown-escape": "^1.1.3",
|
||||||
|
"@types/adm-zip": "^0.5.5",
|
||||||
|
"@types/lz4js": "^0.2.1",
|
||||||
|
"@octokit/plugin-throttling": "^8.2.0",
|
||||||
|
"@octokit/rest": "^20.1.1",
|
||||||
|
"@prisma/client": "^6.6.0",
|
||||||
|
"adm-zip": "^0.5.16",
|
||||||
|
"crc": "^4.3.2",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"lz4js": "^0.2.0",
|
||||||
|
"ts-proto": "^2.2.2",
|
||||||
|
"yaml": "^2.5.0",
|
||||||
|
"ts-deepmerge": "^7.0.2",
|
||||||
|
"@types/decompress": "^4.2.7",
|
||||||
|
"@types/progress": "^2.0.7",
|
||||||
|
"@gltf-transform/core": "^4.0.10",
|
||||||
|
"@gltf-transform/extensions": "^4.0.10",
|
||||||
|
"@gltf-transform/functions": "^4.0.10",
|
||||||
|
"csv-parse": "^5.5.6",
|
||||||
|
"decompress": "^4.2.1",
|
||||||
|
"esbuild": "^0.19.12",
|
||||||
|
"fast-xml-parser": "^4.4.1",
|
||||||
|
"progress": "^2.0.3",
|
||||||
|
"puppeteer": "^23.10.4",
|
||||||
|
"@astrojs/check": "^0.9.4",
|
||||||
|
"@astrojs/sitemap": "^3.2.1",
|
||||||
|
"@playform/compress": "^0.1.9",
|
||||||
|
"@playform/inline": "^0.1.2",
|
||||||
|
"@types/js-cookie": "^3.0.6",
|
||||||
|
"@types/three": "^0.160.0",
|
||||||
|
"astro-compressor": "^1.0.0",
|
||||||
|
"@astrojs/partytown": "^2.1.4",
|
||||||
|
"@astrolib/seo": "^1.0.0-beta.8",
|
||||||
|
"@fontsource/inter": "^5.2.5",
|
||||||
|
"@nanostores/persistent": "^0.10.2",
|
||||||
|
"@nanostores/react": "^0.7.3",
|
||||||
|
"@nivo/bar": "^0.87.0",
|
||||||
|
"@nivo/line": "^0.88.0",
|
||||||
|
"@radix-ui/colors": "^3.0.0",
|
||||||
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
|
"@radix-ui/themes": "^3.1.4",
|
||||||
|
"@react-three/drei": "^9.115.0",
|
||||||
|
"@react-three/fiber": "^8.17.10",
|
||||||
|
"compare-versions": "^6.1.1",
|
||||||
|
"echarts": "^5.5.1",
|
||||||
|
"immer": "^10.1.1",
|
||||||
|
"js-cookie": "^3.0.5",
|
||||||
|
"markdown-to-jsx": "^7.5.0",
|
||||||
|
"nanostores": "^0.11.3",
|
||||||
|
"react-device-detect": "^2.2.3",
|
||||||
|
"react-promise-suspense": "^0.3.4",
|
||||||
|
"three": "^0.169.0",
|
||||||
|
"urlon": "^3.1.0",
|
||||||
|
"zustand": "^4.5.5",
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/node": "^22.14.1",
|
||||||
|
"prettier": "^3.5.3",
|
||||||
|
"prisma": "^6.6.0",
|
||||||
|
"typescript": "^5.8.3",
|
||||||
|
"googleapis": "^144.0.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"protobufjs": "^7.5.2",
|
||||||
|
"quicklime": "^1.2.0",
|
||||||
|
"sharp": "^0.33.5",
|
||||||
|
"@blitzkit/core": "workspace:*",
|
||||||
|
"@blitzkit/i18n": "workspace:*",
|
||||||
|
"@astrojs/react": "^4.3.0",
|
||||||
|
"@types/react": "^19.1.5",
|
||||||
|
"@types/react-dom": "^19.1.5",
|
||||||
|
"astro": "^5.8.0",
|
||||||
|
"react": "^19.1.0",
|
||||||
|
"react-dom": "^19.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# BlitzKit 1.27.12
|
|
||||||
|
|
||||||
This update only affects the website.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Added the ability to sort by HE shell penetration
|
|
||||||
- The Tankopedia compare bars now account for equipment and selected shells
|
|
||||||
- Made the hero section of the Tankopedia a bit shorter to show users that the page is scrollable
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- The "Clear filters" button no longer shows up after clearing the search bar
|
|
||||||
- Guns for some tanks no longer go transparent when far away from the camera
|
|
||||||
- The dynamic armor tab no longer lags and flickers when rotating the turret of a tank
|
|
||||||
- Reimplemented the missing tool backgrounds in the navigation bar hamburger menu
|
|
||||||
- The navigation bar now properly goes transparent for pages that request like the Tankopedia pages
|
|
||||||
- Removed the tank name text outline because it doesn't work on most devices
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# BlitzKit 1.27.13
|
|
||||||
|
|
||||||
This update adds a feature for a future version of WoTB 👁️👃👁️
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Added compatibility for the new mechanic for the upcoming Polish Tank Destroyers
|
|
||||||
- This code will remain dormant until the update for WoTB is released
|
|
||||||
- Added a progress bar to the hero section of the Tankopedia to show that the model is loading
|
|
||||||
- Reordered some Tankopedia statistics to bring important statistics like Damage to the very top
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- The second column in the footer is now aligned on mobile devices
|
|
||||||
- Fixed an issue that stopped the armor highlighting from working on the Kiwi browser and on older devices
|
|
||||||
|
|
||||||
## Technical Changes
|
|
||||||
|
|
||||||
- Removed permissions for robots to crawl non-blitzkit.app domains
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# BlitzKit 1.27.14
|
|
||||||
|
|
||||||
This is the 14th patch for `1.27`, making it the new longest lasting version beating the previous record of `1.15.13`!
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- Optimized the rendering of the shells in the Tankopedia search
|
|
||||||
- The Assault Shells cursor now works on iOS devices
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# BlitzKit 1.27.15
|
|
||||||
|
|
||||||
I did not see this coming
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- The Assault Shell graph now supports damage factors of above 100% now
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# BlitzKit 1.27.16
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Added links to GuidesBlitz to Tankopedia to aid users understand tanks beyond just numbers and stats
|
|
||||||
- Added a gun depression and yaw visualizer
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
- Made the colors of the advanced highlighting mode more subtle
|
|
||||||
- Made the Tankopedia stat lines more condensed
|
|
||||||
- You can now scroll the page even with your cursor on the Tankopedia sandbox
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- Fixed a bug where the range of increased gun depression was incorrectly doubled
|
|
||||||
- Removed an unintended space before the "x" in the "Gun damaged" stat
|
|
||||||
- Fixed an issue causing the 3D renderer to render frames even when off screen
|
|
||||||
- Fixed a differential issue causing excessive rerendering of the stat lines
|
|
||||||
- Images no longer exceed the width of the device in the docs
|
|
||||||
- Assault shells no longer scale the module damage with distance
|
|
||||||
|
|
||||||
## Technical Changes
|
|
||||||
|
|
||||||
- Removed all code relating to the canceled "Shooting Range" mode
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# BlitzKit 1.27.17
|
|
||||||
|
|
||||||
This update was released early for the website. Today, it'll be officially announced and released for the bot
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Added the shell reload visualizer to aid people in getting a feel for how long shell reloads really are
|
|
||||||
- Added lines of stats for the burst shells
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
- Removed the redundant word "Shell" from "Shell reload" and "Shell reloads"
|
|
||||||
- Removed the penetration over distance slider
|
|
||||||
|
|
||||||
## Fixes
|
|
||||||
|
|
||||||
- Fixed the DPM of tanks with burst shells like the ATAC
|
|
||||||
- The DPM will still be different from the game due to a bug in World of Tanks Blitz; I am trying to get Wargaming to fix it; trust BlitzKit!
|
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkit",
|
"name": "blitzkit",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.27.17",
|
"version": "1.28.0-beta.1",
|
||||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "./types.d.ts",
|
"types": "./types.d.ts",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*",
|
||||||
|
"submodules/*"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:assets": "cd packages/scripts && bun run build:assets",
|
"build:assets": "cd packages/scripts && bun run build:assets",
|
||||||
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
"build:averages": "bun --filter=@blitzkit/scripts run build:averages",
|
||||||
"build:bot": "cd packages/scripts && bun run build:bot",
|
"build:bot": "cd packages/scripts && bun run build:bot",
|
||||||
"build:website": "bun build:prisma --no-hints && cd packages/website && bun run build",
|
"build:website": "cd packages/website-ue && bun run build",
|
||||||
"build:prisma": "prisma generate",
|
"build:prisma": "prisma generate",
|
||||||
"build:sitemap": "bun scripts/sitemap.ts",
|
"build:sitemap": "bun scripts/sitemap.ts",
|
||||||
"build:docs": "vitepress build docs",
|
"build:docs": "vitepress build docs",
|
||||||
@@ -20,8 +21,7 @@
|
|||||||
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
||||||
"start:bot": "bun dist/bot/main.js",
|
"start:bot": "bun dist/bot/main.js",
|
||||||
"dev:docs": "vitepress dev docs",
|
"dev:docs": "vitepress dev docs",
|
||||||
"dev:website": "cd packages/website && bun run dev",
|
"dev:website": "cd packages/website-ue && bun run dev",
|
||||||
"dev": "bun run dev:website",
|
|
||||||
"dev:api": "bun --filter=@blitzkit/api run dev",
|
"dev:api": "bun --filter=@blitzkit/api run dev",
|
||||||
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
||||||
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
||||||
@@ -30,30 +30,21 @@
|
|||||||
"lint": "tsc",
|
"lint": "tsc",
|
||||||
"lint:website": "cd packages/website && bun run lint",
|
"lint:website": "cd packages/website && bun run lint",
|
||||||
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
||||||
"update": "yarn upgrade --latest",
|
"update": "yarn upgace --latest",
|
||||||
"tunnel": "cloudflared tunnel --url http://localhost:3000",
|
"tunnel": "cloudflared tunnel --url http://localhost:3000",
|
||||||
"discoverids": "scripts/discoverIds.ts",
|
"discoverids": "scripts/discoverIds.ts",
|
||||||
"build:protos": "bun packages/scripts/src/protos.ts",
|
"build:protos": "bun packages/scripts/src/protos.ts",
|
||||||
"preview:website": "cd packages/website && bun run preview",
|
"preview:website": "cd packages/website && bun run preview",
|
||||||
"build:reviews": "cd packages/scripts && bun build:reviews",
|
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||||
"build:ids": "cd packages/scripts && bun build:ids",
|
"build:ids": "cd packages/scripts && bun build:ids",
|
||||||
"prunestrings": "cd packages/scripts && bun prunestrings"
|
"prunestrings": "cd packages/scripts && bun prunestrings",
|
||||||
|
"build:ffi": "bun build:windows:ffi",
|
||||||
|
"build:windows:ffi": "dotnet publish src/BlitzKit.FFI -r win-x64 /p:PublishAot=true",
|
||||||
|
"build:linux:ffi": "dotnet publish src/BlitzKit.FFI -r linux-x64 /p:PublishAot=true"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cheerio": "^1.1.2",
|
"@types/bun": "^1.2.15",
|
||||||
"googleapis": "^144.0.0",
|
"prettier": "^3.5.3"
|
||||||
"lodash-es": "^4.17.21",
|
|
||||||
"protobufjs": "^7.5.2",
|
|
||||||
"quicklime": "^1.2.0",
|
|
||||||
"sharp": "^0.33.5"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/bun": "latest",
|
|
||||||
"@types/lodash-es": "^4.17.12",
|
|
||||||
"@types/node": "^22.14.1",
|
|
||||||
"prettier": "^3.5.3",
|
|
||||||
"prisma": "^6.6.0",
|
|
||||||
"typescript": "^5.8.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,24 +3,8 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"types": "src/types.d.ts",
|
"types": "src/types.d.ts",
|
||||||
"dependencies": {
|
|
||||||
"@blitzkit/core": "workspace:*",
|
|
||||||
"@blitzkit/i18n": "workspace:*",
|
|
||||||
"satori": "^0.10.14",
|
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
|
||||||
"discord.js": "^14.16.3",
|
|
||||||
"react": "^18.3.1",
|
|
||||||
"@radix-ui/colors": "^3.0.0",
|
|
||||||
"fuzzysort": "^2.0.4",
|
|
||||||
"bepaint": "^0.1.0-beta.3",
|
|
||||||
"dotenv": "^16.4.5",
|
|
||||||
"markdown-escape": "^2.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun --watch src/main.ts",
|
"dev": "bun --watch src/main.ts",
|
||||||
"start": "bun src/main.ts"
|
"start": "bun src/main.ts"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/markdown-escape": "^1.1.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,10 +197,15 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
turret.guns.forEach((gun) => {
|
turret.guns.forEach((gun) => {
|
||||||
if (
|
if (
|
||||||
gun.research_cost !== undefined &&
|
gun.gun_type!.value.base.research_cost !== undefined &&
|
||||||
typeof gun.research_cost.research_cost_type!.value === 'number'
|
typeof gun.gun_type!.value.base.research_cost
|
||||||
|
.research_cost_type!.value === 'number'
|
||||||
) {
|
) {
|
||||||
gunXps.set(gun.id, gun.research_cost.research_cost_type!.value);
|
gunXps.set(
|
||||||
|
gun.gun_type!.value.base.id,
|
||||||
|
gun.gun_type!.value.base.research_cost.research_cost_type!
|
||||||
|
.value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"include": ["src/**/*", "../core/src/blitzkit/supportedLocales.ts", "../i18n/src/unwrapper.ts"]
|
"include": [
|
||||||
|
"src/**/*",
|
||||||
|
"../core/src/blitzkit/supportedLocales.ts",
|
||||||
|
"../i18n/src/unwrapper.ts"
|
||||||
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "../../"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,20 +4,9 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/plugin-throttling": "^8.2.0",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@octokit/rest": "^20.1.1",
|
"js-yaml": "^4.1.0",
|
||||||
"@prisma/client": "^6.6.0",
|
|
||||||
"adm-zip": "^0.5.16",
|
|
||||||
"crc": "^4.3.2",
|
|
||||||
"dotenv": "^16.4.5",
|
|
||||||
"lz4js": "^0.2.0",
|
|
||||||
"pickleparser": "^0.2.1",
|
|
||||||
"protobufjs": "^7.4.0",
|
|
||||||
"ts-proto": "^2.2.2",
|
"ts-proto": "^2.2.2",
|
||||||
"yaml": "^2.5.0"
|
"@blitzkit/closed": "workspace:*"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/adm-zip": "^0.5.5",
|
|
||||||
"@types/lz4js": "^0.2.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import { CatalogItem } from '@protos/blitz_items';
|
||||||
|
import { Any } from '@protos/google/protobuf/any';
|
||||||
|
import { lowerFirst } from 'lodash-es';
|
||||||
|
import { compareUint8Arrays } from '../../../scripts/src/core/github/compareUint8Arrays';
|
||||||
|
import { MessageFns } from '../protos';
|
||||||
|
|
||||||
|
export class CatalogItemAccessor {
|
||||||
|
public id: string;
|
||||||
|
components: Record<string, Any> = {};
|
||||||
|
count: number;
|
||||||
|
|
||||||
|
constructor(private item: CatalogItem) {
|
||||||
|
this.id = item.catalog_id;
|
||||||
|
this.count = item.components.length;
|
||||||
|
|
||||||
|
for (const component of item.components) {
|
||||||
|
if (
|
||||||
|
component.value === undefined ||
|
||||||
|
component.value.component === undefined
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.components[component.key] = component.value.component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
undiscriminatedId() {
|
||||||
|
return this.id.split('.').slice(1).join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromComponent(id: string, component: Any) {
|
||||||
|
return this.fromComponents(id, [component]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromComponents(id: string, components: Any[]) {
|
||||||
|
return new CatalogItemAccessor({
|
||||||
|
catalog_id: id,
|
||||||
|
components: components.map((component) => ({
|
||||||
|
key: lowerFirst(
|
||||||
|
component.type_url.slice(2).split('.').slice(1).join('.'),
|
||||||
|
),
|
||||||
|
value: { type_url: component.type_url, component },
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponent(key: string, value: Any) {
|
||||||
|
this.components[key] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getOptional<Type>(Message: MessageFns<Type>, component: string) {
|
||||||
|
if (component in this.components) {
|
||||||
|
return Message.decode(this.components[component].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get<Type>(Message: MessageFns<Type>, component: string) {
|
||||||
|
const value = this.getOptional(Message, component);
|
||||||
|
if (value === undefined) throw new Error(`Unknown component: ${component}`);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pack() {
|
||||||
|
const item: CatalogItem = { catalog_id: this.id, components: [] };
|
||||||
|
|
||||||
|
for (const componentId in this.components) {
|
||||||
|
const component = this.components[componentId];
|
||||||
|
|
||||||
|
item.components.push({
|
||||||
|
key: componentId,
|
||||||
|
value: { type_url: component.type_url, component },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
encode() {
|
||||||
|
return CatalogItem.encode(this.pack()).finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(other: CatalogItemAccessor) {
|
||||||
|
return (
|
||||||
|
this.count === other.count &&
|
||||||
|
this.item.components.every(
|
||||||
|
(component) =>
|
||||||
|
component.value === undefined ||
|
||||||
|
(component.key in other.components &&
|
||||||
|
(component.value.component === undefined ||
|
||||||
|
compareUint8Arrays(
|
||||||
|
other.components[component.key].value,
|
||||||
|
component.value.component.value,
|
||||||
|
))),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ export * from './getTankStats';
|
|||||||
export * from './idToRegion';
|
export * from './idToRegion';
|
||||||
export * from './isOnGoingRatingSeason';
|
export * from './isOnGoingRatingSeason';
|
||||||
export * from './isValidBlitzId';
|
export * from './isValidBlitzId';
|
||||||
|
export * from './metadata';
|
||||||
export * from './nations';
|
export * from './nations';
|
||||||
export * from './normalizeExtra';
|
export * from './normalizeExtra';
|
||||||
export * from './normalizeIds';
|
export * from './normalizeIds';
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
export class SocketMetadataAccessor {
|
||||||
|
items: Record<string, CatalogItemAccessor> = {};
|
||||||
|
|
||||||
|
constructor(catalogItems: CatalogItem[]) {
|
||||||
|
for (const item of catalogItems) {
|
||||||
|
if (item.catalog_id in this.items) {
|
||||||
|
throw new Error(`Duplicate catalog ID: ${item.catalog_id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items[item.catalog_id] = new CatalogItemAccessor(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get(item: string) {
|
||||||
|
if (item in this.items) return this.items[item];
|
||||||
|
throw new Error(`Unknown catalog ID: ${item}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(item: CatalogItemAccessor) {
|
||||||
|
this.items[item.id] = item;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllTanks() {
|
||||||
|
return this.get('CatalogItemsGroupEntity.all_tanks').get(
|
||||||
|
CatalogItemsComponent,
|
||||||
|
'catalogItemsGroupComponent',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
injectBlitzkit() {
|
||||||
|
this.injectBlitzKitTankComponents();
|
||||||
|
this.injectBlitzKitAllTanksEntity();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
injectBlitzKitTankComponents() {
|
||||||
|
for (const item of this.getAllTanks().catalog_items) {
|
||||||
|
const tank = this.get(item);
|
||||||
|
const value = BlitzKitTankCatalogComponent.encode({
|
||||||
|
id: 'TEST',
|
||||||
|
set: 'TEST',
|
||||||
|
}).finish();
|
||||||
|
|
||||||
|
tank.addComponent('blitzkitTankCatalogComponent', {
|
||||||
|
type_url:
|
||||||
|
'./blitzkit_static_tank_component.BlitzKitTankCatalogComponent',
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
injectBlitzKitAllTanksEntity() {
|
||||||
|
const allTanksEntities: BlitzkitAllTanksComponent = { tanks: [] };
|
||||||
|
|
||||||
|
for (const item of this.getAllTanks().catalog_items) {
|
||||||
|
allTanksEntities.tanks.push(this.get(item).pack());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.add(
|
||||||
|
CatalogItemAccessor.fromComponent(
|
||||||
|
'BlitzKitAllTanksEntity.blitzkit_all_tanks',
|
||||||
|
{
|
||||||
|
type_url:
|
||||||
|
'./blitzkit_static_all_tanks_component.BlitzkitAllTanksComponent',
|
||||||
|
value: BlitzkitAllTanksComponent.encode(allTanksEntities).finish(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RemoteMetadataAccessor {
|
||||||
|
constructor(private base: string) {}
|
||||||
|
|
||||||
|
async get(item: string) {
|
||||||
|
const response = await fetch(`${this.base}/${item}.pb`);
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error(`Unknown catalog ID: ${item}`);
|
||||||
|
|
||||||
|
const buffer = await response.arrayBuffer();
|
||||||
|
const catalogItem = CatalogItem.decode(new Uint8Array(buffer));
|
||||||
|
|
||||||
|
return new CatalogItemAccessor(catalogItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import { CatalogItem } from '@protos/blitz_items';
|
||||||
|
import { Metadata } from '@protos/blitz_metadata';
|
||||||
|
import { LocalizationResourcesComponent } from '@protos/blitz_static_localization_resources_component';
|
||||||
|
import { RemoteStorageComponent } from '@protos/blitz_static_remote_storage_component';
|
||||||
|
import { load } from 'js-yaml';
|
||||||
|
import { minimatch } from 'minimatch';
|
||||||
|
import { CatalogItemAccessor } from 'packages/core/src/blitz/catalogItemAccessor';
|
||||||
|
|
||||||
|
interface LocalizationConfig {
|
||||||
|
namespaces: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MetadataAccessor {
|
||||||
|
items: Record<string, CatalogItem> = {};
|
||||||
|
|
||||||
|
constructor(metadata: Metadata) {
|
||||||
|
for (const item of metadata.catalog_items) {
|
||||||
|
this.items[item.catalog_id] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get(item: string) {
|
||||||
|
if (item in this.items) return new CatalogItemAccessor(this.items[item]);
|
||||||
|
throw new Error(`Item ${item} does not exist in socket metadata`);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(item: CatalogItemAccessor) {
|
||||||
|
this.items[item.id] = item.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(predicate: (item: string) => boolean) {
|
||||||
|
const items: CatalogItemAccessor[] = [];
|
||||||
|
|
||||||
|
for (const item in this.items) {
|
||||||
|
if (predicate(item)) {
|
||||||
|
items.push(new CatalogItemAccessor(this.items[item]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
async strings(locale: string) {
|
||||||
|
const clientConfig = await this.get(
|
||||||
|
'ClientConfigsEntity.default_client_config',
|
||||||
|
);
|
||||||
|
const localizationResources = clientConfig.get(
|
||||||
|
LocalizationResourcesComponent,
|
||||||
|
'localizationResourcesComponent',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!localizationResources.remote_storage) {
|
||||||
|
throw new Error('Localization resources not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { relative_path } = localizationResources.remote_storage;
|
||||||
|
|
||||||
|
let remoteStorage: RemoteStorageComponent | undefined = undefined;
|
||||||
|
|
||||||
|
for (const candidateId of localizationResources.remote_storage.production) {
|
||||||
|
const item = await this.get(candidateId);
|
||||||
|
const candidate = item.get(
|
||||||
|
RemoteStorageComponent,
|
||||||
|
'remoteStorageComponent',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
remoteStorage === undefined ||
|
||||||
|
candidate.download_speed_weight > remoteStorage.download_speed_weight
|
||||||
|
) {
|
||||||
|
remoteStorage = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remoteStorage === undefined) {
|
||||||
|
throw new Error('No suitable production remote storage found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = await fetch(
|
||||||
|
`${remoteStorage.url}/${relative_path}/config.yaml`,
|
||||||
|
)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((text) => load(text) as LocalizationConfig);
|
||||||
|
const strings: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const namespace of config.namespaces) {
|
||||||
|
Object.assign(
|
||||||
|
strings,
|
||||||
|
await fetch(
|
||||||
|
`${remoteStorage.url}/${relative_path}/${namespace}/${locale}.yaml`,
|
||||||
|
)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((text) => {
|
||||||
|
const strings: Record<string, string> = {};
|
||||||
|
const parsed = load(text) as Record<string, string>;
|
||||||
|
|
||||||
|
for (const key in parsed) {
|
||||||
|
strings[key] = parsed[key].replaceAll('\\"', '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
async stringsPartial(locale: string, patterns: string[]) {
|
||||||
|
const strings = await this.strings(locale);
|
||||||
|
const filtered: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const key in strings) {
|
||||||
|
if (patterns.some((pattern) => minimatch(key, pattern))) {
|
||||||
|
filtered[key] = strings[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
toArray() {
|
||||||
|
return Object.values(this.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
toSortedArray() {
|
||||||
|
return this.toArray().sort((a, b) =>
|
||||||
|
a.catalog_id.localeCompare(b.catalog_id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { BlitzKitAvatars } from '@protos/blitzkit';
|
||||||
|
import { MetadataAccessor } from '../../blitz/metadata';
|
||||||
|
|
||||||
|
export abstract class BlitzkitAPI {
|
||||||
|
abstract metadata: MetadataAccessor;
|
||||||
|
|
||||||
|
abstract avatars(): Promise<BlitzKitAvatars>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { BlitzKitAvatars } from '@protos/blitzkit';
|
||||||
|
import { MetadataAccessor } from '../../blitz/metadata';
|
||||||
|
import { BlitzkitAPI } from './abstract';
|
||||||
|
|
||||||
|
export class BlitzkitClientAPI extends BlitzkitAPI {
|
||||||
|
get metadata(): MetadataAccessor {
|
||||||
|
throw new Error('Cannot access metadata from client');
|
||||||
|
}
|
||||||
|
|
||||||
|
async avatars() {
|
||||||
|
const response = await fetch('/api/internal/avatars.pb');
|
||||||
|
const buffer = await response.arrayBuffer();
|
||||||
|
return BlitzKitAvatars.decode(new Uint8Array(buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './abstract';
|
||||||
|
export * from './client';
|
||||||
|
export * from './server';
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { ProfileAvatarComponent } from '@protos/blitz_static_profile_avatar_component';
|
||||||
|
import { SellableComponent } from '@protos/blitz_static_sellable_component';
|
||||||
|
import { StuffUIComponent } from '@protos/blitz_static_stuff_ui_component';
|
||||||
|
import { BlitzKitAvatars } from '@protos/blitzkit';
|
||||||
|
import { BlitzkitAPI } from '.';
|
||||||
|
import { MetadataAccessor } from '../../blitz/metadata';
|
||||||
|
|
||||||
|
export class BlitzkitServerAPI extends BlitzkitAPI {
|
||||||
|
constructor(public metadata: MetadataAccessor) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async avatars() {
|
||||||
|
const avatars: BlitzKitAvatars = { avatars: [] };
|
||||||
|
|
||||||
|
for (const item of this.metadata.filter((item) =>
|
||||||
|
item.startsWith('ProfileAvatarEntity.'),
|
||||||
|
)) {
|
||||||
|
const stuff = item.get(StuffUIComponent, 'UIComponent');
|
||||||
|
const avatar = item.get(ProfileAvatarComponent, 'profileAvatarComponent');
|
||||||
|
const sellable = item.getOptional(SellableComponent, 'sellableComponent');
|
||||||
|
|
||||||
|
avatars.avatars.push({
|
||||||
|
id: item.undiscriminatedId(),
|
||||||
|
name: stuff.display_name,
|
||||||
|
obtaining: stuff.obtaining_methods,
|
||||||
|
description: stuff.description,
|
||||||
|
grade: stuff.grade,
|
||||||
|
category: avatar.category,
|
||||||
|
hidden_if_not_obtained: avatar.hidden_if_not_obtained,
|
||||||
|
sale: sellable?.reward,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return avatars;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@ export * from './uniqueGuns';
|
|||||||
export * from './unwrapBlitzkitResponse';
|
export * from './unwrapBlitzkitResponse';
|
||||||
export * from './votes';
|
export * from './votes';
|
||||||
// export * from './withCORSProxy';
|
// export * from './withCORSProxy';
|
||||||
|
export * from './api';
|
||||||
export * from './createDefaultProvisions';
|
export * from './createDefaultProvisions';
|
||||||
export * from './gallery';
|
export * from './gallery';
|
||||||
export * from './metaSortTank';
|
export * from './metaSortTank';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
GunDefinition,
|
GunDefinition,
|
||||||
GunDefinitionAutoReloader,
|
GunDefinitionAutoReloaderProperties,
|
||||||
ShellDefinition,
|
ShellDefinition,
|
||||||
} from '../protos';
|
} from '../protos';
|
||||||
|
|
||||||
@@ -15,46 +15,34 @@ export function resolveDpm(
|
|||||||
let dps: number;
|
let dps: number;
|
||||||
|
|
||||||
if (gun.gun_type!.$case === 'regular') {
|
if (gun.gun_type!.$case === 'regular') {
|
||||||
dps = alpha / (reloadCoefficient * gun.gun_type!.value.reload);
|
dps = alpha / (reloadCoefficient * gun.gun_type!.value.extension.reload);
|
||||||
} else if (gun.gun_type!.$case === 'auto_loader') {
|
} else if (gun.gun_type!.$case === 'auto_loader') {
|
||||||
const damage = alpha * gun.gun_type!.value.shell_count;
|
dps =
|
||||||
let time = gun.gun_type!.value.clip_reload * reloadCoefficient;
|
(alpha * gun.gun_type!.value.extension.shell_count) /
|
||||||
|
(gun.gun_type!.value.extension.clip_reload * reloadCoefficient +
|
||||||
if (gun.burst) {
|
(gun.gun_type!.value.extension.shell_count - 1) *
|
||||||
time +=
|
gun.gun_type!.value.extension.intra_clip *
|
||||||
(gun.gun_type!.value.shell_count / gun.burst.count - 1) *
|
intraClipCoefficient);
|
||||||
gun.gun_type!.value.intra_clip *
|
|
||||||
intraClipCoefficient;
|
|
||||||
|
|
||||||
time +=
|
|
||||||
(gun.gun_type!.value.shell_count / gun.burst.count) *
|
|
||||||
(gun.burst.count - 1) *
|
|
||||||
gun.burst.interval;
|
|
||||||
} else {
|
|
||||||
time +=
|
|
||||||
(gun.gun_type!.value.shell_count - 1) *
|
|
||||||
gun.gun_type!.value.intra_clip *
|
|
||||||
intraClipCoefficient;
|
|
||||||
}
|
|
||||||
|
|
||||||
dps = damage / time;
|
|
||||||
} else {
|
} else {
|
||||||
const mostOptimalShell = gun.gun_type!.value.shell_reloads.reduce<null | {
|
const mostOptimalShell =
|
||||||
index: number;
|
gun.gun_type!.value.extension.shell_reloads.reduce<null | {
|
||||||
reload: number;
|
index: number;
|
||||||
}>((current, reloadRaw, index) => {
|
reload: number;
|
||||||
const reload =
|
}>((current, reloadRaw, index) => {
|
||||||
reloadRaw * reloadCoefficient +
|
const reload =
|
||||||
(index > 0
|
reloadRaw * reloadCoefficient +
|
||||||
? (gun.gun_type!.value as GunDefinitionAutoReloader).intra_clip *
|
(index > 0
|
||||||
intraClipCoefficient
|
? (
|
||||||
: 0);
|
gun.gun_type!.value
|
||||||
|
.extension as GunDefinitionAutoReloaderProperties
|
||||||
|
).intra_clip * intraClipCoefficient
|
||||||
|
: 0);
|
||||||
|
|
||||||
if (current === null || reload < current.reload) {
|
if (current === null || reload < current.reload) {
|
||||||
return { index, reload };
|
return { index, reload };
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}, null)!;
|
}, null)!;
|
||||||
|
|
||||||
dps = alpha / mostOptimalShell?.reload;
|
dps = alpha / mostOptimalShell?.reload;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import { deburr } from 'lodash-es';
|
import { deburr } from 'lodash-es';
|
||||||
import { SUPPORTED_LOCALES } from '../../../i18n/src/strings';
|
|
||||||
import { I18nString } from '../protos';
|
import { I18nString } from '../protos';
|
||||||
import { fetchCamouflageDefinitions } from './camouflageDefinitions';
|
import { fetchCamouflageDefinitions } from './camouflageDefinitions';
|
||||||
import { fetchTankDefinitions } from './tankDefinitions';
|
import { fetchTankDefinitions } from './tankDefinitions';
|
||||||
@@ -26,8 +26,8 @@ export async function fetchTankNames() {
|
|||||||
searchableNameDeburr,
|
searchableNameDeburr,
|
||||||
camouflages: tank.camouflages
|
camouflages: tank.camouflages
|
||||||
?.map((id) =>
|
?.map((id) =>
|
||||||
SUPPORTED_LOCALES.map(
|
locales.supported.map(
|
||||||
(locale) =>
|
({ locale }) =>
|
||||||
camouflageDefinitions.camouflages[id]?.name.locales[locale],
|
camouflageDefinitions.camouflages[id]?.name.locales[locale],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -42,9 +42,11 @@ export async function fetchTankNames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SEARCH_KEYS = [
|
export const SEARCH_KEYS = [
|
||||||
...SUPPORTED_LOCALES.map((locale) => [
|
...locales.supported
|
||||||
`searchableName.locales.${locale}`,
|
.map(({ locale }) => [
|
||||||
`searchableNameDeburr.locales.${locale}`,
|
`searchableName.locales.${locale}`,
|
||||||
]).flat(),
|
`searchableNameDeburr.locales.${locale}`,
|
||||||
|
])
|
||||||
|
.flat(),
|
||||||
'camouflages',
|
'camouflages',
|
||||||
];
|
];
|
||||||
@@ -7,8 +7,8 @@ export function uniqueGuns(turrets: TurretDefinition[]) {
|
|||||||
|
|
||||||
forEachRight(turrets, (turret) => {
|
forEachRight(turrets, (turret) => {
|
||||||
forEachRight(turret.guns, (gun) => {
|
forEachRight(turret.guns, (gun) => {
|
||||||
if (!gunIds.has(gun.id)) {
|
if (!gunIds.has(gun.gun_type!.value.base.id)) {
|
||||||
gunIds.add(gun.id);
|
gunIds.add(gun.gun_type!.value.base.id);
|
||||||
guns.push({ turret, gun });
|
guns.push({ turret, gun });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,4 @@ export const youtubers = [
|
|||||||
{ id: 'UCxRpZqMElssTdPYDK3x7wyg', name: 'N90' },
|
{ id: 'UCxRpZqMElssTdPYDK3x7wyg', name: 'N90' },
|
||||||
{ id: 'UC28Hc6p2MGoB5s78eHCYkQg', name: 'GuidesBlitz' },
|
{ id: 'UC28Hc6p2MGoB5s78eHCYkQg', name: 'GuidesBlitz' },
|
||||||
{ id: 'UCLMEfqtlwLDN-UXX21RiEww', name: 'WoT Blitz Best Replays' },
|
{ id: 'UCLMEfqtlwLDN-UXX21RiEww', name: 'WoT Blitz Best Replays' },
|
||||||
{ id: 'UC3fZbetRUFoJL0IEN7IhG0Q', name: 'EconomicsMate' },
|
|
||||||
{ id: 'UCtsUVwBlhEnUunAKLn2dtsg', name: 'Megalion69' },
|
|
||||||
];
|
];
|
||||||
@@ -5,10 +5,10 @@
|
|||||||
// source: packages/core/src/protos/camouflage_definitions.proto
|
// source: packages/core/src/protos/camouflage_definitions.proto
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire';
|
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
||||||
import { createBaseI18nString, I18nString } from './i18n';
|
import { createBaseI18nString, I18nString } from "./i18n";
|
||||||
|
|
||||||
export const protobufPackage = 'blitzkit';
|
export const protobufPackage = "blitzkit";
|
||||||
|
|
||||||
export interface CamouflageDefinitions {
|
export interface CamouflageDefinitions {
|
||||||
camouflages: { [key: number]: Camouflage };
|
camouflages: { [key: number]: Camouflage };
|
||||||
@@ -22,8 +22,8 @@ export interface CamouflageDefinitions_CamouflagesEntry {
|
|||||||
export interface Camouflage {
|
export interface Camouflage {
|
||||||
id: number;
|
id: number;
|
||||||
name: I18nString;
|
name: I18nString;
|
||||||
tank_name?: I18nString;
|
tank_name?: I18nString | undefined;
|
||||||
tank_name_full?: I18nString;
|
tank_name_full?: I18nString | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createBaseCamouflageDefinitions(): CamouflageDefinitions {
|
export function createBaseCamouflageDefinitions(): CamouflageDefinitions {
|
||||||
@@ -31,25 +31,15 @@ export function createBaseCamouflageDefinitions(): CamouflageDefinitions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
|
export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
|
||||||
encode(
|
encode(message: CamouflageDefinitions, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||||
message: CamouflageDefinitions,
|
|
||||||
writer: BinaryWriter = new BinaryWriter(),
|
|
||||||
): BinaryWriter {
|
|
||||||
Object.entries(message.camouflages).forEach(([key, value]) => {
|
Object.entries(message.camouflages).forEach(([key, value]) => {
|
||||||
CamouflageDefinitions_CamouflagesEntry.encode(
|
CamouflageDefinitions_CamouflagesEntry.encode({ key: key as any, value }, writer.uint32(10).fork()).join();
|
||||||
{ key: key as any, value },
|
|
||||||
writer.uint32(10).fork(),
|
|
||||||
).join();
|
|
||||||
});
|
});
|
||||||
return writer;
|
return writer;
|
||||||
},
|
},
|
||||||
|
|
||||||
decode(
|
decode(input: BinaryReader | Uint8Array, length?: number): CamouflageDefinitions {
|
||||||
input: BinaryReader | Uint8Array,
|
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||||
length?: number,
|
|
||||||
): CamouflageDefinitions {
|
|
||||||
const reader =
|
|
||||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
let end = length === undefined ? reader.len : reader.pos + length;
|
||||||
const message = createBaseCamouflageDefinitions();
|
const message = createBaseCamouflageDefinitions();
|
||||||
while (reader.pos < end) {
|
while (reader.pos < end) {
|
||||||
@@ -60,10 +50,7 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entry1 = CamouflageDefinitions_CamouflagesEntry.decode(
|
const entry1 = CamouflageDefinitions_CamouflagesEntry.decode(reader, reader.uint32());
|
||||||
reader,
|
|
||||||
reader.uint32(),
|
|
||||||
);
|
|
||||||
if (entry1.value !== undefined) {
|
if (entry1.value !== undefined) {
|
||||||
message.camouflages[entry1.key] = entry1.value;
|
message.camouflages[entry1.key] = entry1.value;
|
||||||
}
|
}
|
||||||
@@ -81,12 +68,10 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
|
|||||||
fromJSON(object: any): CamouflageDefinitions {
|
fromJSON(object: any): CamouflageDefinitions {
|
||||||
return {
|
return {
|
||||||
camouflages: isObject(object.camouflages)
|
camouflages: isObject(object.camouflages)
|
||||||
? Object.entries(object.camouflages).reduce<{
|
? Object.entries(object.camouflages).reduce<{ [key: number]: Camouflage }>((acc, [key, value]) => {
|
||||||
[key: number]: Camouflage;
|
acc[globalThis.Number(key)] = Camouflage.fromJSON(value);
|
||||||
}>((acc, [key, value]) => {
|
return acc;
|
||||||
acc[globalThis.Number(key)] = Camouflage.fromJSON(value);
|
}, {})
|
||||||
return acc;
|
|
||||||
}, {})
|
|
||||||
: {},
|
: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -105,23 +90,20 @@ export const CamouflageDefinitions: MessageFns<CamouflageDefinitions> = {
|
|||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
create<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(
|
create<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(base?: I): CamouflageDefinitions {
|
||||||
base?: I,
|
|
||||||
): CamouflageDefinitions {
|
|
||||||
return CamouflageDefinitions.fromPartial(base ?? ({} as any));
|
return CamouflageDefinitions.fromPartial(base ?? ({} as any));
|
||||||
},
|
},
|
||||||
fromPartial<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(
|
fromPartial<I extends Exact<DeepPartial<CamouflageDefinitions>, I>>(object: I): CamouflageDefinitions {
|
||||||
object: I,
|
|
||||||
): CamouflageDefinitions {
|
|
||||||
const message = createBaseCamouflageDefinitions();
|
const message = createBaseCamouflageDefinitions();
|
||||||
message.camouflages = Object.entries(object.camouflages ?? {}).reduce<{
|
message.camouflages = Object.entries(object.camouflages ?? {}).reduce<{ [key: number]: Camouflage }>(
|
||||||
[key: number]: Camouflage;
|
(acc, [key, value]) => {
|
||||||
}>((acc, [key, value]) => {
|
if (value !== undefined) {
|
||||||
if (value !== undefined) {
|
acc[globalThis.Number(key)] = Camouflage.fromPartial(value);
|
||||||
acc[globalThis.Number(key)] = Camouflage.fromPartial(value);
|
}
|
||||||
}
|
return acc;
|
||||||
return acc;
|
},
|
||||||
}, {});
|
{},
|
||||||
|
);
|
||||||
return message;
|
return message;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -130,116 +112,90 @@ export function createBaseCamouflageDefinitions_CamouflagesEntry(): CamouflageDe
|
|||||||
return { key: 0, value: createBaseCamouflage() };
|
return { key: 0, value: createBaseCamouflage() };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CamouflageDefinitions_CamouflagesEntry: MessageFns<CamouflageDefinitions_CamouflagesEntry> =
|
export const CamouflageDefinitions_CamouflagesEntry: MessageFns<CamouflageDefinitions_CamouflagesEntry> = {
|
||||||
{
|
encode(message: CamouflageDefinitions_CamouflagesEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||||
encode(
|
if (message.key !== undefined) {
|
||||||
message: CamouflageDefinitions_CamouflagesEntry,
|
writer.uint32(8).uint32(message.key);
|
||||||
writer: BinaryWriter = new BinaryWriter(),
|
}
|
||||||
): BinaryWriter {
|
if (message.value !== undefined) {
|
||||||
if (message.key !== undefined) {
|
Camouflage.encode(message.value, writer.uint32(18).fork()).join();
|
||||||
writer.uint32(8).uint32(message.key);
|
}
|
||||||
}
|
return writer;
|
||||||
if (message.value !== undefined) {
|
},
|
||||||
Camouflage.encode(message.value, writer.uint32(18).fork()).join();
|
|
||||||
}
|
|
||||||
return writer;
|
|
||||||
},
|
|
||||||
|
|
||||||
decode(
|
decode(input: BinaryReader | Uint8Array, length?: number): CamouflageDefinitions_CamouflagesEntry {
|
||||||
input: BinaryReader | Uint8Array,
|
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||||
length?: number,
|
let end = length === undefined ? reader.len : reader.pos + length;
|
||||||
): CamouflageDefinitions_CamouflagesEntry {
|
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
|
||||||
const reader =
|
while (reader.pos < end) {
|
||||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
const tag = reader.uint32();
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
switch (tag >>> 3) {
|
||||||
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
|
case 1: {
|
||||||
while (reader.pos < end) {
|
if (tag !== 8) {
|
||||||
const tag = reader.uint32();
|
break;
|
||||||
switch (tag >>> 3) {
|
|
||||||
case 1: {
|
|
||||||
if (tag !== 8) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.key = reader.uint32();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
case 2: {
|
|
||||||
if (tag !== 18) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.value = Camouflage.decode(reader, reader.uint32());
|
message.key = reader.uint32();
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
if (tag !== 18) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message.value = Camouflage.decode(reader, reader.uint32());
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if ((tag & 7) === 4 || tag === 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reader.skip(tag & 7);
|
|
||||||
}
|
}
|
||||||
return message;
|
if ((tag & 7) === 4 || tag === 0) {
|
||||||
},
|
break;
|
||||||
|
|
||||||
fromJSON(object: any): CamouflageDefinitions_CamouflagesEntry {
|
|
||||||
return {
|
|
||||||
key: globalThis.Number(
|
|
||||||
assertSet('CamouflageDefinitions_CamouflagesEntry.key', object.key),
|
|
||||||
),
|
|
||||||
value: Camouflage.fromJSON(
|
|
||||||
assertSet(
|
|
||||||
'CamouflageDefinitions_CamouflagesEntry.value',
|
|
||||||
object.value,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
toJSON(message: CamouflageDefinitions_CamouflagesEntry): unknown {
|
|
||||||
const obj: any = {};
|
|
||||||
if (message.key !== undefined) {
|
|
||||||
obj.key = Math.round(message.key);
|
|
||||||
}
|
}
|
||||||
if (message.value !== undefined) {
|
reader.skip(tag & 7);
|
||||||
obj.value = Camouflage.toJSON(message.value);
|
}
|
||||||
}
|
return message;
|
||||||
return obj;
|
},
|
||||||
},
|
|
||||||
|
|
||||||
create<
|
fromJSON(object: any): CamouflageDefinitions_CamouflagesEntry {
|
||||||
I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>,
|
return {
|
||||||
>(base?: I): CamouflageDefinitions_CamouflagesEntry {
|
key: globalThis.Number(assertSet("CamouflageDefinitions_CamouflagesEntry.key", object.key)),
|
||||||
return CamouflageDefinitions_CamouflagesEntry.fromPartial(
|
value: Camouflage.fromJSON(assertSet("CamouflageDefinitions_CamouflagesEntry.value", object.value)),
|
||||||
base ?? ({} as any),
|
};
|
||||||
);
|
},
|
||||||
},
|
|
||||||
fromPartial<
|
toJSON(message: CamouflageDefinitions_CamouflagesEntry): unknown {
|
||||||
I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>,
|
const obj: any = {};
|
||||||
>(object: I): CamouflageDefinitions_CamouflagesEntry {
|
if (message.key !== undefined) {
|
||||||
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
|
obj.key = Math.round(message.key);
|
||||||
message.key = object.key ?? 0;
|
}
|
||||||
message.value =
|
if (message.value !== undefined) {
|
||||||
object.value !== undefined && object.value !== null
|
obj.value = Camouflage.toJSON(message.value);
|
||||||
? Camouflage.fromPartial(object.value)
|
}
|
||||||
: createBaseCamouflage();
|
return obj;
|
||||||
return message;
|
},
|
||||||
},
|
|
||||||
};
|
create<I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>>(
|
||||||
|
base?: I,
|
||||||
|
): CamouflageDefinitions_CamouflagesEntry {
|
||||||
|
return CamouflageDefinitions_CamouflagesEntry.fromPartial(base ?? ({} as any));
|
||||||
|
},
|
||||||
|
fromPartial<I extends Exact<DeepPartial<CamouflageDefinitions_CamouflagesEntry>, I>>(
|
||||||
|
object: I,
|
||||||
|
): CamouflageDefinitions_CamouflagesEntry {
|
||||||
|
const message = createBaseCamouflageDefinitions_CamouflagesEntry();
|
||||||
|
message.key = object.key ?? 0;
|
||||||
|
message.value = (object.value !== undefined && object.value !== null)
|
||||||
|
? Camouflage.fromPartial(object.value)
|
||||||
|
: createBaseCamouflage();
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export function createBaseCamouflage(): Camouflage {
|
export function createBaseCamouflage(): Camouflage {
|
||||||
return {
|
return { id: 0, name: createBaseI18nString(), tank_name: undefined, tank_name_full: undefined };
|
||||||
id: 0,
|
|
||||||
name: createBaseI18nString(),
|
|
||||||
tank_name: undefined,
|
|
||||||
tank_name_full: undefined,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Camouflage: MessageFns<Camouflage> = {
|
export const Camouflage: MessageFns<Camouflage> = {
|
||||||
encode(
|
encode(message: Camouflage, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||||
message: Camouflage,
|
|
||||||
writer: BinaryWriter = new BinaryWriter(),
|
|
||||||
): BinaryWriter {
|
|
||||||
if (message.id !== 0) {
|
if (message.id !== 0) {
|
||||||
writer.uint32(8).uint32(message.id);
|
writer.uint32(8).uint32(message.id);
|
||||||
}
|
}
|
||||||
@@ -250,17 +206,13 @@ export const Camouflage: MessageFns<Camouflage> = {
|
|||||||
I18nString.encode(message.tank_name, writer.uint32(26).fork()).join();
|
I18nString.encode(message.tank_name, writer.uint32(26).fork()).join();
|
||||||
}
|
}
|
||||||
if (message.tank_name_full !== undefined) {
|
if (message.tank_name_full !== undefined) {
|
||||||
I18nString.encode(
|
I18nString.encode(message.tank_name_full, writer.uint32(34).fork()).join();
|
||||||
message.tank_name_full,
|
|
||||||
writer.uint32(34).fork(),
|
|
||||||
).join();
|
|
||||||
}
|
}
|
||||||
return writer;
|
return writer;
|
||||||
},
|
},
|
||||||
|
|
||||||
decode(input: BinaryReader | Uint8Array, length?: number): Camouflage {
|
decode(input: BinaryReader | Uint8Array, length?: number): Camouflage {
|
||||||
const reader =
|
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
||||||
let end = length === undefined ? reader.len : reader.pos + length;
|
let end = length === undefined ? reader.len : reader.pos + length;
|
||||||
const message = createBaseCamouflage();
|
const message = createBaseCamouflage();
|
||||||
while (reader.pos < end) {
|
while (reader.pos < end) {
|
||||||
@@ -309,14 +261,10 @@ export const Camouflage: MessageFns<Camouflage> = {
|
|||||||
|
|
||||||
fromJSON(object: any): Camouflage {
|
fromJSON(object: any): Camouflage {
|
||||||
return {
|
return {
|
||||||
id: globalThis.Number(assertSet('Camouflage.id', object.id)),
|
id: globalThis.Number(assertSet("Camouflage.id", object.id)),
|
||||||
name: I18nString.fromJSON(assertSet('Camouflage.name', object.name)),
|
name: I18nString.fromJSON(assertSet("Camouflage.name", object.name)),
|
||||||
tank_name: isSet(object.tank_name)
|
tank_name: isSet(object.tank_name) ? I18nString.fromJSON(object.tank_name) : undefined,
|
||||||
? I18nString.fromJSON(object.tank_name)
|
tank_name_full: isSet(object.tank_name_full) ? I18nString.fromJSON(object.tank_name_full) : undefined,
|
||||||
: undefined,
|
|
||||||
tank_name_full: isSet(object.tank_name_full)
|
|
||||||
? I18nString.fromJSON(object.tank_name_full)
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -340,57 +288,37 @@ export const Camouflage: MessageFns<Camouflage> = {
|
|||||||
create<I extends Exact<DeepPartial<Camouflage>, I>>(base?: I): Camouflage {
|
create<I extends Exact<DeepPartial<Camouflage>, I>>(base?: I): Camouflage {
|
||||||
return Camouflage.fromPartial(base ?? ({} as any));
|
return Camouflage.fromPartial(base ?? ({} as any));
|
||||||
},
|
},
|
||||||
fromPartial<I extends Exact<DeepPartial<Camouflage>, I>>(
|
fromPartial<I extends Exact<DeepPartial<Camouflage>, I>>(object: I): Camouflage {
|
||||||
object: I,
|
|
||||||
): Camouflage {
|
|
||||||
const message = createBaseCamouflage();
|
const message = createBaseCamouflage();
|
||||||
message.id = object.id ?? 0;
|
message.id = object.id ?? 0;
|
||||||
message.name =
|
message.name = (object.name !== undefined && object.name !== null)
|
||||||
object.name !== undefined && object.name !== null
|
? I18nString.fromPartial(object.name)
|
||||||
? I18nString.fromPartial(object.name)
|
: createBaseI18nString();
|
||||||
: createBaseI18nString();
|
message.tank_name = (object.tank_name !== undefined && object.tank_name !== null)
|
||||||
message.tank_name =
|
? I18nString.fromPartial(object.tank_name)
|
||||||
object.tank_name !== undefined && object.tank_name !== null
|
: undefined;
|
||||||
? I18nString.fromPartial(object.tank_name)
|
message.tank_name_full = (object.tank_name_full !== undefined && object.tank_name_full !== null)
|
||||||
: undefined;
|
? I18nString.fromPartial(object.tank_name_full)
|
||||||
message.tank_name_full =
|
: undefined;
|
||||||
object.tank_name_full !== undefined && object.tank_name_full !== null
|
|
||||||
? I18nString.fromPartial(object.tank_name_full)
|
|
||||||
: undefined;
|
|
||||||
return message;
|
return message;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type Builtin =
|
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
|
||||||
| Date
|
|
||||||
| Function
|
|
||||||
| Uint8Array
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
export type DeepPartial<T> = T extends Builtin
|
export type DeepPartial<T> = T extends Builtin ? T
|
||||||
? T
|
: T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
|
||||||
: T extends globalThis.Array<infer U>
|
: T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
|
||||||
? globalThis.Array<DeepPartial<U>>
|
: T extends { $case: string; value: unknown } ? { $case: T["$case"]; value?: DeepPartial<T["value"]> }
|
||||||
: T extends ReadonlyArray<infer U>
|
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||||
? ReadonlyArray<DeepPartial<U>>
|
: Partial<T>;
|
||||||
: T extends { $case: string; value: unknown }
|
|
||||||
? { $case: T['$case']; value?: DeepPartial<T['value']> }
|
|
||||||
: T extends {}
|
|
||||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
|
||||||
: Partial<T>;
|
|
||||||
|
|
||||||
type KeysOfUnion<T> = T extends T ? keyof T : never;
|
type KeysOfUnion<T> = T extends T ? keyof T : never;
|
||||||
export type Exact<P, I extends P> = P extends Builtin
|
export type Exact<P, I extends P> = P extends Builtin ? P
|
||||||
? P
|
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };
|
||||||
: P & { [K in keyof P]: Exact<P[K], I[K]> } & {
|
|
||||||
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
|
|
||||||
};
|
|
||||||
|
|
||||||
function isObject(value: any): boolean {
|
function isObject(value: any): boolean {
|
||||||
return typeof value === 'object' && value !== null;
|
return typeof value === "object" && value !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSet(value: any): boolean {
|
function isSet(value: any): boolean {
|
||||||
|
|||||||
@@ -108,55 +108,55 @@ message GunDefinition {
|
|||||||
GunDefinitionAutoLoader auto_loader = 2;
|
GunDefinitionAutoLoader auto_loader = 2;
|
||||||
GunDefinitionAutoReloader auto_reloader = 3;
|
GunDefinitionAutoReloader auto_reloader = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
required uint32 id = 4;
|
|
||||||
required float rotation_speed = 5;
|
|
||||||
optional ResearchCost research_cost = 6;
|
|
||||||
required uint32 weight = 7;
|
|
||||||
required I18nString name = 8;
|
|
||||||
required uint32 tier = 9;
|
|
||||||
repeated ShellDefinition shells = 10;
|
|
||||||
required float camouflage_loss = 11;
|
|
||||||
required float aim_time = 12;
|
|
||||||
required float dispersion_base = 13;
|
|
||||||
required float dispersion_traverse = 14;
|
|
||||||
required float dispersion_shot = 15;
|
|
||||||
required float dispersion_damaged = 16;
|
|
||||||
repeated Unlock unlocks = 17;
|
|
||||||
required uint32 shell_capacity = 18;
|
|
||||||
optional AssaultRanges assault_ranges = 19;
|
|
||||||
optional Burst burst = 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message GunDefinitionRegular {
|
message GunDefinitionRegular {
|
||||||
|
required GunDefinitionBase base = 1;
|
||||||
|
required GunDefinitionRegularProperties extension = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GunDefinitionRegularProperties {
|
||||||
required float reload = 1;
|
required float reload = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GunDefinitionAutoLoader {
|
message GunDefinitionAutoLoader {
|
||||||
|
required GunDefinitionBase base = 1;
|
||||||
|
required GunDefinitionAutoLoaderProperties extension = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GunDefinitionAutoLoaderProperties {
|
||||||
required float clip_reload = 1;
|
required float clip_reload = 1;
|
||||||
required float intra_clip = 2;
|
required float intra_clip = 2;
|
||||||
required float shell_count = 3;
|
required float shell_count = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Burst {
|
message GunDefinitionAutoReloader {
|
||||||
required uint32 count = 1;
|
required GunDefinitionBase base = 1;
|
||||||
required float interval = 2;
|
required GunDefinitionAutoReloaderProperties extension = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GunDefinitionAutoReloader {
|
message GunDefinitionAutoReloaderProperties {
|
||||||
repeated float shell_reloads = 1;
|
repeated float shell_reloads = 1;
|
||||||
required float intra_clip = 2;
|
required float intra_clip = 2;
|
||||||
required float shell_count = 3;
|
required float shell_count = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AssaultRanges {
|
message GunDefinitionBase {
|
||||||
repeated AssaultRange ranges = 1;
|
required uint32 id = 1;
|
||||||
repeated ShellType types = 2;
|
required float rotation_speed = 2;
|
||||||
}
|
optional ResearchCost research_cost = 3;
|
||||||
|
required uint32 weight = 4;
|
||||||
message AssaultRange {
|
required I18nString name = 5;
|
||||||
required float distance = 1;
|
required uint32 tier = 6;
|
||||||
required float factor = 2;
|
repeated ShellDefinition shells = 7;
|
||||||
|
required float camouflage_loss = 8;
|
||||||
|
required float aim_time = 9;
|
||||||
|
required float dispersion_base = 10;
|
||||||
|
required float dispersion_traverse = 11;
|
||||||
|
required float dispersion_shot = 12;
|
||||||
|
required float dispersion_damaged = 13;
|
||||||
|
repeated Unlock unlocks = 14;
|
||||||
|
required uint32 shell_capacity = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ShellDefinition {
|
message ShellDefinition {
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"include": ["src/**/*", "../i18n/src/strings.ts"]
|
"include": ["src/**/*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "../../"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,5 @@
|
|||||||
"name": "@blitzkit/i18n",
|
"name": "@blitzkit/i18n",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts"
|
||||||
"dependencies": {
|
|
||||||
"ts-deepmerge": "^7.0.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {}
|
|
||||||
}
|
}
|
||||||
@@ -1,89 +1,8 @@
|
|||||||
import { merge } from 'ts-deepmerge';
|
import type en from '../strings/en.json';
|
||||||
import en from '../strings/en.json';
|
|
||||||
import es from '../strings/es.json';
|
|
||||||
import fr from '../strings/fr.json';
|
|
||||||
import ja from '../strings/ja.json';
|
|
||||||
import pl from '../strings/pl.json';
|
|
||||||
import pt from '../strings/pt.json';
|
|
||||||
import ru from '../strings/ru.json';
|
|
||||||
import uk from '../strings/uk.json';
|
|
||||||
import zh from '../strings/zh.json';
|
|
||||||
|
|
||||||
export type BlitzKitStrings = typeof en;
|
export type BlitzKitStrings = typeof en;
|
||||||
|
|
||||||
const stringsRaw = { en, es, fr, ja, pl, pt, ru, uk, zh };
|
export const SUPPORTED_LOCALE_FLAGS: Record<string, string> = {
|
||||||
|
|
||||||
export const SUPPORTED_LOCALES = Object.keys(stringsRaw) as SupportedLocale[];
|
|
||||||
|
|
||||||
export const DEFAULT_LOCALE = SUPPORTED_LOCALES[0];
|
|
||||||
|
|
||||||
function redact(string: string) {
|
|
||||||
const matches = [...string.matchAll(/%s\d+/g)];
|
|
||||||
const characters = string
|
|
||||||
.split('')
|
|
||||||
.map((char) => (char === ' ' ? ' ' : '█')) as string[];
|
|
||||||
|
|
||||||
matches.forEach((match) => {
|
|
||||||
const start = match.index;
|
|
||||||
const matchText = match[0];
|
|
||||||
for (let i = 0; i < matchText.length; i++) {
|
|
||||||
characters[start + i] = matchText[i];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return characters.join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function nuke(object: TranslationTree) {
|
|
||||||
for (const key in object) {
|
|
||||||
const typedKey = key as keyof typeof object;
|
|
||||||
|
|
||||||
if (typeof object[typedKey] === 'string') {
|
|
||||||
const value = object[typedKey];
|
|
||||||
object[typedKey] = redact(value as string);
|
|
||||||
} else nuke(object[typedKey] as TranslationTree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const stringsPartial: Partial<Record<SupportedLocale, TranslationTree>> = {};
|
|
||||||
|
|
||||||
for (const locale in stringsRaw) {
|
|
||||||
if (locale === DEFAULT_LOCALE) {
|
|
||||||
stringsPartial[DEFAULT_LOCALE] = stringsRaw[DEFAULT_LOCALE];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const localeStrings = stringsRaw[locale as SupportedLocale];
|
|
||||||
stringsPartial[locale as SupportedLocale] = merge(
|
|
||||||
stringsRaw[DEFAULT_LOCALE],
|
|
||||||
localeStrings,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (import.meta.env.PUBLIC_DEBUG_MISSING_I18N === 'true') {
|
|
||||||
nuke(stringsPartial[locale as SupportedLocale]!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const STRINGS = stringsPartial as Record<
|
|
||||||
SupportedLocale,
|
|
||||||
BlitzKitStrings
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type SupportedLocale = keyof typeof stringsRaw;
|
|
||||||
|
|
||||||
export const SUPPORTED_LOCALE_BLITZ_MAP: Record<SupportedLocale, string> = {
|
|
||||||
en: 'en',
|
|
||||||
es: 'es',
|
|
||||||
fr: 'fr',
|
|
||||||
ja: 'ja',
|
|
||||||
pt: 'pt',
|
|
||||||
ru: 'ru',
|
|
||||||
uk: 'uk',
|
|
||||||
zh: 'zh-Hans',
|
|
||||||
pl: 'pl',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SUPPORTED_LOCALE_FLAGS: Record<SupportedLocale, string> = {
|
|
||||||
en: '🇺🇸',
|
en: '🇺🇸',
|
||||||
es: '🇪🇸',
|
es: '🇪🇸',
|
||||||
fr: '🇫🇷',
|
fr: '🇫🇷',
|
||||||
@@ -95,6 +14,14 @@ export const SUPPORTED_LOCALE_FLAGS: Record<SupportedLocale, string> = {
|
|||||||
pl: '🇵🇱',
|
pl: '🇵🇱',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TranslationTree = { [key: string]: TranslationNode };
|
export const LOCALE_NAMES: Record<string, string> = {
|
||||||
|
en: 'English',
|
||||||
export type TranslationNode = string | TranslationTree;
|
es: 'Español',
|
||||||
|
fr: 'Français',
|
||||||
|
ja: '日本語',
|
||||||
|
pt: 'Português',
|
||||||
|
ru: 'Русский',
|
||||||
|
uk: 'Українська',
|
||||||
|
zh: '中文',
|
||||||
|
pl: 'Polski',
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { I18nString } from '@blitzkit/core';
|
import { I18nString } from '@blitzkit/core';
|
||||||
import { DEFAULT_LOCALE } from './strings';
|
import locales from '../locales.json' with { type: 'json' };
|
||||||
|
|
||||||
export function unwrapper(locale: string) {
|
export function unwrapper(locale: string) {
|
||||||
return function (i18nString: I18nString) {
|
return function (i18nString: I18nString) {
|
||||||
@@ -7,6 +7,6 @@ export function unwrapper(locale: string) {
|
|||||||
return i18nString.locales[locale];
|
return i18nString.locales[locale];
|
||||||
}
|
}
|
||||||
|
|
||||||
return i18nString.locales[DEFAULT_LOCALE];
|
return i18nString.locales[locales.default];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,14 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"common": {
|
"common": {
|
||||||
|
"grades": {
|
||||||
|
"0": "Unspecified grade",
|
||||||
|
"1": "Common",
|
||||||
|
"2": "Rare",
|
||||||
|
"3": "Epic",
|
||||||
|
"4": "Legendary"
|
||||||
|
},
|
||||||
|
|
||||||
"units": {
|
"units": {
|
||||||
"m": "%s1m",
|
"m": "%s1m",
|
||||||
"mm": "%s1mm",
|
"mm": "%s1mm",
|
||||||
@@ -13,7 +21,8 @@
|
|||||||
"hp": "%s1hp",
|
"hp": "%s1hp",
|
||||||
"x": "x%s1",
|
"x": "x%s1",
|
||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"deg_s": "%s1°/s"
|
"deg_s": "%s1°/s",
|
||||||
|
"times": "x%s1"
|
||||||
},
|
},
|
||||||
|
|
||||||
"gun_types": {
|
"gun_types": {
|
||||||
@@ -790,7 +799,6 @@
|
|||||||
"fire.caliber": "caliber",
|
"fire.caliber": "caliber",
|
||||||
"fire.standardPenetration": "standard penetration",
|
"fire.standardPenetration": "standard penetration",
|
||||||
"fire.premiumPenetration": "premium penetration",
|
"fire.premiumPenetration": "premium penetration",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "damage",
|
"fire.damage": "damage",
|
||||||
"fire.moduleDamage": "module damage",
|
"fire.moduleDamage": "module damage",
|
||||||
"fire.shellVelocity": "shell velocity",
|
"fire.shellVelocity": "shell velocity",
|
||||||
@@ -861,6 +869,13 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"tools": {
|
"tools": {
|
||||||
|
"internal": {
|
||||||
|
"name": "Internal",
|
||||||
|
"button": "Internal",
|
||||||
|
"description": "BlitzKit internal tools",
|
||||||
|
"seo_description": "BlitzKit internal tools"
|
||||||
|
},
|
||||||
|
|
||||||
"guess": {
|
"guess": {
|
||||||
"name": "Guess the tank",
|
"name": "Guess the tank",
|
||||||
"button": "Guess away",
|
"button": "Guess away",
|
||||||
@@ -887,10 +902,6 @@
|
|||||||
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
||||||
|
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Hull",
|
"hull": "Hull",
|
||||||
"turret": "Turret",
|
"turret": "Turret",
|
||||||
@@ -913,13 +924,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Ghost Factory",
|
"ghost_factory": "Ghost Factory",
|
||||||
"dead_rail": "Dead Rail"
|
"dead_rail": "Dead Rail"
|
||||||
},
|
|
||||||
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1033,6 +1037,7 @@
|
|||||||
|
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Review videos",
|
"title": "Review videos",
|
||||||
|
"disclaimer": "BlitzKit does not endorse any review videos.",
|
||||||
"join": "Apply to %s1 YouTuber program"
|
"join": "Apply to %s1 YouTuber program"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1089,6 +1094,7 @@
|
|||||||
"hull_traverse_speed": "Hull traverse speed",
|
"hull_traverse_speed": "Hull traverse speed",
|
||||||
"camouflage": "Camouflage",
|
"camouflage": "Camouflage",
|
||||||
"reload": "Reload",
|
"reload": "Reload",
|
||||||
|
|
||||||
"crewCount": "Crew count",
|
"crewCount": "Crew count",
|
||||||
"shellNormalization": "Normalization",
|
"shellNormalization": "Normalization",
|
||||||
"shellRicochet": "Ricochet",
|
"shellRicochet": "Ricochet",
|
||||||
@@ -1096,13 +1102,12 @@
|
|||||||
"dpmEffective": "Effective at 60s",
|
"dpmEffective": "Effective at 60s",
|
||||||
"shells": "Shells",
|
"shells": "Shells",
|
||||||
"mostOptimalShellIndex": "Most optimal shell",
|
"mostOptimalShellIndex": "Most optimal shell",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "Shell reloads",
|
||||||
"shellReload": "Reload",
|
"shellReload": "Shell reload",
|
||||||
"intraClip": "Intra-clip",
|
"intraClip": "Intra-clip",
|
||||||
"caliber": "Caliber",
|
"caliber": "Caliber",
|
||||||
"penetration": "Penetration",
|
"penetration": "Penetration",
|
||||||
"damage": "Damage",
|
"damage": "Damage",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "Clipping potential",
|
"clipDamage": "Clipping potential",
|
||||||
"moduleDamage": "Module damage",
|
"moduleDamage": "Module damage",
|
||||||
"explosionRadius": "Explosion radius",
|
"explosionRadius": "Explosion radius",
|
||||||
@@ -1155,9 +1160,7 @@
|
|||||||
"shellRange": "Shell range",
|
"shellRange": "Shell range",
|
||||||
"shellCapacity": "Shell capacity",
|
"shellCapacity": "Shell capacity",
|
||||||
"gunType": "Gun type",
|
"gunType": "Gun type",
|
||||||
"penetrationAt250m": "Penetration at 250m",
|
"penetrationAt250m": "Penetration at 250m"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1265,17 +1268,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gallery": {
|
|
||||||
"name": "Gallery",
|
"avatars": {
|
||||||
|
"name": "Avatars",
|
||||||
"button": "Browse all",
|
"button": "Browse all",
|
||||||
"description": "Blitz player avatars",
|
"seo_description": "All World of Tanks Blitz player profile avatars",
|
||||||
"seo_description": "All World of Tanks Blitz player avatars",
|
"description": "Player profile avatars",
|
||||||
"last_updated": "Last updated on %s1",
|
|
||||||
|
"no_description": "This avatar has no description.",
|
||||||
|
"download": "Download",
|
||||||
|
"enlarge": "Enlarge",
|
||||||
|
"hidden": "Hidden",
|
||||||
|
"unnamed_avatars": "Unnamed avatars",
|
||||||
"search": {
|
"search": {
|
||||||
"hint": "Search avatars...",
|
"hint": "Search avatars...",
|
||||||
"results": "%s1 avatars"
|
"results": "%s1 avatars"
|
||||||
|
},
|
||||||
|
|
||||||
|
"categories": {
|
||||||
|
"0": "Unspecified",
|
||||||
|
"1": "Premium",
|
||||||
|
"2": "Special",
|
||||||
|
"3": "Accumulative",
|
||||||
|
"4": "Other",
|
||||||
|
"5": "Temporary"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"session": {
|
"session": {
|
||||||
"name": "Session",
|
"name": "Session",
|
||||||
"button": "Start tracking",
|
"button": "Start tracking",
|
||||||
|
|||||||
@@ -698,7 +698,6 @@
|
|||||||
"fire.caliber": "calibre",
|
"fire.caliber": "calibre",
|
||||||
"fire.standardPenetration": "penetración estándar",
|
"fire.standardPenetration": "penetración estándar",
|
||||||
"fire.premiumPenetration": "penetración prémium",
|
"fire.premiumPenetration": "penetración prémium",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "daño",
|
"fire.damage": "daño",
|
||||||
"fire.moduleDamage": "daño al módulo",
|
"fire.moduleDamage": "daño al módulo",
|
||||||
"fire.shellVelocity": "velocidad del proyectil",
|
"fire.shellVelocity": "velocidad del proyectil",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - Nivel %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
"tank_seo_title": "%s1 - Nivel %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
||||||
"tank_seo_description": "%s1 blindaje, estadisticas, equipamiento, proviciones y mas.\n%s2 DPM, %3hp alfa, %s4mm penetracion, %s5kph velocidad maxima, %s6 hp salud",
|
"tank_seo_description": "%s1 blindaje, estadisticas, equipamiento, proviciones y mas.\n%s2 DPM, %3hp alfa, %s4mm penetracion, %s5kph velocidad maxima, %s6 hp salud",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Hull",
|
"hull": "Hull",
|
||||||
"turret": "Turret",
|
"turret": "Turret",
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Ghost Factory",
|
"ghost_factory": "Ghost Factory",
|
||||||
"dead_rail": "Dead Rail"
|
"dead_rail": "Dead Rail"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Vídeos de reseña",
|
"title": "Vídeos de reseña",
|
||||||
|
"disclaimer": "BlitzKit no respalda ningún vídeo de reseñas.",
|
||||||
"join": "Aplica para el programa de YouTube de %s1"
|
"join": "Aplica para el programa de YouTube de %s1"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "Effective at 60s",
|
"dpmEffective": "Effective at 60s",
|
||||||
"shells": "Proyectiles",
|
"shells": "Proyectiles",
|
||||||
"mostOptimalShellIndex": "Proyectil más óptimo",
|
"mostOptimalShellIndex": "Proyectil más óptimo",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "Tiempos de recarga",
|
||||||
"shellReload": "Recarga",
|
"shellReload": "Tiempo de recarga",
|
||||||
"intraClip": "Intra-clip",
|
"intraClip": "Intra-clip",
|
||||||
"caliber": "Calibre",
|
"caliber": "Calibre",
|
||||||
"penetration": "Penetración",
|
"penetration": "Penetración",
|
||||||
"damage": "Daño",
|
"damage": "Daño",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "Clipping potential",
|
"clipDamage": "Clipping potential",
|
||||||
"moduleDamage": "Daño a módulos",
|
"moduleDamage": "Daño a módulos",
|
||||||
"explosionRadius": "Radio de Explosión",
|
"explosionRadius": "Radio de Explosión",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "Rango del proyectil",
|
"shellRange": "Rango del proyectil",
|
||||||
"shellCapacity": "Capacidad de proyectiles",
|
"shellCapacity": "Capacidad de proyectiles",
|
||||||
"gunType": "Tipo de cañón",
|
"gunType": "Tipo de cañón",
|
||||||
"penetrationAt250m": "Penetración a 250 m",
|
"penetrationAt250m": "Penetración a 250 m"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -698,7 +698,6 @@
|
|||||||
"fire.caliber": "caliber",
|
"fire.caliber": "caliber",
|
||||||
"fire.standardPenetration": "standard penetration",
|
"fire.standardPenetration": "standard penetration",
|
||||||
"fire.premiumPenetration": "premium penetration",
|
"fire.premiumPenetration": "premium penetration",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "damage",
|
"fire.damage": "damage",
|
||||||
"fire.moduleDamage": "module damage",
|
"fire.moduleDamage": "module damage",
|
||||||
"fire.shellVelocity": "shell velocity",
|
"fire.shellVelocity": "shell velocity",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
||||||
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Hull",
|
"hull": "Hull",
|
||||||
"turret": "Turret",
|
"turret": "Turret",
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Ghost Factory",
|
"ghost_factory": "Ghost Factory",
|
||||||
"dead_rail": "Dead Rail"
|
"dead_rail": "Dead Rail"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Review videos",
|
"title": "Review videos",
|
||||||
|
"disclaimer": "BlitzKit does not endorse any review videos.",
|
||||||
"join": "Apply to %s1 YouTuber program"
|
"join": "Apply to %s1 YouTuber program"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "Effective at 60s",
|
"dpmEffective": "Effective at 60s",
|
||||||
"shells": "Shells",
|
"shells": "Shells",
|
||||||
"mostOptimalShellIndex": "Most optimal shell",
|
"mostOptimalShellIndex": "Most optimal shell",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "Shell reloads",
|
||||||
"shellReload": "Reload",
|
"shellReload": "Shell reload",
|
||||||
"intraClip": "Intra-clip",
|
"intraClip": "Intra-clip",
|
||||||
"caliber": "Caliber",
|
"caliber": "Caliber",
|
||||||
"penetration": "Penetration",
|
"penetration": "Penetration",
|
||||||
"damage": "Dégâts",
|
"damage": "Dégâts",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "Clipping potential",
|
"clipDamage": "Clipping potential",
|
||||||
"moduleDamage": "Module damage",
|
"moduleDamage": "Module damage",
|
||||||
"explosionRadius": "Explosion radius",
|
"explosionRadius": "Explosion radius",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "Shell range",
|
"shellRange": "Shell range",
|
||||||
"shellCapacity": "Shell capacity",
|
"shellCapacity": "Shell capacity",
|
||||||
"gunType": "Gun type",
|
"gunType": "Gun type",
|
||||||
"penetrationAt250m": "Penetration at 250m",
|
"penetrationAt250m": "Penetration at 250m"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -698,7 +698,6 @@
|
|||||||
"fire.caliber": "砲口径",
|
"fire.caliber": "砲口径",
|
||||||
"fire.standardPenetration": "通常弾貫通力",
|
"fire.standardPenetration": "通常弾貫通力",
|
||||||
"fire.premiumPenetration": "課金弾貫通力",
|
"fire.premiumPenetration": "課金弾貫通力",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "ダメージ",
|
"fire.damage": "ダメージ",
|
||||||
"fire.moduleDamage": "モジュールダメージ",
|
"fire.moduleDamage": "モジュールダメージ",
|
||||||
"fire.shellVelocity": "弾速",
|
"fire.shellVelocity": "弾速",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
||||||
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Hull",
|
"hull": "Hull",
|
||||||
"turret": "Turret",
|
"turret": "Turret",
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Ghost Factory",
|
"ghost_factory": "Ghost Factory",
|
||||||
"dead_rail": "Dead Rail"
|
"dead_rail": "Dead Rail"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Review videos",
|
"title": "Review videos",
|
||||||
|
"disclaimer": "BlitzKitはいかなるレビュー動画も後援していません。",
|
||||||
"join": "%s1 YouTuberプログラムに応募する"
|
"join": "%s1 YouTuberプログラムに応募する"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "60秒での有効値",
|
"dpmEffective": "60秒での有効値",
|
||||||
"shells": "砲弾",
|
"shells": "砲弾",
|
||||||
"mostOptimalShellIndex": "最適な弾数",
|
"mostOptimalShellIndex": "最適な弾数",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "自動装填時間",
|
||||||
"shellReload": "装填時間",
|
"shellReload": "装填時間",
|
||||||
"intraClip": "砲弾再装填時間",
|
"intraClip": "砲弾再装填時間",
|
||||||
"caliber": "口径",
|
"caliber": "口径",
|
||||||
"penetration": "貫通力",
|
"penetration": "貫通力",
|
||||||
"damage": "ダメージ",
|
"damage": "ダメージ",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "弾倉火力",
|
"clipDamage": "弾倉火力",
|
||||||
"moduleDamage": "モジュールダメージ",
|
"moduleDamage": "モジュールダメージ",
|
||||||
"explosionRadius": "爆風半径",
|
"explosionRadius": "爆風半径",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "射程",
|
"shellRange": "射程",
|
||||||
"shellCapacity": "総弾数",
|
"shellCapacity": "総弾数",
|
||||||
"gunType": "主砲タイプ",
|
"gunType": "主砲タイプ",
|
||||||
"penetrationAt250m": "250m での貫通力",
|
"penetrationAt250m": "250m での貫通力"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -380,7 +380,7 @@
|
|||||||
},
|
},
|
||||||
"embeds": {
|
"embeds": {
|
||||||
"name": "osadzenie",
|
"name": "osadzenie",
|
||||||
"description": "Jak działają osadzone"
|
"description": "Jak działa osadzanie"
|
||||||
},
|
},
|
||||||
"introduction": {
|
"introduction": {
|
||||||
"name": "wprowadzenie",
|
"name": "wprowadzenie",
|
||||||
@@ -698,7 +698,6 @@
|
|||||||
"fire.caliber": "caliber",
|
"fire.caliber": "caliber",
|
||||||
"fire.standardPenetration": "standard penetration",
|
"fire.standardPenetration": "standard penetration",
|
||||||
"fire.premiumPenetration": "premium penetration",
|
"fire.premiumPenetration": "premium penetration",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "damage",
|
"fire.damage": "damage",
|
||||||
"fire.moduleDamage": "module damage",
|
"fire.moduleDamage": "module damage",
|
||||||
"fire.shellVelocity": "shell velocity",
|
"fire.shellVelocity": "shell velocity",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
|
||||||
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Hull",
|
"hull": "Hull",
|
||||||
"turret": "Turret",
|
"turret": "Turret",
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Ghost Factory",
|
"ghost_factory": "Ghost Factory",
|
||||||
"dead_rail": "Dead Rail"
|
"dead_rail": "Dead Rail"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Review videos",
|
"title": "Review videos",
|
||||||
|
"disclaimer": "BlitzKit does not endorse any review videos.",
|
||||||
"join": "Apply to %s1 YouTuber program"
|
"join": "Apply to %s1 YouTuber program"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "Effective at 60s",
|
"dpmEffective": "Effective at 60s",
|
||||||
"shells": "Shells",
|
"shells": "Shells",
|
||||||
"mostOptimalShellIndex": "Most optimal shell",
|
"mostOptimalShellIndex": "Most optimal shell",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "Shell reloads",
|
||||||
"shellReload": "Reload",
|
"shellReload": "Shell reload",
|
||||||
"intraClip": "Intra-clip",
|
"intraClip": "Intra-clip",
|
||||||
"caliber": "Caliber",
|
"caliber": "Caliber",
|
||||||
"penetration": "Penetration",
|
"penetration": "Penetration",
|
||||||
"damage": "Uszkodzenia",
|
"damage": "Uszkodzenia",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "Clipping potential",
|
"clipDamage": "Clipping potential",
|
||||||
"moduleDamage": "Module damage",
|
"moduleDamage": "Module damage",
|
||||||
"explosionRadius": "Explosion radius",
|
"explosionRadius": "Explosion radius",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "Shell range",
|
"shellRange": "Shell range",
|
||||||
"shellCapacity": "Shell capacity",
|
"shellCapacity": "Shell capacity",
|
||||||
"gunType": "Gun type",
|
"gunType": "Gun type",
|
||||||
"penetrationAt250m": "Penetration at 250m",
|
"penetrationAt250m": "Penetration at 250m"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -698,7 +698,6 @@
|
|||||||
"fire.caliber": "calibre",
|
"fire.caliber": "calibre",
|
||||||
"fire.standardPenetration": "penetração padrão",
|
"fire.standardPenetration": "penetração padrão",
|
||||||
"fire.premiumPenetration": "penetração premium",
|
"fire.premiumPenetration": "penetração premium",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "dano",
|
"fire.damage": "dano",
|
||||||
"fire.moduleDamage": "dano a módulos",
|
"fire.moduleDamage": "dano a módulos",
|
||||||
"fire.shellVelocity": "velocidade do projétil",
|
"fire.shellVelocity": "velocidade do projétil",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - Nível %s2 %s3 %s4 | %s5 Tanquepedia | World of Tanks Blitz (WoTB)",
|
"tank_seo_title": "%s1 - Nível %s2 %s3 %s4 | %s5 Tanquepedia | World of Tanks Blitz (WoTB)",
|
||||||
"tank_seo_description": "%s1 blindagem, estatísticas, equipamentos, provisões e mais. %s2 DPM, %s3hp alfa, %s4mm de penetração, %s5km/h velocidade máxima, %s6hp vida.",
|
"tank_seo_description": "%s1 blindagem, estatísticas, equipamentos, provisões e mais. %s2 DPM, %s3hp alfa, %s4mm de penetração, %s5km/h velocidade máxima, %s6hp vida.",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Hull",
|
"hull": "Hull",
|
||||||
"turret": "Turret",
|
"turret": "Turret",
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Ghost Factory",
|
"ghost_factory": "Ghost Factory",
|
||||||
"dead_rail": "Dead Rail"
|
"dead_rail": "Dead Rail"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Vídeos de análise",
|
"title": "Vídeos de análise",
|
||||||
|
"disclaimer": "BlitzKit não aprova nenhum vídeo de análise.",
|
||||||
"join": "Candidate-se para %s1 um programa YouTuber"
|
"join": "Candidate-se para %s1 um programa YouTuber"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "Efetivo aos 60s",
|
"dpmEffective": "Efetivo aos 60s",
|
||||||
"shells": "Projéteis",
|
"shells": "Projéteis",
|
||||||
"mostOptimalShellIndex": "Projétil mais ideal",
|
"mostOptimalShellIndex": "Projétil mais ideal",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "Recarga de projétil",
|
||||||
"shellReload": "Recarga",
|
"shellReload": "Recarregamento de projétil",
|
||||||
"intraClip": "Intra-clipe",
|
"intraClip": "Intra-clipe",
|
||||||
"caliber": "Calibre",
|
"caliber": "Calibre",
|
||||||
"penetration": "Penetração",
|
"penetration": "Penetração",
|
||||||
"damage": "Dano",
|
"damage": "Dano",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "Potencial de clipe",
|
"clipDamage": "Potencial de clipe",
|
||||||
"moduleDamage": "Dano a módulos",
|
"moduleDamage": "Dano a módulos",
|
||||||
"explosionRadius": "Raio de Explosão",
|
"explosionRadius": "Raio de Explosão",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "Alcance de projétil",
|
"shellRange": "Alcance de projétil",
|
||||||
"shellCapacity": "Capacidade de projéteis",
|
"shellCapacity": "Capacidade de projéteis",
|
||||||
"gunType": "Tipo de arma",
|
"gunType": "Tipo de arma",
|
||||||
"penetrationAt250m": "Penetração à 250m",
|
"penetrationAt250m": "Penetração à 250m"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -697,8 +697,7 @@
|
|||||||
"fire.reload": "перезарядка",
|
"fire.reload": "перезарядка",
|
||||||
"fire.caliber": "калибр",
|
"fire.caliber": "калибр",
|
||||||
"fire.standardPenetration": "базовое пробитие",
|
"fire.standardPenetration": "базовое пробитие",
|
||||||
"fire.premiumPenetration": "премиумное пробитие ",
|
"fire.premiumPenetration": "улучшенное пробитие ",
|
||||||
"fire.tertiaryPenetration": "пробитие третьего снаряда",
|
|
||||||
"fire.damage": "урон",
|
"fire.damage": "урон",
|
||||||
"fire.moduleDamage": "урон по модулям",
|
"fire.moduleDamage": "урон по модулям",
|
||||||
"fire.shellVelocity": "скорость снаряда",
|
"fire.shellVelocity": "скорость снаряда",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - %s4 %s3 %s2 уровня | Танкопедия %s5 | World of Tanks Blitz (WoTB)",
|
"tank_seo_title": "%s1 - %s4 %s3 %s2 уровня | Танкопедия %s5 | World of Tanks Blitz (WoTB)",
|
||||||
"tank_seo_description": "%s1 броня, статистика, оборудование, снабжение и многое другое. %s2 УВМ, %s3hp альфа, %s4mm пробитие, %s5км/ч лучшая скорость, %s6hp здоровье.",
|
"tank_seo_description": "%s1 броня, статистика, оборудование, снабжение и многое другое. %s2 УВМ, %s3hp альфа, %s4mm пробитие, %s5км/ч лучшая скорость, %s6hp здоровье.",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Штурмовые снаряды"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Корпус",
|
"hull": "Корпус",
|
||||||
"turret": "Башня",
|
"turret": "Башня",
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Промзона",
|
"ghost_factory": "Промзона",
|
||||||
"dead_rail": "Эшелон"
|
"dead_rail": "Эшелон"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Отклонение",
|
|
||||||
"pitch": "Наклон",
|
|
||||||
"min": "Вниз",
|
|
||||||
"max": "Вверх"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Видеообзоры",
|
"title": "Видеообзоры",
|
||||||
|
"disclaimer": "BlitzKit не несёт ответственности за видеообзоры.",
|
||||||
"join": "Предложить ютубера для программы %s1"
|
"join": "Предложить ютубера для программы %s1"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "Эффективность за 60с",
|
"dpmEffective": "Эффективность за 60с",
|
||||||
"shells": "Снарядов в барабане",
|
"shells": "Снарядов в барабане",
|
||||||
"mostOptimalShellIndex": "Самый эффективный снаряд",
|
"mostOptimalShellIndex": "Самый эффективный снаряд",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "Перезарядка снарядов",
|
||||||
"shellReload": "Перезарядка",
|
"shellReload": "Перезарядка",
|
||||||
"intraClip": "Между снарядами",
|
"intraClip": "Между снарядами",
|
||||||
"caliber": "Калибр",
|
"caliber": "Калибр",
|
||||||
"penetration": "Пробитие",
|
"penetration": "Пробитие",
|
||||||
"damage": "Урон",
|
"damage": "Урон",
|
||||||
"damageWithoutAssault": "Урон без штурмовых снарядов",
|
|
||||||
"clipDamage": "Урон с барабана",
|
"clipDamage": "Урон с барабана",
|
||||||
"moduleDamage": "Урон по модулям",
|
"moduleDamage": "Урон по модулям",
|
||||||
"explosionRadius": "Разлет осколков",
|
"explosionRadius": "Разлет осколков",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "Дальность снаряда",
|
"shellRange": "Дальность снаряда",
|
||||||
"shellCapacity": "Боезапас",
|
"shellCapacity": "Боезапас",
|
||||||
"gunType": "Тип орудия",
|
"gunType": "Тип орудия",
|
||||||
"penetrationAt250m": "Пробитие на 250м",
|
"penetrationAt250m": "Пробитие на 250м"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"default": "тест",
|
"default": "тест",
|
||||||
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is %s1 because it has the color of %s2. I like it so much that I will say its name 3 times! %s1! %s1! %s1! Once again, it's %s2, not %s3.",
|
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is %s1 because it has the color of %s2. I like it so much that I will say its name 3 times! %s1! %s1! %s1! Once again, it's %s2, not %s3.",
|
||||||
"fox": "Швидка бура лисиця перестрибує через лінивого собаку."
|
"fox": "The quick brown fox jumps over the lazy dog."
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
"units": {
|
"units": {
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"hp": "%s1хп",
|
"hp": "%s1хп",
|
||||||
"x": "х%s1",
|
"x": "х%s1",
|
||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"deg_s": "%s1°/с"
|
"deg_s": "%s1°/s"
|
||||||
},
|
},
|
||||||
"gun_types": {
|
"gun_types": {
|
||||||
"auto_loader": "Магазинна система заряджання",
|
"auto_loader": "Магазинна система заряджання",
|
||||||
@@ -413,10 +413,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"name": "налагодження",
|
"name": "debug",
|
||||||
"description": "Інформація про налагодження бота",
|
"description": "Debug information about the bot",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "# Налагодження\n\n",
|
"title": "# Debug\n\n",
|
||||||
"version": "Версія",
|
"version": "Версія",
|
||||||
"shard": {
|
"shard": {
|
||||||
"label": "Уламок",
|
"label": "Уламок",
|
||||||
@@ -499,7 +499,7 @@
|
|||||||
},
|
},
|
||||||
"embed": {
|
"embed": {
|
||||||
"title": "Невірний обліковий запис?",
|
"title": "Невірний обліковий запис?",
|
||||||
"description": "Використайте команду ще раз і виберіть ім'я користувача з результатів пошуку."
|
"description": "Use the command again and select a username from the search results."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"search_clans": {
|
"search_clans": {
|
||||||
@@ -508,7 +508,7 @@
|
|||||||
"options": {
|
"options": {
|
||||||
"limit": {
|
"limit": {
|
||||||
"name": "ліміт",
|
"name": "ліміт",
|
||||||
"description": "Максимальна кількість результатів клану (за замовчуванням: %s1)"
|
"description": "The max number of clan results (default: %s1)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"body": {
|
"body": {
|
||||||
@@ -531,16 +531,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rating_leaderboard": {
|
"rating_leaderboard": {
|
||||||
"name": "таблиця рейтингу",
|
"name": "rating-leaderboard",
|
||||||
"description": "Статистика рейтингових боїв",
|
"description": "Rating battles statistics",
|
||||||
"subcommands": {
|
"subcommands": {
|
||||||
"neighbors": {
|
"neighbors": {
|
||||||
"name": "neighbors",
|
"name": "neighbors",
|
||||||
"description": "Neighboring players on the leaderboard"
|
"description": "Neighboring players on the leaderboard"
|
||||||
},
|
},
|
||||||
"league": {
|
"league": {
|
||||||
"name": "ліга",
|
"name": "league",
|
||||||
"description": "Найкращий гравець ліги"
|
"description": "Top players of a league"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
@@ -549,8 +549,8 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"season": {
|
"season": {
|
||||||
"name": "сезон",
|
"name": "season",
|
||||||
"description": "Базова інформація про гравця",
|
"description": "Season number (default: current)",
|
||||||
"choices": {
|
"choices": {
|
||||||
"current": "%s1 (current)"
|
"current": "%s1 (current)"
|
||||||
}
|
}
|
||||||
@@ -578,14 +578,14 @@
|
|||||||
"description": "Коротка статистика за період"
|
"description": "Коротка статистика за період"
|
||||||
},
|
},
|
||||||
"owned_tanks": {
|
"owned_tanks": {
|
||||||
"name": "отримані танки",
|
"name": "owned-tanks",
|
||||||
"description": "Показує всі ваші танки даного рівня",
|
"description": "Shows all own tanks in a tier",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "# %s1's owned tier %s2 tanks\n\n"
|
"title": "# %s1's owned tier %s2 tanks\n\n"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"name": "дозволи",
|
"name": "permissions",
|
||||||
"description": "Checks wether the bot has the required permissions to function",
|
"description": "Checks wether the bot has the required permissions to function",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "# Permissions\n\n%s1",
|
"title": "# Permissions\n\n%s1",
|
||||||
@@ -615,7 +615,7 @@
|
|||||||
},
|
},
|
||||||
"player_info": {
|
"player_info": {
|
||||||
"name": "player-info",
|
"name": "player-info",
|
||||||
"description": "Базова інформація про гравця",
|
"description": "Basic information about a player",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "%s1's information",
|
"title": "%s1's information",
|
||||||
"nickname": "Нік",
|
"nickname": "Нік",
|
||||||
@@ -635,7 +635,7 @@
|
|||||||
"description": "Today's rating statistics"
|
"description": "Today's rating statistics"
|
||||||
},
|
},
|
||||||
"season": {
|
"season": {
|
||||||
"name": "сезон",
|
"name": "season",
|
||||||
"description": "This season's rating statistics"
|
"description": "This season's rating statistics"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -698,7 +698,6 @@
|
|||||||
"fire.caliber": "калібр",
|
"fire.caliber": "калібр",
|
||||||
"fire.standardPenetration": "базове пробиття",
|
"fire.standardPenetration": "базове пробиття",
|
||||||
"fire.premiumPenetration": "преміум пробиття",
|
"fire.premiumPenetration": "преміум пробиття",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "шкода",
|
"fire.damage": "шкода",
|
||||||
"fire.moduleDamage": "шкода по модулях",
|
"fire.moduleDamage": "шкода по модулях",
|
||||||
"fire.shellVelocity": "швидкість польоту снаряда",
|
"fire.shellVelocity": "швидкість польоту снаряда",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - Рівень %s2 %s3 %s4 | %s5 Танкопедія | WoT Blitz",
|
"tank_seo_title": "%s1 - Рівень %s2 %s3 %s4 | %s5 Танкопедія | WoT Blitz",
|
||||||
"tank_seo_description": "%s1 броня, характеристики, обладнання, амуніція та більше. %s2 шкода на хвилину, %s3 разова шкода, %s4 мм пробиття, %s5 км/год максимальна швидкість, %s6 міцність.",
|
"tank_seo_description": "%s1 броня, характеристики, обладнання, амуніція та більше. %s2 шкода на хвилину, %s3 разова шкода, %s4 мм пробиття, %s5 км/год максимальна швидкість, %s6 міцність.",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "Hull",
|
"hull": "Hull",
|
||||||
"turret": "Turret",
|
"turret": "Turret",
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "Ghost Factory",
|
"ghost_factory": "Ghost Factory",
|
||||||
"dead_rail": "Dead Rail"
|
"dead_rail": "Dead Rail"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Review videos",
|
"title": "Review videos",
|
||||||
|
"disclaimer": "BlitzKit does not endorse any review videos.",
|
||||||
"join": "Apply to %s1 YouTuber program"
|
"join": "Apply to %s1 YouTuber program"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "Effective at 60s",
|
"dpmEffective": "Effective at 60s",
|
||||||
"shells": "Снаряди",
|
"shells": "Снаряди",
|
||||||
"mostOptimalShellIndex": "Most optimal shell",
|
"mostOptimalShellIndex": "Most optimal shell",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "Shell reloads",
|
||||||
"shellReload": "Час перезаряджання",
|
"shellReload": "Shell reload",
|
||||||
"intraClip": "Intra-clip",
|
"intraClip": "Intra-clip",
|
||||||
"caliber": "Калібр",
|
"caliber": "Калібр",
|
||||||
"penetration": "Бронепробиття",
|
"penetration": "Бронепробиття",
|
||||||
"damage": "Шкода",
|
"damage": "Шкода",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "Clipping potential",
|
"clipDamage": "Clipping potential",
|
||||||
"moduleDamage": "Шкода по модулях",
|
"moduleDamage": "Шкода по модулях",
|
||||||
"explosionRadius": "Радіус розльоту уламків",
|
"explosionRadius": "Радіус розльоту уламків",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "Shell range",
|
"shellRange": "Shell range",
|
||||||
"shellCapacity": "Shell capacity",
|
"shellCapacity": "Shell capacity",
|
||||||
"gunType": "Тип гармати",
|
"gunType": "Тип гармати",
|
||||||
"penetrationAt250m": "Penetration at 250m",
|
"penetrationAt250m": "Penetration at 250m"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -41,15 +41,15 @@
|
|||||||
"preview": "预览"
|
"preview": "预览"
|
||||||
},
|
},
|
||||||
"locales": {
|
"locales": {
|
||||||
"en": "英语",
|
"en": "英文",
|
||||||
"es": "西班牙语",
|
"es": "西班牙文",
|
||||||
"pt": "葡萄牙语",
|
"pt": "葡萄牙文",
|
||||||
"ru": "俄语",
|
"ru": "俄文",
|
||||||
"uk": "乌克兰语",
|
"uk": "乌克兰文",
|
||||||
"zh": "中文",
|
"zh": "中文",
|
||||||
"ja": "日语",
|
"ja": "日文",
|
||||||
"fr": "法语",
|
"fr": "法文",
|
||||||
"pl": "波兰语"
|
"pl": "波兰文"
|
||||||
},
|
},
|
||||||
"wn8_percentile": {
|
"wn8_percentile": {
|
||||||
"0": "非常差",
|
"0": "非常差",
|
||||||
@@ -283,7 +283,7 @@
|
|||||||
"name": "阶级",
|
"name": "阶级",
|
||||||
"description": "阶级",
|
"description": "阶级",
|
||||||
"choices": {
|
"choices": {
|
||||||
"tier": "%s1阶 - %s2"
|
"tier": "%s1- %s2 级"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -494,7 +494,7 @@
|
|||||||
"accounts_linked": "帐号已绑定",
|
"accounts_linked": "帐号已绑定",
|
||||||
"no_role_permissions": {
|
"no_role_permissions": {
|
||||||
"title": "%s1 验证失败",
|
"title": "%s1 验证失败",
|
||||||
"description": "我没有管理身份的权限。"
|
"description": "我没有管理角色的权限。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"embed": {
|
"embed": {
|
||||||
@@ -517,7 +517,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"search_players": {
|
"search_players": {
|
||||||
"name": "搜索-玩家",
|
"name": "搜索玩家",
|
||||||
"description": "搜索玩家",
|
"description": "搜索玩家",
|
||||||
"options": {
|
"options": {
|
||||||
"limit": {
|
"limit": {
|
||||||
@@ -578,7 +578,7 @@
|
|||||||
"description": "一段时间内的快速统计"
|
"description": "一段时间内的快速统计"
|
||||||
},
|
},
|
||||||
"owned_tanks": {
|
"owned_tanks": {
|
||||||
"name": "已拥有的战车",
|
"name": "已擁有的戰車",
|
||||||
"description": "显示该阶级中所有您已拥有的战车",
|
"description": "显示该阶级中所有您已拥有的战车",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "# %s1 所拥有的 %s2 阶战车\n\n"
|
"title": "# %s1 所拥有的 %s2 阶战车\n\n"
|
||||||
@@ -589,8 +589,8 @@
|
|||||||
"description": "检查机器人是否拥有运行所需的权限",
|
"description": "检查机器人是否拥有运行所需的权限",
|
||||||
"body": {
|
"body": {
|
||||||
"title": "# 权限\n\n%s1",
|
"title": "# 权限\n\n%s1",
|
||||||
"view_channels": "查看频道:需要找到重新整理按钮使用的讯息",
|
"view_channels": "查看頻道:需要找到重新整理按鈕使用的訊息",
|
||||||
"read_message_history": "读取消息历史: 需要找到消息以刷新",
|
"read_message_history": "讀取歷史訊息: 需要找到訊息以重新整理",
|
||||||
"attach_files": "附加文件:需要将图像添加到基于图像的命令",
|
"attach_files": "附加文件:需要将图像添加到基于图像的命令",
|
||||||
"external_emojis": "外部表情符号:需要添加国家旗帜和战车类别"
|
"external_emojis": "外部表情符号:需要添加国家旗帜和战车类别"
|
||||||
}
|
}
|
||||||
@@ -698,7 +698,6 @@
|
|||||||
"fire.caliber": "口径",
|
"fire.caliber": "口径",
|
||||||
"fire.standardPenetration": "标准炮弹穿透力",
|
"fire.standardPenetration": "标准炮弹穿透力",
|
||||||
"fire.premiumPenetration": "加值炮弹穿透力",
|
"fire.premiumPenetration": "加值炮弹穿透力",
|
||||||
"fire.tertiaryPenetration": "tertiary penetration",
|
|
||||||
"fire.damage": "炮弹伤害值",
|
"fire.damage": "炮弹伤害值",
|
||||||
"fire.moduleDamage": "模组伤害值",
|
"fire.moduleDamage": "模组伤害值",
|
||||||
"fire.shellVelocity": "炮弹飞行速度",
|
"fire.shellVelocity": "炮弹飞行速度",
|
||||||
@@ -787,9 +786,6 @@
|
|||||||
"tank_seo_title": "%s1 - %s2 阶 %s3 %s4 | %s5 战车百科 | 战车世界闪击战 (WoTB)",
|
"tank_seo_title": "%s1 - %s2 阶 %s3 %s4 | %s5 战车百科 | 战车世界闪击战 (WoTB)",
|
||||||
"tank_seo_description": "%s1 装甲,统计设备,装备,供给等。 %s2 每分钟伤害, %s3生命值, %s4毫米穿透, %s5kph 最高速度, %s6hp 生命值。",
|
"tank_seo_description": "%s1 装甲,统计设备,装备,供给等。 %s2 每分钟伤害, %s3生命值, %s4毫米穿透, %s5kph 最高速度, %s6hp 生命值。",
|
||||||
"visualizers": {
|
"visualizers": {
|
||||||
"assault": {
|
|
||||||
"title": "Assault shells"
|
|
||||||
},
|
|
||||||
"rotator": {
|
"rotator": {
|
||||||
"hull": "车体",
|
"hull": "车体",
|
||||||
"turret": "炮塔",
|
"turret": "炮塔",
|
||||||
@@ -800,9 +796,9 @@
|
|||||||
},
|
},
|
||||||
"ricochet": {
|
"ricochet": {
|
||||||
"angle": "角度",
|
"angle": "角度",
|
||||||
"normalization": "转正",
|
"normalization": "轉正",
|
||||||
"effective_angle": "有效角度",
|
"effective_angle": "有效角度",
|
||||||
"armor": "装甲",
|
"armor": "裝甲",
|
||||||
"no_ricochet": "高爆弹不会跳弹"
|
"no_ricochet": "高爆弹不会跳弹"
|
||||||
},
|
},
|
||||||
"view_range": {
|
"view_range": {
|
||||||
@@ -810,12 +806,6 @@
|
|||||||
"percentage": "%s1%",
|
"percentage": "%s1%",
|
||||||
"ghost_factory": "幽灵工厂",
|
"ghost_factory": "幽灵工厂",
|
||||||
"dead_rail": "死亡铁道"
|
"dead_rail": "死亡铁道"
|
||||||
},
|
|
||||||
"flexibility": {
|
|
||||||
"yaw": "Yaw",
|
|
||||||
"pitch": "Pitch",
|
|
||||||
"min": "Min",
|
|
||||||
"max": "Max"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
@@ -864,7 +854,7 @@
|
|||||||
"track": "履带"
|
"track": "履带"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"penetration": "%s1生命值 击穿",
|
"penetration": "%s1生命值 擊穿",
|
||||||
"blocked": "抵挡伤害",
|
"blocked": "抵挡伤害",
|
||||||
"ricochet": "跳弹",
|
"ricochet": "跳弹",
|
||||||
"splash": "%s1生命值 溅射"
|
"splash": "%s1生命值 溅射"
|
||||||
@@ -918,6 +908,7 @@
|
|||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "回顾影片",
|
"title": "回顾影片",
|
||||||
|
"disclaimer": "BlitzKit 不支援任何影片回顾。",
|
||||||
"join": "应用到 %s1 YouTuber程序"
|
"join": "应用到 %s1 YouTuber程序"
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
@@ -978,13 +969,12 @@
|
|||||||
"dpmEffective": "60秒内生效",
|
"dpmEffective": "60秒内生效",
|
||||||
"shells": "炮弹 ",
|
"shells": "炮弹 ",
|
||||||
"mostOptimalShellIndex": "最优炮弹",
|
"mostOptimalShellIndex": "最优炮弹",
|
||||||
"shellReloads": "Reloads",
|
"shellReloads": "弹匣装填",
|
||||||
"shellReload": "装填时间",
|
"shellReload": "炮弹装填",
|
||||||
"intraClip": "炮弹装填",
|
"intraClip": "炮弹装填",
|
||||||
"caliber": "口径",
|
"caliber": "口径",
|
||||||
"penetration": "穿深",
|
"penetration": "穿深",
|
||||||
"damage": "伤害",
|
"damage": "伤害",
|
||||||
"damageWithoutAssault": "Damage without assault shells",
|
|
||||||
"clipDamage": "弹匣伤害期望值",
|
"clipDamage": "弹匣伤害期望值",
|
||||||
"moduleDamage": "模组伤害",
|
"moduleDamage": "模组伤害",
|
||||||
"explosionRadius": "溅射半径",
|
"explosionRadius": "溅射半径",
|
||||||
@@ -1037,9 +1027,7 @@
|
|||||||
"shellRange": "射程",
|
"shellRange": "射程",
|
||||||
"shellCapacity": "携弹量",
|
"shellCapacity": "携弹量",
|
||||||
"gunType": "炮管类型",
|
"gunType": "炮管类型",
|
||||||
"penetrationAt250m": "两百五十米处的穿透力",
|
"penetrationAt250m": "两百五十米处的穿透力"
|
||||||
"burstShells": "Burst shell count",
|
|
||||||
"burstInterShell": "Burst inter-shell"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firepower": {
|
"firepower": {
|
||||||
|
|||||||
@@ -12,22 +12,5 @@
|
|||||||
"build:bot": "bun src/buildBot.ts",
|
"build:bot": "bun src/buildBot.ts",
|
||||||
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts",
|
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts",
|
||||||
"prunestrings": "bun src/pruneStrings.ts"
|
"prunestrings": "bun src/pruneStrings.ts"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@blitzkit/core": "workspace:*",
|
|
||||||
"@blitzkit/i18n": "workspace:*",
|
|
||||||
"@gltf-transform/core": "^4.0.10",
|
|
||||||
"@gltf-transform/extensions": "^4.0.10",
|
|
||||||
"@gltf-transform/functions": "^4.0.10",
|
|
||||||
"csv-parse": "^5.5.6",
|
|
||||||
"decompress": "^4.2.1",
|
|
||||||
"esbuild": "^0.19.12",
|
|
||||||
"fast-xml-parser": "^4.4.1",
|
|
||||||
"progress": "^2.0.3",
|
|
||||||
"puppeteer": "^23.10.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/decompress": "^4.2.7",
|
|
||||||
"@types/progress": "^2.0.7"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ import { FileChange } from '../core/github/commitMultipleFiles';
|
|||||||
export async function blitzkitTankIcons() {
|
export async function blitzkitTankIcons() {
|
||||||
console.log('Building blitzkit tank icons...');
|
console.log('Building blitzkit tank icons...');
|
||||||
|
|
||||||
|
console.log('Starting website dev server...');
|
||||||
const browser = await launch();
|
const browser = await launch();
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
const tanks = Object.values((await fetchTankDefinitions()).tanks);
|
const tanks = Object.values((await fetchTankDefinitions()).tanks);
|
||||||
@@ -18,14 +19,12 @@ export async function blitzkitTankIcons() {
|
|||||||
width: BLITZKIT_TANK_ICON_SIZE.width - 1,
|
width: BLITZKIT_TANK_ICON_SIZE.width - 1,
|
||||||
height: BLITZKIT_TANK_ICON_SIZE.height,
|
height: BLITZKIT_TANK_ICON_SIZE.height,
|
||||||
});
|
});
|
||||||
|
await page.goto(`http://localhost:4321/api/tankopedia/tank-icon/${id}/`, {
|
||||||
|
waitUntil: 'networkidle0',
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
if (index === 0) {
|
||||||
await page.goto(`http://localhost:4321/api/tankopedia/tank-icon/${id}/`, {
|
console.log('Dev server started!');
|
||||||
waitUntil: 'networkidle0',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`${id} ${name} time out`, error);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const screenshot = await page.screenshot({
|
const screenshot = await page.screenshot({
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { gameModeBanners } from './gameModeBanners';
|
|||||||
import { glossary } from './glossary';
|
import { glossary } from './glossary';
|
||||||
import { migration } from './migration';
|
import { migration } from './migration';
|
||||||
import { moduleIcons } from './moduleIcons';
|
import { moduleIcons } from './moduleIcons';
|
||||||
|
import { popularTanks } from './popularTanks';
|
||||||
import { shellIcons } from './shellIcons';
|
import { shellIcons } from './shellIcons';
|
||||||
import { skillIcons } from './skillIcons';
|
import { skillIcons } from './skillIcons';
|
||||||
import { tankArmors } from './tankArmors';
|
import { tankArmors } from './tankArmors';
|
||||||
@@ -46,7 +47,7 @@ const methods = [
|
|||||||
boosterIcons,
|
boosterIcons,
|
||||||
tankIcons,
|
tankIcons,
|
||||||
blitzkitTankIcons,
|
blitzkitTankIcons,
|
||||||
// popularTanks,
|
popularTanks,
|
||||||
glossary,
|
glossary,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ export async function tankIcons() {
|
|||||||
|
|
||||||
const nationVehicleId = tank.id;
|
const nationVehicleId = tank.id;
|
||||||
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
|
const id = (nationVehicleId << 8) + (NATION_IDS[nation] << 4) + 1;
|
||||||
|
|
||||||
const parameters = await readYAMLDVPL<TankParameters>(
|
const parameters = await readYAMLDVPL<TankParameters>(
|
||||||
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { toUniqueId } from '@blitzkit/core';
|
import { toUniqueId } from '@blitzkit/core';
|
||||||
import { NodeIO } from '@gltf-transform/core';
|
import { NodeIO } from '@gltf-transform/core';
|
||||||
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
|
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';
|
||||||
import { readdir } from 'fs/promises';
|
import { readdir, writeFile } from 'fs/promises';
|
||||||
import { extractModel } from '../core/blitz/extractModel';
|
import { extractModel } from '../core/blitz/extractModel';
|
||||||
import { readXMLDVPL } from '../core/blitz/readXMLDVPL';
|
import { readXMLDVPL } from '../core/blitz/readXMLDVPL';
|
||||||
import { readYAMLDVPL } from '../core/blitz/readYAMLDVPL';
|
import { readYAMLDVPL } from '../core/blitz/readYAMLDVPL';
|
||||||
@@ -33,6 +33,8 @@ export async function tankModels() {
|
|||||||
|
|
||||||
const id = toUniqueId(nation, tank.id);
|
const id = toUniqueId(nation, tank.id);
|
||||||
|
|
||||||
|
if (id !== 21777) continue;
|
||||||
|
|
||||||
const parameters = await readYAMLDVPL<TankParameters>(
|
const parameters = await readYAMLDVPL<TankParameters>(
|
||||||
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
`${DATA}/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
||||||
);
|
);
|
||||||
@@ -41,6 +43,8 @@ export async function tankModels() {
|
|||||||
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ''),
|
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ''),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await writeFile('../../temp/model.glb', await nodeIO.writeBinary(model));
|
||||||
|
|
||||||
changes.push({
|
changes.push({
|
||||||
path: `3d/tanks/models/${id}.glb`,
|
path: `3d/tanks/models/${id}.glb`,
|
||||||
content: Buffer.from(await nodeIO.writeBinary(model)),
|
content: Buffer.from(await nodeIO.writeBinary(model)),
|
||||||
|
|||||||
@@ -73,13 +73,12 @@ export async function commitMultipleFiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (diff.status === DiffStatus.Unchanged) {
|
if (diff.status === DiffStatus.Unchanged) {
|
||||||
// just don't bother
|
console.log(`🔵 (${diff.change.toLocaleString()}B) ${change.path}`);
|
||||||
// console.log(`🔵 (${diff.change.toLocaleString()}B) ${change.path}`);
|
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
`${
|
`${
|
||||||
diff.status === DiffStatus.New ? '🟢' : '🟡'
|
diff.status === DiffStatus.New ? '🟢' : '🟡'
|
||||||
} (${diff.change > 0 ? '+' : ''}${diff.change.toLocaleString()}B) ${change.path}`,
|
} (+${diff.change.toLocaleString()}B) ${change.path}`,
|
||||||
);
|
);
|
||||||
changes.push(change);
|
changes.push(change);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { exec as execSync } from 'child_process';
|
import { exec as execSync } from 'child_process';
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { readdir, rm, writeFile } from 'fs/promises';
|
import { readdir, rm, writeFile } from 'fs/promises';
|
||||||
|
import { chunk } from 'lodash-es';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
|
|
||||||
const ROOT = 'packages/core/src/protos';
|
|
||||||
|
|
||||||
const exec = promisify(execSync);
|
const exec = promisify(execSync);
|
||||||
|
|
||||||
let executableFileExtension: string;
|
let executableFileExtension: string;
|
||||||
@@ -15,33 +14,44 @@ if (existsSync('node_modules/.bin/protoc-gen-ts_proto.exe')) {
|
|||||||
executableFileExtension = '';
|
executableFileExtension = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const filesRaw = await readdir(`${ROOT}`);
|
// await compile('packages/core/src/protos');
|
||||||
await Promise.all(
|
await compile('submodules/blitzkit-closed/src/unreal/protos');
|
||||||
filesRaw.map(async (file) => {
|
|
||||||
if (!file.endsWith('.proto')) {
|
|
||||||
await rm(`${ROOT}/${file}`);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
const files = filesRaw.filter((file) => file.endsWith('.proto'));
|
async function compile(root: string) {
|
||||||
const args = [
|
const filesRaw = await readdir(root);
|
||||||
`--plugin=./node_modules/.bin/protoc-gen-ts_proto${executableFileExtension}`,
|
|
||||||
'--ts_proto_opt=esModuleInterop=true',
|
|
||||||
'--ts_proto_opt=oneof=unions-value',
|
|
||||||
'--ts_proto_opt=removeEnumPrefix=true',
|
|
||||||
'--ts_proto_opt=unrecognizedEnum=false',
|
|
||||||
'--ts_proto_opt=snakeToCamel=false',
|
|
||||||
'--ts_proto_out=.',
|
|
||||||
...files.map((file) => `${ROOT}/${file}`),
|
|
||||||
];
|
|
||||||
|
|
||||||
await exec(`protoc ${args.join(' ')}`);
|
for (const file of filesRaw) {
|
||||||
await writeFile(
|
if (!file.endsWith('.ts')) continue;
|
||||||
`${ROOT}/index.ts`,
|
await rm(`${root}/${file}`);
|
||||||
'// @ts-nocheck\n' +
|
}
|
||||||
files
|
|
||||||
.map((file) => file.replace('.proto', ''))
|
const allFiles = filesRaw.filter(
|
||||||
.map((file) => `export * from './${file}.ts';`)
|
(file) => file.endsWith('.proto') && !file.startsWith('_'),
|
||||||
.join('\n'),
|
);
|
||||||
);
|
|
||||||
|
for (const files of chunk(allFiles, 32)) {
|
||||||
|
const args = [
|
||||||
|
`-I=${root}`,
|
||||||
|
`--plugin=./node_modules/.bin/protoc-gen-ts_proto${executableFileExtension}`,
|
||||||
|
'--ts_proto_opt=esModuleInterop=true',
|
||||||
|
'--ts_proto_opt=oneof=unions-value',
|
||||||
|
// '--ts_proto_opt=removeEnumPrefix=true',
|
||||||
|
'--ts_proto_opt=unrecognizedEnum=false',
|
||||||
|
'--ts_proto_opt=snakeToCamel=false',
|
||||||
|
`--ts_proto_out=${root}`,
|
||||||
|
...files.map((file) => `${root}/${file}`),
|
||||||
|
];
|
||||||
|
|
||||||
|
await exec(`protoc ${args.join(' ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await writeFile(
|
||||||
|
`${root}/index.ts`,
|
||||||
|
'// @ts-nocheck\n' +
|
||||||
|
allFiles
|
||||||
|
.sort()
|
||||||
|
.map((file) => file.replace('.proto', ''))
|
||||||
|
.map((file) => `export * from './${file}.ts';`)
|
||||||
|
.join('\n'),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "../../"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# build output
|
||||||
|
dist/
|
||||||
|
# generated types
|
||||||
|
.astro/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# logs
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# macOS-specific files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# jetbrains setting folder
|
||||||
|
.idea/
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Astro Starter Kit: Minimal
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bun create astro@latest -- --template minimal
|
||||||
|
```
|
||||||
|
|
||||||
|
[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/minimal)
|
||||||
|
[](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/minimal)
|
||||||
|
[](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/minimal/devcontainer.json)
|
||||||
|
|
||||||
|
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||||
|
|
||||||
|
## 🚀 Project Structure
|
||||||
|
|
||||||
|
Inside of your Astro project, you'll see the following folders and files:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/
|
||||||
|
├── public/
|
||||||
|
├── src/
|
||||||
|
│ └── pages/
|
||||||
|
│ └── index.astro
|
||||||
|
└── package.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
||||||
|
|
||||||
|
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
||||||
|
|
||||||
|
Any static assets, like images, can be placed in the `public/` directory.
|
||||||
|
|
||||||
|
## 🧞 Commands
|
||||||
|
|
||||||
|
All commands are run from the root of the project, from a terminal:
|
||||||
|
|
||||||
|
| Command | Action |
|
||||||
|
| :------------------------ | :----------------------------------------------- |
|
||||||
|
| `bun install` | Installs dependencies |
|
||||||
|
| `bun dev` | Starts local dev server at `localhost:4321` |
|
||||||
|
| `bun build` | Build your production site to `./dist/` |
|
||||||
|
| `bun preview` | Preview your build locally, before deploying |
|
||||||
|
| `bun astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||||
|
| `bun astro -- --help` | Get help using the Astro CLI |
|
||||||
|
|
||||||
|
## 👀 Want to learn more?
|
||||||
|
|
||||||
|
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// @ts-check
|
||||||
|
import sitemap from '@astrojs/sitemap';
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
|
||||||
|
import react from '@astrojs/react';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
integrations: [react(), sitemap()],
|
||||||
|
devToolbar: { enabled: false },
|
||||||
|
outDir: '../../dist/website',
|
||||||
|
|
||||||
|
prefetch: true,
|
||||||
|
site: 'https://blitzkit.app',
|
||||||
|
});
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "@blitzkit/website-ue",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "astro dev",
|
||||||
|
"build": "astro build",
|
||||||
|
"preview": "astro preview",
|
||||||
|
"astro": "astro",
|
||||||
|
"lint": "astro check"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/partytown": "^2.1.4",
|
||||||
|
"@astrojs/react": "^4.3.0",
|
||||||
|
"@astrojs/sitemap": "^3.2.1",
|
||||||
|
"@astrolib/seo": "^1.0.0-beta.8",
|
||||||
|
"@blitzkit/closed": "workspace:*",
|
||||||
|
"@blitzkit/core": "workspace:*",
|
||||||
|
"@radix-ui/colors": "^3.0.0",
|
||||||
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
|
"@radix-ui/themes": "^3.1.4",
|
||||||
|
"@react-three/drei": "^9.115.0",
|
||||||
|
"@react-three/fiber": "^8.17.10",
|
||||||
|
"@types/ffi-napi": "^4.0.10",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/pako": "^2.0.3",
|
||||||
|
"@types/react": "^19.1.5",
|
||||||
|
"@types/react-dom": "^19.1.5",
|
||||||
|
"@types/ref-napi": "^3.0.12",
|
||||||
|
"@types/semver": "^7.7.0",
|
||||||
|
"@types/three": "^0.160.0",
|
||||||
|
"astro": "^5.8.0",
|
||||||
|
"diff": "^8.0.2",
|
||||||
|
"ffi-napi": "^4.0.3",
|
||||||
|
"fuzzysort": "^3.1.0",
|
||||||
|
"immer": "^10.1.1",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"minimatch": "^10.0.1",
|
||||||
|
"minizlib": "^3.0.2",
|
||||||
|
"pako": "^2.1.0",
|
||||||
|
"react": "^19.1.0",
|
||||||
|
"react-dom": "^19.1.0",
|
||||||
|
"ref-napi": "^3.0.3",
|
||||||
|
"semver": "^7.7.2",
|
||||||
|
"sharp": "^0.34.2",
|
||||||
|
"three": "^0.169.0",
|
||||||
|
"zustand": "^4.5.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_741_237)">
|
||||||
|
<rect width="60" height="60" fill="#FDD1EA"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M54.6274 0L55.4558 0.828427L54.0416 2.24264L51.799 0L54.6274 0ZM5.37258 0L4.54416 0.828427L5.95837 2.24264L8.20101 0L5.37258 0ZM48.9706 0L52.6274 3.65685L51.2132 5.07107L46.1421 0L48.9706 0ZM11.0294 0L7.37258 3.65685L8.7868 5.07107L13.8579 0L11.0294 0ZM43.3137 0L49.799 6.48528L48.3848 7.8995L40.4853 0H43.3137ZM16.6863 0L10.201 6.48528L11.6152 7.8995L19.5147 0L16.6863 0ZM37.6569 0L46.9706 9.31371L45.5564 10.7279L34.8284 0L37.6569 0ZM22.3431 0L13.0294 9.31371L14.4437 10.7279L25.1716 0L22.3431 0ZM32 0L44.1421 12.1421L42.7279 13.5563L30 0.828427L17.2721 13.5563L15.8579 12.1421L28 0H32ZM0.284271 0L28.2843 28L26.8701 29.4142L0 2.54416V0L0.284271 0ZM0 5.37258L25.4558 30.8284L24.0416 32.2426L0 8.20101L0 5.37258ZM0 11.0294L22.6274 33.6569L21.2132 35.0711L0 13.8579L0 11.0294ZM0 16.6863L19.799 36.4853L18.3848 37.8995L0 19.5147L0 16.6863ZM0 22.3431L16.9706 39.3137L15.5563 40.7279L0 25.1716L0 22.3431ZM0 28L14.1421 42.1421L12.7279 43.5564L0 30.8284V28ZM0 33.6569L11.3137 44.9706L9.8995 46.3848L0 36.4853L0 33.6569ZM0 39.3137L8.48528 47.799L7.07107 49.2132L0 42.1421L0 39.3137ZM0 44.9706L5.65685 50.6274L4.24264 52.0416L0 47.799L0 44.9706ZM0 50.6274L2.82843 53.4558L1.41421 54.8701L0 53.4558L0 50.6274ZM54.6274 60L30 35.3726L5.37258 60H8.20101L30 38.201L51.799 60H54.6274ZM48.9706 60L30 41.0294L11.0294 60H13.8579L30 43.8579L46.1421 60H48.9706ZM43.3137 60L30 46.6863L16.6863 60H19.5147L30 49.5147L40.4853 60H43.3137ZM37.6569 60L30 52.3431L22.3431 60H25.1716L30 55.1716L34.8284 60H37.6569ZM32 60L30 58L28 60H32ZM59.7157 0L31.7157 28L33.1299 29.4142L60 2.54416V0L59.7157 0ZM60 5.37258L34.5442 30.8284L35.9584 32.2426L60 8.20101V5.37258ZM60 11.0294L37.3726 33.6569L38.7868 35.0711L60 13.8579V11.0294ZM60 16.6863L40.201 36.4853L41.6152 37.8995L60 19.5147V16.6863ZM60 22.3431L43.0294 39.3137L44.4436 40.7279L60 25.1716V22.3431ZM60 28L45.8579 42.1421L47.2721 43.5564L60 30.8284V28ZM60 33.6569L48.6863 44.9706L50.1005 46.3848L60 36.4853V33.6569ZM60 39.3137L51.5147 47.799L52.9289 49.2132L60 42.1421V39.3137ZM60 44.9706L54.3431 50.6274L55.7574 52.0416L60 47.799V44.9706ZM60 50.6274L57.1716 53.4558L58.5858 54.8701L60 53.4558V50.6274ZM39.8995 16.3848L41.3137 14.9706L30 3.65685L18.6863 14.9706L20.1005 16.3848L30 6.48528L39.8995 16.3848ZM37.0711 19.2132L38.4853 17.799L30 9.31371L21.5147 17.799L22.9289 19.2132L30 12.1421L37.0711 19.2132ZM34.2426 22.0416L35.6569 20.6274L30 14.9706L24.3431 20.6274L25.7574 22.0416L30 17.799L34.2426 22.0416ZM31.4142 24.8701L32.8284 23.4558L30 20.6274L27.1716 23.4558L28.5858 24.8701L30 23.4558L31.4142 24.8701ZM56.8701 59.4142L58.2843 58L30 29.7157L1.71573 58L3.12994 59.4142L30 32.5442L56.8701 59.4142Z" fill="#FFBECE"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_741_237">
|
||||||
|
<rect width="60" height="60" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 676 KiB |
|
After Width: | Height: | Size: 443 KiB |
|
After Width: | Height: | Size: 330 KiB |
|
After Width: | Height: | Size: 715 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 274 KiB |
|
After Width: | Height: | Size: 346 KiB |
|
After Width: | Height: | Size: 406 KiB |
|
After Width: | Height: | Size: 360 KiB |
|
After Width: | Height: | Size: 193 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 692 B |
|
After Width: | Height: | Size: 692 B |
@@ -0,0 +1,10 @@
|
|||||||
|
import { Grade } from '@protos/blitz_static_standard_grades_enum';
|
||||||
|
import type { BadgeProps } from '@radix-ui/themes';
|
||||||
|
|
||||||
|
export const GRADE_COLORS = {
|
||||||
|
[Grade.GRADE_UNSPECIFIED]: 'gray',
|
||||||
|
[Grade.GRADE_COMMON]: 'gray',
|
||||||
|
[Grade.GRADE_RARE]: 'blue',
|
||||||
|
[Grade.GRADE_EPIC]: 'purple',
|
||||||
|
[Grade.GRADE_LEGENDARY]: 'amber',
|
||||||
|
} satisfies Record<Grade, BadgeProps['color']>;
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { type FlexProps, Box, Flex, Skeleton, Text } from '@radix-ui/themes';
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { useIntersection } from '../../hooks/useIntersection';
|
||||||
|
import { useLocale } from '../../hooks/useLocale';
|
||||||
|
import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps';
|
||||||
|
import { InlineSkeleton } from '../InlineSkeleton';
|
||||||
|
import type { AvatarGroupProps } from './Group';
|
||||||
|
import { Stack } from './Stack';
|
||||||
|
|
||||||
|
const MAX_AVATARS_PREVIEW = 5;
|
||||||
|
|
||||||
|
export function Content({
|
||||||
|
...props
|
||||||
|
}: FlexProps & MaybeSkeletonComponentProps<AvatarGroupProps>) {
|
||||||
|
const { strings } = useLocale();
|
||||||
|
const container = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useIntersection(() => props.skeleton && props.onIntersection?.(), container, {
|
||||||
|
disabled: !props.skeleton || props.onIntersection === undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
ref={container}
|
||||||
|
direction="column"
|
||||||
|
gap="3"
|
||||||
|
style={{ cursor: props.skeleton ? undefined : 'pointer' }}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Box width="100%" style={{ aspectRatio: '7 / 8' }} position="relative">
|
||||||
|
{props.skeleton && <Skeleton height="100%" />}
|
||||||
|
|
||||||
|
{!props.skeleton && (
|
||||||
|
<Stack avatars={[...props.avatars].slice(-MAX_AVATARS_PREVIEW)} />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Text
|
||||||
|
size="2"
|
||||||
|
wrap="nowrap"
|
||||||
|
align="center"
|
||||||
|
style={{
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
fontStyle:
|
||||||
|
!props.skeleton && props.name === undefined ? 'italic' : undefined,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.skeleton ? (
|
||||||
|
<InlineSkeleton width="100%" />
|
||||||
|
) : (
|
||||||
|
(props.name ?? strings.website.tools.avatars.unnamed_avatars)
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import type { BlitzKitAvatar } from '@protos/blitzkit';
|
||||||
|
import { Dialog } from '@radix-ui/themes';
|
||||||
|
import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps';
|
||||||
|
import { Content } from './Content';
|
||||||
|
import { Popup } from './Popup';
|
||||||
|
|
||||||
|
export interface AvatarGroupProps {
|
||||||
|
name?: string;
|
||||||
|
avatars: { avatar: BlitzKitAvatar }[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AvatarGroup(
|
||||||
|
props: MaybeSkeletonComponentProps<AvatarGroupProps>,
|
||||||
|
) {
|
||||||
|
if (props.skeleton) return <Content {...props} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog.Root>
|
||||||
|
<Dialog.Trigger>
|
||||||
|
<Content {...props} />
|
||||||
|
</Dialog.Trigger>
|
||||||
|
|
||||||
|
<Dialog.Content>
|
||||||
|
<Popup {...props} />
|
||||||
|
</Dialog.Content>
|
||||||
|
</Dialog.Root>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { Grade } from '@protos/blitz_static_standard_grades_enum';
|
||||||
|
import {
|
||||||
|
CardStackIcon,
|
||||||
|
DownloadIcon,
|
||||||
|
ExternalLinkIcon,
|
||||||
|
EyeNoneIcon,
|
||||||
|
StarFilledIcon,
|
||||||
|
} from '@radix-ui/react-icons';
|
||||||
|
import { Badge, Box, Button, Dialog, Flex, Link, Text } from '@radix-ui/themes';
|
||||||
|
import { Var } from '../../core/radix/var';
|
||||||
|
import { useLocale } from '../../hooks/useLocale';
|
||||||
|
import { RewardBadge } from '../RewardBadge';
|
||||||
|
import { GRADE_COLORS } from './Colors';
|
||||||
|
import type { AvatarGroupProps } from './Group';
|
||||||
|
|
||||||
|
export function Popup({ name, avatars }: AvatarGroupProps) {
|
||||||
|
const { strings, gameStrings } = useLocale();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Dialog.Title>{name}</Dialog.Title>
|
||||||
|
|
||||||
|
<Flex direction="column" gap="5" mt="5">
|
||||||
|
{[...avatars].reverse().map(({ avatar }, index) => (
|
||||||
|
<Flex key={index} gap="5">
|
||||||
|
<Box
|
||||||
|
m="1"
|
||||||
|
mb="4"
|
||||||
|
height="10rem"
|
||||||
|
style={{
|
||||||
|
aspectRatio: '7 / 8',
|
||||||
|
borderRadius: Var('radius-4'),
|
||||||
|
outline: `${Var('space-1')} solid ${Var(`${GRADE_COLORS[avatar.grade]}-9`)}`,
|
||||||
|
boxShadow: `0 0 ${
|
||||||
|
1.5 * (avatar.grade / Grade.GRADE_LEGENDARY)
|
||||||
|
}rem ${Var(`${GRADE_COLORS[avatar.grade]}-9`)}`,
|
||||||
|
backgroundImage: 'url(/assets/sad-ghost.png)',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundSize: '3rem',
|
||||||
|
}}
|
||||||
|
position="relative"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(/api/avatars/${avatar.id}.webp)`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Badge
|
||||||
|
mt="1"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '100%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
}}
|
||||||
|
variant="solid"
|
||||||
|
color={GRADE_COLORS[avatar.grade]}
|
||||||
|
>
|
||||||
|
<StarFilledIcon /> {strings.common.grades[avatar.grade]}
|
||||||
|
</Badge>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Flex direction="column" gap="3" justify="center">
|
||||||
|
<Flex gap="1">
|
||||||
|
<Badge color="gray" variant="surface">
|
||||||
|
<CardStackIcon />
|
||||||
|
{strings.website.tools.avatars.categories[avatar.category]}
|
||||||
|
</Badge>
|
||||||
|
|
||||||
|
{avatar.hidden_if_not_obtained && (
|
||||||
|
<Badge color="gray" variant="surface">
|
||||||
|
<EyeNoneIcon /> {strings.website.tools.avatars.hidden}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{avatar.sale && (
|
||||||
|
<RewardBadge
|
||||||
|
reward={avatar.sale}
|
||||||
|
color="gray"
|
||||||
|
variant="surface"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Text>
|
||||||
|
{gameStrings[avatar.description] ??
|
||||||
|
(gameStrings[avatar.obtaining]
|
||||||
|
? undefined
|
||||||
|
: strings.website.tools.avatars.no_description)}{' '}
|
||||||
|
{gameStrings[avatar.obtaining]}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Flex gap="2">
|
||||||
|
<Link href={`/api/avatars/${avatar.id}.webp`} download>
|
||||||
|
<Button variant="solid">
|
||||||
|
<DownloadIcon /> {strings.website.tools.avatars.download}
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link href={`/api/avatars/${avatar.id}.webp`} target="_blank">
|
||||||
|
<Button variant="outline">
|
||||||
|
<ExternalLinkIcon /> {strings.website.tools.avatars.enlarge}
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { Badge, Box } from '@radix-ui/themes';
|
||||||
|
import { literals } from 'packages/i18n/src';
|
||||||
|
import { Var } from '../../core/radix/var';
|
||||||
|
import { useLocale } from '../../hooks/useLocale';
|
||||||
|
import type { AvatarGroupProps } from './Group';
|
||||||
|
|
||||||
|
const dx = '4px';
|
||||||
|
|
||||||
|
export function Stack({ avatars }: { avatars: AvatarGroupProps['avatars'] }) {
|
||||||
|
const { strings } = useLocale();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{avatars.map(({ avatar }, index) => (
|
||||||
|
<Box
|
||||||
|
key={index}
|
||||||
|
position="absolute"
|
||||||
|
top={`calc(${dx} * ${index})`}
|
||||||
|
left={`calc(${dx} * ${index})`}
|
||||||
|
width={`calc(100% - ${dx} * ${avatars.length - 1})`}
|
||||||
|
height={`calc(100% - ${dx} * ${avatars.length - 1})`}
|
||||||
|
style={{
|
||||||
|
filter: `brightness(${(index + 1) / avatars.length})`,
|
||||||
|
borderRadius: Var('radius-4'),
|
||||||
|
boxShadow: Var('shadow-2'),
|
||||||
|
overflow: 'hidden',
|
||||||
|
backgroundImage: 'url(/assets/sad-ghost.png)',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundSize: '3rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(/api/avatars/${avatar.id}.webp)`,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{avatars.length > 1 && index === avatars.length - 1 && (
|
||||||
|
<Box
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{
|
||||||
|
background: `linear-gradient(-45deg, ${Var('black-a9')} 25%, ${Var('black-a1')} 50%)`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{avatars.length > 1 && (
|
||||||
|
<Box position="absolute" bottom="1" right="1">
|
||||||
|
<Badge variant="solid" color="gray" highContrast size="2">
|
||||||
|
{literals(strings.common.units.times, [`${avatars.length}`])}
|
||||||
|
</Badge>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Theme, type ThemeProps } from '@radix-ui/themes';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface BlitzKitThemeProps extends ThemeProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BlitzKitTheme({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
style,
|
||||||
|
...props
|
||||||
|
}: BlitzKitThemeProps) {
|
||||||
|
return (
|
||||||
|
<Theme
|
||||||
|
style={{ minHeight: 'unset', display: 'contents', ...style }}
|
||||||
|
className={`blitzkit-theme ${className}`}
|
||||||
|
grayColor="mauve"
|
||||||
|
appearance="dark"
|
||||||
|
panelBackground="solid"
|
||||||
|
radius="full"
|
||||||
|
accentColor="iris"
|
||||||
|
suppressHydrationWarning
|
||||||
|
suppressContentEditableWarning
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Theme>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
.policies-agreement {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--color-overlay);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.policies-agreement .content-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--color-panel-solid);
|
||||||
|
}
|
||||||
|
|
||||||
|
.policies-agreement .content {
|
||||||
|
max-width: 60rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import { assertSecret, idToRegion } from '@blitzkit/core';
|
||||||
|
import { Button, Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
LocaleProvider,
|
||||||
|
useLocale,
|
||||||
|
type LocaleAcceptorProps,
|
||||||
|
} from '../../hooks/useLocale';
|
||||||
|
import { App } from '../../stores/app';
|
||||||
|
import { CURRENT_POLICIES_AGREEMENT_INDEX } from '../../stores/app/constants';
|
||||||
|
|
||||||
|
import { LinkI18n } from '../LinkI18n';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
type Extension =
|
||||||
|
| {
|
||||||
|
status: 'ok';
|
||||||
|
data: {
|
||||||
|
access_token: string;
|
||||||
|
account_id: number;
|
||||||
|
expires_at: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
status: 'error';
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Checks({ localeData }: LocaleAcceptorProps) {
|
||||||
|
return (
|
||||||
|
<LocaleProvider localeData={localeData}>
|
||||||
|
<App.Provider>
|
||||||
|
<Content />
|
||||||
|
</App.Provider>
|
||||||
|
</LocaleProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wargaming: 14 (refresh: 7)
|
||||||
|
*/
|
||||||
|
function Content() {
|
||||||
|
const { locale } = useLocale();
|
||||||
|
const logins = App.use((state) => state.logins);
|
||||||
|
const mutateApp = App.useMutation();
|
||||||
|
const appStore = App.useStore();
|
||||||
|
const policiesAgreementIndex = App.use(
|
||||||
|
(state) => state.policiesAgreementIndex,
|
||||||
|
);
|
||||||
|
const isLegal = window.location.pathname.startsWith('/legal');
|
||||||
|
const [showPoliciesAgreement, setShowPoliciesAgreement] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function unsubscribe() {
|
||||||
|
window.removeEventListener('scroll', show);
|
||||||
|
window.removeEventListener('pointermove', show);
|
||||||
|
window.removeEventListener('pointerdown', show);
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
setShowPoliciesAgreement(true);
|
||||||
|
unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
policiesAgreementIndex !== CURRENT_POLICIES_AGREEMENT_INDEX &&
|
||||||
|
!isLegal
|
||||||
|
) {
|
||||||
|
window.addEventListener('scroll', show);
|
||||||
|
window.addEventListener('pointermove', show);
|
||||||
|
window.addEventListener('pointerdown', show);
|
||||||
|
}
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
}, [policiesAgreementIndex, isLegal]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (logins.wargaming) {
|
||||||
|
const expiresIn = logins.wargaming.expires - Date.now();
|
||||||
|
const expiresInDays = expiresIn / 1000 / 60 / 60 / 24;
|
||||||
|
|
||||||
|
if (expiresInDays < 0) {
|
||||||
|
mutateApp((draft) => {
|
||||||
|
draft.logins.wargaming = undefined;
|
||||||
|
});
|
||||||
|
} else if (expiresInDays < 7) {
|
||||||
|
const { wargaming } = appStore.getState().logins;
|
||||||
|
|
||||||
|
if (!wargaming) return;
|
||||||
|
|
||||||
|
fetch(
|
||||||
|
`https://api.worldoftanks.${idToRegion(
|
||||||
|
wargaming.id,
|
||||||
|
)}/wot/auth/prolongate/?application_id=${assertSecret(
|
||||||
|
import.meta.env.PUBLIC_WARGAMING_APPLICATION_ID,
|
||||||
|
)}&access_token=${wargaming.token}`,
|
||||||
|
)
|
||||||
|
.then((response) => response.json() as Promise<Extension>)
|
||||||
|
.then((json) => {
|
||||||
|
mutateApp((draft) => {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!showPoliciesAgreement) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex className="policies-agreement" align="end">
|
||||||
|
<Flex p="8" className="content-wrapper" justify="center">
|
||||||
|
<Flex align="start" gap="4" className="content" direction="column">
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
<Heading>
|
||||||
|
{policiesAgreementIndex === -1
|
||||||
|
? "BlitzKit's policies"
|
||||||
|
: "BlitzKit's policies have changed"}
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<Text>
|
||||||
|
This website utilizes cookies to perform analytics and personalize
|
||||||
|
your experience. You can learn more through{' '}
|
||||||
|
<LinkI18n locale={locale} href="/docs/legal/privacy-policy">
|
||||||
|
our privacy policy
|
||||||
|
</LinkI18n>
|
||||||
|
. By using BlitzKit, you also agree to our{' '}
|
||||||
|
<LinkI18n locale={locale} href="/docs/legal/terms-of-service">
|
||||||
|
terms of service
|
||||||
|
</LinkI18n>
|
||||||
|
.
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
mt="2"
|
||||||
|
onClick={() => {
|
||||||
|
appStore.setState({
|
||||||
|
policiesAgreementIndex: CURRENT_POLICIES_AGREEMENT_INDEX,
|
||||||
|
});
|
||||||
|
setShowPoliciesAgreement(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
I agree
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Permission denied
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
---
|
||||||
|
import { Box, Code, Flex, Heading, Link, Text } from '@radix-ui/themes';
|
||||||
|
import packageJson from '../../../../package.json';
|
||||||
|
import { getStrings } from '../core/i18n/getStrings';
|
||||||
|
import { LinkI18n } from './LinkI18n';
|
||||||
|
import { LocaleSwitcherThemeWrapper } from './LocaleSwitcher';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
locale: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { locale } = Astro.props;
|
||||||
|
const localeData = { locale };
|
||||||
|
const strings = await getStrings(locale);
|
||||||
|
---
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.footer {
|
||||||
|
background-color: var(--color-panel);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<Flex className="footer" gap="6" p="6" direction="column" align="center">
|
||||||
|
<Flex
|
||||||
|
align="center"
|
||||||
|
justify="between"
|
||||||
|
maxWidth="40rem"
|
||||||
|
width="100%"
|
||||||
|
flexGrow="1"
|
||||||
|
gap="5"
|
||||||
|
position="relative"
|
||||||
|
direction={{ initial: 'column', sm: 'row' }}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
align={{
|
||||||
|
initial: 'center',
|
||||||
|
sm: 'start',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex align="center" gap="2">
|
||||||
|
<Heading> BlitzKit </Heading>
|
||||||
|
<Code size="1" color="gray" variant="ghost">{packageJson.version}</Code>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Text color="gray">{strings.website.footer.motto}</Text>
|
||||||
|
<Text size="1" color="gray">
|
||||||
|
{strings.website.footer.copyright}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Box mt="2">
|
||||||
|
<LocaleSwitcherThemeWrapper {localeData} client:load />
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
gap="6"
|
||||||
|
width={{
|
||||||
|
initial: '100%',
|
||||||
|
sm: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
gap="1"
|
||||||
|
align={{
|
||||||
|
initial: 'end',
|
||||||
|
sm: 'start',
|
||||||
|
}}
|
||||||
|
flexGrow={{
|
||||||
|
initial: '1',
|
||||||
|
sm: '0',
|
||||||
|
}}
|
||||||
|
flexBasis={{
|
||||||
|
initial: '0',
|
||||||
|
sm: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Heading size="3">{strings.website.footer.about.title}</Heading>
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
align={{
|
||||||
|
initial: 'end',
|
||||||
|
sm: 'start',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LinkI18n {locale} href="/docs/about/credits" color="gray">
|
||||||
|
{strings.website.footer.about.credits}
|
||||||
|
</LinkI18n>
|
||||||
|
<Link
|
||||||
|
href="https://discord.gg/nDt7AjGJQH"
|
||||||
|
target="_blank"
|
||||||
|
color="gray"
|
||||||
|
>
|
||||||
|
{strings.website.footer.about.discord}
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="https://github.com/tresabhi/blitzkit"
|
||||||
|
target="_blank"
|
||||||
|
color="gray"
|
||||||
|
>
|
||||||
|
{strings.website.footer.about.github}
|
||||||
|
</Link>
|
||||||
|
<LinkI18n {locale} href="/docs/patches" color="gray">
|
||||||
|
{strings.website.footer.about.patches}
|
||||||
|
</LinkI18n>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
gap="1"
|
||||||
|
flexGrow={{
|
||||||
|
initial: '1',
|
||||||
|
sm: '0',
|
||||||
|
}}
|
||||||
|
flexBasis={{
|
||||||
|
initial: '0',
|
||||||
|
sm: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Heading size="3">{strings.website.footer.legal.title}</Heading>
|
||||||
|
<Flex direction="column">
|
||||||
|
<LinkI18n {locale} href="/docs/legal/privacy-policy" color="gray">
|
||||||
|
{strings.website.footer.legal.privacy}
|
||||||
|
</LinkI18n>
|
||||||
|
<LinkI18n {locale} href="/docs/legal/terms-of-service" color="gray">
|
||||||
|
{strings.website.footer.legal.terms}
|
||||||
|
</LinkI18n>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
---
|
||||||
|
import { Code, Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
|
import { resolveBranchName } from '../core/blitzkit/branches';
|
||||||
|
import { getStrings } from '../core/i18n/getStrings';
|
||||||
|
import { literals } from '@blitzkit/i18n/src/literals';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
locale: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { locale } = Astro.props;
|
||||||
|
const strings = await getStrings(locale);
|
||||||
|
const branchName = resolveBranchName();
|
||||||
|
const isBranchNamed = branchName !== undefined;
|
||||||
|
---
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#home-hero {
|
||||||
|
--p-1: 0%;
|
||||||
|
--p-2: 0%;
|
||||||
|
--p-3: 0%;
|
||||||
|
--p-4: 0%;
|
||||||
|
--p-7: 0%;
|
||||||
|
|
||||||
|
--g-1-dark: var(--blue-3);
|
||||||
|
--g-1-light: var(--blue-7);
|
||||||
|
--g-2-dark: var(--violet-3);
|
||||||
|
--g-2-light: var(--violet-7);
|
||||||
|
--g-3-dark: var(--purple-3);
|
||||||
|
--g-3-light: var(--purple-7);
|
||||||
|
--g-4-dark: var(--crimson-3);
|
||||||
|
--g-4-light: var(--crimson-7);
|
||||||
|
--g-7-dark: var(--tomato-3);
|
||||||
|
--g-7-light: var(--tomato-7);
|
||||||
|
|
||||||
|
--g-1: color-mix(in srgb, var(--g-1-dark), var(--g-1-light) var(--p-1));
|
||||||
|
--g-2: color-mix(in srgb, var(--g-2-dark), var(--g-2-light) var(--p-2));
|
||||||
|
--g-3: color-mix(in srgb, var(--g-3-dark), var(--g-3-light) var(--p-3));
|
||||||
|
--g-4: color-mix(in srgb, var(--g-4-dark), var(--g-4-light) var(--p-4));
|
||||||
|
--g-7: color-mix(in srgb, var(--g-7-dark), var(--g-7-light) var(--p-7));
|
||||||
|
|
||||||
|
background: linear-gradient(
|
||||||
|
45deg,
|
||||||
|
var(--g-1),
|
||||||
|
var(--g-2),
|
||||||
|
var(--g-3),
|
||||||
|
var(--g-4),
|
||||||
|
var(--g-7)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-hero[data-variant='pride'] {
|
||||||
|
--g-1-dark: var(--crimson-3);
|
||||||
|
--g-1-light: var(--crimson-7);
|
||||||
|
--g-2-dark: var(--orange-3);
|
||||||
|
--g-2-light: var(--orange-7);
|
||||||
|
--g-3-dark: var(--yellow-3);
|
||||||
|
--g-3-light: var(--yellow-7);
|
||||||
|
--g-4-dark: var(--blue-3);
|
||||||
|
--g-4-light: var(--blue-7);
|
||||||
|
--g-7-dark: var(--purple-3);
|
||||||
|
--g-7-light: var(--purple-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#home-hero[data-variant='spooky'] {
|
||||||
|
--g-1-dark: var(--orange-3);
|
||||||
|
--g-1-light: var(--orange-7);
|
||||||
|
--g-2-dark: var(--tomato-3);
|
||||||
|
--g-2-light: var(--tomato-7);
|
||||||
|
--g-3-dark: var(--orange-3);
|
||||||
|
--g-3-light: var(--orange-7);
|
||||||
|
--g-4-dark: var(--tomato-3);
|
||||||
|
--g-4-light: var(--tomato-7);
|
||||||
|
--g-7-dark: var(--orange-3);
|
||||||
|
--g-7-light: var(--orange-7);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { clamp, times } from 'lodash-es';
|
||||||
|
|
||||||
|
const n = 5;
|
||||||
|
const homeHero = document.getElementById('home-hero');
|
||||||
|
|
||||||
|
if (homeHero) {
|
||||||
|
switch (new Date().getMonth()) {
|
||||||
|
case 5:
|
||||||
|
homeHero.dataset.variant = 'pride';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
homeHero.dataset.variant = 'spooky';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('pointermove', (event) => {
|
||||||
|
const x = event.clientX / window.innerWidth;
|
||||||
|
const c = clamp(
|
||||||
|
(1 -
|
||||||
|
(event.clientY + homeHero.getBoundingClientRect().top) /
|
||||||
|
window.innerHeight) **
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
|
// https://www.desmos.com/calculator/ndz2poxk32
|
||||||
|
times(n, (i) => {
|
||||||
|
const p = c * clamp(-n * Math.abs(x - i / (n - 1)) + 1, 0, 3);
|
||||||
|
homeHero.style.setProperty(`--p-${i + 1}`, `${p * 100}%`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
id="home-hero"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
position="relative"
|
||||||
|
px="4"
|
||||||
|
py="9"
|
||||||
|
overflow="hidden"
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
gap="6"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
position="relative"
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
|
<Flex direction="column" align="center" gap="1">
|
||||||
|
<Heading size={{ initial: '8', xs: '9' }} weight="bold" align="center">
|
||||||
|
<Flex align="center" gap={{ initial: '2', xs: '4' }}>
|
||||||
|
BlitzKit
|
||||||
|
{
|
||||||
|
isBranchNamed && (
|
||||||
|
<Code
|
||||||
|
size={{ initial: '7', xs: '8' }}
|
||||||
|
color="gray"
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
{branchName}
|
||||||
|
</Code>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Flex>
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<Text color="gray" align="center" size="4"
|
||||||
|
>{literals(strings.website.home.hero.credit, ['TrèsAbhi'])}</Text
|
||||||
|
>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { Skeleton, type SkeletonProps } from '@radix-ui/themes';
|
||||||
|
|
||||||
|
export function InlineSkeleton({ className, ...props }: SkeletonProps) {
|
||||||
|
return (
|
||||||
|
<Skeleton style={{ display: 'inline-block' }} height="1em" {...props} />
|
||||||
|
);
|
||||||
|
}
|
||||||