mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-11 11:46:10 +01:00
Compare commits
212
Commits
907e71ce03
...
v1.29.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eed9d23646 | ||
|
|
2101dba7c6 | ||
|
|
1b398a5f66 | ||
|
|
d8f9a2633d | ||
|
|
2e79ccf7eb | ||
|
|
be778acf39 | ||
|
|
8d10d7cffa | ||
|
|
5b9041a972 | ||
|
|
1e60b1f61f | ||
|
|
13a636c023 | ||
|
|
8bc0693f3b | ||
|
|
9b842c501c | ||
|
|
8aadda4fb8 | ||
|
|
58c70f98e1 | ||
|
|
54b73d11ce | ||
|
|
d1ac5644a4 | ||
|
|
ae35c1516c | ||
|
|
fd364d434f | ||
|
|
fd37f72f8c | ||
|
|
1427f61c52 | ||
|
|
cd4fa366a0 | ||
|
|
344e7caa81 | ||
|
|
fe7b2aea02 | ||
|
|
fced1e96ef | ||
|
|
778efb2372 | ||
|
|
b67fd5b58c | ||
|
|
2559782a28 | ||
|
|
efb479fece | ||
|
|
fb829d4b81 | ||
|
|
91f4f2edcf | ||
|
|
a692d1ee0b | ||
|
|
31d2ab4746 | ||
|
|
e4e2c30748 | ||
|
|
d633874d90 | ||
|
|
9cb1d0cb3f | ||
|
|
a0bccc7973 | ||
|
|
3efe807e35 | ||
|
|
1cc15f64b0 | ||
|
|
f70864a0db | ||
|
|
5de40b220f | ||
|
|
bd19c9aac9 | ||
|
|
6bc5b7dcb6 | ||
|
|
00795eecdd | ||
|
|
f4e7b2ed98 | ||
|
|
81612793e3 | ||
|
|
d3bdbc39d2 | ||
|
|
7cb67bd44b | ||
|
|
9df09c9a53 | ||
|
|
a9f1d9ebec | ||
|
|
1b834eb848 | ||
|
|
c5518ec9bc | ||
|
|
8c705d7e2e | ||
|
|
efe9f91a2d | ||
|
|
e84bf6b31c | ||
|
|
46234b6cbb | ||
|
|
0bda743a91 | ||
|
|
b19866a1f5 | ||
|
|
9ca329e53f | ||
|
|
47b1eb9ab0 | ||
|
|
6c8fbf7245 | ||
|
|
2ea22512d4 | ||
|
|
697d1fa1b4 | ||
|
|
e4429f15bd | ||
|
|
cd8083ae30 | ||
|
|
9dcf7441c9 | ||
|
|
d4e1f99ce2 | ||
|
|
98de246578 | ||
|
|
45097f198c | ||
|
|
e063719caa | ||
|
|
975d579d21 | ||
|
|
b963ef0981 | ||
|
|
49fab21113 | ||
|
|
cbde48d41b | ||
|
|
1210baa545 | ||
|
|
2c03b530d2 | ||
|
|
ec977899fb | ||
|
|
e5fc2faad7 | ||
|
|
541dfc186b | ||
|
|
182471c4d6 | ||
|
|
e5c66cf232 | ||
|
|
fbbc0b82b4 | ||
|
|
aecc2adb07 | ||
|
|
f8ee2b64a6 | ||
|
|
7c4e28bd09 | ||
|
|
80d61d9e04 | ||
|
|
0c22ac3a97 | ||
|
|
efad6e61f7 | ||
|
|
3563aaecd5 | ||
|
|
5294de848f | ||
|
|
e82aa56cb2 | ||
|
|
e1b2b130a5 | ||
|
|
28f22f1d40 | ||
|
|
a3bb023309 | ||
|
|
797307fb81 | ||
|
|
f9802b44ff | ||
|
|
e26b9c78a3 | ||
|
|
925ae1a0b7 | ||
|
|
9584ecf38b | ||
|
|
338168d7e4 | ||
|
|
711d92887e | ||
|
|
78160041e8 | ||
|
|
1b884a52f9 | ||
|
|
f13c658ef4 | ||
|
|
b72d4058be | ||
|
|
029a781c50 | ||
|
|
adc1791f56 | ||
|
|
15b6ff43c5 | ||
|
|
e2c02f3d86 | ||
|
|
3ce47f6ed0 | ||
|
|
fa91b37d92 | ||
|
|
108644bd44 | ||
|
|
413436376b | ||
|
|
7d118015d0 | ||
|
|
92e7390a5d | ||
|
|
475e25a0d8 | ||
|
|
17115af0d8 | ||
|
|
a9894ade78 | ||
|
|
f5b09873a9 | ||
|
|
ac768d0897 | ||
|
|
f802b997c0 | ||
|
|
db94edea69 | ||
|
|
0809c9ee0c | ||
|
|
0326e8d1d7 | ||
|
|
912c1fb125 | ||
|
|
d07383a722 | ||
|
|
582e608203 | ||
|
|
501a618d5f | ||
|
|
7c7f34d899 | ||
|
|
864d34f344 | ||
|
|
9201fc72ce | ||
|
|
50f82d68b4 | ||
|
|
b81f664379 | ||
|
|
389707d0c8 | ||
|
|
9fbd623d91 | ||
|
|
f36df9e902 | ||
|
|
437bbfdc89 | ||
|
|
7becb7b6ad | ||
|
|
94e8a07f90 | ||
|
|
4ae5283ac4 | ||
|
|
ade238966b | ||
|
|
ea048da7a2 | ||
|
|
263f292a59 | ||
|
|
ff4a87e5b8 | ||
|
|
222b690fba | ||
|
|
e1a6e4e38d | ||
|
|
37adc04cda | ||
|
|
3fc7279f0e | ||
|
|
bd852b9368 | ||
|
|
26304fc281 | ||
|
|
0d8cb5c1ae | ||
|
|
dc60cffdff | ||
|
|
a3e74de277 | ||
|
|
49b5d4f7dc | ||
|
|
2c55455cd7 | ||
|
|
648ac57424 | ||
|
|
5e3cf816ee | ||
|
|
98ea42c7b0 | ||
|
|
873c8a54d3 | ||
|
|
927495ca16 | ||
|
|
cc957466fc | ||
|
|
ef173758aa | ||
|
|
bfceacdf3c | ||
|
|
ed0dde37d2 | ||
|
|
5ba64f231a | ||
|
|
1f06b1fef4 | ||
|
|
7b0625fc8d | ||
|
|
5dce234447 | ||
|
|
0f609717d0 | ||
|
|
3958709348 | ||
|
|
2d869c9fac | ||
|
|
82afaf9494 | ||
|
|
b1d82e624a | ||
|
|
9b60d56a36 | ||
|
|
ee0d4f6996 | ||
|
|
2d43408822 | ||
|
|
868f132105 | ||
|
|
ce428e093b | ||
|
|
ab430dc0ca | ||
|
|
03a51c47bb | ||
|
|
1790443698 | ||
|
|
a60f95340c | ||
|
|
e407463ca7 | ||
|
|
61cc15aafc | ||
|
|
1a947a6300 | ||
|
|
75262647f7 | ||
|
|
9914371dd8 | ||
|
|
a4e48a2feb | ||
|
|
4ab03e56a2 | ||
|
|
06a3791ddd | ||
|
|
36cce4b0c1 | ||
|
|
158141fdc7 | ||
|
|
1d319551e7 | ||
|
|
0552ac790e | ||
|
|
5ad7566874 | ||
|
|
638f178fbf | ||
|
|
1e996cb970 | ||
|
|
8639b31b8f | ||
|
|
889a92e98b | ||
|
|
e7fe3a4baf | ||
|
|
ab10343704 | ||
|
|
9412be2d7c | ||
|
|
66cf590f1c | ||
|
|
7c18549c00 | ||
|
|
9b97d3e27d | ||
|
|
aadc252e47 | ||
|
|
320a764d45 | ||
|
|
5594c0ec3b | ||
|
|
3d69d464f5 | ||
|
|
dd0b2bade7 | ||
|
|
99c90cfa9e | ||
|
|
dd3ce21508 | ||
|
|
b512cb2292 |
No files matched your search
@@ -1,4 +1,4 @@
|
|||||||
name: Build Assets
|
name: Assets
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -6,30 +6,30 @@ on:
|
|||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
cdn_branch:
|
asset_repo:
|
||||||
|
type: choice
|
||||||
|
required: false
|
||||||
|
description: What asset repo to write to
|
||||||
|
options:
|
||||||
|
- blitzkit/assets
|
||||||
|
- blitzkit/assets-preview
|
||||||
|
- blitzkit/assets-dev
|
||||||
|
default: blitzkit/assets
|
||||||
|
|
||||||
|
archive_url:
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: main
|
description: Archive URL to download instead of Steam client
|
||||||
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:
|
schedule:
|
||||||
- cron: '0 2 * * *'
|
- cron: "0 2 * * *"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.cdn_branch }}
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.asset_repo }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||||
@@ -37,8 +37,8 @@ env:
|
|||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||||
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
|
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||||
PUBLIC_ASSET_REPO: blitzkit/assets
|
PUBLIC_ASSET_REPO: ${{ github.event.inputs.asset_repo != '' && github.event.inputs.asset_repo || secrets.PUBLIC_ASSET_REPO }}
|
||||||
PUBLIC_ASSET_BRANCH: main
|
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||||
@@ -54,100 +54,28 @@ env:
|
|||||||
PUBLIC_ASSET_FAST_USER: blitzkit
|
PUBLIC_ASSET_FAST_USER: blitzkit
|
||||||
PUBLIC_ASSET_FAST_REPO: assets
|
PUBLIC_ASSET_FAST_REPO: assets
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
||||||
|
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||||
|
|
||||||
jobs:
|
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:
|
build_assets:
|
||||||
name: Build assets
|
name: Build assets
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: download_client
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- 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:
|
with:
|
||||||
name: depots
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
path: depots
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: AppArmor hack
|
- name: AppArmor hack
|
||||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
||||||
|
|
||||||
- name: Start server and build assets
|
- name: Build assets
|
||||||
run: |
|
run: bun run build:assets --all-targets --manual
|
||||||
bun dev:website --verbosepa &
|
|
||||||
SERVER_PID=$!
|
|
||||||
|
|
||||||
bun run build:assets --all-targets --depot --production
|
|
||||||
|
|
||||||
kill $SERVER_PID || true
|
|
||||||
@@ -3,7 +3,7 @@ name: Averages
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 8 * * *'
|
- cron: "0 8 * * *"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
@@ -15,7 +15,7 @@ env:
|
|||||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||||
ALLOW_ROBOTS: 'true'
|
ALLOW_ROBOTS: "true"
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
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_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||||
@@ -25,6 +25,7 @@ env:
|
|||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -32,16 +33,20 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Build averages
|
- name: Build averages
|
||||||
env:
|
env:
|
||||||
PUBLIC_ASSET_BRANCH: main
|
PUBLIC_ASSET_BRANCH: main
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
name: Build Bot
|
name: Bot
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -15,13 +15,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
- name: Build Prisma
|
|
||||||
run: bun run build:prisma
|
|
||||||
|
|
||||||
- name: Build bot
|
- name: Build bot
|
||||||
run: bun run build:bot
|
run: bun run build:bot
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
name: Discover IDs
|
name: IDs
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 1'
|
- cron: "0 0 * * 1"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
@@ -11,11 +11,11 @@ concurrency:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -23,10 +23,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Discover IDs
|
- name: Discover IDs
|
||||||
run: bun build:ids --production
|
run: bun build:ids --production
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
name: Host Bot
|
name: Host
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: main
|
branches: main
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 */5 * * *'
|
- cron: "0 */5 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
release:
|
release:
|
||||||
types: [created, published, released, edited]
|
types: [created, published, released, edited]
|
||||||
@@ -35,6 +35,7 @@ env:
|
|||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||||
SERVICING: ${{ secrets.SERVICING }}
|
SERVICING: ${{ secrets.SERVICING }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -42,8 +43,9 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
# with:
|
- uses: arduino/setup-protoc@v3
|
||||||
# bun-version: 1.1.33
|
with:
|
||||||
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- name: Download release assets
|
- name: Download release assets
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -3,7 +3,29 @@ name: Rating Asia
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 17 * * *'
|
- cron: "0 17 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PUBLIC_ASSET_BRANCH: main
|
||||||
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
|
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 }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -11,31 +33,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Generate leaderboard
|
- 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
|
run: bun build:ratingleaderboard --region=asia
|
||||||
@@ -3,7 +3,29 @@ name: Rating Europe
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 23 * * *'
|
- cron: "0 23 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PUBLIC_ASSET_BRANCH: main
|
||||||
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
|
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 }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -11,31 +33,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Generate leaderboard
|
- 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
|
run: bun build:ratingleaderboard --region=eu
|
||||||
@@ -3,7 +3,29 @@ name: Rating North America
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 5 * * *'
|
- cron: "0 5 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PUBLIC_ASSET_BRANCH: main
|
||||||
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
|
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
||||||
|
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 }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
host:
|
host:
|
||||||
@@ -11,31 +33,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Generate leaderboard
|
- 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
|
run: bun build:ratingleaderboard --region=com
|
||||||
@@ -11,12 +11,13 @@ concurrency:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -27,11 +28,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
- name: Install dependencies
|
with:
|
||||||
run: bun install
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Find reviews
|
- name: Find reviews
|
||||||
run: bun packages/scripts/src/reviews.ts
|
run: bun run build:reviews
|
||||||
@@ -5,7 +5,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 4 * * *'
|
- cron: "0 4 * * *"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@@ -31,6 +31,7 @@ env:
|
|||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||||
SERVICING: ${{ secrets.SERVICING }}
|
SERVICING: ${{ secrets.SERVICING }}
|
||||||
|
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -41,12 +42,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v1
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
- uses: arduino/setup-protoc@v3
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
- uses: actions/configure-pages@v5
|
- uses: actions/configure-pages@v5
|
||||||
|
- run: bun run setup
|
||||||
- name: Install dependencies
|
|
||||||
run: bun install
|
|
||||||
|
|
||||||
- name: Build website
|
- name: Build website
|
||||||
run: bun run build:website
|
run: bun run build:website
|
||||||
|
|||||||
+3
-9
@@ -1,9 +1,3 @@
|
|||||||
[submodule "submodules/blitzkit-closed"]
|
[submodule "packages/closed"]
|
||||||
path = submodules/blitzkit-closed
|
path = packages/closed
|
||||||
url = https://github.com/tresabhi/blitzkit-closed
|
url = https://github.com/blitzkit/closed.git
|
||||||
[submodule "submodules/CUE4Parse"]
|
|
||||||
path = submodules/CUE4Parse
|
|
||||||
url = https://github.com/FabianFG/CUE4Parse
|
|
||||||
[submodule "submodules/blitzkit-internal"]
|
|
||||||
path = submodules/blitzkit-internal
|
|
||||||
url = https://github.com/blitzkit/internal
|
|
||||||
Vendored
+18
@@ -11,6 +11,7 @@
|
|||||||
"analyticsreporting",
|
"analyticsreporting",
|
||||||
"APAC",
|
"APAC",
|
||||||
"apcr",
|
"apcr",
|
||||||
|
"appinfo",
|
||||||
"applypatches",
|
"applypatches",
|
||||||
"artefacts",
|
"artefacts",
|
||||||
"astrojs",
|
"astrojs",
|
||||||
@@ -34,12 +35,14 @@
|
|||||||
"blitzkit",
|
"blitzkit",
|
||||||
"blitzrinth",
|
"blitzrinth",
|
||||||
"blitzstars",
|
"blitzstars",
|
||||||
|
"bufbuild",
|
||||||
"cacheable",
|
"cacheable",
|
||||||
"Callouts",
|
"Callouts",
|
||||||
"Camo",
|
"Camo",
|
||||||
"Carro",
|
"Carro",
|
||||||
"CCPAOPTOUT",
|
"CCPAOPTOUT",
|
||||||
"CDON",
|
"CDON",
|
||||||
|
"clanid",
|
||||||
"classname",
|
"classname",
|
||||||
"cleandist",
|
"cleandist",
|
||||||
"closedkrieg",
|
"closedkrieg",
|
||||||
@@ -62,8 +65,10 @@
|
|||||||
"deburr",
|
"deburr",
|
||||||
"decalmask",
|
"decalmask",
|
||||||
"decompressor",
|
"decompressor",
|
||||||
|
"dedup",
|
||||||
"defence",
|
"defence",
|
||||||
"degressive",
|
"degressive",
|
||||||
|
"depotdownloader",
|
||||||
"devkrieg",
|
"devkrieg",
|
||||||
"diacriticless",
|
"diacriticless",
|
||||||
"DIDS",
|
"DIDS",
|
||||||
@@ -74,6 +79,7 @@
|
|||||||
"DVPLCRC",
|
"DVPLCRC",
|
||||||
"dvpm",
|
"dvpm",
|
||||||
"dxgi",
|
"dxgi",
|
||||||
|
"easimon",
|
||||||
"echarts",
|
"echarts",
|
||||||
"Everytime",
|
"Everytime",
|
||||||
"FASTNAME",
|
"FASTNAME",
|
||||||
@@ -86,11 +92,13 @@
|
|||||||
"Fullscreen",
|
"Fullscreen",
|
||||||
"fullstats",
|
"fullstats",
|
||||||
"fuzzysort",
|
"fuzzysort",
|
||||||
|
"gamemode",
|
||||||
"gameplay",
|
"gameplay",
|
||||||
"glsl",
|
"glsl",
|
||||||
"GLTF",
|
"GLTF",
|
||||||
"gtag",
|
"gtag",
|
||||||
"haha",
|
"haha",
|
||||||
|
"Herdbreaker",
|
||||||
"highp",
|
"highp",
|
||||||
"iife",
|
"iife",
|
||||||
"imgur",
|
"imgur",
|
||||||
@@ -104,6 +112,7 @@
|
|||||||
"leaderboards",
|
"leaderboards",
|
||||||
"lerp",
|
"lerp",
|
||||||
"LINEARSIZE",
|
"LINEARSIZE",
|
||||||
|
"linktarget",
|
||||||
"lmao",
|
"lmao",
|
||||||
"loadouts",
|
"loadouts",
|
||||||
"loddist",
|
"loddist",
|
||||||
@@ -126,6 +135,7 @@
|
|||||||
"NEGATIVEX",
|
"NEGATIVEX",
|
||||||
"NEGATIVEY",
|
"NEGATIVEY",
|
||||||
"NEGATIVEZ",
|
"NEGATIVEZ",
|
||||||
|
"networkidle",
|
||||||
"NITROPAY",
|
"NITROPAY",
|
||||||
"nivo",
|
"nivo",
|
||||||
"nmatname",
|
"nmatname",
|
||||||
@@ -136,11 +146,13 @@
|
|||||||
"Oopsy",
|
"Oopsy",
|
||||||
"opentest",
|
"opentest",
|
||||||
"OPTML",
|
"OPTML",
|
||||||
|
"otemp",
|
||||||
"outdir",
|
"outdir",
|
||||||
"outfile",
|
"outfile",
|
||||||
"ownedtanks",
|
"ownedtanks",
|
||||||
"padder",
|
"padder",
|
||||||
"partytown",
|
"partytown",
|
||||||
|
"patchnotes",
|
||||||
"PIXELFORMAT",
|
"PIXELFORMAT",
|
||||||
"playerachievements",
|
"playerachievements",
|
||||||
"playerinfo",
|
"playerinfo",
|
||||||
@@ -153,11 +165,15 @@
|
|||||||
"Promisable",
|
"Promisable",
|
||||||
"proto",
|
"proto",
|
||||||
"protobuf",
|
"protobuf",
|
||||||
|
"protoc",
|
||||||
"protos",
|
"protos",
|
||||||
|
"proxyclient",
|
||||||
|
"prunestrings",
|
||||||
"Pyogenics",
|
"Pyogenics",
|
||||||
"ratingleaderboard",
|
"ratingleaderboard",
|
||||||
"raycaster",
|
"raycaster",
|
||||||
"Redirector",
|
"Redirector",
|
||||||
|
"Relogin",
|
||||||
"researchable",
|
"researchable",
|
||||||
"Resvg",
|
"Resvg",
|
||||||
"rizz",
|
"rizz",
|
||||||
@@ -206,12 +222,14 @@
|
|||||||
"Unregistering",
|
"Unregistering",
|
||||||
"unrotate",
|
"unrotate",
|
||||||
"unwrapper",
|
"unwrapper",
|
||||||
|
"userns",
|
||||||
"vercel",
|
"vercel",
|
||||||
"vickers",
|
"vickers",
|
||||||
"vitepress",
|
"vitepress",
|
||||||
"Vovko",
|
"Vovko",
|
||||||
"wargaming",
|
"wargaming",
|
||||||
"webp",
|
"webp",
|
||||||
|
"wgpkg",
|
||||||
"whitespaces",
|
"whitespaces",
|
||||||
"WHSS",
|
"WHSS",
|
||||||
"winrate",
|
"winrate",
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# BlitzKit
|
# BlitzKit
|
||||||
|
|
||||||
Tools for everything and anything World of Tanks Blitz.
|
Tools for everything and anything, World of Tanks Blitz.
|
||||||
|
|
||||||
This GitHub repository contains the code for BlitzKit and all its services. You may need to checkout sensitive closed-source submodules in order to locally develop some aspects of BlitzKit. Communicate with `@tresabhi` on Discord to get started or talk about sensitive content like environment variables or submodules.
|
This GitHub repository contains the code for BlitzKit and all its services. If you are here, looking to use BlitzKit, go to https://blitzkit.app/.
|
||||||
|
|
||||||
|
If you intend to contribute to the code, note that you may need to check out sensitive, closed-source submodules to locally develop certain aspects of BlitzKit. Communicate with `@tresabhi` on Discord to get started or discuss sensitive content, such as environment variables or submodules.
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
@@ -13,23 +15,21 @@ This GitHub repository contains the code for BlitzKit and all its services. You
|
|||||||
| [packages/core](packages/core) | | | Mutual internal code shared between all other packages. |
|
| [packages/core](packages/core) | | | Mutual internal code shared between all other packages. |
|
||||||
| [packages/i18n](packages/i18n) | | [Crowdin](https://crowdin.com/project/blitzkrieg) | Translations served as JSON shared across all other packages, including some utility code. |
|
| [packages/i18n](packages/i18n) | | [Crowdin](https://crowdin.com/project/blitzkrieg) | Translations served as JSON shared across all other packages, including some utility code. |
|
||||||
| [packages/scripts](packages/scripts) | | | CLI utilities for the development and deployment of BlitzKit services. |
|
| [packages/scripts](packages/scripts) | | | CLI utilities for the development and deployment of BlitzKit services. |
|
||||||
| [packages/varuna](packages/varuna) | Varuna | [NPM](https://www.npmjs.com/package/varuna) | React and Astro oriented state management library, awaiting separation from BlitzKit. Unavailable from NPM at this time. |
|
| [packages/varuna](packages/varuna) | Varuna | [NPM](https://www.npmjs.com/package/varuna) | React and Astro-oriented state management library, awaiting separation from BlitzKit. Unavailable from NPM at this time. |
|
||||||
| [packages/website](packages/website) | BlitzKit | https://blitzkit.app | The BlitzKit website providing a wide range of tools, APIs, and interconnecting all other services. |
|
| [packages/website](packages/website) | BlitzKit | https://blitzkit.app | The BlitzKit website provides a wide range of tools, APIs, and interconnects all other services. |
|
||||||
|
|
||||||
## Submodules
|
## Submodules
|
||||||
|
|
||||||
| Submodule | Title | Source | Memo |
|
| Submodule | Title | Source | Memo |
|
||||||
| ------------------------------------------------------------ | ----------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------ | --------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [submodules/blitzkit-closed](submodules/blitzkit-closed) | ClosedKit | [blitzkit/closed](https://github.com/blitzkit/closed) | Closed source, sensitive code hidden from the public to prevent bad actors from abusing the game. Discuss with `@tresabhi` on Discord for **special permission** to access. |
|
| [submodules/blitzkit-closed](packages/blitzkit-closed) | ClosedKit | [blitzkit/closed](https://github.com/blitzkit/closed) | Closed source, sensitive code hidden from the public to prevent bad actors from abusing the game. Discuss with `@tresabhi` on Discord for **special permission** to access. |
|
||||||
| [submodules/blitzkit-internal](submodules/blitzkit-internal) | InternalKit | [blitzkit/internal](https://github.com/blitzkit/internal) | Closed source, sensitive internal documentation hidden from the public to prevent bad actors from abusing the game. Access to this submodule is **not negotiable**. |
|
|
||||||
| [submodules/CUE4Parse](submodules/CUE4Parse) | CUE4Parse | [FabianFG/CUE4Parse](https://github.com/FabianFG/CUE4Parse) | An Unreal Engine archives and packages parsing library in C#. |
|
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
| Name | Source | BlitzKit Default | Memo |
|
| Name | Source | BlitzKit Default | Memo |
|
||||||
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `PUBLIC_WARGAMING_APPLICATION_ID` | [Wargaming Developer's Room](https://developers.wargaming.net/) | | Application ID needed to communicate with Wargaming APIs. |
|
| `PUBLIC_WARGAMING_APPLICATION_ID` | [Wargaming Developer's Room](https://developers.wargaming.net/) | | Application ID needed to communicate with Wargaming APIs. |
|
||||||
| `PUBLIC_PROMOTE_OPENTEST` | | `false` | Optional boolean dictating wether the website advertises [the opentest subdomain of BlitzKit](https://opentest.blitzkit.app/). |
|
| `PUBLIC_PROMOTE_OPENTEST` | | `false` | Optional boolean dictating whether the website advertises [the opentest subdomain of BlitzKit](https://opentest.blitzkit.app/). |
|
||||||
| `ALLOW_ROBOTS` | | `true` | Toggles between `Allow: /` and `Disallow: /` in the website's `/robots.txt`. This is usually `false` for all BlitzKit's subdomains. |
|
| `ALLOW_ROBOTS` | | `true` | Toggles between `Allow: /` and `Disallow: /` in the website's `/robots.txt`. This is usually `false` for all BlitzKit's subdomains. |
|
||||||
| `WOTB_GLOSSARY`, `WOTB_GLOSSARY_DOMAIN`, `WOTB_GLOSSARY_PATH` | | | |
|
| `WOTB_GLOSSARY`, `WOTB_GLOSSARY_DOMAIN`, `WOTB_GLOSSARY_PATH` | | | |
|
||||||
| `PUBLIC_GOOGLE_TAG_MANAGER_ID` | [Google Tag Manager](https://tagmanager.google.com/) | `G-GL2JVHCGPQ` | Google Tag Manager's unique identifier for analytical purposes. |
|
| `PUBLIC_GOOGLE_TAG_MANAGER_ID` | [Google Tag Manager](https://tagmanager.google.com/) | `G-GL2JVHCGPQ` | Google Tag Manager's unique identifier for analytical purposes. |
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# BlitzKit 1.28.3
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Turrets and guns can now be rotated in Mixer without any pitch or yaw limits
|
||||||
|
- Added nation icons to the search results for Guesser
|
||||||
|
- The table now occupies the whole screen in Compare
|
||||||
|
- Added the ability to log in with a Wargaming account in the navbar
|
||||||
|
- Added owned/unowned filters in the Tankopedia filters
|
||||||
|
- Revamped Tankopedia quick controls to be more accessible and obvious
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Missing tank icons across the website have been fixed
|
||||||
|
- Events of starting and stopping of the transform tanks now use an asynchronous event instead of a reactive state, making them faster
|
||||||
|
- Removed a hook call on root context, speeding up load times
|
||||||
|
- Tankopedia's pitch input now follows the same sign convention as the pitch and yaw visualizer
|
||||||
|
- Shadows are no longer disabled when the scene is unloaded when the user scrolls away from the canvas
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# BlitzKit 1.28.4
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- The tank names in the Tankopedia sandbox now have less margin from the navbar
|
||||||
|
- Controls in the Tankopedia sandbox are now shown in all modes, except for the advanced highlighting button which only appears in the dynamic armor mode
|
||||||
|
- The settings page now reacts to input again
|
||||||
|
- The settings page now has a tab title and description for search engines
|
||||||
|
- Added support for transparent textures, fixing tanks like the Herdbreaker and the WZ-132-1
|
||||||
|
- The tank filters in the Performance and Tier-List tools work once again
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# BlitzKit 1.29.0
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Added the Playlist tool
|
||||||
|
- Don't know what to play today? Let BlitzKit do the thinking!
|
||||||
|
- Navigate to [the tool on BlitzKit](https://blitzkit.app/playlist)
|
||||||
|
- Make sure you login with your Wargaming account to unlock all features like live tracking and filtering by owned tanks
|
||||||
|
- Use filters to pick tiers, nations, etc. then hit Generate playlist
|
||||||
|
- BlitzKit will generate a checklist for you to go through as you play
|
||||||
|
- Don't like the order of tanks? Hit Shuffle, Sort by Last played and Least played, or straight up remove tanks from the list by using the (-) button
|
||||||
|
- If you're logged in, BlitzKit will automatically check off tanks as you play them
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.1
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- Recreated the full dependency tree for BlitzKit
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.2
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- Implemented new workflow capabilities to deploy BlitzKit OpenTest and Preview remotely, from any device
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.3
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- Added a significantly more memory and network efficient AssetUploader abstraction
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.4
|
||||||
|
|
||||||
|
## Technical Changes
|
||||||
|
|
||||||
|
- BlitzKit now partially downloads game files instead of the entire game, allowing for faster updates
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# BlitzKit 1.29.5
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Added new lighting to be a bit softer on tanks
|
||||||
|
- Added a button with the sun icon to toggle high graphics
|
||||||
|
- Added a new reveal and transition animation between tabs
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Track wheels on some tanks no longer look translucent
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# BlitzKit 1.29.6
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Simplified the ownership and test tank filters in the tank search
|
||||||
|
- Renamed "Guess the tank" to simply "Guess"
|
||||||
|
- The player count value in the Performance tool is now set to Total by default
|
||||||
|
- Added Compare-like red/green highlighting to the Performance tool
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- Removed the last updated info bar in Performance for some more screen real estate
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- The remove played tanks in the Playlist tool now shows even when logged out
|
||||||
|
- The Guess game now has a page title
|
||||||
|
- The compare table now occupies the minimum width possible instead of expanding all columns excessively
|
||||||
+15
-30
@@ -1,22 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkit",
|
"name": "blitzkit",
|
||||||
|
"version": "1.29.6",
|
||||||
|
"license": "BlitzKit License",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.28.2",
|
|
||||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
|
||||||
"type": "module",
|
|
||||||
"types": "./types.d.ts",
|
|
||||||
"workspaces": [
|
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"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 && bun run build",
|
||||||
"build:prisma": "prisma generate",
|
"build:prisma": "prisma generate",
|
||||||
"build:sitemap": "bun scripts/sitemap.ts",
|
|
||||||
"build:docs": "vitepress build docs",
|
|
||||||
"build:proxyclient": "cd packages/scripts && bun run build:proxyclient",
|
"build:proxyclient": "cd packages/scripts && bun run build:proxyclient",
|
||||||
|
"build:catalogitemaccesssor": "cd packages/scripts && bun run build:catalogitemaccesssor",
|
||||||
"build:ratingleaderboard": "cd packages/scripts && bun run build:ratingleaderboard",
|
"build:ratingleaderboard": "cd packages/scripts && bun run build:ratingleaderboard",
|
||||||
"build:app": "cd packages/app && bun run build",
|
"build:app": "cd packages/app && bun run build",
|
||||||
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
"dev:bot": "bun run build:bot --dev && bun start:bot",
|
||||||
@@ -36,30 +30,21 @@
|
|||||||
"update": "yarn upgrade --latest",
|
"update": "yarn upgrade --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": "cd packages/scripts && bun run build:protos",
|
||||||
"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",
|
||||||
|
"setup": "bun install && bun run build:prisma && bun run build:protos && bun run build:proxyclient",
|
||||||
|
"patchnotes": "cd packages/scripts && bun run patchnotes"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"type": "module",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/xmpp__client": "^0.13.3",
|
"@prisma/client": "^6.18.0",
|
||||||
"@xmpp/client": "^0.13.6",
|
"prisma": "^6.18.0",
|
||||||
"astro-favicons": "^3.1.5",
|
"typescript": "^5.9.3"
|
||||||
"cheerio": "^1.1.2",
|
|
||||||
"googleapis": "^160.0.0",
|
|
||||||
"lodash-es": "^4.17.21",
|
|
||||||
"protobufjs": "^7.5.4",
|
|
||||||
"quicklime": "^1.2.0",
|
|
||||||
"sharp": "^0.34.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/bun": "^1.2.22",
|
|
||||||
"@types/lodash-es": "^4.17.12",
|
|
||||||
"@types/node": "^24.5.2",
|
|
||||||
"prettier": "^3.6.2",
|
|
||||||
"prisma": "^6.16.2",
|
|
||||||
"typescript": "^5.9.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+20
-12
@@ -1,26 +1,34 @@
|
|||||||
{
|
{
|
||||||
"name": "@blitzkit/bot",
|
"name": "@blitzkit/bot",
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"types": "src/types.d.ts",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzkit/core": "workspace:*",
|
"@blitzkit/core": "workspace:*",
|
||||||
"@blitzkit/i18n": "workspace:*",
|
"@blitzkit/i18n": "workspace:*",
|
||||||
"satori": "^0.18.3",
|
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
|
||||||
"discord.js": "^14.22.1",
|
|
||||||
"react": "^19.1.1",
|
|
||||||
"@radix-ui/colors": "^3.0.0",
|
"@radix-ui/colors": "^3.0.0",
|
||||||
"fuzzysort": "^3.1.0",
|
"@radix-ui/themes": "^3.2.1",
|
||||||
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
|
"@types/adm-zip": "^0.5.7",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/markdown-escape": "^1.1.3",
|
||||||
|
"@types/react": "^19.2.2",
|
||||||
|
"adm-zip": "^0.5.16",
|
||||||
"bepaint": "^0.1.0-beta.3",
|
"bepaint": "^0.1.0-beta.3",
|
||||||
|
"discord.js": "^14.22.1",
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.2.2",
|
||||||
"markdown-escape": "^2.0.0"
|
"fuzzysort": "^3.1.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"markdown-escape": "^2.0.0",
|
||||||
|
"pickleparser": "^0.2.1",
|
||||||
|
"prisma": "^6.17.1",
|
||||||
|
"protobufjs": "^7.5.4",
|
||||||
|
"react": "^19.2.0",
|
||||||
|
"satori": "^0.18.3",
|
||||||
|
"sharp": "^0.34.4"
|
||||||
},
|
},
|
||||||
|
"private": true,
|
||||||
"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": {
|
"type": "module",
|
||||||
"@types/markdown-escape": "^1.1.3"
|
"types": "src/types.d.ts"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,31 @@
|
|||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { COMMANDS_RAW, CommandRegistry } from '../events/interactionCreate';
|
import {
|
||||||
|
COMMANDS_RAW,
|
||||||
|
type CommandRegistry,
|
||||||
|
} from "../events/interactionCreate";
|
||||||
|
|
||||||
const subcommands = [
|
const subcommands = [
|
||||||
'embeds',
|
"embeds",
|
||||||
'introduction',
|
"introduction",
|
||||||
'invite',
|
"invite",
|
||||||
'timezones',
|
"timezones",
|
||||||
'credits',
|
"credits",
|
||||||
] as const;
|
] as const;
|
||||||
type Subcommand = (typeof subcommands)[number];
|
type Subcommand = (typeof subcommands)[number];
|
||||||
|
|
||||||
const DOCS: Record<Subcommand, string> = {
|
const DOCS: Record<Subcommand, string> = {
|
||||||
embeds: 'guide/embeds',
|
embeds: "guide/embeds",
|
||||||
introduction: 'guide/introduction',
|
introduction: "guide/introduction",
|
||||||
invite: 'guide/invite',
|
invite: "guide/invite",
|
||||||
timezones: 'guide/timezones',
|
timezones: "guide/timezones",
|
||||||
credits: 'about/credits',
|
credits: "about/credits",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('about', [
|
command: createLocalizedCommand("about", [
|
||||||
{ subcommand: 'commands' },
|
{ subcommand: "commands" },
|
||||||
...subcommands.map((subcommand) => ({ subcommand })),
|
...subcommands.map((subcommand) => ({ subcommand })),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
|||||||
const subcommand = interaction.options.getSubcommand();
|
const subcommand = interaction.options.getSubcommand();
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
|
|
||||||
if (subcommand === 'commands') {
|
if (subcommand === "commands") {
|
||||||
return `${strings.bot.commands.about.subcommands.commands.body}${(
|
return `${strings.bot.commands.about.subcommands.commands.body}${(
|
||||||
await Promise.all(COMMANDS_RAW)
|
await Promise.all(COMMANDS_RAW)
|
||||||
)
|
)
|
||||||
@@ -40,7 +43,7 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
|||||||
(b.command.name_localizations?.[interaction.locale] ??
|
(b.command.name_localizations?.[interaction.locale] ??
|
||||||
b.command.name)
|
b.command.name)
|
||||||
? -1
|
? -1
|
||||||
: 1,
|
: 1
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
(registry) =>
|
(registry) =>
|
||||||
@@ -51,9 +54,9 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
|||||||
registry.command.description_localizations?.[
|
registry.command.description_localizations?.[
|
||||||
interaction.locale
|
interaction.locale
|
||||||
] ?? registry.command.description
|
] ?? registry.command.description
|
||||||
}`,
|
}`
|
||||||
)
|
)
|
||||||
.join('\n')}`;
|
.join("\n")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `https://raw.githubusercontent.com/tresabhi/blitzkit/main/docs/${DOCS[subcommand as Subcommand]}.md`;
|
const url = `https://raw.githubusercontent.com/tresabhi/blitzkit/main/docs/${DOCS[subcommand as Subcommand]}.md`;
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
import {
|
|
||||||
BlitzTankClass,
|
|
||||||
Region,
|
|
||||||
regionToRegionSubdomain,
|
|
||||||
} from '@blitzkit/core';
|
|
||||||
import { literals } from '@blitzkit/i18n';
|
|
||||||
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
|
|
||||||
import { chunkLines } from '../core/discord/chunkLines';
|
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
|
||||||
import { translator } from '../core/localization/translator';
|
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
|
||||||
|
|
||||||
type Auction = null | {
|
|
||||||
count: number;
|
|
||||||
has_next: boolean;
|
|
||||||
results: Result[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type Result =
|
|
||||||
| {
|
|
||||||
id?: number;
|
|
||||||
type: 'vehicle';
|
|
||||||
countable?: boolean;
|
|
||||||
entity?: Entity;
|
|
||||||
initial_count: number;
|
|
||||||
current_count: number;
|
|
||||||
saleable?: boolean;
|
|
||||||
available_from?: Date;
|
|
||||||
available_before?: Date;
|
|
||||||
price?: Price;
|
|
||||||
next_price: Price | null;
|
|
||||||
available: true;
|
|
||||||
display?: boolean;
|
|
||||||
next_price_datetime: Date;
|
|
||||||
next_price_timestamp: number;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
available: false;
|
|
||||||
type: 'vehicle';
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Entity {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
nation: string;
|
|
||||||
subnation: string;
|
|
||||||
use_subnation_flag: boolean;
|
|
||||||
type_slug: BlitzTankClass;
|
|
||||||
level: number;
|
|
||||||
roman_level: string;
|
|
||||||
user_string: string;
|
|
||||||
image_url: string;
|
|
||||||
preview_image_url: string;
|
|
||||||
is_premium: boolean;
|
|
||||||
is_collectible: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Price {
|
|
||||||
currency: Currency;
|
|
||||||
value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Currency {
|
|
||||||
name: 'gold';
|
|
||||||
count: number;
|
|
||||||
title: 'Gold';
|
|
||||||
image_url: string;
|
|
||||||
sizes: unknown;
|
|
||||||
type: 'currency';
|
|
||||||
}
|
|
||||||
|
|
||||||
const WARNING_COUNT = 500;
|
|
||||||
|
|
||||||
export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
|
|
||||||
resolve({
|
|
||||||
command: createLocalizedCommand('auction'),
|
|
||||||
|
|
||||||
async handler(interaction) {
|
|
||||||
const { strings } = translator(interaction.locale);
|
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
|
||||||
const region: Region = 'com';
|
|
||||||
const pageSize = 80;
|
|
||||||
const saleable = true;
|
|
||||||
const data = await fetch(
|
|
||||||
`https://${regionToRegionSubdomain(
|
|
||||||
region,
|
|
||||||
)}.wotblitz.com/en/api/events/items/auction/?page_size=${
|
|
||||||
pageSize
|
|
||||||
}&type[]=vehicle&saleable=${saleable}`,
|
|
||||||
).then((response) => response.json() as Promise<Auction>);
|
|
||||||
|
|
||||||
if (data === null) {
|
|
||||||
return strings.bot.commands.auction.errors.no_auction;
|
|
||||||
}
|
|
||||||
|
|
||||||
const saleableTanks = data.results.filter((result) => result.available);
|
|
||||||
const nextPricesTimestamp = saleableTanks[0].next_price_timestamp;
|
|
||||||
|
|
||||||
const title = `# ${strings.bot.commands.auction.body.title}`;
|
|
||||||
const subtitle = `${literals(strings.bot.commands.auction.body.subtitle, [
|
|
||||||
`${saleableTanks.length} / ${data.results.length}`,
|
|
||||||
`<t:${nextPricesTimestamp}:R>`,
|
|
||||||
'<https://wotblitz.com/auction/>',
|
|
||||||
])}`;
|
|
||||||
const body = saleableTanks.map((data, index) => {
|
|
||||||
const tank = awaitedTankDefinitions.tanks[data.entity!.id];
|
|
||||||
|
|
||||||
if (!tank) return '';
|
|
||||||
|
|
||||||
const name = `[${tank.name}](<https://blitzkit.app/tanks/${
|
|
||||||
tank.slug
|
|
||||||
}>)`;
|
|
||||||
const next =
|
|
||||||
data.next_price === null
|
|
||||||
? ''
|
|
||||||
: `\n-# ${literals(strings.bot.commands.auction.body.next, [
|
|
||||||
`<:gold:1317173197082333244> ${data.next_price.value.toLocaleString(
|
|
||||||
interaction.locale,
|
|
||||||
)}`,
|
|
||||||
])}`;
|
|
||||||
const available = literals(
|
|
||||||
strings.bot.commands.auction.body.available,
|
|
||||||
[
|
|
||||||
data.current_count.toLocaleString(interaction.locale),
|
|
||||||
data.initial_count.toLocaleString(interaction.locale),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
const isOut = data.current_count === 0;
|
|
||||||
const outString = isOut ? '~~' : '';
|
|
||||||
const isLow = data.current_count <= WARNING_COUNT;
|
|
||||||
|
|
||||||
return `${index + 1}. ${
|
|
||||||
outString
|
|
||||||
}${name} <:gold:1317173197082333244> ${data.price!.value.toLocaleString(
|
|
||||||
interaction.locale,
|
|
||||||
)}${outString}\n-#${isLow ? ' ‼️ ' : ' '}${available}${isOut ? '' : next}`;
|
|
||||||
});
|
|
||||||
const header = `${title}\n${subtitle}`;
|
|
||||||
const lines = [header, ...body];
|
|
||||||
|
|
||||||
return chunkLines(lines, '\n\n');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -13,7 +13,7 @@ import { resolvePeriodFromButton } from '../../core/discord/resolvePeriodFromBut
|
|||||||
import { resolvePeriodFromCommand } from '../../core/discord/resolvePeriodFromCommand';
|
import { resolvePeriodFromCommand } from '../../core/discord/resolvePeriodFromCommand';
|
||||||
import { resolvePlayerFromButton } from '../../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from '../../core/discord/resolvePlayerFromButton';
|
||||||
import { resolvePlayerFromCommand } from '../../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from '../../core/discord/resolvePlayerFromCommand';
|
||||||
import { CommandRegistry } from '../../events/interactionCreate';
|
import type { CommandRegistry } from '../../events/interactionCreate';
|
||||||
import { renderBreakdown } from './render';
|
import { renderBreakdown } from './render';
|
||||||
|
|
||||||
export const breakdownCommand = new Promise<CommandRegistry>(
|
export const breakdownCommand = new Promise<CommandRegistry>(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
BlitzStats,
|
type BlitzStats,
|
||||||
calculateWN8,
|
calculateWN8,
|
||||||
getAccountInfo,
|
getAccountInfo,
|
||||||
getClanAccountInfo,
|
getClanAccountInfo,
|
||||||
@@ -17,11 +17,11 @@ import { TitleBar } from "../../components/TitleBar";
|
|||||||
import { filtersToDescription } from "../../core/blitzkit/filtersToDescription";
|
import { filtersToDescription } from "../../core/blitzkit/filtersToDescription";
|
||||||
import { tankDefinitions } from "../../core/blitzkit/nonBlockingPromises";
|
import { tankDefinitions } from "../../core/blitzkit/nonBlockingPromises";
|
||||||
import { UserError } from "../../core/blitzkit/userError";
|
import { UserError } from "../../core/blitzkit/userError";
|
||||||
import { filterStats, StatFilters } from "../../core/blitzstars/filterStats";
|
import { filterStats, type StatFilters } from "../../core/blitzstars/filterStats";
|
||||||
import { getStatsInPeriod } from "../../core/blitzstars/getStatsInPeriod";
|
import { getStatsInPeriod } from "../../core/blitzstars/getStatsInPeriod";
|
||||||
import { blitzStarsTankAverages } from "../../core/blitzstars/tankAverages";
|
import { blitzStarsTankAverages } from "../../core/blitzstars/tankAverages";
|
||||||
import { ResolvedPeriod } from "../../core/discord/resolvePeriodFromCommand";
|
import type { ResolvedPeriod } from "../../core/discord/resolvePeriodFromCommand";
|
||||||
import { ResolvedPlayer } from "../../core/discord/resolvePlayerFromCommand";
|
import type { ResolvedPlayer } from "../../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from "../../core/localization/translator";
|
import { translator } from "../../core/localization/translator";
|
||||||
|
|
||||||
const ROWS_PER_PAGE = 8;
|
const ROWS_PER_PAGE = 8;
|
||||||
@@ -193,9 +193,9 @@ export async function renderBreakdown(
|
|||||||
title={
|
title={
|
||||||
tankDefinition
|
tankDefinition
|
||||||
? unwrap(tankDefinition.name)
|
? unwrap(tankDefinition.name)
|
||||||
: literals(strings.bot.commands.breakdown.body.unknown_tank, [
|
: literals(strings.bot.commands.breakdown.body.unknown_tank, {
|
||||||
`${id}`,
|
id,
|
||||||
])
|
})
|
||||||
}
|
}
|
||||||
stats={[
|
stats={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import packageJSON from '../../../../package.json';
|
import packageJSON from "../../../../package.json";
|
||||||
import { client } from '../core/discord/client';
|
import { client } from "../core/discord/client";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const executionStart = new Date().getTime();
|
const executionStart = new Date().getTime();
|
||||||
|
|
||||||
export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('debug'),
|
command: createLocalizedCommand("debug"),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
@@ -23,15 +23,15 @@ export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
[
|
[
|
||||||
strings.bot.commands.debug.body.uptime,
|
strings.bot.commands.debug.body.uptime,
|
||||||
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
|
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
|
||||||
(uptime / 1000 / 60) % 60,
|
(uptime / 1000 / 60) % 60
|
||||||
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
|
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
|
||||||
uptime % 1000,
|
uptime % 1000
|
||||||
)}ms`,
|
)}ms`,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
return `${strings.bot.commands.debug.body.title}${list
|
return `${strings.bot.commands.debug.body.title}${list
|
||||||
.map(([key, value]) => `- ${key}: ${value}`)
|
.map(([key, value]) => `- ${key}: ${value}`)
|
||||||
.join('\n')}`;
|
.join("\n")}`;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,48 +1,48 @@
|
|||||||
import { emblemURL, getAccountInfo, getClanAccountInfo } from '@blitzkit/core';
|
import { emblemURL, getAccountInfo, getClanAccountInfo } from "@blitzkit/core";
|
||||||
import { Locale, SlashCommandSubcommandGroupBuilder } from 'discord.js';
|
import { Locale, SlashCommandSubcommandGroupBuilder } from "discord.js";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import * as Graph from '../components/Graph';
|
import * as Graph from "../components/Graph";
|
||||||
import { LineColor } from '../components/Graph/components/Line/constants';
|
import { LineColor } from "../components/Graph/components/Line/constants";
|
||||||
import { NoData } from '../components/NoData';
|
import { NoData } from "../components/NoData";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { resolveTankId } from '../core/blitz/resolveTankId';
|
import { resolveTankId } from "../core/blitz/resolveTankId";
|
||||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
import { getBlitzStarsLinkButton } from "../core/blitzstars/getBlitzStarsLinkButton";
|
||||||
import { getPlayerHistories } from '../core/blitzstars/getPlayerHistories';
|
import { getPlayerHistories } from "../core/blitzstars/getPlayerHistories";
|
||||||
import { getTankHistories } from '../core/blitzstars/getTankHistories';
|
import { getTankHistories } from "../core/blitzstars/getTankHistories";
|
||||||
import { addPeriodSubCommands } from '../core/discord/addPeriodSubCommands';
|
import { addPeriodSubCommands } from "../core/discord/addPeriodSubCommands";
|
||||||
import { addTankChoices } from '../core/discord/addTankChoices';
|
import { addTankChoices } from "../core/discord/addTankChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
|
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { buttonRefresh } from '../core/discord/buttonRefresh';
|
import { buttonRefresh } from "../core/discord/buttonRefresh";
|
||||||
import { commandToURL } from '../core/discord/commandToURL';
|
import { commandToURL } from "../core/discord/commandToURL";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
|
import { getCustomPeriodParams } from "../core/discord/getCustomPeriodParams";
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPeriod,
|
type ResolvedPeriod,
|
||||||
resolvePeriodFromCommand,
|
resolvePeriodFromCommand,
|
||||||
} from '../core/discord/resolvePeriodFromCommand';
|
} from "../core/discord/resolvePeriodFromCommand";
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPlayer,
|
type ResolvedPlayer,
|
||||||
resolvePlayerFromCommand,
|
resolvePlayerFromCommand,
|
||||||
} from '../core/discord/resolvePlayerFromCommand';
|
} from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
type EvolutionStatType = 'player' | 'tank';
|
type EvolutionStatType = "player" | "tank";
|
||||||
|
|
||||||
async function render(
|
async function render(
|
||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
{ start, end, name }: ResolvedPeriod,
|
{ start, end, name }: ResolvedPeriod,
|
||||||
type: 'player' | 'tank',
|
type: "player" | "tank",
|
||||||
tankId: number | null,
|
tankId: number | null,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const logo = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const logo = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
const histories = await (type === 'player'
|
const histories = await (type === "player"
|
||||||
? getPlayerHistories(region, id, {
|
? getPlayerHistories(region, id, {
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
@@ -61,7 +61,7 @@ async function render(
|
|||||||
[
|
[
|
||||||
history.all.battles,
|
history.all.battles,
|
||||||
(history.all.wins / history.all.battles) * 100,
|
(history.all.wins / history.all.battles) * 100,
|
||||||
] as Graph.PlotItem,
|
] as Graph.PlotItem
|
||||||
);
|
);
|
||||||
const times = histories.map((history) => history.last_battle_time);
|
const times = histories.map((history) => history.last_battle_time);
|
||||||
const minTime = Math.min(...times);
|
const minTime = Math.min(...times);
|
||||||
@@ -82,7 +82,7 @@ async function render(
|
|||||||
verticalMargin={{
|
verticalMargin={{
|
||||||
min: minY,
|
min: minY,
|
||||||
max: maxY,
|
max: maxY,
|
||||||
suffix: '%',
|
suffix: "%",
|
||||||
precision: 2,
|
precision: 2,
|
||||||
}}
|
}}
|
||||||
horizontalMargin={{
|
horizontalMargin={{
|
||||||
@@ -110,22 +110,22 @@ async function render(
|
|||||||
export const evolutionCommand = new Promise<CommandRegistry>(
|
export const evolutionCommand = new Promise<CommandRegistry>(
|
||||||
async (resolve) => {
|
async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('evolution', [
|
command: createLocalizedCommand("evolution", [
|
||||||
{
|
{
|
||||||
group: 'player',
|
group: "player",
|
||||||
modify(option: SlashCommandSubcommandGroupBuilder) {
|
modify(option: SlashCommandSubcommandGroupBuilder) {
|
||||||
addPeriodSubCommands(option, (option) =>
|
addPeriodSubCommands(option, (option) =>
|
||||||
option.addStringOption(addUsernameChoices),
|
option.addStringOption(addUsernameChoices)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
group: 'tank',
|
group: "tank",
|
||||||
modify(option: SlashCommandSubcommandGroupBuilder) {
|
modify(option: SlashCommandSubcommandGroupBuilder) {
|
||||||
addPeriodSubCommands(option, (option) =>
|
addPeriodSubCommands(option, (option) =>
|
||||||
option
|
option
|
||||||
.addStringOption(addTankChoices)
|
.addStringOption(addTankChoices)
|
||||||
.addStringOption(addUsernameChoices),
|
.addStringOption(addUsernameChoices)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -136,9 +136,9 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
interaction.options.getSubcommandGroup() as EvolutionStatType;
|
interaction.options.getSubcommandGroup() as EvolutionStatType;
|
||||||
const player = await resolvePlayerFromCommand(interaction);
|
const player = await resolvePlayerFromCommand(interaction);
|
||||||
const period = resolvePeriodFromCommand(player.region, interaction);
|
const period = resolvePeriodFromCommand(player.region, interaction);
|
||||||
const tankIdRaw = interaction.options.getString('tank')!;
|
const tankIdRaw = interaction.options.getString("tank")!;
|
||||||
const tankId =
|
const tankId =
|
||||||
commandGroup === 'tank'
|
commandGroup === "tank"
|
||||||
? await resolveTankId(tankIdRaw, interaction.locale)
|
? await resolveTankId(tankIdRaw, interaction.locale)
|
||||||
: null;
|
: null;
|
||||||
const path = commandToURL(interaction, {
|
const path = commandToURL(interaction, {
|
||||||
@@ -153,13 +153,13 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
period,
|
period,
|
||||||
commandGroup,
|
commandGroup,
|
||||||
tankId,
|
tankId,
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
buttonRefresh(interaction, path),
|
buttonRefresh(interaction, path),
|
||||||
await getBlitzStarsLinkButton(
|
await getBlitzStarsLinkButton(
|
||||||
player.region,
|
player.region,
|
||||||
player.id,
|
player.id,
|
||||||
tankId ?? undefined,
|
tankId ?? undefined
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
@@ -171,7 +171,7 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
|
|
||||||
async button(interaction) {
|
async button(interaction) {
|
||||||
const url = new URL(`https://example.com/${interaction.customId}`);
|
const url = new URL(`https://example.com/${interaction.customId}`);
|
||||||
const path = url.pathname.split('/');
|
const path = url.pathname.split("/");
|
||||||
const commandGroup = path[2] as EvolutionStatType;
|
const commandGroup = path[2] as EvolutionStatType;
|
||||||
const player = await resolvePlayerFromButton(interaction);
|
const player = await resolvePlayerFromButton(interaction);
|
||||||
const period = resolvePeriodFromButton(player.region, interaction);
|
const period = resolvePeriodFromButton(player.region, interaction);
|
||||||
@@ -180,10 +180,10 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
player,
|
player,
|
||||||
period,
|
period,
|
||||||
commandGroup,
|
commandGroup,
|
||||||
parseInt(url.searchParams.get('tankId') ?? '0') || null,
|
parseInt(url.searchParams.get("tankId") ?? "0") || null,
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
@@ -11,7 +11,7 @@ import { NoData } from '../components/NoData';
|
|||||||
import { TierWeights } from '../components/TierWeights';
|
import { TierWeights } from '../components/TierWeights';
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from '../components/TitleBar';
|
||||||
import { filtersToDescription } from '../core/blitzkit/filtersToDescription';
|
import { filtersToDescription } from '../core/blitzkit/filtersToDescription';
|
||||||
import { filterStats, StatFilters } from '../core/blitzstars/filterStats';
|
import { filterStats, type StatFilters } from '../core/blitzstars/filterStats';
|
||||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
||||||
import { getStatsInPeriod } from '../core/blitzstars/getStatsInPeriod';
|
import { getStatsInPeriod } from '../core/blitzstars/getStatsInPeriod';
|
||||||
import { addPeriodicFilterOptions } from '../core/discord/addPeriodicFilterOptions';
|
import { addPeriodicFilterOptions } from '../core/discord/addPeriodicFilterOptions';
|
||||||
@@ -26,15 +26,15 @@ import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
|
|||||||
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
||||||
import {
|
import {
|
||||||
ResolvedPeriod,
|
type ResolvedPeriod,
|
||||||
resolvePeriodFromCommand,
|
resolvePeriodFromCommand,
|
||||||
} from '../core/discord/resolvePeriodFromCommand';
|
} from '../core/discord/resolvePeriodFromCommand';
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
||||||
import {
|
import {
|
||||||
ResolvedPlayer,
|
type ResolvedPlayer,
|
||||||
resolvePlayerFromCommand,
|
resolvePlayerFromCommand,
|
||||||
} from '../core/discord/resolvePlayerFromCommand';
|
} from '../core/discord/resolvePlayerFromCommand';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from '../events/interactionCreate';
|
||||||
|
|
||||||
async function render(
|
async function render(
|
||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
import { getAccountInfo, getClanInfo } from '@blitzkit/core';
|
import { getAccountInfo, getClanInfo } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { GenericStats } from '../components/GenericStats';
|
import { GenericStats } from "../components/GenericStats";
|
||||||
import { NoData } from '../components/NoData';
|
import { NoData } from "../components/NoData";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { addClanChoices } from '../core/discord/addClanChoices';
|
import { addClanChoices } from "../core/discord/addClanChoices";
|
||||||
import { autocompleteClan } from '../core/discord/autocompleteClan';
|
import { autocompleteClan } from "../core/discord/autocompleteClan";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { resolveClanFromCommand } from '../core/discord/resolveClanFromCommand';
|
import { resolveClanFromCommand } from "../core/discord/resolveClanFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const DEFAULT_THRESHOLD = 7;
|
const DEFAULT_THRESHOLD = 7;
|
||||||
|
|
||||||
export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('inactive')
|
command: createLocalizedCommand("inactive")
|
||||||
.addStringOption(addClanChoices)
|
.addStringOption(addClanChoices)
|
||||||
.addNumberOption((option) => {
|
.addNumberOption((option) => {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
|
|
||||||
return option
|
return option
|
||||||
.setName('threshold')
|
.setName("threshold")
|
||||||
.setNameLocalizations(
|
.setNameLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands.inactive.options.threshold.name,
|
(strings) => strings.bot.commands.inactive.options.threshold.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.inactive.options.threshold.description,
|
strings.bot.commands.inactive.options.threshold.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.inactive.options.threshold.description,
|
strings.bot.commands.inactive.options.threshold.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setMinValue(0);
|
.setMinValue(0);
|
||||||
}),
|
}),
|
||||||
@@ -47,7 +47,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const { region, id } = await resolveClanFromCommand(interaction);
|
const { region, id } = await resolveClanFromCommand(interaction);
|
||||||
const threshold =
|
const threshold =
|
||||||
interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD;
|
interaction.options.getNumber("threshold")! ?? DEFAULT_THRESHOLD;
|
||||||
const time = new Date().getTime() / 1000;
|
const time = new Date().getTime() / 1000;
|
||||||
const clanInfo = await getClanInfo(region, id);
|
const clanInfo = await getClanInfo(region, id);
|
||||||
const accountInfo = await getAccountInfo(region, clanInfo.members_ids);
|
const accountInfo = await getAccountInfo(region, clanInfo.members_ids);
|
||||||
@@ -57,7 +57,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
[
|
[
|
||||||
account.nickname,
|
account.nickname,
|
||||||
(time - account.last_battle_time) / 60 / 60 / 24,
|
(time - account.last_battle_time) / 60 / 60 / 24,
|
||||||
] as [string, number],
|
] as [string, number]
|
||||||
)
|
)
|
||||||
.filter(([, inactiveDays]) => inactiveDays >= threshold)
|
.filter(([, inactiveDays]) => inactiveDays >= threshold)
|
||||||
.sort((a, b) => b[1] - a[1])
|
.sort((a, b) => b[1] - a[1])
|
||||||
@@ -65,10 +65,10 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
([name, days]) =>
|
([name, days]) =>
|
||||||
[
|
[
|
||||||
name,
|
name,
|
||||||
literals(strings.bot.commands.inactive.body.listing, [
|
literals(strings.bot.commands.inactive.body.listing, {
|
||||||
days.toFixed(0),
|
days: days.toFixed(0),
|
||||||
]),
|
}),
|
||||||
] as [string, string],
|
] as [string, string]
|
||||||
);
|
);
|
||||||
const hasInactiveMembers = inactive.length > 0;
|
const hasInactiveMembers = inactive.length > 0;
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanInfo.emblem_set_id}.png`}
|
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanInfo.emblem_set_id}.png`}
|
||||||
description={`${literals(
|
description={`${literals(
|
||||||
strings.bot.commands.inactive.body.subtitle,
|
strings.bot.commands.inactive.body.subtitle,
|
||||||
[`${threshold}`],
|
{ days: threshold }
|
||||||
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
|||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from '../core/discord/embedInfo';
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from '../core/localization/translator';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from '../events/interactionCreate';
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from '../stitches.config';
|
||||||
|
|
||||||
export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
|
|||||||
@@ -5,31 +5,31 @@ import {
|
|||||||
flags,
|
flags,
|
||||||
getAccountInfo,
|
getAccountInfo,
|
||||||
getTankStats,
|
getTankStats,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import {
|
import {
|
||||||
gameDefinitions,
|
gameDefinitions,
|
||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
} from '../core/blitzkit/nonBlockingPromises';
|
} from "../core/blitzkit/nonBlockingPromises";
|
||||||
import { addTierChoices } from '../core/discord/addTierChoices';
|
import { addTierChoices } from "../core/discord/addTierChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { chunkLines } from '../core/discord/chunkLines';
|
import { chunkLines } from "../core/discord/chunkLines";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('owned-tanks')
|
command: createLocalizedCommand("owned-tanks")
|
||||||
.addStringOption(addTierChoices)
|
.addStringOption(addTierChoices)
|
||||||
.addStringOption(addUsernameChoices),
|
.addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings, unwrap } = translator(interaction.locale);
|
const { strings, unwrap } = translator(interaction.locale);
|
||||||
const tier = Number(interaction.options.getString('tier'));
|
const tier = Number(interaction.options.getString("tier"));
|
||||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
const tankStats = await getTankStats(region, id);
|
const tankStats = await getTankStats(region, id);
|
||||||
@@ -43,7 +43,7 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tankStats.map(async (tankData) => ({
|
tankStats.map(async (tankData) => ({
|
||||||
tankDefinitions: (await tankDefinitions).tanks[tankData.tank_id]!,
|
tankDefinitions: (await tankDefinitions).tanks[tankData.tank_id]!,
|
||||||
id: tankData.tank_id,
|
id: tankData.tank_id,
|
||||||
})),
|
}))
|
||||||
)
|
)
|
||||||
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
).filter((tank) => tank.tankDefinitions?.tier === tier);
|
||||||
const groupedTanks: Record<string, TankDefinition[]> = {};
|
const groupedTanks: Record<string, TankDefinition[]> = {};
|
||||||
@@ -60,25 +60,25 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
const awaitedGameDefinitions = await gameDefinitions;
|
const awaitedGameDefinitions = await gameDefinitions;
|
||||||
const title = literals(strings.bot.commands.owned_tanks.body.title, [
|
const title = literals(strings.bot.commands.owned_tanks.body.title, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
TIER_ROMAN_NUMERALS[tier],
|
tier: TIER_ROMAN_NUMERALS[tier],
|
||||||
]);
|
});
|
||||||
const tankList = tankStats
|
const tankList = tankStats
|
||||||
.map(({ tank_id }) => awaitedTankDefinitions.tanks[tank_id])
|
.map(({ tank_id }) => awaitedTankDefinitions.tanks[tank_id])
|
||||||
.filter((tank) => tank.tier === tier)
|
.filter((tank) => tank.tier === tier)
|
||||||
.sort(
|
.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class),
|
TANK_CLASSES.indexOf(a.class) - TANK_CLASSES.indexOf(b.class)
|
||||||
)
|
)
|
||||||
.sort(
|
.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
awaitedGameDefinitions.nations.indexOf(a.nation) -
|
||||||
awaitedGameDefinitions.nations.indexOf(b.nation),
|
awaitedGameDefinitions.nations.indexOf(b.nation)
|
||||||
)
|
)
|
||||||
.map(
|
.map(
|
||||||
(tank) =>
|
(tank) =>
|
||||||
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name))}](<https://blitzkit.app/tanks/${tank.slug}>)`,
|
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name))}](<https://blitzkit.app/tanks/${tank.slug}>)`
|
||||||
);
|
);
|
||||||
const lines = [title, ...tankList];
|
const lines = [title, ...tankList];
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('permissions'),
|
command: createLocalizedCommand("permissions"),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
@@ -14,33 +14,33 @@ export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
new Date().getDay() === 5 && new Date().getDate() === 13;
|
new Date().getDay() === 5 && new Date().getDate() === 13;
|
||||||
const permissions = [
|
const permissions = [
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('ViewChannel'),
|
interaction.appPermissions?.has("ViewChannel"),
|
||||||
strings.bot.commands.permissions.body.view_channels,
|
strings.bot.commands.permissions.body.view_channels,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('ReadMessageHistory'),
|
interaction.appPermissions?.has("ReadMessageHistory"),
|
||||||
strings.bot.commands.permissions.body.read_message_history,
|
strings.bot.commands.permissions.body.read_message_history,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('AttachFiles'),
|
interaction.appPermissions?.has("AttachFiles"),
|
||||||
strings.bot.commands.permissions.body.attach_files,
|
strings.bot.commands.permissions.body.attach_files,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
interaction.appPermissions?.has('UseExternalEmojis'),
|
interaction.appPermissions?.has("UseExternalEmojis"),
|
||||||
strings.bot.commands.permissions.body.external_emojis,
|
strings.bot.commands.permissions.body.external_emojis,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
const body = permissions
|
const body = permissions
|
||||||
.map(([hasPermission, description]) => {
|
.map(([hasPermission, description]) => {
|
||||||
if (hasPermission) {
|
if (hasPermission) {
|
||||||
return `${isFridayThe13th ? '😇' : '✅'} ${description}`;
|
return `${isFridayThe13th ? "😇" : "✅"} ${description}`;
|
||||||
} else {
|
} else {
|
||||||
return `${isFridayThe13th ? '💀' : '❌'} ${description}`;
|
return `${isFridayThe13th ? "💀" : "❌"} ${description}`;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join('\n');
|
.join("\n");
|
||||||
|
|
||||||
return literals(strings.bot.commands.permissions.body.title, [body]);
|
return literals(strings.bot.commands.permissions.body.title, { body });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
handlesInteraction: true,
|
handlesInteraction: true,
|
||||||
|
|
||||||
command: createLocalizedCommand('ping', [
|
command: createLocalizedCommand("ping", [
|
||||||
{ subcommand: 'blitzkit' },
|
{ subcommand: "blitzkit" },
|
||||||
{ subcommand: 'wotb' },
|
{ subcommand: "wotb" },
|
||||||
]),
|
]),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
@@ -17,17 +17,17 @@ export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const subcommand = interaction.options.getSubcommand();
|
const subcommand = interaction.options.getSubcommand();
|
||||||
const executionStart = Date.now();
|
const executionStart = Date.now();
|
||||||
|
|
||||||
if (subcommand === 'blitzkit') {
|
if (subcommand === "blitzkit") {
|
||||||
await interaction.editReply(strings.bot.commands.ping.body.pong);
|
await interaction.editReply(strings.bot.commands.ping.body.pong);
|
||||||
} else {
|
} else {
|
||||||
await fetch('https://api.wotblitz.com/');
|
await fetch("https://api.wotblitz.com/");
|
||||||
}
|
}
|
||||||
|
|
||||||
const executionTime = Date.now() - executionStart;
|
const executionTime = Date.now() - executionStart;
|
||||||
interaction.editReply(
|
interaction.editReply(
|
||||||
literals(strings.bot.commands.ping.body.pong_with_time, [
|
literals(strings.bot.commands.ping.body.pong_with_time, {
|
||||||
`${Math.round(executionTime)}`,
|
time: executionTime.toFixed(0),
|
||||||
]),
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { getAccountInfo } from '@blitzkit/core';
|
import { getAccountInfo } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from "../core/discord/embedInfo";
|
||||||
import { markdownTable } from '../core/discord/markdownTable';
|
import { markdownTable } from "../core/discord/markdownTable";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command:
|
command:
|
||||||
createLocalizedCommand('player-info').addStringOption(addUsernameChoices),
|
createLocalizedCommand("player-info").addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
@@ -22,9 +22,9 @@ export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
|
|
||||||
return embedInfo(
|
return embedInfo(
|
||||||
literals(strings.bot.commands.player_info.body.title, [
|
literals(strings.bot.commands.player_info.body.title, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
]),
|
}),
|
||||||
|
|
||||||
markdownTable([
|
markdownTable([
|
||||||
[
|
[
|
||||||
@@ -51,16 +51,16 @@ export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
[
|
[
|
||||||
strings.bot.commands.player_info.body.created,
|
strings.bot.commands.player_info.body.created,
|
||||||
new Date(accountInfo.created_at * 1000).toLocaleDateString(
|
new Date(accountInfo.created_at * 1000).toLocaleDateString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
strings.bot.commands.player_info.body.last_battle,
|
strings.bot.commands.player_info.body.last_battle,
|
||||||
new Date(accountInfo.last_battle_time * 1000).toLocaleDateString(
|
new Date(accountInfo.last_battle_time * 1000).toLocaleDateString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
]),
|
])
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -8,42 +8,42 @@ import {
|
|||||||
getRatingInfo,
|
getRatingInfo,
|
||||||
getRatingNeighbors,
|
getRatingNeighbors,
|
||||||
imgur,
|
imgur,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { SlashCommandSubcommandBuilder } from 'discord.js';
|
import { SlashCommandSubcommandBuilder } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { Glow } from '../components/AllStatsOverview/components/HeroStat/components/Glow';
|
import { Glow } from "../components/AllStatsOverview/components/HeroStat/components/Glow";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { DeltaCaret } from '../components/DeltaCaret';
|
import { DeltaCaret } from "../components/DeltaCaret";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { normalizeLeagueIcon } from '../core/blitz/normalizeLeagueIcon';
|
import { normalizeLeagueIcon } from "../core/blitz/normalizeLeagueIcon";
|
||||||
import { iconPng } from '../core/blitzkit/iconPng';
|
import { iconPng } from "../core/blitzkit/iconPng";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
const LEAGUE_ACCENT = [
|
const LEAGUE_ACCENT = [
|
||||||
'_purple',
|
"_purple",
|
||||||
'_sand',
|
"_sand",
|
||||||
'_amber',
|
"_amber",
|
||||||
'_mauve',
|
"_mauve",
|
||||||
'_brown',
|
"_brown",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('rating', [
|
command: createLocalizedCommand("rating", [
|
||||||
{
|
{
|
||||||
subcommand: 'today',
|
subcommand: "today",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option.addStringOption(addUsernameChoices);
|
option.addStringOption(addUsernameChoices);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
subcommand: 'season',
|
subcommand: "season",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option.addStringOption(addUsernameChoices);
|
option.addStringOption(addUsernameChoices);
|
||||||
},
|
},
|
||||||
@@ -52,11 +52,11 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const subcommand = interaction.options.getSubcommand(true) as
|
const subcommand = interaction.options.getSubcommand(true) as
|
||||||
| 'season'
|
| "season"
|
||||||
| 'today';
|
| "today";
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
|
|
||||||
const ratingInfo = await getRatingInfo(region);
|
const ratingInfo = await getRatingInfo(region);
|
||||||
@@ -67,20 +67,20 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
const leaderboard = await getArchivedRatingLeaderboard(
|
const leaderboard = await getArchivedRatingLeaderboard(
|
||||||
region,
|
region,
|
||||||
ratingInfo.current_season - (subcommand === 'today' ? 0 : 1),
|
ratingInfo.current_season - (subcommand === "today" ? 0 : 1)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (leaderboard.version!.$case === 'v1') {
|
if (leaderboard.version!.$case === "v1") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Encountered bkrl minimal format in latest season. Wait till next cron?',
|
"Encountered bkrl minimal format in latest season. Wait till next cron?"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const accountInfo = await getAccountInfo(region, id, [
|
const accountInfo = await getAccountInfo(region, id, [
|
||||||
'statistics.rating',
|
"statistics.rating",
|
||||||
]);
|
]);
|
||||||
const statsIndex = leaderboard.version!.value.entries.findIndex(
|
const statsIndex = leaderboard.version!.value.entries.findIndex(
|
||||||
(entry) => entry.id === id,
|
(entry) => entry.id === id
|
||||||
);
|
);
|
||||||
const statsA = leaderboard
|
const statsA = leaderboard
|
||||||
? leaderboard.version!.value.entries[statsIndex!]
|
? leaderboard.version!.value.entries[statsIndex!]
|
||||||
@@ -90,9 +90,9 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const statsB2Array = (await getRatingNeighbors(region, id, 0)).neighbors;
|
const statsB2Array = (await getRatingNeighbors(region, id, 0)).neighbors;
|
||||||
|
|
||||||
if (statsB2Array === undefined) {
|
if (statsB2Array === undefined) {
|
||||||
return literals(strings.bot.commands.rating.errors.no_participation, [
|
return literals(strings.bot.commands.rating.errors.no_participation, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const [statsB2] = statsB2Array;
|
const [statsB2] = statsB2Array;
|
||||||
@@ -102,15 +102,15 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
return strings.bot.commands.rating.errors.unrecorded_stats;
|
return strings.bot.commands.rating.errors.unrecorded_stats;
|
||||||
}
|
}
|
||||||
if (!statsB1) {
|
if (!statsB1) {
|
||||||
return literals(strings.bot.commands.rating.errors.no_participation, [
|
return literals(strings.bot.commands.rating.errors.no_participation, {
|
||||||
markdownEscape(accountInfo.nickname),
|
name: markdownEscape(accountInfo.nickname),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const reward = ratingInfo.rewards.find(
|
const reward = ratingInfo.rewards.find(
|
||||||
(reward) =>
|
(reward) =>
|
||||||
statsB2.number >= reward.from_position &&
|
statsB2.number >= reward.from_position &&
|
||||||
statsB2.number <= reward.to_position,
|
statsB2.number <= reward.to_position
|
||||||
);
|
);
|
||||||
const positionDelta = leaderboard
|
const positionDelta = leaderboard
|
||||||
? statsB2.number - positionA!
|
? statsB2.number - positionA!
|
||||||
@@ -118,11 +118,11 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const delta = deltaBkrlBlitzStats(
|
const delta = deltaBkrlBlitzStats(
|
||||||
statsA,
|
statsA,
|
||||||
accountInfo.statistics.rating!,
|
accountInfo.statistics.rating!,
|
||||||
statsB2,
|
statsB2
|
||||||
);
|
);
|
||||||
const leagueTheme = LEAGUE_ACCENT[league.index];
|
const leagueTheme = LEAGUE_ACCENT[league.index];
|
||||||
let rewardImage = reward
|
let rewardImage = reward
|
||||||
? reward.type === 'vehicle'
|
? reward.type === "vehicle"
|
||||||
? reward.vehicle.preview_image_url
|
? reward.vehicle.preview_image_url
|
||||||
: reward.stuff.image_url
|
: reward.stuff.image_url
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -131,7 +131,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { ok } = await fetch(rewardImage);
|
const { ok } = await fetch(rewardImage);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
rewardImage = imgur('kP88vqr');
|
rewardImage = imgur("kP88vqr");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,24 +147,24 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
padding: 16,
|
padding: 16,
|
||||||
backgroundColor: theme.colors[`appBackground2${leagueTheme}`],
|
backgroundColor: theme.colors[`appBackground2${leagueTheme}`],
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
border: `1px solid ${
|
border: `1px solid ${
|
||||||
theme.colors[`componentInteractive${leagueTheme}`]
|
theme.colors[`componentInteractive${leagueTheme}`]
|
||||||
}`,
|
}`,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
width: '100%',
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{reward === undefined && (
|
{reward === undefined && (
|
||||||
@@ -172,17 +172,17 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
endOpacity={3 / 4}
|
endOpacity={3 / 4}
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
transform: 'translateX(-16px) rotate(90deg)',
|
transform: "translateX(-16px) rotate(90deg)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -190,24 +190,24 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
style={{
|
style={{
|
||||||
width: 64,
|
width: 64,
|
||||||
height: 64,
|
height: 64,
|
||||||
objectFit: 'contain',
|
objectFit: "contain",
|
||||||
}}
|
}}
|
||||||
src={normalizeLeagueIcon(
|
src={normalizeLeagueIcon(
|
||||||
ratingInfo.leagues[league.index].big_icon,
|
ratingInfo.leagues[league.index].big_icon
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-start',
|
justifyContent: "flex-start",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -232,7 +232,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Math.abs(delta.score).toLocaleString(
|
{Math.abs(delta.score).toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -241,9 +241,9 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-start',
|
justifyContent: "flex-start",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -267,7 +267,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Math.abs(positionDelta).toLocaleString(
|
{Math.abs(positionDelta).toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -279,23 +279,23 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
{reward && (
|
{reward && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-end',
|
justifyContent: "flex-end",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -303,13 +303,13 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors[`textHighContrast${leagueTheme}`],
|
color: theme.colors[`textHighContrast${leagueTheme}`],
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
maxWidth: 136,
|
maxWidth: 136,
|
||||||
textAlign: 'right',
|
textAlign: "right",
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: "nowrap",
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: "ellipsis",
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{reward.type === 'vehicle'
|
{reward.type === "vehicle"
|
||||||
? reward.vehicle.user_string
|
? reward.vehicle.user_string
|
||||||
: reward.stuff.title}
|
: reward.stuff.title}
|
||||||
</span>
|
</span>
|
||||||
@@ -317,9 +317,9 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'flex-end',
|
justifyContent: "flex-end",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -329,7 +329,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Reward
|
Reward
|
||||||
{reward.type === 'stuff' ? ` x${reward.count}` : ''}
|
{reward.type === "stuff" ? ` x${reward.count}` : ""}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -338,7 +338,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
style={{
|
style={{
|
||||||
width: 64,
|
width: 64,
|
||||||
height: 64,
|
height: 64,
|
||||||
objectFit: 'cover',
|
objectFit: "cover",
|
||||||
}}
|
}}
|
||||||
src={await iconPng(rewardImage!)}
|
src={await iconPng(rewardImage!)}
|
||||||
/>
|
/>
|
||||||
@@ -350,7 +350,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
endOpacity={3 / 4}
|
endOpacity={3 / 4}
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
transform: 'translateX(16px) rotate(-90deg)',
|
transform: "translateX(16px) rotate(-90deg)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -362,10 +362,10 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
direction="reverse"
|
direction="reverse"
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
top: -40,
|
top: -40,
|
||||||
left: '50%',
|
left: "50%",
|
||||||
transform: 'translateX(-50%)',
|
transform: "translateX(-50%)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -373,32 +373,32 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<Glow
|
<Glow
|
||||||
color={theme.colors[`solidBackground${leagueTheme}`]}
|
color={theme.colors[`solidBackground${leagueTheme}`]}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
bottom: -40,
|
bottom: -40,
|
||||||
left: '50%',
|
left: "50%",
|
||||||
transform: 'translateX(-50%)',
|
transform: "translateX(-50%)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{delta.battles > 0 && (
|
{delta.battles > 0 && (
|
||||||
<div style={{ padding: '8px 0', display: 'flex' }}>
|
<div style={{ padding: "8px 0", display: "flex" }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{delta.battles.toLocaleString(interaction.locale)}
|
{delta.battles.toLocaleString(interaction.locale)}
|
||||||
@@ -414,19 +414,19 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(100 * (delta.wins / delta.battles)).toFixed(0)}%
|
{(100 * (delta.wins / delta.battles)).toFixed(0)}%
|
||||||
@@ -442,23 +442,23 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Math.round(delta.damage / delta.battles).toLocaleString(
|
{Math.round(delta.damage / delta.battles).toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
@@ -472,19 +472,19 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(100 * (delta.survived / delta.battles)).toFixed(0)}%
|
{(100 * (delta.survived / delta.battles)).toFixed(0)}%
|
||||||
@@ -500,19 +500,19 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(delta.kills / delta.battles).toFixed(2)}
|
{(delta.kills / delta.battles).toFixed(2)}
|
||||||
|
|||||||
@@ -10,30 +10,30 @@ import {
|
|||||||
imgur,
|
imgur,
|
||||||
isOnGoingRatingSeason,
|
isOnGoingRatingSeason,
|
||||||
LEAGUES,
|
LEAGUES,
|
||||||
RatingInfo,
|
type RatingInfo,
|
||||||
RatingLeaderboard,
|
RatingLeaderboard,
|
||||||
Region,
|
type Region,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
type APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { range } from 'lodash-es';
|
import { range } from "lodash-es";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import * as Leaderboard from '../components/Leaderboard';
|
import * as Leaderboard from "../components/Leaderboard";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { UserError } from '../core/blitzkit/userError';
|
import { UserError } from "../core/blitzkit/userError";
|
||||||
import { addRegionChoices } from '../core/discord/addRegionChoices';
|
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
interface SimplifiedPlayer {
|
interface SimplifiedPlayer {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -51,7 +51,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
const onGoingSeason = await isOnGoingRatingSeason();
|
const onGoingSeason = await isOnGoingRatingSeason();
|
||||||
const seasonNumbers = range(
|
const seasonNumbers = range(
|
||||||
FIRST_MINIMAL_ARCHIVED_RATING_SEASON,
|
FIRST_MINIMAL_ARCHIVED_RATING_SEASON,
|
||||||
latestArchivedSeasonNumber + (onGoingSeason ? 1 : 0) + 1,
|
latestArchivedSeasonNumber + (onGoingSeason ? 1 : 0) + 1
|
||||||
);
|
);
|
||||||
|
|
||||||
function addOptions(option: SlashCommandSubcommandBuilder) {
|
function addOptions(option: SlashCommandSubcommandBuilder) {
|
||||||
@@ -66,51 +66,50 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.limit.name,
|
strings.bot.commands.rating_leaderboard.options.limit.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
literals(
|
literals(
|
||||||
strings.bot.commands.rating_leaderboard.options.limit
|
strings.bot.commands.rating_leaderboard.options.limit
|
||||||
.description,
|
.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ count: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.limit
|
strings.bot.commands.rating_leaderboard.options.limit
|
||||||
.description,
|
.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ count: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(false)
|
.setRequired(false)
|
||||||
.setMinValue(5)
|
.setMinValue(5)
|
||||||
.setMaxValue(30),
|
.setMaxValue(30)
|
||||||
)
|
)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
option
|
option
|
||||||
.setName(
|
.setName(
|
||||||
strings.bot.commands.rating_leaderboard.options.season.name,
|
strings.bot.commands.rating_leaderboard.options.season.name
|
||||||
)
|
)
|
||||||
.setNameLocalizations(
|
.setNameLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.season.name,
|
strings.bot.commands.rating_leaderboard.options.season.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.rating_leaderboard.options.season
|
strings.bot.commands.rating_leaderboard.options.season.description
|
||||||
.description,
|
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.season
|
strings.bot.commands.rating_leaderboard.options.season
|
||||||
.description,
|
.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(false)
|
.setRequired(false)
|
||||||
.addChoices(
|
.addChoices(
|
||||||
@@ -124,7 +123,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? literals(
|
? literals(
|
||||||
strings.bot.commands.rating_leaderboard.options.season
|
strings.bot.commands.rating_leaderboard.options.season
|
||||||
.choices.current,
|
.choices.current,
|
||||||
[`${number}`],
|
{ season: number }
|
||||||
)
|
)
|
||||||
: `${number}`,
|
: `${number}`,
|
||||||
value: `${number}`,
|
value: `${number}`,
|
||||||
@@ -133,27 +132,27 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options
|
strings.bot.commands.rating_leaderboard.options
|
||||||
.season.choices.current,
|
.season.choices.current,
|
||||||
[`${number}`],
|
{ season: number }
|
||||||
)
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
} satisfies APIApplicationCommandOptionChoice<string>;
|
} satisfies APIApplicationCommandOptionChoice<string>;
|
||||||
})
|
})
|
||||||
.reverse(),
|
.reverse()
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('rating-leaderboard', [
|
command: createLocalizedCommand("rating-leaderboard", [
|
||||||
{
|
{
|
||||||
subcommand: 'neighbors',
|
subcommand: "neighbors",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option.addStringOption(addUsernameChoices);
|
option.addStringOption(addUsernameChoices);
|
||||||
addOptions(option);
|
addOptions(option);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
subcommand: 'league',
|
subcommand: "league",
|
||||||
modify(option: SlashCommandSubcommandBuilder) {
|
modify(option: SlashCommandSubcommandBuilder) {
|
||||||
option
|
option
|
||||||
.addStringOption((option) => {
|
.addStringOption((option) => {
|
||||||
@@ -161,7 +160,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
|
|
||||||
return option
|
return option
|
||||||
.setName(
|
.setName(
|
||||||
strings.bot.commands.rating_leaderboard.options.league.name,
|
strings.bot.commands.rating_leaderboard.options.league.name
|
||||||
)
|
)
|
||||||
.setNameLocalizations(
|
.setNameLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
@@ -169,19 +168,19 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
strings.bot.commands.rating_leaderboard.options.league
|
strings.bot.commands.rating_leaderboard.options.league
|
||||||
.name,
|
.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.rating_leaderboard.options.league
|
strings.bot.commands.rating_leaderboard.options.league
|
||||||
.description,
|
.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.rating_leaderboard.options.league
|
strings.bot.commands.rating_leaderboard.options.league
|
||||||
.description,
|
.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.addChoices(
|
.addChoices(
|
||||||
...LEAGUES.map(
|
...LEAGUES.map(
|
||||||
@@ -195,10 +194,10 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
(
|
(
|
||||||
strings.common.leagues as Record<string, string>
|
strings.common.leagues as Record<string, string>
|
||||||
)[name],
|
)[name]
|
||||||
),
|
),
|
||||||
}) satisfies APIApplicationCommandOptionChoice<string>,
|
}) satisfies APIApplicationCommandOptionChoice<string>
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(true);
|
.setRequired(true);
|
||||||
})
|
})
|
||||||
@@ -213,10 +212,10 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const subcommand = interaction.options.getSubcommand(true) as
|
const subcommand = interaction.options.getSubcommand(true) as
|
||||||
| 'league'
|
| "league"
|
||||||
| 'neighbors';
|
| "neighbors";
|
||||||
const limit = interaction.options.getInteger('limit') ?? DEFAULT_LIMIT;
|
const limit = interaction.options.getInteger("limit") ?? DEFAULT_LIMIT;
|
||||||
const seasonOption = interaction.options.getString('season');
|
const seasonOption = interaction.options.getString("season");
|
||||||
const season = seasonOption
|
const season = seasonOption
|
||||||
? parseInt(seasonOption)
|
? parseInt(seasonOption)
|
||||||
: onGoingSeason
|
: onGoingSeason
|
||||||
@@ -232,11 +231,11 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
let playerId: number | undefined;
|
let playerId: number | undefined;
|
||||||
let regionRatingInfo: RatingInfo | null;
|
let regionRatingInfo: RatingInfo | null;
|
||||||
|
|
||||||
if (subcommand === 'league') {
|
if (subcommand === "league") {
|
||||||
const leagueIndex = parseInt(
|
const leagueIndex = parseInt(
|
||||||
interaction.options.getString('league')!,
|
interaction.options.getString("league")!
|
||||||
);
|
);
|
||||||
const region = interaction.options.getString('region') as Region;
|
const region = interaction.options.getString("region") as Region;
|
||||||
regionRatingInfo = await (isCurrentSeason
|
regionRatingInfo = await (isCurrentSeason
|
||||||
? getRatingInfo(region)
|
? getRatingInfo(region)
|
||||||
: null);
|
: null);
|
||||||
@@ -259,8 +258,8 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
position: player.number,
|
position: player.number,
|
||||||
clan: player.clan_tag,
|
clan: player.clan_tag,
|
||||||
nickname: player.nickname,
|
nickname: player.nickname,
|
||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
: await getArchivedRatingLeaderboard(region, season!).then(
|
: await getArchivedRatingLeaderboard(region, season!).then(
|
||||||
async (players) => {
|
async (players) => {
|
||||||
@@ -269,17 +268,17 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? 0
|
? 0
|
||||||
: players.version!.value.entries.findIndex(
|
: players.version!.value.entries.findIndex(
|
||||||
(player) =>
|
(player) =>
|
||||||
player.score < LEAGUES[leagueIndex - 1].minScore,
|
player.score < LEAGUES[leagueIndex - 1].minScore
|
||||||
);
|
);
|
||||||
const lastPlayerIndex = firstPlayerIndex + limit - 1;
|
const lastPlayerIndex = firstPlayerIndex + limit - 1;
|
||||||
const trimmed = players.version!.value.entries.slice(
|
const trimmed = players.version!.value.entries.slice(
|
||||||
firstPlayerIndex,
|
firstPlayerIndex,
|
||||||
lastPlayerIndex + 1,
|
lastPlayerIndex + 1
|
||||||
);
|
);
|
||||||
const clanData = await getClanAccountInfo(
|
const clanData = await getClanAccountInfo(
|
||||||
region,
|
region,
|
||||||
trimmed.map(({ id }) => id),
|
trimmed.map(({ id }) => id),
|
||||||
['clan'],
|
["clan"]
|
||||||
);
|
);
|
||||||
|
|
||||||
return trimmed.map(
|
return trimmed.map(
|
||||||
@@ -294,16 +293,16 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
literals(
|
literals(
|
||||||
strings.bot.commands.rating_leaderboard.body
|
strings.bot.commands.rating_leaderboard.body
|
||||||
.deleted_player,
|
.deleted_player,
|
||||||
[`${player.id}`],
|
{ id: player.id }
|
||||||
),
|
),
|
||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
const leagueInfo = LEAGUES[leagueIndex];
|
const leagueInfo = LEAGUES[leagueIndex];
|
||||||
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
||||||
region,
|
region,
|
||||||
season,
|
season
|
||||||
);
|
);
|
||||||
|
|
||||||
players = result;
|
players = result;
|
||||||
@@ -316,12 +315,12 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? (strings.common.leagues as Record<string, string>)[
|
? (strings.common.leagues as Record<string, string>)[
|
||||||
LEAGUES[leagueInfo.index].name
|
LEAGUES[leagueInfo.index].name
|
||||||
]
|
]
|
||||||
: ''
|
: ""
|
||||||
} - ${strings.common.regions.short[region]}`;
|
} - ${strings.common.regions.short[region]}`;
|
||||||
titleImage = imgur(leagueInfo.icon);
|
titleImage = imgur(leagueInfo.icon);
|
||||||
titleDescription = literals(
|
titleDescription = literals(
|
||||||
strings.bot.commands.rating_leaderboard.body.top_players,
|
strings.bot.commands.rating_leaderboard.body.top_players,
|
||||||
[`${limit}`],
|
{ count: limit }
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { region, id } = await resolvePlayerFromCommand(interaction);
|
const { region, id } = await resolvePlayerFromCommand(interaction);
|
||||||
@@ -338,7 +337,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const neighbors = isCurrentSeason
|
const neighbors = isCurrentSeason
|
||||||
? await getRatingNeighbors(region, id, Math.round(limit / 2)).then(
|
? await getRatingNeighbors(region, id, Math.round(limit / 2)).then(
|
||||||
(players) =>
|
(players) =>
|
||||||
@@ -350,13 +349,13 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
score: player.score,
|
score: player.score,
|
||||||
clan: player.clan_tag,
|
clan: player.clan_tag,
|
||||||
nickname: player.nickname,
|
nickname: player.nickname,
|
||||||
}) satisfies SimplifiedPlayer,
|
}) satisfies SimplifiedPlayer
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
: await getArchivedRatingLeaderboard(region, season!).then(
|
: await getArchivedRatingLeaderboard(region, season!).then(
|
||||||
async (players) => {
|
async (players) => {
|
||||||
const playerIndex = players.version!.value.entries.findIndex(
|
const playerIndex = players.version!.value.entries.findIndex(
|
||||||
(player) => player.id === id,
|
(player) => player.id === id
|
||||||
);
|
);
|
||||||
|
|
||||||
if (playerIndex === -1) {
|
if (playerIndex === -1) {
|
||||||
@@ -364,20 +363,20 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
literals(
|
literals(
|
||||||
strings.bot.commands.rating_leaderboard.body
|
strings.bot.commands.rating_leaderboard.body
|
||||||
.no_participation,
|
.no_participation,
|
||||||
[markdownEscape(accountInfo.nickname), `${season}`],
|
{ player: markdownEscape(accountInfo.nickname), season }
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const halfRange = Math.round(limit / 2);
|
const halfRange = Math.round(limit / 2);
|
||||||
const trimmed = players.version!.value.entries.slice(
|
const trimmed = players.version!.value.entries.slice(
|
||||||
playerIndex - halfRange,
|
playerIndex - halfRange,
|
||||||
playerIndex + halfRange + 1,
|
playerIndex + halfRange + 1
|
||||||
);
|
);
|
||||||
const clanData = await getClanAccountInfo(
|
const clanData = await getClanAccountInfo(
|
||||||
region,
|
region,
|
||||||
trimmed.map((player) => player.id),
|
trimmed.map((player) => player.id),
|
||||||
['clan'],
|
["clan"]
|
||||||
);
|
);
|
||||||
|
|
||||||
return trimmed.map((player, index) => ({
|
return trimmed.map((player, index) => ({
|
||||||
@@ -389,18 +388,18 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
? clanData[index]!.account_name
|
? clanData[index]!.account_name
|
||||||
: `Deleted ${player.id}`,
|
: `Deleted ${player.id}`,
|
||||||
}));
|
}));
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
archivedLeaderboard = await getArchivedRatingLeaderboard(
|
||||||
region,
|
region,
|
||||||
season,
|
season
|
||||||
);
|
);
|
||||||
|
|
||||||
players = neighbors;
|
players = neighbors;
|
||||||
titleImage = clan
|
titleImage = clan
|
||||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
||||||
: undefined;
|
: undefined;
|
||||||
titleName = neighbors ? accountInfo.nickname : '';
|
titleName = neighbors ? accountInfo.nickname : "";
|
||||||
titleDescription =
|
titleDescription =
|
||||||
strings.bot.commands.rating_leaderboard.body.neighbors;
|
strings.bot.commands.rating_leaderboard.body.neighbors;
|
||||||
playersAfter =
|
playersAfter =
|
||||||
@@ -414,7 +413,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
const items = players.map((player) => {
|
const items = players.map((player) => {
|
||||||
const midnightIndex =
|
const midnightIndex =
|
||||||
archivedLeaderboard?.version!.value.entries.findIndex(
|
archivedLeaderboard?.version!.value.entries.findIndex(
|
||||||
(item) => item.id === player.id,
|
(item) => item.id === player.id
|
||||||
);
|
);
|
||||||
const midnightScore =
|
const midnightScore =
|
||||||
midnightIndex === undefined
|
midnightIndex === undefined
|
||||||
@@ -453,7 +452,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
<Leaderboard.Gap
|
<Leaderboard.Gap
|
||||||
message={literals(
|
message={literals(
|
||||||
strings.bot.commands.rating_leaderboard.body.more,
|
strings.bot.commands.rating_leaderboard.body.more,
|
||||||
[`${playersAfter.toLocaleString(interaction.locale)}`],
|
{ count: playersAfter.toLocaleString(interaction.locale) }
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -465,5 +464,5 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
|||||||
|
|
||||||
autocomplete: autocompleteUsername,
|
autocomplete: autocompleteUsername,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
@@ -20,7 +20,7 @@ import { blitzStarsTankAverages } from '../core/blitzstars/tankAverages';
|
|||||||
import { buttonLink } from '../core/discord/buttonLink';
|
import { buttonLink } from '../core/discord/buttonLink';
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from '../core/localization/translator';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from '../events/interactionCreate';
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from '../stitches.config';
|
||||||
|
|
||||||
type WotInspectorReplaySubmission =
|
type WotInspectorReplaySubmission =
|
||||||
|
|||||||
@@ -8,31 +8,31 @@ import {
|
|||||||
TANK_ICONS,
|
TANK_ICONS,
|
||||||
TankType,
|
TankType,
|
||||||
TIER_ROMAN_NUMERALS,
|
TIER_ROMAN_NUMERALS,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { escapeMarkdown, Locale } from 'discord.js';
|
import { escapeMarkdown, Locale } from "discord.js";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { resolveTankId } from '../core/blitz/resolveTankId';
|
import { resolveTankId } from "../core/blitz/resolveTankId";
|
||||||
import { buildTechTreeLine } from '../core/blitzkit/buildTechTreeLine';
|
import { buildTechTreeLine } from "../core/blitzkit/buildTechTreeLine";
|
||||||
import { iconPng } from '../core/blitzkit/iconPng';
|
import { iconPng } from "../core/blitzkit/iconPng";
|
||||||
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
|
import { tankDefinitions } from "../core/blitzkit/nonBlockingPromises";
|
||||||
import { resolveAncestry } from '../core/blitzkit/resolveAncestry';
|
import { resolveAncestry } from "../core/blitzkit/resolveAncestry";
|
||||||
import { tankIconPng } from '../core/blitzkit/tankIconPng';
|
import { tankIconPng } from "../core/blitzkit/tankIconPng";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
|
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from "../events/interactionCreate";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('research')
|
command: createLocalizedCommand("research")
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
option
|
option
|
||||||
.setName(strings.bot.commands.research.options.target_tank.name)
|
.setName(strings.bot.commands.research.options.target_tank.name)
|
||||||
@@ -41,20 +41,20 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.target_tank.name,
|
strings.bot.commands.research.options.target_tank.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.research.options.target_tank.description,
|
strings.bot.commands.research.options.target_tank.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.target_tank.description,
|
strings.bot.commands.research.options.target_tank.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setAutocomplete(true)
|
.setAutocomplete(true)
|
||||||
.setRequired(true),
|
.setRequired(true)
|
||||||
)
|
)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
option
|
option
|
||||||
@@ -64,20 +64,20 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.starting_tank.name,
|
strings.bot.commands.research.options.starting_tank.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
strings.bot.commands.research.options.starting_tank.description,
|
strings.bot.commands.research.options.starting_tank.description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.research.options.starting_tank.description,
|
strings.bot.commands.research.options.starting_tank.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setAutocomplete(true)
|
.setAutocomplete(true)
|
||||||
.setRequired(false),
|
.setRequired(false)
|
||||||
)
|
)
|
||||||
.addStringOption(addUsernameChoices),
|
.addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
@@ -85,11 +85,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { strings, unwrap } = translator(interaction.locale);
|
const { strings, unwrap } = translator(interaction.locale);
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
const targetTankId = await resolveTankId(
|
const targetTankId = await resolveTankId(
|
||||||
interaction.options.getString('target-tank', true),
|
interaction.options.getString("target-tank", true),
|
||||||
interaction.locale,
|
interaction.locale,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
const startingTankRaw = interaction.options.getString('starting-tank');
|
const startingTankRaw = interaction.options.getString("starting-tank");
|
||||||
const targetTank = awaitedTankDefinitions.tanks[targetTankId];
|
const targetTank = awaitedTankDefinitions.tanks[targetTankId];
|
||||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||||
let startingTankId: number;
|
let startingTankId: number;
|
||||||
@@ -99,46 +99,45 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
startingTankId = await resolveTankId(
|
startingTankId = await resolveTankId(
|
||||||
startingTankRaw,
|
startingTankRaw,
|
||||||
interaction.locale,
|
interaction.locale,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (targetTankId === startingTankId) {
|
if (targetTankId === startingTankId) {
|
||||||
return literals(
|
return literals(
|
||||||
strings.bot.commands.research.errors.start_end_equal,
|
strings.bot.commands.research.errors.start_end_equal,
|
||||||
[escapeMarkdown(unwrap(targetTank.name))],
|
{ tank: escapeMarkdown(unwrap(targetTank.name)) }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const startingTank = awaitedTankDefinitions.tanks[startingTankId];
|
const startingTank = awaitedTankDefinitions.tanks[startingTankId];
|
||||||
|
|
||||||
if (startingTank.tier > targetTank.tier) {
|
if (startingTank.tier > targetTank.tier) {
|
||||||
return literals(strings.bot.commands.research.errors.unordered, [
|
return literals(strings.bot.commands.research.errors.unordered, {
|
||||||
escapeMarkdown(unwrap(startingTank.name)),
|
tank_1: escapeMarkdown(unwrap(startingTank.name)),
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank_2: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
});
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!targetTankAncestry.includes(startingTankId)) {
|
if (!targetTankAncestry.includes(startingTankId)) {
|
||||||
return literals(
|
return literals(
|
||||||
strings.bot.commands.research.errors.tanks_not_on_line,
|
strings.bot.commands.research.errors.tanks_not_on_line,
|
||||||
[
|
{
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank_1: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
escapeMarkdown(unwrap(startingTank.name)),
|
tank_2: escapeMarkdown(unwrap(startingTank.name)),
|
||||||
],
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetTank.type !== TankType.RESEARCHABLE) {
|
if (targetTank.type !== TankType.RESEARCHABLE) {
|
||||||
return literals(strings.bot.commands.research.errors.non_tech_tree, [
|
return literals(strings.bot.commands.research.errors.non_tech_tree, {
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetTank.tier === 1) {
|
if (targetTank.tier === 1) {
|
||||||
return literals(strings.bot.commands.research.errors.tier_1, [
|
return literals(strings.bot.commands.research.errors.tier_1, {
|
||||||
escapeMarkdown(unwrap(targetTank.name)),
|
tank: escapeMarkdown(unwrap(targetTank.name)),
|
||||||
]);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const tankStats = await getTankStats(region, id);
|
const tankStats = await getTankStats(region, id);
|
||||||
@@ -150,18 +149,18 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
if (tankStats.some(({ tank_id }) => tank_id === targetTankId)) {
|
if (tankStats.some(({ tank_id }) => tank_id === targetTankId)) {
|
||||||
return literals(
|
return literals(
|
||||||
strings.bot.commands.research.errors.already_researched,
|
strings.bot.commands.research.errors.already_researched,
|
||||||
[escapeMarkdown(unwrap(targetTank.name))],
|
{ tank: escapeMarkdown(unwrap(targetTank.name)) }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const foundAncestor = targetTankAncestry.find(
|
const foundAncestor = targetTankAncestry.find(
|
||||||
(id) =>
|
(id) =>
|
||||||
awaitedTankDefinitions.tanks[id].tier === 1 ||
|
awaitedTankDefinitions.tanks[id].tier === 1 ||
|
||||||
tankStats.some(({ tank_id }) => tank_id === id),
|
tankStats.some(({ tank_id }) => tank_id === id)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (foundAncestor === undefined) {
|
if (foundAncestor === undefined) {
|
||||||
throw new Error('No first owned tech tree found.');
|
throw new Error("No first owned tech tree found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
startingTankId = foundAncestor;
|
startingTankId = foundAncestor;
|
||||||
@@ -169,12 +168,12 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
const techTreeLine = await buildTechTreeLine(
|
const techTreeLine = await buildTechTreeLine(
|
||||||
startingTankId,
|
startingTankId,
|
||||||
targetTankId,
|
targetTankId
|
||||||
);
|
);
|
||||||
|
|
||||||
const line = [...techTreeLine, startingTankId].reverse();
|
const line = [...techTreeLine, startingTankId].reverse();
|
||||||
const { nickname } = await getAccountInfo(region, id);
|
const { nickname } = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
const costs = await Promise.all(
|
const costs = await Promise.all(
|
||||||
line.map(async (id) => {
|
line.map(async (id) => {
|
||||||
@@ -187,18 +186,18 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tank.turrets.forEach((turret) => {
|
tank.turrets.forEach((turret) => {
|
||||||
if (
|
if (
|
||||||
turret.research_cost !== undefined &&
|
turret.research_cost !== undefined &&
|
||||||
typeof turret.research_cost.research_cost_type!.value === 'number'
|
typeof turret.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
turretXps.set(
|
turretXps.set(
|
||||||
turret.id,
|
turret.id,
|
||||||
turret.research_cost.research_cost_type!.value,
|
turret.research_cost.research_cost_type!.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
turret.guns.forEach((gun) => {
|
turret.guns.forEach((gun) => {
|
||||||
if (
|
if (
|
||||||
gun.research_cost !== undefined &&
|
gun.research_cost !== undefined &&
|
||||||
typeof gun.research_cost.research_cost_type!.value === 'number'
|
typeof gun.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
gunXps.set(gun.id, gun.research_cost.research_cost_type!.value);
|
gunXps.set(gun.id, gun.research_cost.research_cost_type!.value);
|
||||||
}
|
}
|
||||||
@@ -208,11 +207,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tank.engines.forEach((engine) => {
|
tank.engines.forEach((engine) => {
|
||||||
if (
|
if (
|
||||||
engine.research_cost !== undefined &&
|
engine.research_cost !== undefined &&
|
||||||
typeof engine.research_cost.research_cost_type!.value === 'number'
|
typeof engine.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
engineXps.set(
|
engineXps.set(
|
||||||
engine.id,
|
engine.id,
|
||||||
engine.research_cost.research_cost_type!.value,
|
engine.research_cost.research_cost_type!.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -220,11 +219,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
tank.tracks.forEach((track) => {
|
tank.tracks.forEach((track) => {
|
||||||
if (
|
if (
|
||||||
track.research_cost !== undefined &&
|
track.research_cost !== undefined &&
|
||||||
typeof track.research_cost.research_cost_type!.value === 'number'
|
typeof track.research_cost.research_cost_type!.value === "number"
|
||||||
) {
|
) {
|
||||||
trackXps.set(
|
trackXps.set(
|
||||||
track.id,
|
track.id,
|
||||||
track.research_cost.research_cost_type!.value,
|
track.research_cost.research_cost_type!.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -249,10 +248,10 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
purchase: tank.price.value,
|
purchase: tank.price.value,
|
||||||
equipment: equipmentPriceMatrix[tank.tier].reduce(
|
equipment: equipmentPriceMatrix[tank.tier].reduce(
|
||||||
(a, b) => a + 3 * b,
|
(a, b) => a + 3 * b,
|
||||||
0,
|
0
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const image = (
|
const image = (
|
||||||
@@ -267,14 +266,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
backgroundColor: theme.colors.appBackground2,
|
backgroundColor: theme.colors.appBackground2,
|
||||||
border: theme.borderStyles.subtle,
|
border: theme.borderStyles.subtle,
|
||||||
@@ -285,10 +284,10 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
right: 24,
|
right: 24,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -304,23 +303,23 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
padding: '16px 0',
|
padding: "16px 0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="XP icon"
|
alt="XP icon"
|
||||||
src={await iconPng(asset('icons/currencies/xp.webp'))}
|
src={await iconPng(asset("icons/currencies/xp.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -330,7 +329,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Experience:{' '}
|
Experience:{" "}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + (b.research ?? 0) + b.upgrades, 0)
|
.reduce((a, b) => a + (b.research ?? 0) + b.upgrades, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
@@ -339,14 +338,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(asset('icons/currencies/silver.webp'))}
|
src={await iconPng(asset("icons/currencies/silver.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -356,7 +355,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Purchase:{' '}
|
Purchase:{" "}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + b.purchase, 0)
|
.reduce((a, b) => a + b.purchase, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
@@ -365,14 +364,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(asset('icons/currencies/silver.webp'))}
|
src={await iconPng(asset("icons/currencies/silver.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -382,7 +381,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Equipment:{' '}
|
Equipment:{" "}
|
||||||
{costs
|
{costs
|
||||||
.reduce((a, b) => a + b.equipment, 0)
|
.reduce((a, b) => a + b.equipment, 0)
|
||||||
.toLocaleString(interaction.locale)}
|
.toLocaleString(interaction.locale)}
|
||||||
@@ -399,7 +398,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
key={id}
|
key={id}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
backgroundColor: theme.colors.appBackground2,
|
backgroundColor: theme.colors.appBackground2,
|
||||||
border: theme.borderStyles.subtle,
|
border: theme.borderStyles.subtle,
|
||||||
@@ -408,9 +407,9 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: 48,
|
width: 48,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -426,9 +425,9 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
right: '5%',
|
right: "5%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -437,23 +436,23 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
style={{
|
style={{
|
||||||
height: 100,
|
height: 100,
|
||||||
width: 100,
|
width: 100,
|
||||||
objectFit: 'contain',
|
objectFit: "contain",
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
left: '25%',
|
left: "25%",
|
||||||
top: 0,
|
top: 0,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
position: 'absolute',
|
position: "absolute",
|
||||||
bottom: 8,
|
bottom: 8,
|
||||||
left: '50%',
|
left: "50%",
|
||||||
transform: 'translateX(-50%)',
|
transform: "translateX(-50%)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -476,23 +475,23 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
padding: '16px 0',
|
padding: "16px 0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="XP icon"
|
alt="XP icon"
|
||||||
src={await iconPng(asset('icons/currencies/xp.webp'))}
|
src={await iconPng(asset("icons/currencies/xp.webp"))}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
@@ -504,11 +503,11 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.research,
|
strings.bot.commands.research.body.research,
|
||||||
[
|
{
|
||||||
`${costs[index].research?.toLocaleString(
|
cost: costs[index].research?.toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
)}`,
|
),
|
||||||
],
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -516,15 +515,15 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
{costs[index].upgrades > 0 && (
|
{costs[index].upgrades > 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Free XP icon"
|
alt="Free XP icon"
|
||||||
src={await iconPng(
|
src={await iconPng(
|
||||||
asset('icons/currencies/free-xp.webp'),
|
asset("icons/currencies/free-xp.webp")
|
||||||
)}
|
)}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
@@ -537,7 +536,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.upgrades,
|
strings.bot.commands.research.body.upgrades,
|
||||||
[costs[index].upgrades.toLocaleString()],
|
{ cost: costs[index].upgrades.toLocaleString() }
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -545,15 +544,15 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(
|
src={await iconPng(
|
||||||
asset('icons/currencies/silver.webp'),
|
asset("icons/currencies/silver.webp")
|
||||||
)}
|
)}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
@@ -566,26 +565,26 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.purchase,
|
strings.bot.commands.research.body.purchase,
|
||||||
[
|
{
|
||||||
costs[index].purchase.toLocaleString(
|
cost: costs[index].purchase.toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="Silver icon"
|
alt="Silver icon"
|
||||||
src={await iconPng(
|
src={await iconPng(
|
||||||
asset('icons/currencies/silver.webp'),
|
asset("icons/currencies/silver.webp")
|
||||||
)}
|
)}
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
@@ -598,18 +597,18 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
>
|
>
|
||||||
{literals(
|
{literals(
|
||||||
strings.bot.commands.research.body.equipment,
|
strings.bot.commands.research.body.equipment,
|
||||||
[
|
{
|
||||||
costs[index].equipment.toLocaleString(
|
cost: costs[index].equipment.toLocaleString(
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
),
|
),
|
||||||
],
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}),
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CommandWrapper>
|
</CommandWrapper>
|
||||||
@@ -621,7 +620,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
autocomplete(interaction) {
|
autocomplete(interaction) {
|
||||||
autocompleteTanks(interaction, true, ['target-tank', 'starting-tank']);
|
autocompleteTanks(interaction, true, ["target-tank", "starting-tank"]);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
import { ClanList, fetchBlitz, Region } from '@blitzkit/core';
|
import { type ClanList, fetchBlitz, type Region } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { addClanChoices } from '../core/discord/addClanChoices';
|
import { addClanChoices } from "../core/discord/addClanChoices";
|
||||||
import { addRegionChoices } from '../core/discord/addRegionChoices';
|
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from "../core/discord/embedInfo";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const DEFAULT_LIMIT = 25;
|
const DEFAULT_LIMIT = 25;
|
||||||
|
|
||||||
export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('search-clans')
|
command: createLocalizedCommand("search-clans")
|
||||||
.addStringOption(addRegionChoices)
|
.addStringOption(addRegionChoices)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
addClanChoices(option).setAutocomplete(false),
|
addClanChoices(option).setAutocomplete(false)
|
||||||
)
|
)
|
||||||
.addIntegerOption((option) => {
|
.addIntegerOption((option) => {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
@@ -28,21 +28,21 @@ export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands.search_clans.options.limit.name,
|
(strings) => strings.bot.commands.search_clans.options.limit.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
literals(
|
literals(
|
||||||
strings.bot.commands.search_clans.options.limit.description,
|
strings.bot.commands.search_clans.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.search_clans.options.limit.description,
|
strings.bot.commands.search_clans.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setMinValue(1)
|
.setMinValue(1)
|
||||||
.setMaxValue(100);
|
.setMaxValue(100);
|
||||||
@@ -50,24 +50,24 @@ export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const region = interaction.options.getString('region') as Region;
|
const region = interaction.options.getString("region") as Region;
|
||||||
const clan = interaction.options.getString('clan')!;
|
const clan = interaction.options.getString("clan")!;
|
||||||
const limit = interaction.options.getInteger('limit') ?? DEFAULT_LIMIT;
|
const limit = interaction.options.getInteger("limit") ?? DEFAULT_LIMIT;
|
||||||
const clanList = await fetchBlitz<ClanList>(region, 'clans/list', {
|
const clanList = await fetchBlitz<ClanList>(region, "clans/list", {
|
||||||
search: clan,
|
search: clan,
|
||||||
limit,
|
limit,
|
||||||
});
|
});
|
||||||
|
|
||||||
return embedInfo(
|
return embedInfo(
|
||||||
literals(strings.bot.commands.search_clans.body.title, [
|
literals(strings.bot.commands.search_clans.body.title, {
|
||||||
markdownEscape(clan),
|
search: markdownEscape(clan),
|
||||||
strings.common.regions.normal[region],
|
region: strings.common.regions.normal[region],
|
||||||
]),
|
}),
|
||||||
clanList.length === 0
|
clanList.length === 0
|
||||||
? strings.bot.commands.search_clans.body.no_results
|
? strings.bot.commands.search_clans.body.no_results
|
||||||
: `\`\`\`\n${clanList
|
: `\`\`\`\n${clanList
|
||||||
.map((clan) => `${clan.name} [${clan.tag}]`)
|
.map((clan) => `${clan.name} [${clan.tag}]`)
|
||||||
.join('\n')}\n\`\`\``,
|
.join("\n")}\n\`\`\``
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
AccountList,
|
type AccountList,
|
||||||
fetchBlitz,
|
fetchBlitz,
|
||||||
Region,
|
type Region,
|
||||||
usernamePattern,
|
usernamePattern,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { addRegionChoices } from '../core/discord/addRegionChoices';
|
import { addRegionChoices } from "../core/discord/addRegionChoices";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { embedInfo } from '../core/discord/embedInfo';
|
import { embedInfo } from "../core/discord/embedInfo";
|
||||||
import { localizationObject } from '../core/discord/localizationObject';
|
import { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
const DEFAULT_LIMIT = 25;
|
const DEFAULT_LIMIT = 25;
|
||||||
|
|
||||||
@@ -21,10 +21,10 @@ export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('search-players')
|
command: createLocalizedCommand("search-players")
|
||||||
.addStringOption(addRegionChoices)
|
.addStringOption(addRegionChoices)
|
||||||
.addStringOption((option) =>
|
.addStringOption((option) =>
|
||||||
addUsernameChoices(option).setAutocomplete(false).setRequired(true),
|
addUsernameChoices(option).setAutocomplete(false).setRequired(true)
|
||||||
)
|
)
|
||||||
.addIntegerOption((option) =>
|
.addIntegerOption((option) =>
|
||||||
option
|
option
|
||||||
@@ -34,49 +34,49 @@ export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.search_players.options.limit.name,
|
strings.bot.commands.search_players.options.limit.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(
|
.setDescription(
|
||||||
literals(
|
literals(
|
||||||
strings.bot.commands.search_players.options.limit.description,
|
strings.bot.commands.search_players.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
strings.bot.commands.search_players.options.limit.description,
|
strings.bot.commands.search_players.options.limit.description,
|
||||||
[`${DEFAULT_LIMIT}`],
|
{ limit: DEFAULT_LIMIT }
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setMinValue(1)
|
.setMinValue(1)
|
||||||
.setMaxValue(100),
|
.setMaxValue(100)
|
||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const region = interaction.options.getString('region') as Region;
|
const region = interaction.options.getString("region") as Region;
|
||||||
const name = interaction.options.getString('username')!;
|
const name = interaction.options.getString("username")!;
|
||||||
const limit = interaction.options.getInteger('limit') ?? 25;
|
const limit = interaction.options.getInteger("limit") ?? 25;
|
||||||
const trimmedSearch = name.trim();
|
const trimmedSearch = name.trim();
|
||||||
const players = usernamePattern.test(trimmedSearch)
|
const players = usernamePattern.test(trimmedSearch)
|
||||||
? await fetchBlitz<AccountList>(region, 'account/list', {
|
? await fetchBlitz<AccountList>(region, "account/list", {
|
||||||
search: trimmedSearch,
|
search: trimmedSearch,
|
||||||
limit,
|
limit,
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return embedInfo(
|
return embedInfo(
|
||||||
literals(strings.bot.commands.search_players.body.title, [
|
literals(strings.bot.commands.search_players.body.title, {
|
||||||
markdownEscape(trimmedSearch),
|
search: markdownEscape(trimmedSearch),
|
||||||
strings.common.regions.normal[region],
|
region: strings.common.regions.normal[region],
|
||||||
]),
|
}),
|
||||||
`\`\`\`${
|
`\`\`\`${
|
||||||
players.length === 0
|
players.length === 0
|
||||||
? strings.bot.commands.search_players.body.no_results
|
? strings.bot.commands.search_players.body.no_results
|
||||||
: players.map((player) => player.nickname).join('\n')
|
: players.map((player) => player.nickname).join("\n")
|
||||||
}\`\`\``,
|
}\`\`\``
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,50 +1,50 @@
|
|||||||
import { emblemURL, getAccountInfo, getClanAccountInfo } from '@blitzkit/core';
|
import { emblemURL, getAccountInfo, getClanAccountInfo } from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { AllStatsOverview } from '../components/AllStatsOverview';
|
import { AllStatsOverview } from "../components/AllStatsOverview";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { NoData } from '../components/NoData';
|
import { NoData } from "../components/NoData";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { filtersToDescription } from '../core/blitzkit/filtersToDescription';
|
import { filtersToDescription } from "../core/blitzkit/filtersToDescription";
|
||||||
import { filterStats, StatFilters } from '../core/blitzstars/filterStats';
|
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
|
||||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
import { getBlitzStarsLinkButton } from "../core/blitzstars/getBlitzStarsLinkButton";
|
||||||
import { getStatsInPeriod } from '../core/blitzstars/getStatsInPeriod';
|
import { getStatsInPeriod } from "../core/blitzstars/getStatsInPeriod";
|
||||||
import { addPeriodicFilterOptions } from '../core/discord/addPeriodicFilterOptions';
|
import { addPeriodicFilterOptions } from "../core/discord/addPeriodicFilterOptions";
|
||||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
import { addUsernameChoices } from "../core/discord/addUsernameChoices";
|
||||||
import { autocompleteTanks } from '../core/discord/autocompleteTanks';
|
import { autocompleteTanks } from "../core/discord/autocompleteTanks";
|
||||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
import { autocompleteUsername } from "../core/discord/autocompleteUsername";
|
||||||
import { buttonRefresh } from '../core/discord/buttonRefresh';
|
import { buttonRefresh } from "../core/discord/buttonRefresh";
|
||||||
import { commandToURL } from '../core/discord/commandToURL';
|
import { commandToURL } from "../core/discord/commandToURL";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
|
import { getCustomPeriodParams } from "../core/discord/getCustomPeriodParams";
|
||||||
import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
|
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
|
||||||
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
import { getFiltersFromCommand } from "../core/discord/getFiltersFromCommand";
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPeriod,
|
type ResolvedPeriod,
|
||||||
resolvePeriodFromCommand,
|
resolvePeriodFromCommand,
|
||||||
} from '../core/discord/resolvePeriodFromCommand';
|
} from "../core/discord/resolvePeriodFromCommand";
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import {
|
import {
|
||||||
ResolvedPlayer,
|
type ResolvedPlayer,
|
||||||
resolvePlayerFromCommand,
|
resolvePlayerFromCommand,
|
||||||
} from '../core/discord/resolvePlayerFromCommand';
|
} from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
async function render(
|
async function render(
|
||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
{ start, end, name }: ResolvedPeriod,
|
{ start, end, name }: ResolvedPeriod,
|
||||||
filters: StatFilters,
|
filters: StatFilters,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const { nickname } = await getAccountInfo(region, id);
|
const { nickname } = await getAccountInfo(region, id);
|
||||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
const clan = (await getClanAccountInfo(region, id, ["clan"]))?.clan;
|
||||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
const diffedTankStats = await getStatsInPeriod(
|
const diffedTankStats = await getStatsInPeriod(
|
||||||
region,
|
region,
|
||||||
id,
|
id,
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
locale,
|
locale
|
||||||
);
|
);
|
||||||
const { stats, supplementary } = await filterStats(diffedTankStats, filters);
|
const { stats, supplementary } = await filterStats(diffedTankStats, filters);
|
||||||
const filterDescriptions = await filtersToDescription(filters, locale);
|
const filterDescriptions = await filtersToDescription(filters, locale);
|
||||||
@@ -72,8 +72,8 @@ async function render(
|
|||||||
export const statsCommand = new Promise<CommandRegistry>(async (resolve) => {
|
export const statsCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: await addPeriodicFilterOptions(
|
command: await addPeriodicFilterOptions(
|
||||||
createLocalizedCommand('stats'),
|
createLocalizedCommand("stats"),
|
||||||
(option) => option.addStringOption(addUsernameChoices),
|
(option) => option.addStringOption(addUsernameChoices)
|
||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton
|
|||||||
import { resolvePeriodFromCommand } from '../core/discord/resolvePeriodFromCommand';
|
import { resolvePeriodFromCommand } from '../core/discord/resolvePeriodFromCommand';
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
||||||
import { CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from '../events/interactionCreate';
|
||||||
import { renderBreakdown } from './breakdown/render';
|
import { renderBreakdown } from './breakdown/render';
|
||||||
|
|
||||||
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
|
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||||
|
|||||||
+10
-10
@@ -1,8 +1,8 @@
|
|||||||
import { ComponentProps } from 'react';
|
import { type ComponentProps } from "react";
|
||||||
|
|
||||||
export interface GlowProps extends ComponentProps<'div'> {
|
export interface GlowProps extends ComponentProps<"div"> {
|
||||||
color: string;
|
color: string;
|
||||||
direction?: 'default' | 'reverse';
|
direction?: "default" | "reverse";
|
||||||
rotation?: number;
|
rotation?: number;
|
||||||
startOpacity?: number;
|
startOpacity?: number;
|
||||||
endOpacity?: number;
|
endOpacity?: number;
|
||||||
@@ -12,7 +12,7 @@ const width = 16;
|
|||||||
|
|
||||||
export function Glow({
|
export function Glow({
|
||||||
color,
|
color,
|
||||||
direction = 'default',
|
direction = "default",
|
||||||
rotation = 0,
|
rotation = 0,
|
||||||
style,
|
style,
|
||||||
startOpacity = 0,
|
startOpacity = 0,
|
||||||
@@ -21,20 +21,20 @@ export function Glow({
|
|||||||
}: GlowProps) {
|
}: GlowProps) {
|
||||||
const color1 = `${color}${Math.round(endOpacity * 255)
|
const color1 = `${color}${Math.round(endOpacity * 255)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.padStart(2, '0')}`;
|
.padStart(2, "0")}`;
|
||||||
const color2 = `${color}${Math.round(startOpacity * 255)
|
const color2 = `${color}${Math.round(startOpacity * 255)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.padStart(2, '0')}`;
|
.padStart(2, "0")}`;
|
||||||
const background = `linear-gradient(${
|
const background = `linear-gradient(${
|
||||||
direction === 'default' ? 0 : 180
|
direction === "default" ? 0 : 180
|
||||||
}deg, ${color1} 0%, ${color2} 100%)`;
|
}deg, ${color1} 0%, ${color2} 100%)`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: direction === 'default' ? 'flex-end' : 'flex-start',
|
alignItems: direction === "default" ? "flex-end" : "flex-start",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
transform: `rotate(${rotation}deg)`,
|
transform: `rotate(${rotation}deg)`,
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
getWN8Percentile,
|
getWN8Percentile,
|
||||||
Percentile,
|
Percentile,
|
||||||
SupplementaryStats,
|
type SupplementaryStats,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from 'discord.js';
|
||||||
import { translator } from '../../core/localization/translator';
|
import { translator } from '../../core/localization/translator';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
|
|
||||||
interface RootProps {
|
interface RootProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -8,7 +8,7 @@ export function Root({ children }: RootProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="session-tracker-root"
|
className="session-tracker-root"
|
||||||
style={{ display: 'flex', flexDirection: 'column', gap: 8 }}
|
style={{ display: "flex", flexDirection: "column", gap: 8 }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { createColors } from 'bepaint';
|
import { createColors } from 'bepaint';
|
||||||
import {
|
import {
|
||||||
AccentColor,
|
type AccentColor,
|
||||||
GrayColor,
|
type GrayColor,
|
||||||
PALETTES,
|
PALETTES,
|
||||||
} from '../../../core/radix/radixColors';
|
} from '../../../core/radix/radixColors';
|
||||||
import { RowStat } from './RowStat';
|
import { RowStat } from './RowStat';
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Percentile } from '@blitzkit/core';
|
import { Percentile } from "@blitzkit/core";
|
||||||
import { createColors } from 'bepaint';
|
import { createColors } from "bepaint";
|
||||||
import {
|
import {
|
||||||
AccentColor,
|
type AccentColor,
|
||||||
GrayColor,
|
type GrayColor,
|
||||||
PALETTES,
|
PALETTES,
|
||||||
} from '../../../core/radix/radixColors';
|
} from "../../../core/radix/radixColors";
|
||||||
import { PercentileIndicator } from '../../PercentileIndicator';
|
import { PercentileIndicator } from "../../PercentileIndicator";
|
||||||
|
|
||||||
interface RowStatProps {
|
interface RowStatProps {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -22,7 +22,7 @@ export function RowStat({
|
|||||||
delta,
|
delta,
|
||||||
percentile,
|
percentile,
|
||||||
minimized = false,
|
minimized = false,
|
||||||
color = 'slate',
|
color = "slate",
|
||||||
}: RowStatProps) {
|
}: RowStatProps) {
|
||||||
const theme = createColors(PALETTES[`${color}Dark`]);
|
const theme = createColors(PALETTES[`${color}Dark`]);
|
||||||
|
|
||||||
@@ -30,29 +30,29 @@ export function RowStat({
|
|||||||
<div
|
<div
|
||||||
className="session-tracker-row-stat"
|
className="session-tracker-row-stat"
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{percentile === undefined && delta !== undefined && delta !== 0 && (
|
{percentile === undefined && delta !== undefined && delta !== 0 && (
|
||||||
<img
|
<img
|
||||||
alt={delta > 0 ? 'Increase' : 'Decrease'}
|
alt={delta > 0 ? "Increase" : "Decrease"}
|
||||||
src={
|
src={
|
||||||
(delta ?? 0) > 0
|
(delta ?? 0) > 0
|
||||||
? 'https://i.imgur.com/qbjiXa1.png'
|
? "https://i.imgur.com/qbjiXa1.png"
|
||||||
: 'https://i.imgur.com/3uyNhun.png'
|
: "https://i.imgur.com/3uyNhun.png"
|
||||||
}
|
}
|
||||||
style={{ width: 12, height: 12 }}
|
style={{ width: 12, height: 12 }}
|
||||||
/>
|
/>
|
||||||
@@ -66,7 +66,7 @@ export function RowStat({
|
|||||||
color: theme.textHighContrast,
|
color: theme.textHighContrast,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
textAlign: 'center',
|
textAlign: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
@@ -77,7 +77,7 @@ export function RowStat({
|
|||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: theme.textLowContrast,
|
color: theme.textLowContrast,
|
||||||
textAlign: 'center',
|
textAlign: "center",
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
interface CommandWrapperProps {
|
interface CommandWrapperProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -10,14 +10,14 @@ export function CommandWrapper({ children, fat }: CommandWrapperProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
padding: `16px ${fat ? 0 : 16}px`,
|
padding: `16px ${fat ? 0 : 16}px`,
|
||||||
gap: 16,
|
gap: 16,
|
||||||
width: '100%',
|
width: "100%",
|
||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
backgroundColor: theme.colors.appBackground1,
|
backgroundColor: theme.colors.appBackground1,
|
||||||
position: 'relative',
|
position: "relative",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
BlitzStats,
|
type BlitzStats,
|
||||||
getWN8Percentile,
|
getWN8Percentile,
|
||||||
isNumber,
|
isNumber,
|
||||||
SupplementaryStats,
|
type SupplementaryStats,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from 'discord.js';
|
||||||
import { translator } from '../../core/localization/translator';
|
import { translator } from '../../core/localization/translator';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { GenericStat } from '..';
|
import { type GenericStat } from "..";
|
||||||
import { GenericStatsRow } from './GenericStatsRow';
|
import { GenericStatsRow } from "./GenericStatsRow";
|
||||||
|
|
||||||
interface GenericStatsColumnProps {
|
interface GenericStatsColumnProps {
|
||||||
stats: GenericStat[];
|
stats: GenericStat[];
|
||||||
@@ -7,7 +7,7 @@ interface GenericStatsColumnProps {
|
|||||||
|
|
||||||
export function GenericStatsColumn({ stats }: GenericStatsColumnProps) {
|
export function GenericStatsColumn({ stats }: GenericStatsColumnProps) {
|
||||||
return (
|
return (
|
||||||
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 8 }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 8 }}>
|
||||||
{stats.map((stat) => (
|
{stats.map((stat) => (
|
||||||
<GenericStatsRow key={stat[0]} stat={stat} />
|
<GenericStatsRow key={stat[0]} stat={stat} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { GenericStat } from '..';
|
import { type GenericStat } from "..";
|
||||||
import { theme } from '../../../stitches.config';
|
import { theme } from "../../../stitches.config";
|
||||||
import { PercentileIndicator } from '../../PercentileIndicator';
|
import { PercentileIndicator } from "../../PercentileIndicator";
|
||||||
|
|
||||||
interface GenericStatsRowProps {
|
interface GenericStatsRowProps {
|
||||||
stat: GenericStat;
|
stat: GenericStat;
|
||||||
@@ -10,18 +10,18 @@ export function GenericStatsRow({ stat }: GenericStatsRowProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
color: theme.colors.textLowContrast,
|
color: theme.colors.textLowContrast,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: "nowrap",
|
||||||
maxWidth: 128,
|
maxWidth: 128,
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{stat[0]}
|
{stat[0]}
|
||||||
@@ -32,9 +32,9 @@ export function GenericStatsRow({ stat }: GenericStatsRowProps) {
|
|||||||
color: theme.colors.textHighContrast,
|
color: theme.colors.textHighContrast,
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { times } from 'lodash-es';
|
import { times } from 'lodash-es';
|
||||||
import { theme } from '../../../../stitches.config';
|
import { theme } from '../../../../stitches.config';
|
||||||
import { MarginInputProps } from '../Root';
|
import { type MarginInputProps } from '../Root';
|
||||||
import { MarginOrientation } from './constants';
|
import { MarginOrientation } from './constants';
|
||||||
|
|
||||||
interface MarginProps extends MarginInputProps {
|
interface MarginProps extends MarginInputProps {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { times } from 'lodash-es';
|
import { times } from "lodash-es";
|
||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
import { theme } from '../../../../stitches.config';
|
import { theme } from "../../../../stitches.config";
|
||||||
import { Margin } from '../Margin';
|
import { Margin } from "../Margin";
|
||||||
import { MarginOrientation } from '../Margin/constants';
|
import { MarginOrientation } from "../Margin/constants";
|
||||||
import { GRAPH_HEIGHT, GRAPH_WIDTH } from './constants';
|
import { GRAPH_HEIGHT, GRAPH_WIDTH } from "./constants";
|
||||||
|
|
||||||
export interface MarginInputProps {
|
export interface MarginInputProps {
|
||||||
min: number;
|
min: number;
|
||||||
@@ -32,12 +32,12 @@ export function Root({
|
|||||||
xTitle,
|
xTitle,
|
||||||
}: RootProps) {
|
}: RootProps) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
paddingLeft: 64,
|
paddingLeft: 64,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: 16, color: theme.colors.textHighContrast }}>
|
<span style={{ fontSize: 16, color: theme.colors.textHighContrast }}>
|
||||||
@@ -48,7 +48,7 @@ export function Root({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: 'flex', gap: 16 }}>
|
<div style={{ display: "flex", gap: 16 }}>
|
||||||
{verticalMargin && (
|
{verticalMargin && (
|
||||||
<Margin {...verticalMargin} verticalSeparations={separations} />
|
<Margin {...verticalMargin} verticalSeparations={separations} />
|
||||||
)}
|
)}
|
||||||
@@ -94,9 +94,9 @@ export function Root({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
paddingLeft: 64,
|
paddingLeft: 64,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ComponentProps } from 'react';
|
import { type ComponentProps } from "react";
|
||||||
import { theme } from '../../../stitches.config';
|
import { theme } from "../../../stitches.config";
|
||||||
|
|
||||||
interface ItemProps extends ComponentProps<'div'> {
|
interface ItemProps extends ComponentProps<"div"> {
|
||||||
position: number;
|
position: number;
|
||||||
deltaPosition?: number;
|
deltaPosition?: number;
|
||||||
score?: number;
|
score?: number;
|
||||||
@@ -25,15 +25,15 @@ export function Item({
|
|||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
style={{
|
style={{
|
||||||
cursor: 'pointer',
|
cursor: "pointer",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
padding: 8,
|
padding: 8,
|
||||||
backgroundColor: highlight
|
backgroundColor: highlight
|
||||||
? theme.colors.componentInteractive_blue
|
? theme.colors.componentInteractive_blue
|
||||||
: theme.colors.componentInteractive,
|
: theme.colors.componentInteractive,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -50,9 +50,9 @@ export function Item({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -83,22 +83,22 @@ export function Item({
|
|||||||
{deltaPosition !== undefined && deltaPosition !== 0 && (
|
{deltaPosition !== undefined && deltaPosition !== 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt={deltaPosition > 0 ? 'Increase' : 'Decrease'}
|
alt={deltaPosition > 0 ? "Increase" : "Decrease"}
|
||||||
style={{
|
style={{
|
||||||
width: 8,
|
width: 8,
|
||||||
height: 8,
|
height: 8,
|
||||||
}}
|
}}
|
||||||
src={
|
src={
|
||||||
deltaPosition > 0
|
deltaPosition > 0
|
||||||
? 'https://i.imgur.com/qbjiXa1.png'
|
? "https://i.imgur.com/qbjiXa1.png"
|
||||||
: 'https://i.imgur.com/3uyNhun.png'
|
: "https://i.imgur.com/3uyNhun.png"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
@@ -119,11 +119,11 @@ export function Item({
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
width: 96,
|
width: 96,
|
||||||
justifyContent: 'flex-end',
|
justifyContent: "flex-end",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{deltaScore !== 0 && deltaScore !== undefined && (
|
{deltaScore !== 0 && deltaScore !== undefined && (
|
||||||
@@ -140,15 +140,15 @@ export function Item({
|
|||||||
)}
|
)}
|
||||||
{deltaScore !== 0 && deltaScore !== undefined && (
|
{deltaScore !== 0 && deltaScore !== undefined && (
|
||||||
<img
|
<img
|
||||||
alt={deltaScore > 0 ? 'Increase' : 'Decrease'}
|
alt={deltaScore > 0 ? "Increase" : "Decrease"}
|
||||||
style={{
|
style={{
|
||||||
width: 8,
|
width: 8,
|
||||||
height: 8,
|
height: 8,
|
||||||
}}
|
}}
|
||||||
src={
|
src={
|
||||||
deltaScore > 0
|
deltaScore > 0
|
||||||
? 'https://i.imgur.com/qbjiXa1.png'
|
? "https://i.imgur.com/qbjiXa1.png"
|
||||||
: 'https://i.imgur.com/3uyNhun.png'
|
: "https://i.imgur.com/3uyNhun.png"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from 'react';
|
||||||
|
|
||||||
interface RootProps {
|
interface RootProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from 'react';
|
||||||
|
|
||||||
interface ColumnProps {
|
interface ColumnProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
|
|
||||||
interface RootProps {
|
interface RootProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -8,8 +8,8 @@ export function Root({ children }: RootProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 16,
|
gap: 16,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { type ReactNode } from "react";
|
||||||
|
|
||||||
interface RowProps {
|
interface RowProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -8,7 +8,7 @@ export function Row({ children }: RowProps) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TierWeightsRecord } from '@blitzkit/core';
|
import type { TierWeightsRecord } from "@blitzkit/core";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
interface TierWeightsProps {
|
interface TierWeightsProps {
|
||||||
weights: TierWeightsRecord;
|
weights: TierWeightsRecord;
|
||||||
@@ -7,7 +7,7 @@ interface TierWeightsProps {
|
|||||||
|
|
||||||
export function TierWeights({ weights }: TierWeightsProps) {
|
export function TierWeights({ weights }: TierWeightsProps) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', gap: 8 }}>
|
<div style={{ display: "flex", gap: 8 }}>
|
||||||
{Object.entries(weights).map(([tier, weight]) => (
|
{Object.entries(weights).map(([tier, weight]) => (
|
||||||
<div
|
<div
|
||||||
key={tier}
|
key={tier}
|
||||||
@@ -15,11 +15,11 @@ export function TierWeights({ weights }: TierWeightsProps) {
|
|||||||
backgroundColor: theme.colors.appBackground1_light,
|
backgroundColor: theme.colors.appBackground1_light,
|
||||||
flex: weight,
|
flex: weight,
|
||||||
color: theme.colors.textHighContrast_light,
|
color: theme.colors.textHighContrast_light,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
minWidth: 16,
|
minWidth: 16,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
import { SEARCH_KEYS } from '@blitzkit/core';
|
import { SEARCH_KEYS } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { go } from 'fuzzysort';
|
import { go } from "fuzzysort";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { tankDefinitions, tankNames } from '../blitzkit/nonBlockingPromises';
|
import { tankDefinitions, tankNames } from "../blitzkit/nonBlockingPromises";
|
||||||
import { UserError } from '../blitzkit/userError';
|
import { UserError } from "../blitzkit/userError";
|
||||||
import { tankNamesTechTreeOnly } from '../discord/autocompleteTanks';
|
import { tankNamesTechTreeOnly } from "../discord/autocompleteTanks";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
export async function resolveTankId(
|
export async function resolveTankId(
|
||||||
tank: string | number,
|
tank: string | number,
|
||||||
locale: Locale,
|
locale: Locale,
|
||||||
techTreeOnly = false,
|
techTreeOnly = false
|
||||||
) {
|
) {
|
||||||
const { strings } = translator(locale);
|
const { strings } = translator(locale);
|
||||||
const number = typeof tank === 'string' ? Number(tank) : tank;
|
const number = typeof tank === "string" ? Number(tank) : tank;
|
||||||
|
|
||||||
if (Number.isNaN(number)) {
|
if (Number.isNaN(number)) {
|
||||||
const searchResult = go(
|
const searchResult = go(
|
||||||
`${tank}`,
|
`${tank}`,
|
||||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||||
{ keys: SEARCH_KEYS, limit: 1 },
|
{ keys: SEARCH_KEYS, limit: 1 }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (searchResult.length === 0) {
|
if (searchResult.length === 0) {
|
||||||
throw new UserError(
|
throw new UserError(
|
||||||
literals(strings.bot.common.errors.tank_name_not_found, [
|
literals(strings.bot.common.errors.tank_name_not_found, {
|
||||||
markdownEscape(`${tank}`),
|
search: markdownEscape(`${tank}`),
|
||||||
]),
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return searchResult[0].obj.id;
|
return searchResult[0].obj.id;
|
||||||
@@ -39,7 +39,9 @@ export async function resolveTankId(
|
|||||||
return number;
|
return number;
|
||||||
} else {
|
} else {
|
||||||
throw new UserError(
|
throw new UserError(
|
||||||
literals(strings.bot.common.errors.tank_id_not_found, [`${number}`]),
|
literals(strings.bot.common.errors.tank_id_not_found, {
|
||||||
|
search: number,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { fetchTankDefinitions, TIER_ROMAN_NUMERALS } from '@blitzkit/core';
|
import { fetchTankDefinitions, TIER_ROMAN_NUMERALS } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { StatFilters } from '../blitzstars/filterStats';
|
import { type StatFilters } from "../blitzstars/filterStats";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
export async function filtersToDescription(
|
export async function filtersToDescription(
|
||||||
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const { strings, bkLocale } = translator(locale);
|
const { strings, bkLocale } = translator(locale);
|
||||||
const awaitedTankDefinitions = await fetchTankDefinitions();
|
const awaitedTankDefinitions = await fetchTankDefinitions();
|
||||||
@@ -18,11 +18,13 @@ export async function filtersToDescription(
|
|||||||
info.push((strings.common.nations as Record<string, string>)[nation]);
|
info.push((strings.common.nations as Record<string, string>)[nation]);
|
||||||
if (tier) {
|
if (tier) {
|
||||||
info.push(
|
info.push(
|
||||||
literals(strings.bot.common.filters.tier, [TIER_ROMAN_NUMERALS[tier]]),
|
literals(strings.bot.common.filters.tier, {
|
||||||
|
tier: TIER_ROMAN_NUMERALS[tier],
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (tankClass) info.push(strings.common.tank_class_short[tankClass]);
|
if (tankClass) info.push(strings.common.tank_class_short[tankClass]);
|
||||||
if (type) info.push(strings.common.tree_type[type]);
|
if (type) info.push(strings.common.tree_type[type]);
|
||||||
|
|
||||||
return info.length === 0 ? strings.bot.common.filters.none : info.join(', ');
|
return info.length === 0 ? strings.bot.common.filters.none : info.join(", ");
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { getTimeDaysAgo, Region } from '@blitzkit/core';
|
import { getTimeDaysAgo, type Region } from '@blitzkit/core';
|
||||||
import { PeriodSize } from '../discord/addPeriodSubCommands';
|
import type { PeriodSize } from '../discord/addPeriodSubCommands';
|
||||||
|
|
||||||
export function getPeriodStart(region: Region, period: PeriodSize) {
|
export function getPeriodStart(region: Region, period: PeriodSize) {
|
||||||
if (period === 'career') return 0;
|
if (period === 'career') return 0;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import sharp from 'sharp';
|
import sharp from "sharp";
|
||||||
|
|
||||||
const cache: Record<string, Buffer> = {};
|
const cache: Record<string, Buffer> = {};
|
||||||
|
|
||||||
export async function iconPng(url: string) {
|
export async function iconPng(url: string) {
|
||||||
if (!url.endsWith('.webp')) return url;
|
if (!url.endsWith(".webp")) return url;
|
||||||
|
|
||||||
if (!cache[url]) {
|
if (!cache[url]) {
|
||||||
const imageResponse = await fetch(url);
|
const imageResponse = await fetch(url);
|
||||||
@@ -12,5 +12,5 @@ export async function iconPng(url: string) {
|
|||||||
cache[url] = imageBufferPNG;
|
cache[url] = imageBufferPNG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `data:image/png;base64,${cache[url].toString('base64')}`;
|
return `data:image/png;base64,${cache[url].toString("base64")}`;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { TankClass, TankType } from '@blitzkit/core';
|
import { TankClass, TankType } from "@blitzkit/core";
|
||||||
import { SupplementaryStats } from '@blitzkit/core/src/blitz/getAccountInfo';
|
import type { SupplementaryStats } from "@blitzkit/core/src/blitz/getAccountInfo";
|
||||||
import { calculateWN8 } from '@blitzkit/core/src/statistics/calculateWN8';
|
import { calculateWN8 } from "@blitzkit/core/src/statistics/calculateWN8";
|
||||||
import { BlitzStats } from '@blitzkit/core/src/statistics/compositeStats';
|
import type { BlitzStats } from "@blitzkit/core/src/statistics/compositeStats";
|
||||||
import { sumAllStats } from '@blitzkit/core/src/statistics/sumAllStats';
|
import { sumAllStats } from "@blitzkit/core/src/statistics/sumAllStats";
|
||||||
import { tankDefinitions } from '../blitzkit/nonBlockingPromises';
|
import { tankDefinitions } from "../blitzkit/nonBlockingPromises";
|
||||||
import { blitzStarsTankAverages } from './tankAverages';
|
import { blitzStarsTankAverages } from "./tankAverages";
|
||||||
|
|
||||||
export interface StatFilters {
|
export interface StatFilters {
|
||||||
nation?: string;
|
nation?: string;
|
||||||
@@ -16,7 +16,7 @@ export interface StatFilters {
|
|||||||
|
|
||||||
export async function filterStats(
|
export async function filterStats(
|
||||||
{ diff, order }: DiffedTankStats,
|
{ diff, order }: DiffedTankStats,
|
||||||
filters: StatFilters,
|
filters: StatFilters
|
||||||
) {
|
) {
|
||||||
// tank, if provided, takes priority over all other filters
|
// tank, if provided, takes priority over all other filters
|
||||||
if (filters.tank) filters = { tank: filters.tank };
|
if (filters.tank) filters = { tank: filters.tank };
|
||||||
@@ -45,14 +45,14 @@ export async function filterStats(
|
|||||||
const battlesOfTanksWithAverages = filteredOrder.reduce<number>(
|
const battlesOfTanksWithAverages = filteredOrder.reduce<number>(
|
||||||
(accumulator, id) =>
|
(accumulator, id) =>
|
||||||
awaitedTankAverages[id] ? accumulator + diff[id].battles : accumulator,
|
awaitedTankAverages[id] ? accumulator + diff[id].battles : accumulator,
|
||||||
0,
|
0
|
||||||
);
|
);
|
||||||
const battlesOfTanksWithTankDefinition = filteredOrder.reduce<number>(
|
const battlesOfTanksWithTankDefinition = filteredOrder.reduce<number>(
|
||||||
(accumulator, id) =>
|
(accumulator, id) =>
|
||||||
awaitedTankDefinitions.tanks[id]
|
awaitedTankDefinitions.tanks[id]
|
||||||
? accumulator + diff[id].battles
|
? accumulator + diff[id].battles
|
||||||
: accumulator,
|
: accumulator,
|
||||||
0,
|
0
|
||||||
);
|
);
|
||||||
const supplementary = {
|
const supplementary = {
|
||||||
WN8:
|
WN8:
|
||||||
@@ -63,7 +63,7 @@ export async function filterStats(
|
|||||||
calculateWN8(awaitedTankAverages[id].all, diff[id]) *
|
calculateWN8(awaitedTankAverages[id].all, diff[id]) *
|
||||||
diff[id].battles
|
diff[id].battles
|
||||||
: accumulator,
|
: accumulator,
|
||||||
0,
|
0
|
||||||
) / battlesOfTanksWithAverages,
|
) / battlesOfTanksWithAverages,
|
||||||
tier:
|
tier:
|
||||||
filteredOrder.reduce<number>(
|
filteredOrder.reduce<number>(
|
||||||
@@ -72,7 +72,7 @@ export async function filterStats(
|
|||||||
? accumulator +
|
? accumulator +
|
||||||
awaitedTankDefinitions.tanks[id]!.tier * diff[id].battles
|
awaitedTankDefinitions.tanks[id]!.tier * diff[id].battles
|
||||||
: accumulator,
|
: accumulator,
|
||||||
0,
|
0
|
||||||
) / battlesOfTanksWithTankDefinition,
|
) / battlesOfTanksWithTankDefinition,
|
||||||
} satisfies SupplementaryStats;
|
} satisfies SupplementaryStats;
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { getAccountInfo, Region } from '@blitzkit/core';
|
import { getAccountInfo, type Region } from "@blitzkit/core";
|
||||||
import { buttonLink } from '../discord/buttonLink';
|
import { buttonLink } from "../discord/buttonLink";
|
||||||
|
|
||||||
export async function getBlitzStarsLinkButton(
|
export async function getBlitzStarsLinkButton(
|
||||||
region: Region,
|
region: Region,
|
||||||
id: number,
|
id: number,
|
||||||
tankId?: number,
|
tankId?: number
|
||||||
) {
|
) {
|
||||||
const { nickname } = await getAccountInfo(region, id);
|
const { nickname } = await getAccountInfo(region, id);
|
||||||
|
|
||||||
return buttonLink(
|
return buttonLink(
|
||||||
`https://www.blitzstars.com/player/${region}/${nickname}${
|
`https://www.blitzstars.com/player/${region}/${nickname}${
|
||||||
tankId ? `/tank/${tankId!}` : ''
|
tankId ? `/tank/${tankId!}` : ""
|
||||||
}`,
|
}`,
|
||||||
'BlitzStars',
|
"BlitzStars"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Region, emptyAllStats, getAccountInfo } from '@blitzkit/core';
|
import { type Region, emptyAllStats, getAccountInfo } from '@blitzkit/core';
|
||||||
import {
|
import {
|
||||||
GetHistoriesOptions,
|
type GetHistoriesOptions,
|
||||||
Histories,
|
type Histories,
|
||||||
History,
|
type History,
|
||||||
getHistoriesDefaultOptions,
|
getHistoriesDefaultOptions,
|
||||||
} from '../../types/histories';
|
} from '../../types/histories';
|
||||||
import { PlayerStats } from './getPlayerStats';
|
import type { PlayerStats } from './getPlayerStats';
|
||||||
|
|
||||||
export async function getPlayerHistories(
|
export async function getPlayerHistories(
|
||||||
server: Region,
|
server: Region,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BlitzStats, Region } from '@blitzkit/core';
|
import type { BlitzStats, Region } from "@blitzkit/core";
|
||||||
|
|
||||||
interface IndividualPlayerStats {
|
interface IndividualPlayerStats {
|
||||||
clan: { clan_id: number; name: string; tag: string };
|
clan: { clan_id: number; name: string; tag: string };
|
||||||
@@ -25,13 +25,13 @@ export async function getPlayerStats<
|
|||||||
ReturnType = Ids extends number ? PlayerStats : PlayerStats[],
|
ReturnType = Ids extends number ? PlayerStats : PlayerStats[],
|
||||||
>(region: Region, ids: Ids) {
|
>(region: Region, ids: Ids) {
|
||||||
const stats = await Promise.all(
|
const stats = await Promise.all(
|
||||||
((typeof ids === 'number' ? [ids] : ids) as number[]).map((id) =>
|
((typeof ids === "number" ? [ids] : ids) as number[]).map((id) =>
|
||||||
fetch(`https://www.blitzstars.com/api/playerstats/${id}`).then(
|
fetch(`https://www.blitzstars.com/api/playerstats/${id}`).then(
|
||||||
(response) => response.json() as Promise<PlayerStats>,
|
(response) => response.json() as Promise<PlayerStats>
|
||||||
),
|
)
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeof ids === 'number') return stats[0] as ReturnType;
|
if (typeof ids === "number") return stats[0] as ReturnType;
|
||||||
return stats as ReturnType;
|
return stats as ReturnType;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { BlitzStats, emptyAllStats, Region } from '@blitzkit/core';
|
import { type BlitzStats, emptyAllStats, type Region } from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { DiffedTankStats } from './filterStats';
|
import type { DiffedTankStats } from "./filterStats";
|
||||||
import {
|
import {
|
||||||
getTankHistories,
|
getTankHistories,
|
||||||
TankHistories,
|
type TankHistories,
|
||||||
TankHistoryRaw,
|
type TankHistoryRaw,
|
||||||
} from './getTankHistories';
|
} from "./getTankHistories";
|
||||||
|
|
||||||
const emptyTankHistoryNode: TankHistoryRaw = {
|
const emptyTankHistoryNode: TankHistoryRaw = {
|
||||||
account_id: 0,
|
account_id: 0,
|
||||||
@@ -22,7 +22,7 @@ export async function getStatsInPeriod(
|
|||||||
id: number,
|
id: number,
|
||||||
start: number,
|
start: number,
|
||||||
end: number,
|
end: number,
|
||||||
locale: Locale,
|
locale: Locale
|
||||||
) {
|
) {
|
||||||
const history = await getTankHistories(server, id, locale, {
|
const history = await getTankHistories(server, id, locale, {
|
||||||
includeLatestHistories: true,
|
includeLatestHistories: true,
|
||||||
@@ -43,8 +43,8 @@ export async function getStatsInPeriod(
|
|||||||
// find the ones played within the range
|
// find the ones played within the range
|
||||||
const inRangeTanks = tanks.filter((tankId) =>
|
const inRangeTanks = tanks.filter((tankId) =>
|
||||||
tankSortedHistory[tankId].some(
|
tankSortedHistory[tankId].some(
|
||||||
(node) => node.last_battle_time > start && node.last_battle_time < end,
|
(node) => node.last_battle_time > start && node.last_battle_time < end
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
const playedTanks: number[] = [];
|
const playedTanks: number[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { Region, emptyAllStats, getTankStats } from '@blitzkit/core';
|
import { type Region, emptyAllStats, getTankStats } from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import {
|
import {
|
||||||
GetHistoriesOptions,
|
type GetHistoriesOptions,
|
||||||
Histories,
|
type Histories,
|
||||||
History,
|
type History,
|
||||||
getHistoriesDefaultOptions,
|
getHistoriesDefaultOptions,
|
||||||
} from '../../types/histories';
|
} from "../../types/histories";
|
||||||
import { UserError } from '../blitzkit/userError';
|
import { UserError } from "../blitzkit/userError";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
export interface TankHistory extends History {
|
export interface TankHistory extends History {
|
||||||
tank_id: number;
|
tank_id: number;
|
||||||
@@ -36,12 +36,12 @@ export async function getTankHistories(
|
|||||||
server: Region,
|
server: Region,
|
||||||
id: number,
|
id: number,
|
||||||
locale: Locale,
|
locale: Locale,
|
||||||
options?: Partial<GetTankHistoriesOptions>,
|
options?: Partial<GetTankHistoriesOptions>
|
||||||
) {
|
) {
|
||||||
const { strings } = translator(locale);
|
const { strings } = translator(locale);
|
||||||
const mergedOptions = { ...getTankHistoriesDefaultOptions, ...options };
|
const mergedOptions = { ...getTankHistoriesDefaultOptions, ...options };
|
||||||
const tankHistoriesResponse = await fetch(
|
const tankHistoriesResponse = await fetch(
|
||||||
`https://www.blitzstars.com/api/tankhistories/for/${id}/`,
|
`https://www.blitzstars.com/api/tankhistories/for/${id}/`
|
||||||
);
|
);
|
||||||
const tankHistories = (
|
const tankHistories = (
|
||||||
(await tankHistoriesResponse.json()) as TankHistoriesRaw
|
(await tankHistoriesResponse.json()) as TankHistoriesRaw
|
||||||
@@ -51,7 +51,7 @@ export async function getTankHistories(
|
|||||||
all: history.all,
|
all: history.all,
|
||||||
last_battle_time: history.last_battle_time,
|
last_battle_time: history.last_battle_time,
|
||||||
tank_id: history.tank_id,
|
tank_id: history.tank_id,
|
||||||
}) satisfies TankHistory,
|
}) satisfies TankHistory
|
||||||
);
|
);
|
||||||
const compliantTanks: number[] = [];
|
const compliantTanks: number[] = [];
|
||||||
const lastBattles: Record<number, number> = {};
|
const lastBattles: Record<number, number> = {};
|
||||||
@@ -73,7 +73,7 @@ export async function getTankHistories(
|
|||||||
lastBattles[tank_id] = battles;
|
lastBattles[tank_id] = battles;
|
||||||
|
|
||||||
return complies;
|
return complies;
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const latestNodes: TankHistories = [];
|
const latestNodes: TankHistories = [];
|
||||||
@@ -112,7 +112,7 @@ export async function getTankHistories(
|
|||||||
all: emptyAllStats,
|
all: emptyAllStats,
|
||||||
last_battle_time: -Infinity,
|
last_battle_time: -Infinity,
|
||||||
tank_id: tankId,
|
tank_id: tankId,
|
||||||
} satisfies TankHistory),
|
} satisfies TankHistory)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
TANK_TYPES,
|
TANK_TYPES,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
type APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { REGIONS } from '@blitzkit/core';
|
import { REGIONS } from "@blitzkit/core";
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
type APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandStringOption,
|
SlashCommandStringOption,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { localizationObject } from './localizationObject';
|
import { localizationObject } from "./localizationObject";
|
||||||
|
|
||||||
export function addRegionChoices(option: SlashCommandStringOption) {
|
export function addRegionChoices(option: SlashCommandStringOption) {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
@@ -16,14 +16,14 @@ export function addRegionChoices(option: SlashCommandStringOption) {
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.region.name,
|
(strings) => strings.bot.common.options.region.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(strings.bot.common.options.region.description)
|
.setDescription(strings.bot.common.options.region.description)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.region.description,
|
(strings) => strings.bot.common.options.region.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.addChoices(
|
.addChoices(
|
||||||
...REGIONS.map(
|
...REGIONS.map(
|
||||||
@@ -32,10 +32,10 @@ export function addRegionChoices(option: SlashCommandStringOption) {
|
|||||||
value: region,
|
value: region,
|
||||||
name: strings.common.regions.normal[region],
|
name: strings.common.regions.normal[region],
|
||||||
name_localizations: localizationObject(
|
name_localizations: localizationObject(
|
||||||
(strings) => strings.common.regions.normal[region],
|
(strings) => strings.common.regions.normal[region]
|
||||||
),
|
),
|
||||||
}) satisfies APIApplicationCommandOptionChoice,
|
}) satisfies APIApplicationCommandOptionChoice
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(true);
|
.setRequired(true);
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { numberToRomanNumeral } from '@blitzkit/core';
|
import { numberToRomanNumeral } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import {
|
import {
|
||||||
APIApplicationCommandOptionChoice,
|
APIApplicationCommandOptionChoice,
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandStringOption,
|
SlashCommandStringOption,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { range } from 'lodash-es';
|
import { range } from "lodash-es";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { localizationObject } from './localizationObject';
|
import { localizationObject } from "./localizationObject";
|
||||||
|
|
||||||
export function addTierChoices(option: SlashCommandStringOption) {
|
export function addTierChoices(option: SlashCommandStringOption) {
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
@@ -18,30 +18,30 @@ export function addTierChoices(option: SlashCommandStringOption) {
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.tier.name,
|
(strings) => strings.bot.common.options.tier.name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(strings.bot.common.options.tier.description)
|
.setDescription(strings.bot.common.options.tier.description)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.common.options.tier.description,
|
(strings) => strings.bot.common.options.tier.description
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setChoices(
|
.setChoices(
|
||||||
...range(10, 0).map(
|
...range(10, 0).map(
|
||||||
(tier) =>
|
(tier) =>
|
||||||
({
|
({
|
||||||
name: literals(strings.bot.common.options.tier.choices.tier, [
|
name: literals(strings.bot.common.options.tier.choices.tier, {
|
||||||
`${tier}`,
|
tier_1: tier,
|
||||||
numberToRomanNumeral(tier),
|
tier_2: numberToRomanNumeral(tier),
|
||||||
]),
|
}),
|
||||||
value: `${tier}`,
|
value: `${tier}`,
|
||||||
name_localizations: localizationObject(
|
name_localizations: localizationObject(
|
||||||
(strings) => strings.bot.common.options.tier.choices.tier,
|
(strings) => strings.bot.common.options.tier.choices.tier,
|
||||||
[`${tier}`, numberToRomanNumeral(tier)],
|
{ tier_1: tier, tier_2: numberToRomanNumeral(tier) }
|
||||||
),
|
),
|
||||||
}) satisfies APIApplicationCommandOptionChoice,
|
}) satisfies APIApplicationCommandOptionChoice
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setRequired(true);
|
.setRequired(true);
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,25 @@
|
|||||||
import { fetchTankNames, SEARCH_KEYS, TankType } from '@blitzkit/core';
|
import { fetchTankNames, SEARCH_KEYS, TankType } from "@blitzkit/core";
|
||||||
import {
|
import {
|
||||||
ApplicationCommandOptionChoiceData,
|
type ApplicationCommandOptionChoiceData,
|
||||||
AutocompleteInteraction,
|
AutocompleteInteraction,
|
||||||
CacheType,
|
type CacheType,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { go } from 'fuzzysort';
|
import { go } from "fuzzysort";
|
||||||
import { tankNames } from '../blitzkit/nonBlockingPromises';
|
import { tankNames } from "../blitzkit/nonBlockingPromises";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import {
|
import {
|
||||||
DISCORD_CHOICES_MAX_NAME_SIZE,
|
DISCORD_CHOICES_MAX_NAME_SIZE,
|
||||||
OVERFLOW_SUFFIX,
|
OVERFLOW_SUFFIX,
|
||||||
} from './autocompleteClan/constants';
|
} from "./autocompleteClan/constants";
|
||||||
|
|
||||||
export const tankNamesTechTreeOnly = fetchTankNames().then((names) =>
|
export const tankNamesTechTreeOnly = fetchTankNames().then((names) =>
|
||||||
names.filter((tank) => tank.treeType === TankType.RESEARCHABLE),
|
names.filter((tank) => tank.treeType === TankType.RESEARCHABLE)
|
||||||
);
|
);
|
||||||
|
|
||||||
export async function autocompleteTanks(
|
export async function autocompleteTanks(
|
||||||
interaction: AutocompleteInteraction<CacheType>,
|
interaction: AutocompleteInteraction<CacheType>,
|
||||||
techTreeOnly = false,
|
techTreeOnly = false,
|
||||||
fields = ['tank'],
|
fields = ["tank"]
|
||||||
) {
|
) {
|
||||||
const { unwrap } = translator(interaction.locale);
|
const { unwrap } = translator(interaction.locale);
|
||||||
const focusedOption = interaction.options.getFocused(true);
|
const focusedOption = interaction.options.getFocused(true);
|
||||||
@@ -31,7 +31,7 @@ export async function autocompleteTanks(
|
|||||||
go(
|
go(
|
||||||
focusedOption.value,
|
focusedOption.value,
|
||||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||||
{ keys: SEARCH_KEYS, limit: 10 },
|
{ keys: SEARCH_KEYS, limit: 10 }
|
||||||
).map(async (item) => {
|
).map(async (item) => {
|
||||||
let name = unwrap(item.obj.searchableName);
|
let name = unwrap(item.obj.searchableName);
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ export async function autocompleteTanks(
|
|||||||
0,
|
0,
|
||||||
unwrap(item.obj.searchableName).length -
|
unwrap(item.obj.searchableName).length -
|
||||||
overSize -
|
overSize -
|
||||||
OVERFLOW_SUFFIX.length,
|
OVERFLOW_SUFFIX.length
|
||||||
)}${OVERFLOW_SUFFIX}`;
|
)}${OVERFLOW_SUFFIX}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +50,8 @@ export async function autocompleteTanks(
|
|||||||
name,
|
name,
|
||||||
value: `${item.obj.id}`,
|
value: `${item.obj.id}`,
|
||||||
} satisfies ApplicationCommandOptionChoiceData<string>;
|
} satisfies ApplicationCommandOptionChoiceData<string>;
|
||||||
}),
|
})
|
||||||
)
|
)
|
||||||
: [],
|
: []
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
ComponentEmojiResolvable,
|
type ComponentEmojiResolvable,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
|
|
||||||
export function buttonLink(
|
export function buttonLink(
|
||||||
url: string,
|
url: string,
|
||||||
label: string,
|
label: string,
|
||||||
emoji?: ComponentEmojiResolvable,
|
emoji?: ComponentEmojiResolvable
|
||||||
) {
|
) {
|
||||||
const button = new ButtonBuilder()
|
const button = new ButtonBuilder()
|
||||||
.setStyle(ButtonStyle.Link)
|
.setStyle(ButtonStyle.Link)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
ComponentEmojiResolvable,
|
type ComponentEmojiResolvable,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
|
|
||||||
export function buttonPrimary(
|
export function buttonPrimary(
|
||||||
id: string,
|
id: string,
|
||||||
label: string,
|
label: string,
|
||||||
emoji?: ComponentEmojiResolvable,
|
emoji?: ComponentEmojiResolvable
|
||||||
) {
|
) {
|
||||||
const button = new ButtonBuilder()
|
const button = new ButtonBuilder()
|
||||||
.setCustomId(id)
|
.setCustomId(id)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
import { type CacheType, ChatInputCommandInteraction } from "discord.js";
|
||||||
|
|
||||||
export interface Parameters {
|
export interface Parameters {
|
||||||
[key: string]: string | number | boolean | undefined | null;
|
[key: string]: string | number | boolean | undefined | null;
|
||||||
@@ -9,7 +9,7 @@ export interface Parameters {
|
|||||||
|
|
||||||
export function commandToURL(
|
export function commandToURL(
|
||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
parameters?: Parameters,
|
parameters?: Parameters
|
||||||
) {
|
) {
|
||||||
const pathname = [
|
const pathname = [
|
||||||
interaction.commandName,
|
interaction.commandName,
|
||||||
@@ -17,11 +17,11 @@ export function commandToURL(
|
|||||||
interaction.options.getSubcommand(false),
|
interaction.options.getSubcommand(false),
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('/');
|
.join("/");
|
||||||
const params = (parameters ? Object.entries(parameters) : [])
|
const params = (parameters ? Object.entries(parameters) : [])
|
||||||
.filter(([, value]) => value !== undefined && value !== null)
|
.filter(([, value]) => value !== undefined && value !== null)
|
||||||
.map(([key, value]) => `${key}=${value}`)
|
.map(([key, value]) => `${key}=${value}`)
|
||||||
.join('&');
|
.join("&");
|
||||||
|
|
||||||
return `${pathname}${params.length > 0 ? `?${params}` : ''}`;
|
return `${pathname}${params.length > 0 ? `?${params}` : ""}`;
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { BlitzKitStrings } from '@blitzkit/i18n';
|
import { type BlitzKitStrings } from "@blitzkit/i18n";
|
||||||
import {
|
import {
|
||||||
Locale,
|
Locale,
|
||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
SlashCommandSubcommandBuilder,
|
SlashCommandSubcommandBuilder,
|
||||||
SlashCommandSubcommandGroupBuilder,
|
SlashCommandSubcommandGroupBuilder,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { localizationObject } from './localizationObject';
|
import { localizationObject } from "./localizationObject";
|
||||||
|
|
||||||
interface CreateLocalizedCommandSubcommand {
|
interface CreateLocalizedCommandSubcommand {
|
||||||
subcommand: string;
|
subcommand: string;
|
||||||
@@ -22,12 +22,12 @@ export function createLocalizedCommand(
|
|||||||
command: string,
|
command: string,
|
||||||
sub?:
|
sub?:
|
||||||
| CreateLocalizedCommandSubcommand[]
|
| CreateLocalizedCommandSubcommand[]
|
||||||
| CreateLocalizedCommandSubcommandGroup[],
|
| CreateLocalizedCommandSubcommandGroup[]
|
||||||
) {
|
) {
|
||||||
const commandPathItem = command.replaceAll(
|
const commandPathItem = command.replaceAll(
|
||||||
'-',
|
"-",
|
||||||
'_',
|
"_"
|
||||||
) as keyof BlitzKitStrings['bot']['commands'];
|
) as keyof BlitzKitStrings["bot"]["commands"];
|
||||||
const { strings } = translator(Locale.EnglishUS);
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
const slashCommand = new SlashCommandBuilder()
|
const slashCommand = new SlashCommandBuilder()
|
||||||
.setName(command)
|
.setName(command)
|
||||||
@@ -35,19 +35,19 @@ export function createLocalizedCommand(
|
|||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands[commandPathItem].name,
|
(strings) => strings.bot.commands[commandPathItem].name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.setDescription(strings.bot.commands[commandPathItem].description)
|
.setDescription(strings.bot.commands[commandPathItem].description)
|
||||||
.setDescriptionLocalizations(
|
.setDescriptionLocalizations(
|
||||||
localizationObject(
|
localizationObject(
|
||||||
(strings) => strings.bot.commands[commandPathItem].description,
|
(strings) => strings.bot.commands[commandPathItem].description
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sub) {
|
if (sub) {
|
||||||
sub.map((subItem) => {
|
sub.map((subItem) => {
|
||||||
if ('subcommand' in subItem) {
|
if ("subcommand" in subItem) {
|
||||||
const subcommandNameLocalizations = localizationObject(
|
const subcommandNameLocalizations = localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
(
|
(
|
||||||
@@ -56,7 +56,7 @@ export function createLocalizedCommand(
|
|||||||
}
|
}
|
||||||
).subcommands[subItem.subcommand].name,
|
).subcommands[subItem.subcommand].name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
const subcommandDescriptionLocalizations = localizationObject(
|
const subcommandDescriptionLocalizations = localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
@@ -64,7 +64,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
subcommands: Record<string, { description: string }>;
|
subcommands: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).subcommands[subItem.subcommand].description,
|
).subcommands[subItem.subcommand].description
|
||||||
);
|
);
|
||||||
|
|
||||||
slashCommand.addSubcommand((option) => {
|
slashCommand.addSubcommand((option) => {
|
||||||
@@ -78,7 +78,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
subcommands: Record<string, { description: string }>;
|
subcommands: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).subcommands[subItem.subcommand].description,
|
).subcommands[subItem.subcommand].description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
||||||
});
|
});
|
||||||
@@ -91,7 +91,7 @@ export function createLocalizedCommand(
|
|||||||
}
|
}
|
||||||
).groups[subItem.group].name,
|
).groups[subItem.group].name,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
true
|
||||||
);
|
);
|
||||||
const subcommandDescriptionLocalizations = localizationObject(
|
const subcommandDescriptionLocalizations = localizationObject(
|
||||||
(strings) =>
|
(strings) =>
|
||||||
@@ -99,7 +99,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
groups: Record<string, { description: string }>;
|
groups: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).groups[subItem.group].description,
|
).groups[subItem.group].description
|
||||||
);
|
);
|
||||||
|
|
||||||
slashCommand.addSubcommandGroup((option) => {
|
slashCommand.addSubcommandGroup((option) => {
|
||||||
@@ -113,7 +113,7 @@ export function createLocalizedCommand(
|
|||||||
strings.bot.commands[commandPathItem] as unknown as {
|
strings.bot.commands[commandPathItem] as unknown as {
|
||||||
groups: Record<string, { description: string }>;
|
groups: Record<string, { description: string }>;
|
||||||
}
|
}
|
||||||
).groups[subItem.group].description,
|
).groups[subItem.group].description
|
||||||
)
|
)
|
||||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { ChatInputCommandInteraction } from 'discord.js';
|
import { ChatInputCommandInteraction } from "discord.js";
|
||||||
import { PeriodType } from './addPeriodSubCommands';
|
import type { PeriodType } from "./addPeriodSubCommands";
|
||||||
|
|
||||||
export function getCustomPeriodParams(
|
export function getCustomPeriodParams(
|
||||||
interaction: ChatInputCommandInteraction,
|
interaction: ChatInputCommandInteraction,
|
||||||
forcedNonCustomPeriod = false,
|
forcedNonCustomPeriod = false
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
!forcedNonCustomPeriod &&
|
!forcedNonCustomPeriod &&
|
||||||
(interaction.options.getSubcommand() as PeriodType) === 'custom'
|
(interaction.options.getSubcommand() as PeriodType) === "custom"
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
start: interaction.options.getInteger('start', true),
|
start: interaction.options.getInteger("start", true),
|
||||||
end: interaction.options.getInteger('end', true),
|
end: interaction.options.getInteger("end", true),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { TankClass, TankType } from '@blitzkit/core';
|
import { TankClass, TankType } from "@blitzkit/core";
|
||||||
import { ButtonInteraction } from 'discord.js';
|
import { ButtonInteraction } from "discord.js";
|
||||||
import { StatFilters } from '../blitzstars/filterStats';
|
import type { StatFilters } from "../blitzstars/filterStats";
|
||||||
|
|
||||||
export function getFiltersFromButton(interaction: ButtonInteraction) {
|
export function getFiltersFromButton(interaction: ButtonInteraction) {
|
||||||
const url = new URL(`https://example.com/${interaction.customId}`);
|
const url = new URL(`https://example.com/${interaction.customId}`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nation: url.searchParams.get('nation') ?? undefined,
|
nation: url.searchParams.get("nation") ?? undefined,
|
||||||
tank: parseInt(url.searchParams.get('tank') ?? '0') || undefined,
|
tank: parseInt(url.searchParams.get("tank") ?? "0") || undefined,
|
||||||
class:
|
class:
|
||||||
(Number(url.searchParams.get('class')) as TankClass | undefined) ??
|
(Number(url.searchParams.get("class")) as TankClass | undefined) ??
|
||||||
undefined,
|
undefined,
|
||||||
type:
|
type:
|
||||||
(Number(url.searchParams.get('type')) as TankType | undefined) ??
|
(Number(url.searchParams.get("type")) as TankType | undefined) ??
|
||||||
undefined,
|
undefined,
|
||||||
tier: parseInt(url.searchParams.get('tier') ?? '0') || undefined,
|
tier: parseInt(url.searchParams.get("tier") ?? "0") || undefined,
|
||||||
} satisfies StatFilters;
|
} satisfies StatFilters;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ChatInputCommandInteraction } from 'discord.js';
|
import { ChatInputCommandInteraction } from 'discord.js';
|
||||||
import { resolveTankId } from '../blitz/resolveTankId';
|
import { resolveTankId } from '../blitz/resolveTankId';
|
||||||
import { StatFilters } from '../blitzstars/filterStats';
|
import type { StatFilters } from '../blitzstars/filterStats';
|
||||||
|
|
||||||
export async function getFiltersFromCommand(
|
export async function getFiltersFromCommand(
|
||||||
interaction: ChatInputCommandInteraction,
|
interaction: ChatInputCommandInteraction,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { PeriodSize } from './addPeriodSubCommands';
|
import type { PeriodSize } from "./addPeriodSubCommands";
|
||||||
|
|
||||||
export function getPeriodOptionName(period: PeriodSize, locale: Locale) {
|
export function getPeriodOptionName(period: PeriodSize, locale: Locale) {
|
||||||
const { strings } = translator(locale);
|
const { strings } = translator(locale);
|
||||||
if (period === 'career') return strings.bot.common.periods.career;
|
if (period === "career") return strings.bot.common.periods.career;
|
||||||
if (period === 'today') return strings.bot.common.periods.today;
|
if (period === "today") return strings.bot.common.periods.today;
|
||||||
return literals(strings.bot.common.periods.days, [period]);
|
return literals(strings.bot.common.periods.days, { days: period });
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { BlitzKitStrings, literals as literalsFunc } from '@blitzkit/i18n';
|
import { type BlitzKitStrings, literals as literalsFunc } from "@blitzkit/i18n";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { SUPPORTED_LOCALES_DISCORD } from '../localization/strings/constants';
|
import { SUPPORTED_LOCALES_DISCORD } from "../localization/strings/constants";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
const validNameRegex =
|
const validNameRegex =
|
||||||
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
|
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
|
||||||
|
|
||||||
export function localizationObject(
|
export function localizationObject(
|
||||||
path: (strings: BlitzKitStrings) => string,
|
path: (strings: BlitzKitStrings) => string,
|
||||||
literals: string[] = [],
|
literals?: Record<string, string | number>,
|
||||||
strict = false,
|
strict = false
|
||||||
) {
|
) {
|
||||||
return SUPPORTED_LOCALES_DISCORD.reduce<Partial<Record<Locale, string>>>(
|
return SUPPORTED_LOCALES_DISCORD.reduce<Partial<Record<Locale, string>>>(
|
||||||
(localizations, locale) => {
|
(localizations, locale) => {
|
||||||
@@ -20,7 +20,7 @@ export function localizationObject(
|
|||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Invalid localization for ${locale} (${path}): ${translation}; skipping...`,
|
`Invalid localization for ${locale} (${path}): ${translation}; skipping...`
|
||||||
);
|
);
|
||||||
return localizations;
|
return localizations;
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,6 @@ export function localizationObject(
|
|||||||
[locale]: translation,
|
[locale]: translation,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{},
|
{}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,12 @@ import {
|
|||||||
AttachmentBuilder,
|
AttachmentBuilder,
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
InteractionEditReplyOptions,
|
type InteractionEditReplyOptions,
|
||||||
InteractionReplyOptions,
|
type InteractionReplyOptions,
|
||||||
MessageEditOptions,
|
type MessageEditOptions,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
import { InteractionReturnable } from "../../events/interactionCreate";
|
import type { InteractionReturnable } from "../../events/interactionCreate";
|
||||||
import { Writeable } from "../../types/writable";
|
import type { Writeable } from "../../types/writable";
|
||||||
import { jsxToPngThreaded } from "../blitzkit/jsxToPngThreaded";
|
import { jsxToPngThreaded } from "../blitzkit/jsxToPngThreaded";
|
||||||
import { RenderConfiguration } from "../blitzkit/renderConfiguration";
|
import { RenderConfiguration } from "../blitzkit/renderConfiguration";
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
import { Region } from '@blitzkit/core';
|
import type { Region } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { ChatInputCommandInteraction } from 'discord.js';
|
import { ChatInputCommandInteraction } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { searchClansAcrossRegionsBotWrapper } from '../blitz/searchClansAcrossRegionsBotWrapper';
|
import { searchClansAcrossRegionsBotWrapper } from "../blitz/searchClansAcrossRegionsBotWrapper";
|
||||||
import { UserError } from '../blitzkit/userError';
|
import { UserError } from "../blitzkit/userError";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
|
|
||||||
export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/;
|
export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/;
|
||||||
|
|
||||||
export async function resolveClanFromCommand(
|
export async function resolveClanFromCommand(
|
||||||
interaction: ChatInputCommandInteraction,
|
interaction: ChatInputCommandInteraction
|
||||||
) {
|
) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const clan = interaction.options.getString('clan', true);
|
const clan = interaction.options.getString("clan", true);
|
||||||
|
|
||||||
if (serverAndIdPattern.test(clan)) {
|
if (serverAndIdPattern.test(clan)) {
|
||||||
const [server, accountId] = clan.split('/');
|
const [server, accountId] = clan.split("/");
|
||||||
return { region: server as Region, id: Number(accountId) };
|
return { region: server as Region, id: Number(accountId) };
|
||||||
} else {
|
} else {
|
||||||
const accounts = await searchClansAcrossRegionsBotWrapper(
|
const accounts = await searchClansAcrossRegionsBotWrapper(
|
||||||
clan,
|
clan,
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
);
|
);
|
||||||
|
|
||||||
if (accounts[0]) {
|
if (accounts[0]) {
|
||||||
return { region: accounts[0].region, id: accounts[0].clan_id };
|
return { region: accounts[0].region, id: accounts[0].clan_id };
|
||||||
} else {
|
} else {
|
||||||
throw new UserError(
|
throw new UserError(
|
||||||
literals(strings.bot.common.errors.clan_not_found, [
|
literals(strings.bot.common.errors.clan_not_found, {
|
||||||
markdownEscape(clan),
|
search: markdownEscape(clan),
|
||||||
]),
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { getTimeDaysAgo, Region } from '@blitzkit/core';
|
import { getTimeDaysAgo, type Region } from "@blitzkit/core";
|
||||||
import { ButtonInteraction } from 'discord.js';
|
import { ButtonInteraction } from "discord.js";
|
||||||
import { getPeriodNow } from '../blitzkit/getPeriodNow';
|
import { getPeriodNow } from "../blitzkit/getPeriodNow";
|
||||||
import { getPeriodStart } from '../blitzkit/getPeriodStart';
|
import { getPeriodStart } from "../blitzkit/getPeriodStart";
|
||||||
import { PeriodType } from './addPeriodSubCommands';
|
import type { PeriodType } from "./addPeriodSubCommands";
|
||||||
import { getPeriodOptionName } from './getPeriodOptionName';
|
import { getPeriodOptionName } from "./getPeriodOptionName";
|
||||||
import { ResolvedPeriod } from './resolvePeriodFromCommand';
|
import type { ResolvedPeriod } from "./resolvePeriodFromCommand";
|
||||||
|
|
||||||
export function resolvePeriodFromButton(
|
export function resolvePeriodFromButton(
|
||||||
region: Region,
|
region: Region,
|
||||||
interaction: ButtonInteraction,
|
interaction: ButtonInteraction
|
||||||
) {
|
) {
|
||||||
let name: string;
|
let name: string;
|
||||||
let start: number;
|
let start: number;
|
||||||
let end: number;
|
let end: number;
|
||||||
const url = new URL(`https://example.com/${interaction.customId}`);
|
const url = new URL(`https://example.com/${interaction.customId}`);
|
||||||
const path = url.pathname.split('/');
|
const path = url.pathname.split("/");
|
||||||
const periodSubcommand = path.at(-1) as PeriodType;
|
const periodSubcommand = path.at(-1) as PeriodType;
|
||||||
|
|
||||||
if (periodSubcommand === 'custom') {
|
if (periodSubcommand === "custom") {
|
||||||
const startRaw = parseInt(url!.searchParams.get('start')!);
|
const startRaw = parseInt(url!.searchParams.get("start")!);
|
||||||
const endRaw = parseInt(url!.searchParams.get('end')!);
|
const endRaw = parseInt(url!.searchParams.get("end")!);
|
||||||
const startDaysAgoMin = Math.min(startRaw, endRaw);
|
const startDaysAgoMin = Math.min(startRaw, endRaw);
|
||||||
const endDaysAgoMax = Math.max(startRaw, endRaw);
|
const endDaysAgoMax = Math.max(startRaw, endRaw);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { getTimeDaysAgo, Region } from '@blitzkit/core';
|
import { getTimeDaysAgo, type Region } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
import { type CacheType, ChatInputCommandInteraction } from "discord.js";
|
||||||
import { getPeriodNow } from '../blitzkit/getPeriodNow';
|
import { getPeriodNow } from "../blitzkit/getPeriodNow";
|
||||||
import { getPeriodStart } from '../blitzkit/getPeriodStart';
|
import { getPeriodStart } from "../blitzkit/getPeriodStart";
|
||||||
import { translator } from '../localization/translator';
|
import { translator } from "../localization/translator";
|
||||||
import { PeriodType } from './addPeriodSubCommands';
|
import type { PeriodType } from "./addPeriodSubCommands";
|
||||||
import { getPeriodOptionName } from './getPeriodOptionName';
|
import { getPeriodOptionName } from "./getPeriodOptionName";
|
||||||
|
|
||||||
export interface ResolvedPeriod {
|
export interface ResolvedPeriod {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -16,7 +16,7 @@ export interface ResolvedPeriod {
|
|||||||
export function resolvePeriodFromCommand(
|
export function resolvePeriodFromCommand(
|
||||||
region: Region,
|
region: Region,
|
||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
forcedPeriod?: PeriodType,
|
forcedPeriod?: PeriodType
|
||||||
) {
|
) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
let name: string;
|
let name: string;
|
||||||
@@ -26,16 +26,16 @@ export function resolvePeriodFromCommand(
|
|||||||
? forcedPeriod
|
? forcedPeriod
|
||||||
: (interaction.options.getSubcommand() as PeriodType);
|
: (interaction.options.getSubcommand() as PeriodType);
|
||||||
|
|
||||||
if (periodSubcommand === 'custom') {
|
if (periodSubcommand === "custom") {
|
||||||
const startOption = interaction.options.getInteger('start', true);
|
const startOption = interaction.options.getInteger("start", true);
|
||||||
const endOption = interaction.options.getInteger('end', true);
|
const endOption = interaction.options.getInteger("end", true);
|
||||||
const startDaysAgoMin = Math.min(startOption, endOption);
|
const startDaysAgoMin = Math.min(startOption, endOption);
|
||||||
const endDaysAgoMax = Math.max(startOption, endOption);
|
const endDaysAgoMax = Math.max(startOption, endOption);
|
||||||
|
|
||||||
name = literals(strings.bot.common.periods.custom, [
|
name = literals(strings.bot.common.periods.custom, {
|
||||||
`${startDaysAgoMin}`,
|
day_1: startDaysAgoMin,
|
||||||
`${endDaysAgoMax}`,
|
day_2: endDaysAgoMax,
|
||||||
]);
|
});
|
||||||
start = getTimeDaysAgo(region, endDaysAgoMax);
|
start = getTimeDaysAgo(region, endDaysAgoMax);
|
||||||
end = getTimeDaysAgo(region, startDaysAgoMin);
|
end = getTimeDaysAgo(region, startDaysAgoMin);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Region } from '@blitzkit/core';
|
import type { Region } from "@blitzkit/core";
|
||||||
import { ButtonInteraction } from 'discord.js';
|
import { ButtonInteraction } from "discord.js";
|
||||||
import { ResolvedPlayer } from './resolvePlayerFromCommand';
|
import type { ResolvedPlayer } from "./resolvePlayerFromCommand";
|
||||||
|
|
||||||
export async function resolvePlayerFromButton(interaction: ButtonInteraction) {
|
export async function resolvePlayerFromButton(interaction: ButtonInteraction) {
|
||||||
const url = new URL(`https://exmaple.com/${interaction.customId}`);
|
const url = new URL(`https://exmaple.com/${interaction.customId}`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: parseInt(url.searchParams.get('id')!),
|
id: parseInt(url.searchParams.get("id")!),
|
||||||
region: url.searchParams.get('region') as Region,
|
region: url.searchParams.get("region") as Region,
|
||||||
} satisfies ResolvedPlayer;
|
} satisfies ResolvedPlayer;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { idToRegion, Region } from '@blitzkit/core';
|
import { idToRegion, type Region } from "@blitzkit/core";
|
||||||
import { literals } from '@blitzkit/i18n';
|
import { literals } from "@blitzkit/i18n";
|
||||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
import { type CacheType, ChatInputCommandInteraction } from "discord.js";
|
||||||
import markdownEscape from 'markdown-escape';
|
import markdownEscape from "markdown-escape";
|
||||||
import { searchPlayersAcrossRegionsBotWrapper } from '../../blitz/searchPlayersAcrossRegionsBotWrapper';
|
import { searchPlayersAcrossRegionsBotWrapper } from "../../blitz/searchPlayersAcrossRegionsBotWrapper";
|
||||||
import { getBlitzFromDiscord } from '../../blitzkit/getBlitzFromDiscord';
|
import { getBlitzFromDiscord } from "../../blitzkit/getBlitzFromDiscord";
|
||||||
import { UserError } from '../../blitzkit/userError';
|
import { UserError } from "../../blitzkit/userError";
|
||||||
import { translator } from '../../localization/translator';
|
import { translator } from "../../localization/translator";
|
||||||
|
|
||||||
export interface ResolvedPlayer {
|
export interface ResolvedPlayer {
|
||||||
region: Region;
|
region: Region;
|
||||||
@@ -13,10 +13,10 @@ export interface ResolvedPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function resolvePlayerFromCommand(
|
export async function resolvePlayerFromCommand(
|
||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
interaction: ChatInputCommandInteraction<CacheType>
|
||||||
) {
|
) {
|
||||||
const { strings } = translator(interaction.locale);
|
const { strings } = translator(interaction.locale);
|
||||||
const commandUsername = interaction.options.getString('username');
|
const commandUsername = interaction.options.getString("username");
|
||||||
|
|
||||||
if (commandUsername !== null) {
|
if (commandUsername !== null) {
|
||||||
const id = parseInt(commandUsername);
|
const id = parseInt(commandUsername);
|
||||||
@@ -27,7 +27,7 @@ export async function resolvePlayerFromCommand(
|
|||||||
} else {
|
} else {
|
||||||
const accounts = await searchPlayersAcrossRegionsBotWrapper(
|
const accounts = await searchPlayersAcrossRegionsBotWrapper(
|
||||||
commandUsername,
|
commandUsername,
|
||||||
interaction.locale,
|
interaction.locale
|
||||||
);
|
);
|
||||||
|
|
||||||
if (accounts[0]) {
|
if (accounts[0]) {
|
||||||
@@ -37,9 +37,9 @@ export async function resolvePlayerFromCommand(
|
|||||||
} satisfies ResolvedPlayer;
|
} satisfies ResolvedPlayer;
|
||||||
} else {
|
} else {
|
||||||
throw new UserError(
|
throw new UserError(
|
||||||
literals(strings.bot.common.errors.player_not_found, [
|
literals(strings.bot.common.errors.player_not_found, {
|
||||||
markdownEscape(commandUsername),
|
search: markdownEscape(commandUsername),
|
||||||
]),
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
import * as colors from '@radix-ui/colors';
|
import * as colors from "@radix-ui/colors";
|
||||||
import { Theme } from '@radix-ui/themes';
|
import { Theme } from "@radix-ui/themes";
|
||||||
import { ComponentProps } from 'react';
|
import type { ComponentProps } from "react";
|
||||||
|
|
||||||
export type AccentColor = Exclude<
|
export type AccentColor = Exclude<
|
||||||
ComponentProps<typeof Theme>['accentColor'],
|
ComponentProps<typeof Theme>["accentColor"],
|
||||||
'gray' | undefined
|
"gray" | undefined
|
||||||
>;
|
>;
|
||||||
export type AccentColorDark = `${AccentColor}Dark`;
|
export type AccentColorDark = `${AccentColor}Dark`;
|
||||||
export type GrayColor = Exclude<
|
export type GrayColor = Exclude<
|
||||||
ComponentProps<typeof Theme>['grayColor'],
|
ComponentProps<typeof Theme>["grayColor"],
|
||||||
'auto' | undefined
|
"auto" | undefined
|
||||||
>;
|
>;
|
||||||
export type GrayColorDark = `${GrayColor}Dark`;
|
export type GrayColorDark = `${GrayColor}Dark`;
|
||||||
|
|
||||||
export const ACCENT_COLORS: AccentColor[] = [
|
export const ACCENT_COLORS: AccentColor[] = [
|
||||||
'tomato',
|
"tomato",
|
||||||
'red',
|
"red",
|
||||||
'ruby',
|
"ruby",
|
||||||
'crimson',
|
"crimson",
|
||||||
'pink',
|
"pink",
|
||||||
'plum',
|
"plum",
|
||||||
'purple',
|
"purple",
|
||||||
'violet',
|
"violet",
|
||||||
'iris',
|
"iris",
|
||||||
'indigo',
|
"indigo",
|
||||||
'blue',
|
"blue",
|
||||||
'cyan',
|
"cyan",
|
||||||
'teal',
|
"teal",
|
||||||
'jade',
|
"jade",
|
||||||
'green',
|
"green",
|
||||||
'grass',
|
"grass",
|
||||||
'brown',
|
"brown",
|
||||||
'orange',
|
"orange",
|
||||||
'sky',
|
"sky",
|
||||||
'mint',
|
"mint",
|
||||||
'lime',
|
"lime",
|
||||||
'yellow',
|
"yellow",
|
||||||
'amber',
|
"amber",
|
||||||
'gold',
|
"gold",
|
||||||
'bronze',
|
"bronze",
|
||||||
];
|
];
|
||||||
export const GRAY_COLORS: GrayColor[] = [
|
export const GRAY_COLORS: GrayColor[] = [
|
||||||
'gray',
|
"gray",
|
||||||
'mauve',
|
"mauve",
|
||||||
'slate',
|
"slate",
|
||||||
'sage',
|
"sage",
|
||||||
'olive',
|
"olive",
|
||||||
'sand',
|
"sand",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const PALETTES: Record<
|
export const PALETTES: Record<
|
||||||
|
|||||||
@@ -3,21 +3,21 @@ import {
|
|||||||
AttachmentBuilder,
|
AttachmentBuilder,
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
ButtonStyle,
|
ButtonStyle,
|
||||||
CacheType,
|
type CacheType,
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
InteractionReplyOptions,
|
type InteractionReplyOptions,
|
||||||
} from 'discord.js';
|
} from "discord.js";
|
||||||
import { InteractionRawReturnable, commands } from '..';
|
import { type InteractionRawReturnable, commands } from "..";
|
||||||
import { UserError } from '../../../core/blitzkit/userError';
|
import { UserError } from "../../../core/blitzkit/userError";
|
||||||
import { buttonLink } from '../../../core/discord/buttonLink';
|
import { buttonLink } from "../../../core/discord/buttonLink";
|
||||||
import { embedWarning } from '../../../core/discord/embedWarning';
|
import { embedWarning } from "../../../core/discord/embedWarning";
|
||||||
import { normalizeInteractionReturnable } from '../../../core/discord/normalizeInteractionReturnable';
|
import { normalizeInteractionReturnable } from "../../../core/discord/normalizeInteractionReturnable";
|
||||||
import { psa } from '../../../core/discord/psa';
|
import { psa } from "../../../core/discord/psa";
|
||||||
import { translator } from '../../../core/localization/translator';
|
import { translator } from "../../../core/localization/translator";
|
||||||
import { Writeable } from '../../../types/writable';
|
import type { Writeable } from "../../../types/writable";
|
||||||
|
|
||||||
export async function handleChatInputCommand(
|
export async function handleChatInputCommand(
|
||||||
interaction: ChatInputCommandInteraction<CacheType>,
|
interaction: ChatInputCommandInteraction<CacheType>
|
||||||
) {
|
) {
|
||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
|
|
||||||
@@ -33,10 +33,10 @@ export async function handleChatInputCommand(
|
|||||||
|
|
||||||
(Array.isArray(returnable) ? returnable : [returnable]).forEach(
|
(Array.isArray(returnable) ? returnable : [returnable]).forEach(
|
||||||
(object) => {
|
(object) => {
|
||||||
if (typeof object === 'string') {
|
if (typeof object === "string") {
|
||||||
chunks.push([object]);
|
chunks.push([object]);
|
||||||
} else chunks.at(-1)?.push(object!);
|
} else chunks.at(-1)?.push(object!);
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
@@ -49,17 +49,17 @@ export async function handleChatInputCommand(
|
|||||||
(psa.data.commands === undefined ||
|
(psa.data.commands === undefined ||
|
||||||
psa.data.commands.includes(interaction.commandName))
|
psa.data.commands.includes(interaction.commandName))
|
||||||
) {
|
) {
|
||||||
if (psa.data.type === undefined || psa.data.type === 'embed') {
|
if (psa.data.type === undefined || psa.data.type === "embed") {
|
||||||
if (!reply.embeds) reply.embeds = [];
|
if (!reply.embeds) reply.embeds = [];
|
||||||
|
|
||||||
const embed = embedWarning(psa.data.title, psa.data.description);
|
const embed = embedWarning(psa.data.title, psa.data.description);
|
||||||
|
|
||||||
if (psa.data.image) embed.setImage(psa.data.image);
|
if (psa.data.image) embed.setImage(psa.data.image);
|
||||||
(reply.embeds as Writeable<typeof reply.embeds>).push(embed);
|
(reply.embeds as Writeable<typeof reply.embeds>).push(embed);
|
||||||
} else if (psa.data.type === 'image') {
|
} else if (psa.data.type === "image") {
|
||||||
if (!reply.files) reply.files = [];
|
if (!reply.files) reply.files = [];
|
||||||
(reply.files as Writeable<typeof reply.files>).push(
|
(reply.files as Writeable<typeof reply.files>).push(
|
||||||
new AttachmentBuilder(psa.data.image),
|
new AttachmentBuilder(psa.data.image)
|
||||||
);
|
);
|
||||||
reply.content = reply.content ?? psa.data.title;
|
reply.content = reply.content ?? psa.data.title;
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ export async function handleChatInputCommand(
|
|||||||
(
|
(
|
||||||
reply.components[0] as ActionRowBuilder<ButtonBuilder>
|
reply.components[0] as ActionRowBuilder<ButtonBuilder>
|
||||||
).addComponents(
|
).addComponents(
|
||||||
psa.data.links.map(({ title, url }) => buttonLink(url, title)),
|
psa.data.links.map(({ title, url }) => buttonLink(url, title))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,17 +93,17 @@ export async function handleChatInputCommand(
|
|||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (psa.data.type === undefined || psa.data.type === 'embed') {
|
if (psa.data.type === undefined || psa.data.type === "embed") {
|
||||||
if (!followUp.embeds) followUp.embeds = [];
|
if (!followUp.embeds) followUp.embeds = [];
|
||||||
|
|
||||||
const embed = embedWarning(psa.data.title, psa.data.description);
|
const embed = embedWarning(psa.data.title, psa.data.description);
|
||||||
|
|
||||||
if (psa.data.image) embed.setImage(psa.data.image);
|
if (psa.data.image) embed.setImage(psa.data.image);
|
||||||
(followUp.embeds as Writeable<typeof followUp.embeds>).push(embed);
|
(followUp.embeds as Writeable<typeof followUp.embeds>).push(embed);
|
||||||
} else if (psa.data.type === 'image') {
|
} else if (psa.data.type === "image") {
|
||||||
if (!followUp.files) followUp.files = [];
|
if (!followUp.files) followUp.files = [];
|
||||||
(followUp.files as Writeable<typeof followUp.files>).push(
|
(followUp.files as Writeable<typeof followUp.files>).push(
|
||||||
new AttachmentBuilder(psa.data.image),
|
new AttachmentBuilder(psa.data.image)
|
||||||
);
|
);
|
||||||
followUp.content = followUp.content ?? psa.data.title;
|
followUp.content = followUp.content ?? psa.data.title;
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ export async function handleChatInputCommand(
|
|||||||
(
|
(
|
||||||
followUp.components[0] as ActionRowBuilder<ButtonBuilder>
|
followUp.components[0] as ActionRowBuilder<ButtonBuilder>
|
||||||
).addComponents(
|
).addComponents(
|
||||||
psa.data.links.map(({ title, url }) => buttonLink(url, title)),
|
psa.data.links.map(({ title, url }) => buttonLink(url, title))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +132,8 @@ export async function handleChatInputCommand(
|
|||||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
.setLabel(strings.bot.common.errors.get_help)
|
.setLabel(strings.bot.common.errors.get_help)
|
||||||
.setURL('https://discord.gg/nDt7AjGJQH')
|
.setURL("https://discord.gg/nDt7AjGJQH")
|
||||||
.setStyle(ButtonStyle.Link),
|
.setStyle(ButtonStyle.Link)
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
if (error instanceof UserError) {
|
if (error instanceof UserError) {
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ import {
|
|||||||
AutocompleteInteraction,
|
AutocompleteInteraction,
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
ButtonInteraction,
|
ButtonInteraction,
|
||||||
CacheType,
|
type CacheType,
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
EmbedBuilder,
|
EmbedBuilder,
|
||||||
Interaction,
|
type Interaction,
|
||||||
REST,
|
REST,
|
||||||
Routes,
|
Routes,
|
||||||
SlashCommandBuilder,
|
SlashCommandBuilder,
|
||||||
SlashCommandOptionsOnlyBuilder,
|
type SlashCommandOptionsOnlyBuilder,
|
||||||
SlashCommandSubcommandsOnlyBuilder,
|
type SlashCommandSubcommandsOnlyBuilder,
|
||||||
} from "discord.js";
|
} from "discord.js";
|
||||||
import { aboutCommand } from "../../commands/about";
|
import { aboutCommand } from "../../commands/about";
|
||||||
import { breakdownCommand } from "../../commands/breakdown";
|
import { breakdownCommand } from "../../commands/breakdown";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// a cleaner simplification of Blitz Stars' histories because it's a mess there
|
// a cleaner simplification of Blitz Stars' histories because it's a mess there
|
||||||
|
|
||||||
import { BlitzStats } from '@blitzkit/core';
|
import { type BlitzStats } from '@blitzkit/core';
|
||||||
|
|
||||||
export interface History {
|
export interface History {
|
||||||
all: BlitzStats;
|
all: BlitzStats;
|
||||||
|
|||||||
Submodule
+1
Submodule packages/closed added at 5b4a85d503.
@@ -4,20 +4,26 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@blitzkit/i18n": "workspace:*",
|
||||||
|
"@bufbuild/protobuf": "^2.9.0",
|
||||||
"@octokit/plugin-throttling": "^11.0.1",
|
"@octokit/plugin-throttling": "^11.0.1",
|
||||||
"@octokit/rest": "^22.0.0",
|
"@octokit/rest": "^22.0.0",
|
||||||
"@prisma/client": "^6.16.2",
|
"@prisma/client": "^6.16.2",
|
||||||
|
"@types/adm-zip": "^0.5.7",
|
||||||
|
"@types/bun": "^1.3.1",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/lz4js": "^0.2.1",
|
||||||
|
"@types/three": "^0.180.0",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
"crc": "^4.3.2",
|
"crc": "^4.3.2",
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.2.2",
|
||||||
|
"fast-xml-parser": "^5.3.2",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
"lz4js": "^0.2.0",
|
"lz4js": "^0.2.0",
|
||||||
"pickleparser": "^0.2.1",
|
"pickleparser": "^0.2.1",
|
||||||
"protobufjs": "^7.5.4",
|
"protobufjs": "^7.5.4",
|
||||||
|
"three": "^0.180.0",
|
||||||
"ts-proto": "^2.7.7",
|
"ts-proto": "^2.7.7",
|
||||||
"yaml": "^2.8.1"
|
"yaml": "^2.8.1"
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/adm-zip": "^0.5.7",
|
|
||||||
"@types/lz4js": "^0.2.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
export enum BlitzVFSSourceType {
|
||||||
|
Steam,
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlitzVFSSource = {
|
||||||
|
type: BlitzVFSSourceType;
|
||||||
|
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
|
||||||
|
app: number;
|
||||||
|
os: "windows";
|
||||||
|
};
|
||||||
|
|
||||||
|
export class BlitzVFS {
|
||||||
|
constructor(private source: BlitzVFSSource) {}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
async file(path: string) {
|
||||||
|
return new Uint8Array();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { type ShellDefinition, ShellType } from '@blitzkit/core';
|
import { ShellDefinition, ShellType } from "../protos";
|
||||||
|
|
||||||
export function canSplash(type: ShellDefinition['type']): type is ShellType.HE {
|
export function canSplash(type: ShellDefinition["type"]): type is ShellType.HE {
|
||||||
return type === ShellType.HE;
|
return type === ShellType.HE;
|
||||||
}
|
}
|
||||||
Loaded 100 of 354 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user