Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44711a58c7 | ||
|
|
e7337145d2 | ||
|
|
c116b40dfc | ||
|
|
d88f7ad539 | ||
|
|
b5d61cebb3 | ||
|
|
551108e047 | ||
|
|
5feec9bf1e | ||
|
|
313691d3e9 | ||
|
|
950c99d3d7 | ||
|
|
80cc74a945 | ||
|
|
4e586253c0 | ||
|
|
08980158e4 | ||
|
|
1e917c7b89 | ||
|
|
8d3678ddcb | ||
|
|
6a58c5ea1d | ||
|
|
b9bbf22f2c | ||
|
|
c99ed0cb53 | ||
|
|
cef18d4f64 | ||
|
|
824169fc25 | ||
|
|
841b5708ae | ||
|
|
8ad110f73b | ||
|
|
0869ea09c8 | ||
|
|
0e57943d33 | ||
|
|
8b01b7c192 | ||
|
|
a7bd671309 | ||
|
|
406ad52c8d | ||
|
|
b6c4c4e852 | ||
|
|
8394f2ec1e | ||
|
|
f14e73d811 | ||
|
|
f193d5c503 | ||
|
|
6a06cb17a3 | ||
|
|
427b189a34 | ||
|
|
bf218b0975 | ||
|
|
eab4266fd1 | ||
|
|
86b4b63a7c | ||
|
|
5412c479c8 | ||
|
|
547614fa89 | ||
|
|
e803d96f20 | ||
|
|
009caeeaf1 | ||
|
|
bfa80cd549 | ||
|
|
987c798b7e | ||
|
|
8dbe7cb155 | ||
|
|
053f1e3ac8 | ||
|
|
588c0a809b | ||
|
|
dde059b1f9 | ||
|
|
102072746a | ||
|
|
10d7fe1e75 | ||
|
|
4cc4e664df | ||
|
|
d5269e763b | ||
|
|
bae7ca2720 | ||
|
|
a0b81bfb83 | ||
|
|
629e9f814e | ||
|
|
f39d1bab4e | ||
|
|
bf61cb17de | ||
|
|
c8ba6b1eca | ||
|
|
1d8c823703 | ||
|
|
3594c9a971 | ||
|
|
f478a08bd9 | ||
|
|
115fa5acad | ||
|
|
c24a2989fa | ||
|
|
a6cfb522b3 | ||
|
|
12e645f6e2 | ||
|
|
ccb86ae824 | ||
|
|
9a3f64fcd6 | ||
|
|
001709c25c | ||
|
|
e50b8d11bf | ||
|
|
ea782af079 | ||
|
|
0ebf9f6c3d | ||
|
|
6fec467ec8 | ||
|
|
8b0f1cdfed | ||
|
|
f6008bd288 | ||
|
|
1776c8fc15 | ||
|
|
99f41b9805 | ||
|
|
d4f11fc52a | ||
|
|
750aeb39c9 | ||
|
|
0f355bc2fc | ||
|
|
6ebd3063ed | ||
|
|
b070cad92a | ||
|
|
204fbbff59 | ||
|
|
98e7760142 | ||
|
|
6c1c088d44 | ||
|
|
0b7f717057 | ||
|
|
728cb43f05 | ||
|
|
ff02f06cbc | ||
|
|
7a817cbe8c | ||
|
|
58e0876aa0 | ||
|
|
f84f846e76 | ||
|
|
ddb869e767 | ||
|
|
015d457d23 | ||
|
|
ba6a83a9cb | ||
|
|
689985ed93 | ||
|
|
bf9262f1f1 | ||
|
|
821bd363ad | ||
|
|
4a9fc65e71 | ||
|
|
81877f5abd | ||
|
|
01eed3e045 | ||
|
|
7bc423b570 | ||
|
|
dba56f8946 | ||
|
|
c1f765d5f7 | ||
|
|
7f5b5b614f | ||
|
|
5cd149b2b9 | ||
|
|
0bc2d0aaf6 | ||
|
|
1dc9a341d1 | ||
|
|
2ad1e71176 | ||
|
|
ca6973f529 | ||
|
|
323d624ec7 | ||
|
|
49f84db473 | ||
|
|
7399c402af | ||
|
|
cbfcb29691 | ||
|
|
ae616fbaf3 | ||
|
|
35275d4aa8 | ||
|
|
dda63830ec | ||
|
|
79b4f05809 | ||
|
|
b50c47b744 | ||
|
|
f7c6fdd861 | ||
|
|
47b583821e | ||
|
|
369ac113fa | ||
|
|
fc4d8b5ad0 | ||
|
|
72e1cf7d6a | ||
|
|
dd96556e2a | ||
|
|
a7ee51526a | ||
|
|
610b59f4c6 | ||
|
|
63ce327458 | ||
|
|
6ec7a50320 | ||
|
|
60a29ef2e7 | ||
|
|
52c3a0abe0 | ||
|
|
5bbe5c2720 | ||
|
|
c0c6a21e43 | ||
|
|
a7f93698a6 | ||
|
|
1a18058228 | ||
|
|
67024daa25 | ||
|
|
de6137d1a5 | ||
|
|
11e87bd519 | ||
|
|
3b4e089756 | ||
|
|
4a6f5845f9 | ||
|
|
e9684ce033 | ||
|
|
27abf1b0de | ||
|
|
f5f3f70e35 | ||
|
|
2d282a3261 | ||
|
|
a2d0d2d8c0 | ||
|
|
ea412086d4 | ||
|
|
455679a981 | ||
|
|
a21bc6174d | ||
|
|
fae1a89402 | ||
|
|
5a1a0c59f1 | ||
|
|
c98271f783 | ||
|
|
033660c2d9 | ||
|
|
1a639c51e1 | ||
|
|
1366579dd1 | ||
|
|
f5ed2c2c40 | ||
|
|
1598de9f5f | ||
|
|
6f47f5cc99 | ||
|
|
1117dcb935 | ||
|
|
01a58f9aa8 | ||
|
|
9096644d51 | ||
|
|
d42fc0e3f6 | ||
|
|
17d1526b6f | ||
|
|
db8ac195d4 | ||
|
|
c5f5f69fd6 | ||
|
|
44203223fd | ||
|
|
bdabadcd49 | ||
|
|
220e4388d4 | ||
|
|
51b2d1ce86 | ||
|
|
f3c1825c57 | ||
|
|
359dfcd102 | ||
|
|
649cdd893f | ||
|
|
0cb974acf5 | ||
|
|
9bca5dccc7 | ||
|
|
d707f1cc5d | ||
|
|
4ed4395535 | ||
|
|
0209d48475 | ||
|
|
437bee4a85 | ||
|
|
4b8e73fa57 | ||
|
|
b96f925d9a | ||
|
|
1551dc50fd | ||
|
|
daf4cef61c | ||
|
|
496e127f64 | ||
|
|
da1af66c77 | ||
|
|
01409985a2 | ||
|
|
a86ac0619a | ||
|
|
385d165512 | ||
|
|
fcfc97b964 | ||
|
|
53d05e73a6 | ||
|
|
40a1eb861d | ||
|
|
1d3cb95b89 | ||
|
|
010303a818 | ||
|
|
7281b9fed0 | ||
|
|
c5785c7ae6 | ||
|
|
698731cb9a | ||
|
|
99bae8f2c5 | ||
|
|
5034ec1aa0 | ||
|
|
be821c1f8b | ||
|
|
a364b79a9b | ||
|
|
0aa6e1e79a | ||
|
|
d2a6379131 | ||
|
|
07ce61d19f | ||
|
|
ad9f2d8609 | ||
|
|
57702d8a43 | ||
|
|
9a30af3818 | ||
|
|
23751fbdf3 | ||
|
|
db6d181f78 | ||
|
|
56ca4dcc61 | ||
|
|
d08b537721 | ||
|
|
c1a2edb489 | ||
|
|
164b7fa454 | ||
|
|
428483cf4c | ||
|
|
89f02eb399 | ||
|
|
4ce127516c | ||
|
|
6f4f487dfe | ||
|
|
57dd60e804 | ||
|
|
d24fd2250c | ||
|
|
e00bcdfc06 | ||
|
|
67dd204ee6 | ||
|
|
e130583fa4 | ||
|
|
6ad20a0fcf | ||
|
|
9fad644d7a | ||
|
|
8cb523dd06 | ||
|
|
b50ee23a26 | ||
|
|
a973cf699b | ||
|
|
102abf49c4 | ||
|
|
8929e503ea | ||
|
|
a2a794eb74 | ||
|
|
2e95f5dd95 | ||
|
|
23a42230cb | ||
|
|
e66daed7ae | ||
|
|
f2d0f68f07 | ||
|
|
be4af0bf84 | ||
|
|
15172e8b33 | ||
|
|
c6b7918525 | ||
|
|
4f1c4421e5 | ||
|
|
7b830f5a71 | ||
|
|
6ce1135835 | ||
|
|
66eaaef6de | ||
|
|
48fbf59036 | ||
|
|
0e0f4fbe9f | ||
|
|
6ba6e10108 | ||
|
|
cf8fa4ffb4 | ||
|
|
2b0180dce2 | ||
|
|
caee848a47 | ||
|
|
d01b7cf707 | ||
|
|
8921f84c38 | ||
|
|
6830df01fa | ||
|
|
67da59ef41 | ||
|
|
036cc9915d | ||
|
|
57b6ba19f0 | ||
|
|
32b5593d07 | ||
|
|
3b757562d2 | ||
|
|
4c8c2d0868 | ||
|
|
b2f266401f | ||
|
|
5541eca23d | ||
|
|
122d65840e | ||
|
|
ed4b72d85c | ||
|
|
4033e8618f | ||
|
|
42cada1811 | ||
|
|
ff7ed213c8 | ||
|
|
a0367af06b | ||
|
|
58c2965c53 | ||
|
|
edae41409a | ||
|
|
383d3a36ef | ||
|
|
6a958da390 | ||
|
|
ef154f99d5 | ||
|
|
4a20102de3 | ||
|
|
4e170f2917 | ||
|
|
a70d788f6b |
No files matched your search
@@ -1,82 +0,0 @@
|
|||||||
name: Assets
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: main
|
|
||||||
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
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
|
|
||||||
|
|
||||||
asset_source:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
description: "Archive URL or Steam to download (example: steam:APP_ID/DEPOT_ID or zip:URL_TO_ZIP)"
|
|
||||||
default: "steam:444200/444202"
|
|
||||||
|
|
||||||
schedule:
|
|
||||||
- cron: "0 2 * * *"
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event.inputs.asset_repo }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
PUBLIC_ASSET_REPO: ${{ github.event.inputs.asset_repo != '' && github.event.inputs.asset_repo || secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: true
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
|
||||||
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
|
|
||||||
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
|
|
||||||
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
|
|
||||||
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
|
|
||||||
PUBLIC_DEBUG_MISSING_I18N: false
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_FAST_USER: blitzkit
|
|
||||||
PUBLIC_ASSET_FAST_REPO: assets
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }}
|
|
||||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_assets:
|
|
||||||
name: Build assets
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: AppArmor hack
|
|
||||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
|
||||||
|
|
||||||
- name: Build assets
|
|
||||||
run: bun run build:assets --all-targets --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
name: Averages
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 8 * * *"
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
|
||||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: "true"
|
|
||||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
|
||||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
|
||||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
|
||||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
|
||||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: Build averages
|
|
||||||
env:
|
|
||||||
PUBLIC_ASSET_BRANCH: main
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
VIDEOS_SHEET: ${{ secrets.VIDEOS_SHEET }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
run: bun run build:averages --production
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
name: Bot
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build bot
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: Build bot
|
|
||||||
run: bun run build:bot
|
|
||||||
|
|
||||||
- name: Archive build
|
|
||||||
uses: actions/upload-artifact@v5
|
|
||||||
with:
|
|
||||||
name: bot
|
|
||||||
path: dist/bot
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
name: IDs
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * 1"
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: Discover IDs
|
|
||||||
run: bun build:ids --production
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
name: Host
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: main
|
|
||||||
schedule:
|
|
||||||
- cron: "0 */5 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [created, published, released, edited]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DISCORD_CLIENT_ID: ${{ secrets.DISCORD_CLIENT_ID }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
|
||||||
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: ${{ secrets.ALLOW_ROBOTS }}
|
|
||||||
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 }}
|
|
||||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
|
||||||
SERVICING: ${{ secrets.SERVICING }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
host:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
- name: Download release assets
|
|
||||||
run: |
|
|
||||||
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/blitzkit/blitzkit/releases/latest \
|
|
||||||
| grep "browser_download_url.*bot.zip" \
|
|
||||||
| cut -d : -f 2,3 \
|
|
||||||
| tr -d \")
|
|
||||||
curl -L -o bot.zip $DOWNLOAD_URL
|
|
||||||
mkdir -p dist/bot
|
|
||||||
unzip bot.zip -d dist/bot
|
|
||||||
|
|
||||||
- name: Install sharp
|
|
||||||
run: bun init -y && bun add sharp
|
|
||||||
|
|
||||||
- name: Move directories
|
|
||||||
run: mv dist/bot/prisma .
|
|
||||||
|
|
||||||
- name: Run bot
|
|
||||||
run: bun run dist/bot/main.js
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
name: Rating Asia
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- 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:
|
|
||||||
host:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: Generate leaderboard
|
|
||||||
run: bun build:ratingleaderboard --region=asia
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
name: Rating Europe
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- 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:
|
|
||||||
host:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: Generate leaderboard
|
|
||||||
run: bun build:ratingleaderboard --region=eu
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
name: Rating North America
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- 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:
|
|
||||||
host:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: Generate leaderboard
|
|
||||||
run: bun build:ratingleaderboard --region=com
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
name: Reviews
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
- cron: 0 0 * * 2
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
env:
|
|
||||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
|
||||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
|
||||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
|
||||||
- uses: arduino/setup-protoc@v3
|
|
||||||
with:
|
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
|
||||||
- run: bun run setup
|
|
||||||
|
|
||||||
- name: Find reviews
|
|
||||||
run: bun run build:reviews
|
|
||||||
@@ -17,36 +17,30 @@ concurrency:
|
|||||||
cancel-in-progress: ${{ github.ref == 'refs/heads/main' }}
|
cancel-in-progress: ${{ github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
WOTB_SERVER: ${{ secrets.WOTB_SERVER }}
|
||||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
|
||||||
ALLOW_ROBOTS: ${{ secrets.ALLOW_ROBOTS }}
|
|
||||||
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 }}
|
|
||||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
|
||||||
SERVICING: ${{ secrets.SERVICING }}
|
|
||||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build website
|
name: Build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
token: ${{ secrets.GH_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- uses: oven-sh/setup-bun@v2
|
- uses: oven-sh/setup-bun@v2
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
|
|
||||||
- uses: arduino/setup-protoc@v3
|
- uses: arduino/setup-protoc@v3
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GH_TOKEN }}
|
repo-token: ${{ secrets.GH_TOKEN }}
|
||||||
|
|
||||||
- uses: actions/configure-pages@v5
|
- uses: actions/configure-pages@v5
|
||||||
|
|
||||||
- run: bun run setup
|
- run: bun run setup
|
||||||
|
|
||||||
- name: Build website
|
- name: Build website
|
||||||
@@ -58,7 +52,7 @@ jobs:
|
|||||||
path: dist/website
|
path: dist/website
|
||||||
|
|
||||||
deploy-github-pages:
|
deploy-github-pages:
|
||||||
if: ${{ github.ref == 'refs/heads/main' }}
|
if: ${{ github.ref == 'refs/heads/ue' && github.repository == 'blitzkit/host-beta' }}
|
||||||
name: Deploy to GitHub Pages
|
name: Deploy to GitHub Pages
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
@@ -22,7 +22,7 @@ depots
|
|||||||
public/sitemap*
|
public/sitemap*
|
||||||
/firebase.json
|
/firebase.json
|
||||||
target
|
target
|
||||||
# packages/core/src/protos/*.ts
|
packages/website-ue/src/protos/*.ts
|
||||||
/.vercel
|
/.vercel
|
||||||
.astro
|
.astro
|
||||||
.vercel
|
.vercel
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
[submodule "packages/closed"]
|
[submodule "packages/closed"]
|
||||||
path = packages/closed
|
path = packages/closed
|
||||||
url = https://github.com/blitzkit/closed.git
|
url = https://github.com/blitzkit/closed.git
|
||||||
|
[submodule "packages/cue4parse"]
|
||||||
|
path = packages/cue4parse
|
||||||
|
url = https://github.com/FabianFG/CUE4Parse.git
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
"astrojs",
|
"astrojs",
|
||||||
"astrolib",
|
"astrolib",
|
||||||
"atgm",
|
"atgm",
|
||||||
|
"autocrop",
|
||||||
"Autoloader",
|
"Autoloader",
|
||||||
"Autoreloader",
|
"Autoreloader",
|
||||||
"AYUV",
|
"AYUV",
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
"Ddpf",
|
"Ddpf",
|
||||||
"Ddsd",
|
"Ddsd",
|
||||||
"deadrail",
|
"deadrail",
|
||||||
|
"DEBUFF",
|
||||||
"debugflags",
|
"debugflags",
|
||||||
"deburr",
|
"deburr",
|
||||||
"decalmask",
|
"decalmask",
|
||||||
@@ -146,6 +148,7 @@
|
|||||||
"noout",
|
"noout",
|
||||||
"normalmap",
|
"normalmap",
|
||||||
"oneof",
|
"oneof",
|
||||||
|
"Oodle",
|
||||||
"oopsies",
|
"oopsies",
|
||||||
"Oopsy",
|
"Oopsy",
|
||||||
"opentest",
|
"opentest",
|
||||||
@@ -161,6 +164,7 @@
|
|||||||
"playerachievements",
|
"playerachievements",
|
||||||
"playerinfo",
|
"playerinfo",
|
||||||
"playform",
|
"playform",
|
||||||
|
"Playtest",
|
||||||
"pngjs",
|
"pngjs",
|
||||||
"POSITIVEX",
|
"POSITIVEX",
|
||||||
"POSITIVEY",
|
"POSITIVEY",
|
||||||
@@ -177,6 +181,7 @@
|
|||||||
"ratingleaderboard",
|
"ratingleaderboard",
|
||||||
"raycaster",
|
"raycaster",
|
||||||
"Redirector",
|
"Redirector",
|
||||||
|
"REGEN",
|
||||||
"Relogin",
|
"Relogin",
|
||||||
"researchable",
|
"researchable",
|
||||||
"Resvg",
|
"Resvg",
|
||||||
@@ -190,11 +195,14 @@
|
|||||||
"searchplayers",
|
"searchplayers",
|
||||||
"searchtanks",
|
"searchtanks",
|
||||||
"SHAREDEXP",
|
"SHAREDEXP",
|
||||||
|
"Skia",
|
||||||
"SKLLD",
|
"SKLLD",
|
||||||
|
"sluggify",
|
||||||
"smoothstep",
|
"smoothstep",
|
||||||
"Smri",
|
"Smri",
|
||||||
"Specularity",
|
"Specularity",
|
||||||
"SSAO",
|
"SSAO",
|
||||||
|
"stackable",
|
||||||
"startcase",
|
"startcase",
|
||||||
"statkit",
|
"statkit",
|
||||||
"statsfull",
|
"statsfull",
|
||||||
@@ -218,6 +226,7 @@
|
|||||||
"tungstentip",
|
"tungstentip",
|
||||||
"Turretless",
|
"Turretless",
|
||||||
"TYPELESS",
|
"TYPELESS",
|
||||||
|
"uasset",
|
||||||
"ubjson",
|
"ubjson",
|
||||||
"Unicum",
|
"Unicum",
|
||||||
"UNLOCALIZED",
|
"UNLOCALIZED",
|
||||||
@@ -227,6 +236,7 @@
|
|||||||
"unrotate",
|
"unrotate",
|
||||||
"unwrapper",
|
"unwrapper",
|
||||||
"userns",
|
"userns",
|
||||||
|
"usmap",
|
||||||
"vercel",
|
"vercel",
|
||||||
"vickers",
|
"vickers",
|
||||||
"vitepress",
|
"vitepress",
|
||||||
@@ -239,6 +249,7 @@
|
|||||||
"winrate",
|
"winrate",
|
||||||
"wireframe",
|
"wireframe",
|
||||||
"Woah",
|
"Woah",
|
||||||
|
"wooorm",
|
||||||
"WOTB",
|
"WOTB",
|
||||||
"wotblitz",
|
"wotblitz",
|
||||||
"wotbreplay",
|
"wotbreplay",
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# BlitzKit 1.29.12
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- BlitzKit no longer uses BlitzStars for tank averages for some commands
|
||||||
|
- BlitzKit Performance was created to completely replace BlitzStars but BlitzStars was still used for some older commands
|
||||||
|
- But since BlitzStars keeps having downtime, it has been completely removed
|
||||||
|
- Upgraded all dependencies to the latest versions
|
||||||
|
- The replay command is now properly localized across all languages
|
||||||
|
- Special Chinese characters are now properly handled
|
||||||
|
- Commands are now registered synchronously, allowing errors to reveal their exact origins
|
||||||
|
- Error handling now properly exists the process after logging the error
|
||||||
|
- The bot now uses Discord's new `clientReady` instead of the ambiguous `ready` event
|
||||||
|
- Both the armor and model extractors now use the new BlitzKit `SteamVFS`
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# BlitzKit 1.29.13
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- The screenshot button now automatically crops your image so you don't have excessive blank space all around
|
||||||
|
- Increased the max zoom out distance in Tankopedia to 50m
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Turrets in Tankopedia now stay within a range of -180 and +180 degrees
|
||||||
|
- Tanks with transparency like the T34 and Herdbreaker are now properly rendered
|
||||||
|
- This will take a few days to roll out for all tanks (see screenshots below for the fixed models)
|
||||||
|
- High End Consumables now give a 33% boost instead of 70%
|
||||||
|
- Static Armor now properly deselects all irrelevant armor plates
|
||||||
|
- Removed a few debug loggers left behind
|
||||||
|
- Static Armor now properly rerenders armor plates when their thicknesses are changed
|
||||||
|
- The Ricochet Visualizer now stays in place when dragging around on mobile
|
||||||
|
- Reduced the text in the Tankopedia Compare segmented display to fit on smaller screens
|
||||||
|
- Sorting by tertiary shells no longer crashes for some tanks
|
||||||
|
- The Tank Filters are now left aligned on smaller screens for readability
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# BlitzKit 1.29.14
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
- BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API
|
||||||
|
- Disabled the following commands:
|
||||||
|
- `/stats`
|
||||||
|
- `/today`
|
||||||
|
- `/breakdown`
|
||||||
|
- `/evolution`
|
||||||
|
- `/full-stats`
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# BlitzKit 1.29.15
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
- Tanks now use alpha clipping to render translucency, fixing a lot of "ghostly" looking tanks
|
||||||
@@ -1,41 +1,42 @@
|
|||||||
{
|
{
|
||||||
"name": "blitzkit",
|
"name": "blitzkit",
|
||||||
"version": "1.29.11",
|
"version": "2.0.0-beta.2",
|
||||||
"license": "BlitzKit License",
|
"license": "BlitzKit License",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build:game": "cd packages/game && bun run build",
|
||||||
"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": "cd packages/website && bun run build",
|
"build:website": "cd packages/website-ue && bun run build",
|
||||||
"build:prisma": "prisma generate",
|
"build:prisma": "prisma generate",
|
||||||
"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: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 --dev",
|
||||||
"start:bot": "bun dist/bot/main.js",
|
"start:bot": "bun dist/bot/main.js",
|
||||||
"dev:docs": "vitepress dev docs",
|
"dev:docs": "vitepress dev docs",
|
||||||
"dev:website": "cd packages/website && bun run dev",
|
"dev:website": "cd packages/website-ue && bun run dev",
|
||||||
"dev:app": "cd packages/app && bun run dev",
|
"dev:app": "cd packages/app && bun run dev",
|
||||||
"dev": "bun run dev:website",
|
"dev": "bun run dev:website",
|
||||||
"dev:api": "bun --filter=@blitzkit/api run dev",
|
"dev:api": "bun --filter=@blitzkit/api run dev",
|
||||||
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
||||||
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
||||||
"start:website": "bun --filter=@blitzkit/website run start",
|
"start:website": "bun --filter=@blitzkit/website-ue run start",
|
||||||
"host:docs": "vitepress preview docs",
|
"host:docs": "vitepress preview docs",
|
||||||
"lint": "tsc",
|
"lint": "tsc",
|
||||||
"lint:website": "cd packages/website && bun run lint",
|
"lint:website": "cd packages/website-ue && bun run lint",
|
||||||
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
"format": "prettier --write \"**/*.@(json|js|jsx|css|md|ts|tsx|html|xml|yml|gltf)\"",
|
||||||
"update": "yarn upgrade --latest",
|
"update": "yarn 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": "cd packages/scripts && bun run build:protos",
|
"build:protos": "cd packages/scripts && bun run build:protos",
|
||||||
"preview:website": "cd packages/website && bun run preview",
|
"preview:website": "cd packages/website-ue && 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",
|
"setup": "bun install && bun run build:prisma && bun run build:protos && bun run build:proxyclient && bun run build:catalogitemaccesssor",
|
||||||
"patchnotes": "cd packages/scripts && bun run patchnotes"
|
"patchnotes": "cd packages/scripts && bun run patchnotes"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -43,8 +44,10 @@
|
|||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||||
"@prisma/client": "^6.18.0",
|
"@prisma/client": "^6.18.0",
|
||||||
"prisma": "^6.18.0",
|
"prisma": "^6.18.0",
|
||||||
|
"sharp": "^0.34.5",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,9 +356,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -2105,9 +2105,9 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-conv"
|
name = "num-conv"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
@@ -3907,30 +3907,30 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.44"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
|
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"itoa",
|
"itoa",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde",
|
"serde_core",
|
||||||
"time-core",
|
"time-core",
|
||||||
"time-macros",
|
"time-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-core"
|
name = "time-core"
|
||||||
version = "0.1.6"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
|
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.24"
|
version = "0.2.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
|
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"time-core",
|
"time-core",
|
||||||
|
|||||||
@@ -4,25 +4,26 @@
|
|||||||
"@blitzkit/core": "workspace:*",
|
"@blitzkit/core": "workspace:*",
|
||||||
"@blitzkit/i18n": "workspace:*",
|
"@blitzkit/i18n": "workspace:*",
|
||||||
"@radix-ui/colors": "^3.0.0",
|
"@radix-ui/colors": "^3.0.0",
|
||||||
"@radix-ui/themes": "^3.2.1",
|
"@radix-ui/themes": "^3.3.0",
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
"@types/adm-zip": "^0.5.7",
|
"@types/adm-zip": "^0.5.7",
|
||||||
|
"@types/bun": "^1.3.9",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/markdown-escape": "^1.1.3",
|
"@types/markdown-escape": "^1.1.3",
|
||||||
"@types/react": "^19.2.2",
|
"@types/react": "^19.2.14",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
"bepaint": "^0.1.0-beta.3",
|
"bepaint": "^0.1.0-beta.3",
|
||||||
"discord.js": "^14.22.1",
|
"discord.js": "^14.25.1",
|
||||||
"dotenv": "^17.2.2",
|
"dotenv": "^17.3.1",
|
||||||
"fuzzysort": "^3.1.0",
|
"fuzzysort": "^3.1.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.23",
|
||||||
"markdown-escape": "^2.0.0",
|
"markdown-escape": "^2.0.0",
|
||||||
"pickleparser": "^0.2.1",
|
"pickleparser": "^0.2.1",
|
||||||
"prisma": "^6.17.1",
|
"prisma": "^6.19.2",
|
||||||
"protobufjs": "^7.5.4",
|
"protobufjs": "^7.5.4",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.4",
|
||||||
"satori": "^0.18.3",
|
"satori": "^0.18.4",
|
||||||
"sharp": "^0.34.4"
|
"sharp": "^0.34.5"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 {
|
import {
|
||||||
COMMANDS_RAW,
|
commandsArray,
|
||||||
type CommandRegistry,
|
type CommandRegistry,
|
||||||
} from "../events/interactionCreate";
|
} from "../events/interactionCreate";
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
|||||||
|
|
||||||
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(commandsArray)
|
||||||
)
|
)
|
||||||
.sort((a, b) =>
|
.sort((a, b) =>
|
||||||
(a.command.name_localizations?.[interaction.locale] ??
|
(a.command.name_localizations?.[interaction.locale] ??
|
||||||
@@ -43,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) =>
|
||||||
@@ -54,7 +54,7 @@ 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")}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,46 @@
|
|||||||
import { getBlitzStarsLinkButton } from '../../core/blitzstars/getBlitzStarsLinkButton';
|
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 { createLocalizedCommand } from "../../core/discord/createLocalizedCommand";
|
||||||
import { buttonRefresh } from '../../core/discord/buttonRefresh';
|
import { getFiltersFromButton } from "../../core/discord/getFiltersFromButton";
|
||||||
import { commandToURL } from '../../core/discord/commandToURL';
|
import { resolvePeriodFromButton } from "../../core/discord/resolvePeriodFromButton";
|
||||||
import { createLocalizedCommand } from '../../core/discord/createLocalizedCommand';
|
import { resolvePlayerFromButton } from "../../core/discord/resolvePlayerFromButton";
|
||||||
import { getCustomPeriodParams } from '../../core/discord/getCustomPeriodParams';
|
import { translator } from "../../core/localization/translator";
|
||||||
import { getFiltersFromButton } from '../../core/discord/getFiltersFromButton';
|
import type { CommandRegistry } from "../../events/interactionCreate";
|
||||||
import { getFiltersFromCommand } from '../../core/discord/getFiltersFromCommand';
|
import { renderBreakdown } from "./render";
|
||||||
import { resolvePeriodFromButton } from '../../core/discord/resolvePeriodFromButton';
|
|
||||||
import { resolvePeriodFromCommand } from '../../core/discord/resolvePeriodFromCommand';
|
|
||||||
import { resolvePlayerFromButton } from '../../core/discord/resolvePlayerFromButton';
|
|
||||||
import { resolvePlayerFromCommand } from '../../core/discord/resolvePlayerFromCommand';
|
|
||||||
import type { CommandRegistry } from '../../events/interactionCreate';
|
|
||||||
import { renderBreakdown } from './render';
|
|
||||||
|
|
||||||
export const breakdownCommand = new Promise<CommandRegistry>(
|
export const breakdownCommand = new Promise<CommandRegistry>(
|
||||||
async (resolve) => {
|
async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: await addPeriodicFilterOptions(
|
command: await addPeriodicFilterOptions(
|
||||||
createLocalizedCommand('breakdown'),
|
createLocalizedCommand("breakdown"),
|
||||||
(option) => option.addStringOption(addUsernameChoices),
|
(option) => option.addStringOption(addUsernameChoices),
|
||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const player = await resolvePlayerFromCommand(interaction);
|
const { strings } = translator(interaction.locale);
|
||||||
const period = resolvePeriodFromCommand(player.region, interaction);
|
return strings.bot.commands.dead;
|
||||||
const filters = await getFiltersFromCommand(interaction);
|
|
||||||
const path = commandToURL(interaction, {
|
|
||||||
...player,
|
|
||||||
...getCustomPeriodParams(interaction),
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
|
|
||||||
return [
|
// const player = await resolvePlayerFromCommand(interaction);
|
||||||
...(await renderBreakdown(
|
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||||
player,
|
// const filters = await getFiltersFromCommand(interaction);
|
||||||
period,
|
// const path = commandToURL(interaction, {
|
||||||
filters,
|
// ...player,
|
||||||
interaction.locale,
|
// ...getCustomPeriodParams(interaction),
|
||||||
)),
|
// ...filters,
|
||||||
buttonRefresh(interaction, path),
|
// });
|
||||||
await getBlitzStarsLinkButton(player.region, player.id),
|
|
||||||
];
|
// return [
|
||||||
|
// ...(await renderBreakdown(
|
||||||
|
// player,
|
||||||
|
// period,
|
||||||
|
// filters,
|
||||||
|
// interaction.locale,
|
||||||
|
// )),
|
||||||
|
// buttonRefresh(interaction, path),
|
||||||
|
// await getBlitzStarsLinkButton(player.region, player.id),
|
||||||
|
// ];
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: (interaction) => {
|
autocomplete: (interaction) => {
|
||||||
|
|||||||
@@ -15,11 +15,16 @@ 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 { tankDefinitions } from "../../core/blitzkit/nonBlockingPromises";
|
import {
|
||||||
|
averageDefinitions,
|
||||||
|
tankDefinitions,
|
||||||
|
} from "../../core/blitzkit/nonBlockingPromises";
|
||||||
import { UserError } from "../../core/blitzkit/userError";
|
import { UserError } from "../../core/blitzkit/userError";
|
||||||
import { filterStats, type 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 type { ResolvedPeriod } from "../../core/discord/resolvePeriodFromCommand";
|
import type { ResolvedPeriod } from "../../core/discord/resolvePeriodFromCommand";
|
||||||
import type { ResolvedPlayer } from "../../core/discord/resolvePlayerFromCommand";
|
import type { ResolvedPlayer } from "../../core/discord/resolvePlayerFromCommand";
|
||||||
import { translator } from "../../core/localization/translator";
|
import { translator } from "../../core/localization/translator";
|
||||||
@@ -31,11 +36,11 @@ export async function renderBreakdown(
|
|||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
{ start, end, name }: ResolvedPeriod,
|
{ start, end, name }: ResolvedPeriod,
|
||||||
filters: StatFilters,
|
filters: StatFilters,
|
||||||
locale: Locale
|
locale: Locale,
|
||||||
) {
|
) {
|
||||||
const { strings, unwrap } = translator(locale);
|
const { strings, unwrap } = translator(locale);
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
const awaitedTankAverages = await blitzStarsTankAverages;
|
const awaitedTankAverages = await averageDefinitions;
|
||||||
const statsInPeriod = await getStatsInPeriod(region, id, start, end, locale);
|
const statsInPeriod = await getStatsInPeriod(region, id, start, end, locale);
|
||||||
const { filteredOrder } = await filterStats(statsInPeriod, filters);
|
const { filteredOrder } = await filterStats(statsInPeriod, filters);
|
||||||
const accountInfo = await getAccountInfo(region, id);
|
const accountInfo = await getAccountInfo(region, id);
|
||||||
@@ -53,14 +58,14 @@ export async function renderBreakdown(
|
|||||||
}
|
}
|
||||||
|
|
||||||
filteredOrder.forEach((id) => {
|
filteredOrder.forEach((id) => {
|
||||||
const tankAveragesEntry = awaitedTankAverages[id];
|
const tankAveragesEntry = awaitedTankAverages.averages[id];
|
||||||
const current = statsInPeriod.diff[id];
|
const current = statsInPeriod.diff[id];
|
||||||
const career = tankStats.find((tank) => tank.tank_id === id)!.all;
|
const career = tankStats.find((tank) => tank.tank_id === id)!.all;
|
||||||
const currentWN8 = tankAveragesEntry
|
const currentWN8 = tankAveragesEntry
|
||||||
? calculateWN8(tankAveragesEntry.all, current)
|
? calculateWN8(tankAveragesEntry.mu, current)
|
||||||
: undefined;
|
: undefined;
|
||||||
const careerWN8 = tankAveragesEntry
|
const careerWN8 = tankAveragesEntry
|
||||||
? calculateWN8(tankAveragesEntry.all, career)
|
? calculateWN8(tankAveragesEntry.mu, career)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
orderedCurrentStats.push(current);
|
orderedCurrentStats.push(current);
|
||||||
@@ -69,65 +74,65 @@ export async function renderBreakdown(
|
|||||||
orderedCareerWN8.push(careerWN8);
|
orderedCareerWN8.push(careerWN8);
|
||||||
});
|
});
|
||||||
tankStats.forEach((tank) => {
|
tankStats.forEach((tank) => {
|
||||||
const tankAveragesEntry = awaitedTankAverages[tank.tank_id];
|
const tankAveragesEntry = awaitedTankAverages.averages[tank.tank_id];
|
||||||
|
|
||||||
orderedCareerWN8Full.push(
|
orderedCareerWN8Full.push(
|
||||||
tankAveragesEntry
|
tankAveragesEntry
|
||||||
? calculateWN8(tankAveragesEntry.all, tank.all)
|
? calculateWN8(tankAveragesEntry.mu, tank.all)
|
||||||
: undefined
|
: undefined,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentBattles = orderedCurrentStats.reduce(
|
const currentBattles = orderedCurrentStats.reduce(
|
||||||
(accumulator, current) => accumulator + current.battles,
|
(accumulator, current) => accumulator + current.battles,
|
||||||
0
|
0,
|
||||||
);
|
);
|
||||||
const careerBattles = tankStats.reduce(
|
const careerBattles = tankStats.reduce(
|
||||||
(accumulator, current) => accumulator + current.all.battles,
|
(accumulator, current) => accumulator + current.all.battles,
|
||||||
0
|
0,
|
||||||
);
|
);
|
||||||
const currentWinrate =
|
const currentWinrate =
|
||||||
orderedCurrentStats.reduce(
|
orderedCurrentStats.reduce(
|
||||||
(accumulator, current) => accumulator + current.wins,
|
(accumulator, current) => accumulator + current.wins,
|
||||||
0
|
0,
|
||||||
) / currentBattles;
|
) / currentBattles;
|
||||||
const careerWinrate =
|
const careerWinrate =
|
||||||
tankStats.reduce(
|
tankStats.reduce(
|
||||||
(accumulator, current) => accumulator + current.all.wins,
|
(accumulator, current) => accumulator + current.all.wins,
|
||||||
0
|
0,
|
||||||
) / careerBattles;
|
) / careerBattles;
|
||||||
const currentWN8 =
|
const currentWN8 =
|
||||||
orderedCurrentWN8.reduce<number>(
|
orderedCurrentWN8.reduce<number>(
|
||||||
(accumulator, current, index) =>
|
(accumulator, current, index) =>
|
||||||
accumulator + (current ?? 0) * orderedCurrentStats[index].battles,
|
accumulator + (current ?? 0) * orderedCurrentStats[index].battles,
|
||||||
0
|
0,
|
||||||
) /
|
) /
|
||||||
orderedCurrentStats.reduce(
|
orderedCurrentStats.reduce(
|
||||||
(accumulator, current, index) =>
|
(accumulator, current, index) =>
|
||||||
accumulator +
|
accumulator +
|
||||||
(orderedCurrentWN8[index] === undefined ? 0 : current.battles),
|
(orderedCurrentWN8[index] === undefined ? 0 : current.battles),
|
||||||
0
|
0,
|
||||||
);
|
);
|
||||||
const careerWN8 =
|
const careerWN8 =
|
||||||
orderedCareerWN8Full.reduce<number>(
|
orderedCareerWN8Full.reduce<number>(
|
||||||
(accumulator, current) => accumulator + (current ?? 0),
|
(accumulator, current) => accumulator + (current ?? 0),
|
||||||
0
|
0,
|
||||||
) /
|
) /
|
||||||
tankStats.reduce(
|
tankStats.reduce(
|
||||||
(accumulator, current, index) =>
|
(accumulator, current, index) =>
|
||||||
accumulator +
|
accumulator +
|
||||||
(orderedCareerWN8Full[index] === undefined ? 0 : current.all.battles),
|
(orderedCareerWN8Full[index] === undefined ? 0 : current.all.battles),
|
||||||
0
|
0,
|
||||||
);
|
);
|
||||||
const currentDamage =
|
const currentDamage =
|
||||||
orderedCurrentStats.reduce(
|
orderedCurrentStats.reduce(
|
||||||
(accumulator, current) => accumulator + current.damage_dealt,
|
(accumulator, current) => accumulator + current.damage_dealt,
|
||||||
0
|
0,
|
||||||
) / currentBattles;
|
) / currentBattles;
|
||||||
const careerDamage =
|
const careerDamage =
|
||||||
tankStats.reduce(
|
tankStats.reduce(
|
||||||
(accumulator, current) => accumulator + current.all.damage_dealt,
|
(accumulator, current) => accumulator + current.all.damage_dealt,
|
||||||
0
|
0,
|
||||||
) / careerBattles;
|
) / careerBattles;
|
||||||
|
|
||||||
const children: React.JSX.Element[] = [];
|
const children: React.JSX.Element[] = [];
|
||||||
@@ -172,7 +177,7 @@ export async function renderBreakdown(
|
|||||||
delta: currentDamage - careerDamage,
|
delta: currentDamage - careerDamage,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
filteredOrder.forEach((id, index) => {
|
filteredOrder.forEach((id, index) => {
|
||||||
@@ -206,7 +211,7 @@ export async function renderBreakdown(
|
|||||||
{
|
{
|
||||||
title: strings.bot.commands.breakdown.body.winrate,
|
title: strings.bot.commands.breakdown.body.winrate,
|
||||||
current: `${(100 * (current.wins / current.battles)).toFixed(
|
current: `${(100 * (current.wins / current.battles)).toFixed(
|
||||||
2
|
2,
|
||||||
)}%`,
|
)}%`,
|
||||||
career: `${(100 * (career.wins / career.battles)).toFixed(2)}%`,
|
career: `${(100 * (career.wins / career.battles)).toFixed(2)}%`,
|
||||||
delta:
|
delta:
|
||||||
@@ -230,24 +235,24 @@ export async function renderBreakdown(
|
|||||||
{
|
{
|
||||||
title: strings.bot.commands.breakdown.body.damage,
|
title: strings.bot.commands.breakdown.body.damage,
|
||||||
current: Math.round(
|
current: Math.round(
|
||||||
current.damage_dealt / current.battles
|
current.damage_dealt / current.battles,
|
||||||
).toLocaleString(),
|
).toLocaleString(),
|
||||||
career: Math.round(
|
career: Math.round(
|
||||||
career.damage_dealt / career.battles
|
career.damage_dealt / career.battles,
|
||||||
).toLocaleString(),
|
).toLocaleString(),
|
||||||
delta:
|
delta:
|
||||||
current.damage_dealt / current.battles -
|
current.damage_dealt / current.battles -
|
||||||
career.damage_dealt / career.battles,
|
career.damage_dealt / career.battles,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const pages = chunk(
|
const pages = chunk(
|
||||||
children,
|
children,
|
||||||
Math.max(Math.ceil(children.length / MAX_PAGES), ROWS_PER_PAGE)
|
Math.max(Math.ceil(children.length / MAX_PAGES), ROWS_PER_PAGE),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (filteredOrder.length > 0) {
|
if (filteredOrder.length > 0) {
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ 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 { 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";
|
||||||
@@ -14,20 +12,12 @@ 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 { commandToURL } from "../core/discord/commandToURL";
|
|
||||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { getCustomPeriodParams } from "../core/discord/getCustomPeriodParams";
|
|
||||||
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import {
|
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
|
||||||
type ResolvedPeriod,
|
|
||||||
resolvePeriodFromCommand,
|
|
||||||
} from "../core/discord/resolvePeriodFromCommand";
|
|
||||||
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import {
|
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
|
||||||
type ResolvedPlayer,
|
import { translator } from "../core/localization/translator";
|
||||||
resolvePlayerFromCommand,
|
|
||||||
} from "../core/discord/resolvePlayerFromCommand";
|
|
||||||
import type { CommandRegistry } from "../events/interactionCreate";
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
|
|
||||||
type EvolutionStatType = "player" | "tank";
|
type EvolutionStatType = "player" | "tank";
|
||||||
@@ -37,7 +27,7 @@ async function render(
|
|||||||
{ 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;
|
||||||
@@ -61,7 +51,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);
|
||||||
@@ -115,7 +105,7 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
group: "player",
|
group: "player",
|
||||||
modify(option: SlashCommandSubcommandGroupBuilder) {
|
modify(option: SlashCommandSubcommandGroupBuilder) {
|
||||||
addPeriodSubCommands(option, (option) =>
|
addPeriodSubCommands(option, (option) =>
|
||||||
option.addStringOption(addUsernameChoices)
|
option.addStringOption(addUsernameChoices),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -125,43 +115,46 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
addPeriodSubCommands(option, (option) =>
|
addPeriodSubCommands(option, (option) =>
|
||||||
option
|
option
|
||||||
.addStringOption(addTankChoices)
|
.addStringOption(addTankChoices)
|
||||||
.addStringOption(addUsernameChoices)
|
.addStringOption(addUsernameChoices),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const commandGroup =
|
const { strings } = translator(interaction.locale);
|
||||||
interaction.options.getSubcommandGroup() as EvolutionStatType;
|
return strings.bot.commands.dead;
|
||||||
const player = await resolvePlayerFromCommand(interaction);
|
|
||||||
const period = resolvePeriodFromCommand(player.region, interaction);
|
|
||||||
const tankIdRaw = interaction.options.getString("tank")!;
|
|
||||||
const tankId =
|
|
||||||
commandGroup === "tank"
|
|
||||||
? await resolveTankId(tankIdRaw, interaction.locale)
|
|
||||||
: null;
|
|
||||||
const path = commandToURL(interaction, {
|
|
||||||
...player,
|
|
||||||
...getCustomPeriodParams(interaction),
|
|
||||||
tankId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return [
|
// const commandGroup =
|
||||||
await render(
|
// interaction.options.getSubcommandGroup() as EvolutionStatType;
|
||||||
player,
|
// const player = await resolvePlayerFromCommand(interaction);
|
||||||
period,
|
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||||
commandGroup,
|
// const tankIdRaw = interaction.options.getString("tank")!;
|
||||||
tankId,
|
// const tankId =
|
||||||
interaction.locale
|
// commandGroup === "tank"
|
||||||
),
|
// ? await resolveTankId(tankIdRaw, interaction.locale)
|
||||||
buttonRefresh(interaction, path),
|
// : null;
|
||||||
await getBlitzStarsLinkButton(
|
// const path = commandToURL(interaction, {
|
||||||
player.region,
|
// ...player,
|
||||||
player.id,
|
// ...getCustomPeriodParams(interaction),
|
||||||
tankId ?? undefined
|
// tankId,
|
||||||
),
|
// });
|
||||||
];
|
|
||||||
|
// return [
|
||||||
|
// await render(
|
||||||
|
// player,
|
||||||
|
// period,
|
||||||
|
// commandGroup,
|
||||||
|
// tankId,
|
||||||
|
// interaction.locale
|
||||||
|
// ),
|
||||||
|
// buttonRefresh(interaction, path),
|
||||||
|
// await getBlitzStarsLinkButton(
|
||||||
|
// player.region,
|
||||||
|
// player.id,
|
||||||
|
// tankId ?? undefined
|
||||||
|
// ),
|
||||||
|
// ];
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: (interaction) => {
|
autocomplete: (interaction) => {
|
||||||
@@ -181,9 +174,9 @@ export const evolutionCommand = new Promise<CommandRegistry>(
|
|||||||
period,
|
period,
|
||||||
commandGroup,
|
commandGroup,
|
||||||
parseInt(url.searchParams.get("tankId") ?? "0") || null,
|
parseInt(url.searchParams.get("tankId") ?? "0") || null,
|
||||||
interaction.locale
|
interaction.locale,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
@@ -3,38 +3,28 @@ import {
|
|||||||
getAccountInfo,
|
getAccountInfo,
|
||||||
getClanAccountInfo,
|
getClanAccountInfo,
|
||||||
getTierWeights,
|
getTierWeights,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { GenericAllStats } from '../components/GenericAllStats';
|
import { GenericAllStats } from "../components/GenericAllStats";
|
||||||
import { NoData } from '../components/NoData';
|
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, type StatFilters } from '../core/blitzstars/filterStats';
|
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
|
||||||
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 { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { buttonRefresh } from '../core/discord/buttonRefresh';
|
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
|
||||||
import { commandToURL } from '../core/discord/commandToURL';
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
|
||||||
import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
|
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
|
||||||
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
import { translator } from "../core/localization/translator";
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
import type { CommandRegistry } from "../events/interactionCreate";
|
||||||
import {
|
|
||||||
type ResolvedPeriod,
|
|
||||||
resolvePeriodFromCommand,
|
|
||||||
} from '../core/discord/resolvePeriodFromCommand';
|
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
|
||||||
import {
|
|
||||||
type ResolvedPlayer,
|
|
||||||
resolvePlayerFromCommand,
|
|
||||||
} from '../core/discord/resolvePlayerFromCommand';
|
|
||||||
import type { CommandRegistry } from '../events/interactionCreate';
|
|
||||||
|
|
||||||
async function render(
|
async function render(
|
||||||
{ region, id }: ResolvedPlayer,
|
{ region, id }: ResolvedPlayer,
|
||||||
@@ -43,7 +33,7 @@ async function render(
|
|||||||
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,
|
||||||
@@ -86,25 +76,28 @@ export const fullStatsCommand = new Promise<CommandRegistry>(
|
|||||||
async (resolve) => {
|
async (resolve) => {
|
||||||
resolve({
|
resolve({
|
||||||
command: await addPeriodicFilterOptions(
|
command: await addPeriodicFilterOptions(
|
||||||
createLocalizedCommand('full-stats'),
|
createLocalizedCommand("full-stats"),
|
||||||
(option) => option.addStringOption(addUsernameChoices),
|
(option) => option.addStringOption(addUsernameChoices),
|
||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const player = await resolvePlayerFromCommand(interaction);
|
const { strings } = translator(interaction.locale);
|
||||||
const period = resolvePeriodFromCommand(player.region, interaction);
|
return strings.bot.commands.dead;
|
||||||
const filters = await getFiltersFromCommand(interaction);
|
|
||||||
const path = commandToURL(interaction, {
|
|
||||||
...player,
|
|
||||||
...getCustomPeriodParams(interaction),
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all([
|
// const player = await resolvePlayerFromCommand(interaction);
|
||||||
render(player, period, filters, interaction.locale),
|
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||||
buttonRefresh(interaction, path),
|
// const filters = await getFiltersFromCommand(interaction);
|
||||||
getBlitzStarsLinkButton(player.region, player.id),
|
// const path = commandToURL(interaction, {
|
||||||
]);
|
// ...player,
|
||||||
|
// ...getCustomPeriodParams(interaction),
|
||||||
|
// ...filters,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return Promise.all([
|
||||||
|
// render(player, period, filters, interaction.locale),
|
||||||
|
// buttonRefresh(interaction, path),
|
||||||
|
// getBlitzStarsLinkButton(player.region, player.id),
|
||||||
|
// ]);
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: (interaction) => {
|
autocomplete: (interaction) => {
|
||||||
|
|||||||
@@ -5,28 +5,29 @@ import {
|
|||||||
idToRegion,
|
idToRegion,
|
||||||
tankIcon,
|
tankIcon,
|
||||||
TIER_ROMAN_NUMERALS,
|
TIER_ROMAN_NUMERALS,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
import { Locale } from 'discord.js';
|
import { Locale } from "discord.js";
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from "lodash-es";
|
||||||
import { CommandWrapper } from '../components/CommandWrapper';
|
import { CommandWrapper } from "../components/CommandWrapper";
|
||||||
import { TitleBar } from '../components/TitleBar';
|
import { TitleBar } from "../components/TitleBar";
|
||||||
import { iconPng } from '../core/blitzkit/iconPng';
|
import { iconPng } from "../core/blitzkit/iconPng";
|
||||||
import {
|
import {
|
||||||
|
averageDefinitions,
|
||||||
mapDefinitions,
|
mapDefinitions,
|
||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
} from '../core/blitzkit/nonBlockingPromises';
|
} from "../core/blitzkit/nonBlockingPromises";
|
||||||
import { RenderConfiguration } from '../core/blitzkit/renderConfiguration';
|
import { RenderConfiguration } from "../core/blitzkit/renderConfiguration";
|
||||||
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 { localizationObject } from "../core/discord/localizationObject";
|
||||||
import { translator } from '../core/localization/translator';
|
import { translator } from "../core/localization/translator";
|
||||||
import { type CommandRegistry } from '../events/interactionCreate';
|
import { type CommandRegistry } from "../events/interactionCreate";
|
||||||
import { theme } from '../stitches.config';
|
import { theme } from "../stitches.config";
|
||||||
|
|
||||||
type WotInspectorReplaySubmission =
|
type WotInspectorReplaySubmission =
|
||||||
| { status: 'error'; data: unknown; error: { message: string } }
|
| { status: "error"; data: unknown; error: { message: string } }
|
||||||
| {
|
| {
|
||||||
status: 'ok';
|
status: "ok";
|
||||||
data: {
|
data: {
|
||||||
download_url: string;
|
download_url: string;
|
||||||
view_url: string;
|
view_url: string;
|
||||||
@@ -209,9 +210,9 @@ function stat(value: string | number, flex = 2) {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex,
|
flex,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: 16 }}>{value}</span>
|
<span style={{ fontSize: 16 }}>{value}</span>
|
||||||
@@ -227,15 +228,15 @@ async function playerListing(
|
|||||||
recordingPlayer = false,
|
recordingPlayer = false,
|
||||||
) {
|
) {
|
||||||
const { unwrap } = translator(locale);
|
const { unwrap } = translator(locale);
|
||||||
const awaitedTankAverages = await blitzStarsTankAverages;
|
const awaitedTankAverages = await averageDefinitions;
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
const tank = awaitedTankDefinitions.tanks[player.vehicle_descr];
|
const tank = awaitedTankDefinitions.tanks[player.vehicle_descr];
|
||||||
const blockAccent = recordingPlayer ? '_amber' : '';
|
const blockAccent = recordingPlayer ? "_amber" : "";
|
||||||
const healthAccent = protagonistTeam
|
const healthAccent = protagonistTeam
|
||||||
? recordingPlayer
|
? recordingPlayer
|
||||||
? '_amber'
|
? "_amber"
|
||||||
: '_green'
|
: "_green"
|
||||||
: '_red';
|
: "_red";
|
||||||
|
|
||||||
// our turret ids are always off by 1 or 2 lol so imma just grab the closest
|
// our turret ids are always off by 1 or 2 lol so imma just grab the closest
|
||||||
// TODO: 💀
|
// TODO: 💀
|
||||||
@@ -245,11 +246,11 @@ async function playerListing(
|
|||||||
)[0];
|
)[0];
|
||||||
const totalHealth = turret.health + tank.health;
|
const totalHealth = turret.health + tank.health;
|
||||||
const healthLeft = clamp(player.hitpoints_left / totalHealth, 0, 1);
|
const healthLeft = clamp(player.hitpoints_left / totalHealth, 0, 1);
|
||||||
const tankAveragesEntry = awaitedTankAverages[player.vehicle_descr];
|
const tankAveragesEntry = awaitedTankAverages.averages[player.vehicle_descr];
|
||||||
const wn8 =
|
const wn8 =
|
||||||
tankAveragesEntry === undefined
|
tankAveragesEntry === undefined
|
||||||
? -1
|
? -1
|
||||||
: calculateWN8(tankAveragesEntry.all, {
|
: calculateWN8(tankAveragesEntry.mu, {
|
||||||
battles: 1,
|
battles: 1,
|
||||||
damage_dealt: player.damage_made,
|
damage_dealt: player.damage_made,
|
||||||
dropped_capture_points: player.base_defend_points,
|
dropped_capture_points: player.base_defend_points,
|
||||||
@@ -262,8 +263,8 @@ async function playerListing(
|
|||||||
<div
|
<div
|
||||||
key={player.entity_id}
|
key={player.entity_id}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
backgroundColor: theme.colors[`appBackground2${blockAccent}`],
|
backgroundColor: theme.colors[`appBackground2${blockAccent}`],
|
||||||
padding: 8,
|
padding: 8,
|
||||||
@@ -271,11 +272,11 @@ async function playerListing(
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@@ -284,22 +285,22 @@ async function playerListing(
|
|||||||
style={{
|
style={{
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
objectFit: 'contain',
|
objectFit: "contain",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
// align
|
// align
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -324,23 +325,23 @@ async function playerListing(
|
|||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: theme.colors[`textLowContrast${blockAccent}`],
|
color: theme.colors[`textLowContrast${blockAccent}`],
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: "nowrap",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{player.name}
|
{player.name}
|
||||||
{player.clan_tag ? ` [${player.clan_tag}]` : ''}
|
{player.clan_tag ? ` [${player.clan_tag}]` : ""}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{stat(player.damage_made.toLocaleString())}
|
{stat(player.damage_made.toLocaleString())}
|
||||||
{stat(wn8 === -1 ? '--' : Math.round(wn8).toLocaleString())}
|
{stat(wn8 === -1 ? "--" : Math.round(wn8).toLocaleString())}
|
||||||
{stat(player.exp.toLocaleString())}
|
{stat(player.exp.toLocaleString())}
|
||||||
{stat(player.enemies_destroyed, 1)}
|
{stat(player.enemies_destroyed, 1)}
|
||||||
</div>
|
</div>
|
||||||
@@ -349,15 +350,15 @@ async function playerListing(
|
|||||||
style={{
|
style={{
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
backgroundColor: theme.colors[`componentInteractive${healthAccent}`],
|
backgroundColor: theme.colors[`componentInteractive${healthAccent}`],
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
width: 4,
|
width: 4,
|
||||||
height: '100%',
|
height: "100%",
|
||||||
transform: 'scaleY(-1)',
|
transform: "scaleY(-1)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: "100%",
|
||||||
height: `${healthLeft * 100}%`,
|
height: `${healthLeft * 100}%`,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
backgroundColor: theme.colors[`solidBackground${healthAccent}`],
|
backgroundColor: theme.colors[`solidBackground${healthAccent}`],
|
||||||
@@ -373,8 +374,8 @@ function Header() {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: 8,
|
padding: 8,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -382,16 +383,16 @@ function Header() {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 2,
|
flex: 2,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -406,9 +407,9 @@ function Header() {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 2,
|
flex: 2,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -423,9 +424,9 @@ function Header() {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 2,
|
flex: 2,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -440,9 +441,9 @@ function Header() {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
@@ -460,28 +461,42 @@ function Header() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
||||||
|
const { strings } = translator(Locale.EnglishUS);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: createLocalizedCommand('replay').addAttachmentOption((option) =>
|
command: createLocalizedCommand("replay").addAttachmentOption((option) =>
|
||||||
option.setName('file').setDescription('Replay file').setRequired(true),
|
option
|
||||||
|
.setName(strings.bot.commands.replay.options.file.name)
|
||||||
|
.setNameLocalizations(
|
||||||
|
localizationObject(
|
||||||
|
(strings) => strings.bot.commands.replay.options.file.name,
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.setDescription(strings.bot.commands.replay.options.file.description)
|
||||||
|
.setDescriptionLocalizations(
|
||||||
|
localizationObject(
|
||||||
|
(strings) => strings.bot.commands.replay.options.file.description,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.setRequired(true),
|
||||||
),
|
),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const awaitedMapDefinitions = await mapDefinitions;
|
const awaitedMapDefinitions = await mapDefinitions;
|
||||||
const file = interaction.options.getAttachment('file')!;
|
const file = interaction.options.getAttachment("file")!;
|
||||||
// const file = {
|
|
||||||
// url: 'https://cdn.discordapp.com/ephemeral-attachments/1232434891652861972/1232781496016834581/20240328_1530__TresAbhi_M60_1157057448155406708.wotbreplay?ex=662ab4bc&is=6629633c&hm=c784cd10e80232350ddaf291fa987b879c4d0a8083b78298c9eee4fa0d507f6c&',
|
|
||||||
// };
|
|
||||||
const submissionData = (await fetch(
|
const submissionData = (await fetch(
|
||||||
`https://wotinspector.com/api/replay/upload/?url=${encodeURIComponent(
|
`https://wotinspector.com/api/replay/upload/?url=${encodeURIComponent(
|
||||||
file.url,
|
file.url,
|
||||||
)}`,
|
)}`,
|
||||||
).then((response) => response.json())) as WotInspectorReplaySubmission;
|
).then((response) => response.json())) as WotInspectorReplaySubmission;
|
||||||
|
|
||||||
if (submissionData.status === 'error') {
|
if (submissionData.status === "error") {
|
||||||
return `# Uh oh! WoT Inspector didn't like that.\n\nThere was an error processing your replay. Get help on [the official Discord server](https://discord.gg/nDt7AjGJQH).`;
|
return `# Uh oh! WoT Inspector didn't like that.\n\nThere was an error processing your replay. Get help on [the official Discord server](https://discord.gg/nDt7AjGJQH).`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const replayId = submissionData.data.download_url.split('/').at(-1)!;
|
const replayId = submissionData.data.download_url.split("/").at(-1)!;
|
||||||
const replayData = (await fetch(
|
const replayData = (await fetch(
|
||||||
`https://api.wotinspector.com/v2/blitz/replays/${replayId}/`,
|
`https://api.wotinspector.com/v2/blitz/replays/${replayId}/`,
|
||||||
).then((response) => response.json())) as WotInspectorReplay;
|
).then((response) => response.json())) as WotInspectorReplay;
|
||||||
@@ -493,7 +508,7 @@ export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
await getClanAccountInfo(
|
await getClanAccountInfo(
|
||||||
idToRegion(replayData.protagonist),
|
idToRegion(replayData.protagonist),
|
||||||
replayData.protagonist,
|
replayData.protagonist,
|
||||||
['clan'],
|
["clan"],
|
||||||
)
|
)
|
||||||
)?.clan;
|
)?.clan;
|
||||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||||
@@ -506,22 +521,22 @@ export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
image={clanImage}
|
image={clanImage}
|
||||||
description={`${
|
description={`${
|
||||||
replayData.protagonist_team === replayData.winner_team
|
replayData.protagonist_team === replayData.winner_team
|
||||||
? 'Victory'
|
? "Victory"
|
||||||
: 'Defeat'
|
: "Defeat"
|
||||||
} • ${awaitedMapDefinitions.maps[replayData.map_id].name}`}
|
} • ${awaitedMapDefinitions.maps[replayData.map_id].name}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -547,8 +562,8 @@ export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: 4,
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -569,8 +584,8 @@ export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CommandWrapper>,
|
</CommandWrapper>,
|
||||||
buttonLink(submissionData.data.view_url, 'WoT Inspector'),
|
buttonLink(submissionData.data.view_url, "WoT Inspector"),
|
||||||
buttonLink(submissionData.data.download_url, 'Download'),
|
buttonLink(submissionData.data.download_url, "Download"),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,35 +6,25 @@ 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, type StatFilters } from "../core/blitzstars/filterStats";
|
import { filterStats, type StatFilters } from "../core/blitzstars/filterStats";
|
||||||
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 { commandToURL } from "../core/discord/commandToURL";
|
|
||||||
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
import { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
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 { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import {
|
import { type ResolvedPeriod } from "../core/discord/resolvePeriodFromCommand";
|
||||||
type ResolvedPeriod,
|
|
||||||
resolvePeriodFromCommand,
|
|
||||||
} from "../core/discord/resolvePeriodFromCommand";
|
|
||||||
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import {
|
import { type ResolvedPlayer } from "../core/discord/resolvePlayerFromCommand";
|
||||||
type ResolvedPlayer,
|
import { translator } from "../core/localization/translator";
|
||||||
resolvePlayerFromCommand,
|
|
||||||
} from "../core/discord/resolvePlayerFromCommand";
|
|
||||||
import type { 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;
|
||||||
@@ -44,7 +34,7 @@ async function render(
|
|||||||
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);
|
||||||
@@ -73,24 +63,27 @@ 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) {
|
||||||
const player = await resolvePlayerFromCommand(interaction);
|
const { strings } = translator(interaction.locale);
|
||||||
const period = resolvePeriodFromCommand(player.region, interaction);
|
return strings.bot.commands.dead;
|
||||||
const filters = await getFiltersFromCommand(interaction);
|
|
||||||
const path = commandToURL(interaction, {
|
|
||||||
...player,
|
|
||||||
...getCustomPeriodParams(interaction),
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all([
|
// const player = await resolvePlayerFromCommand(interaction);
|
||||||
render(player, period, filters, interaction.locale),
|
// const period = resolvePeriodFromCommand(player.region, interaction);
|
||||||
buttonRefresh(interaction, path),
|
// const filters = await getFiltersFromCommand(interaction);
|
||||||
getBlitzStarsLinkButton(player.region, player.id),
|
// const path = commandToURL(interaction, {
|
||||||
]);
|
// ...player,
|
||||||
|
// ...getCustomPeriodParams(interaction),
|
||||||
|
// ...filters,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return Promise.all([
|
||||||
|
// render(player, period, filters, interaction.locale),
|
||||||
|
// buttonRefresh(interaction, path),
|
||||||
|
// getBlitzStarsLinkButton(player.region, player.id),
|
||||||
|
// ]);
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: (interaction) => {
|
autocomplete: (interaction) => {
|
||||||
|
|||||||
@@ -1,50 +1,47 @@
|
|||||||
import { gameDefinitions } from '../core/blitzkit/nonBlockingPromises';
|
import { gameDefinitions } from "../core/blitzkit/nonBlockingPromises";
|
||||||
import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton';
|
import { addFilterOptions } from "../core/discord/addFilterOptions";
|
||||||
import { addFilterOptions } from '../core/discord/addFilterOptions';
|
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 { createLocalizedCommand } from "../core/discord/createLocalizedCommand";
|
||||||
import { buttonRefresh } from '../core/discord/buttonRefresh';
|
import { getFiltersFromButton } from "../core/discord/getFiltersFromButton";
|
||||||
import { commandToURL } from '../core/discord/commandToURL';
|
import { resolvePeriodFromButton } from "../core/discord/resolvePeriodFromButton";
|
||||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
import { resolvePlayerFromButton } from "../core/discord/resolvePlayerFromButton";
|
||||||
import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams';
|
import { translator } from "../core/localization/translator";
|
||||||
import { getFiltersFromButton } from '../core/discord/getFiltersFromButton';
|
import { type CommandRegistry } from "../events/interactionCreate";
|
||||||
import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand';
|
import { renderBreakdown } from "./breakdown/render";
|
||||||
import { resolvePeriodFromButton } from '../core/discord/resolvePeriodFromButton';
|
|
||||||
import { resolvePeriodFromCommand } from '../core/discord/resolvePeriodFromCommand';
|
|
||||||
import { resolvePlayerFromButton } from '../core/discord/resolvePlayerFromButton';
|
|
||||||
import { resolvePlayerFromCommand } from '../core/discord/resolvePlayerFromCommand';
|
|
||||||
import { type CommandRegistry } from '../events/interactionCreate';
|
|
||||||
import { renderBreakdown } from './breakdown/render';
|
|
||||||
|
|
||||||
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
|
export const todayCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||||
const awaitedGameDefinitions = await gameDefinitions;
|
const awaitedGameDefinitions = await gameDefinitions;
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
command: addFilterOptions(
|
command: addFilterOptions(
|
||||||
createLocalizedCommand('today'),
|
createLocalizedCommand("today"),
|
||||||
awaitedGameDefinitions.nations,
|
awaitedGameDefinitions.nations,
|
||||||
).addStringOption(addUsernameChoices),
|
).addStringOption(addUsernameChoices),
|
||||||
|
|
||||||
async handler(interaction) {
|
async handler(interaction) {
|
||||||
const player = await resolvePlayerFromCommand(interaction);
|
const { strings } = translator(interaction.locale);
|
||||||
const period = resolvePeriodFromCommand(
|
return strings.bot.commands.dead;
|
||||||
player.region,
|
|
||||||
interaction,
|
|
||||||
'today',
|
|
||||||
);
|
|
||||||
const filters = await getFiltersFromCommand(interaction);
|
|
||||||
const path = commandToURL(interaction, {
|
|
||||||
...player,
|
|
||||||
...getCustomPeriodParams(interaction, true),
|
|
||||||
...filters,
|
|
||||||
});
|
|
||||||
|
|
||||||
return [
|
// const player = await resolvePlayerFromCommand(interaction);
|
||||||
...(await renderBreakdown(player, period, filters, interaction.locale)),
|
// const period = resolvePeriodFromCommand(
|
||||||
buttonRefresh(interaction, path),
|
// player.region,
|
||||||
await getBlitzStarsLinkButton(player.region, player.id),
|
// interaction,
|
||||||
];
|
// 'today',
|
||||||
|
// );
|
||||||
|
// const filters = await getFiltersFromCommand(interaction);
|
||||||
|
// const path = commandToURL(interaction, {
|
||||||
|
// ...player,
|
||||||
|
// ...getCustomPeriodParams(interaction, true),
|
||||||
|
// ...filters,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return [
|
||||||
|
// ...(await renderBreakdown(player, period, filters, interaction.locale)),
|
||||||
|
// buttonRefresh(interaction, path),
|
||||||
|
// await getBlitzStarsLinkButton(player.region, player.id),
|
||||||
|
// ];
|
||||||
},
|
},
|
||||||
|
|
||||||
autocomplete: (interaction) => {
|
autocomplete: (interaction) => {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
|
fetchAverageDefinitions,
|
||||||
fetchDiscoveredIdsDefinitions,
|
fetchDiscoveredIdsDefinitions,
|
||||||
fetchGameDefinitions,
|
fetchGameDefinitions,
|
||||||
fetchMapDefinitions,
|
fetchMapDefinitions,
|
||||||
fetchTankDefinitions,
|
fetchTankDefinitions,
|
||||||
fetchTankNames,
|
fetchTankNames,
|
||||||
} from '@blitzkit/core';
|
} from "@blitzkit/core";
|
||||||
|
|
||||||
|
export const averageDefinitions = fetchAverageDefinitions();
|
||||||
export const tankDefinitions = fetchTankDefinitions();
|
export const tankDefinitions = fetchTankDefinitions();
|
||||||
export const gameDefinitions = fetchGameDefinitions();
|
export const gameDefinitions = fetchGameDefinitions();
|
||||||
export const tankNames = fetchTankNames();
|
export const tankNames = fetchTankNames();
|
||||||
|
|||||||
@@ -1,29 +1,37 @@
|
|||||||
import { usersDatabase } from '../db/users';
|
import { usersDatabase } from "../db/users";
|
||||||
import { client } from '../discord/client';
|
import { client } from "../discord/client";
|
||||||
|
|
||||||
const EXIT_EVENTS = [
|
const EXIT_EVENTS = ["SIGINT", "SIGTERM", "SIGUSR1", "SIGUSR2"];
|
||||||
'beforeExit',
|
|
||||||
'exit',
|
|
||||||
'SIGINT',
|
|
||||||
'SIGTERM',
|
|
||||||
'SIGUSR1',
|
|
||||||
'SIGUSR2',
|
|
||||||
];
|
|
||||||
|
|
||||||
async function cleanup() {
|
let cleaningUp = false;
|
||||||
console.log('Cleaning up...');
|
|
||||||
|
|
||||||
await Promise.all([usersDatabase.$disconnect(), client.destroy()]);
|
async function cleanup(signal: string) {
|
||||||
|
if (cleaningUp) return;
|
||||||
|
cleaningUp = true;
|
||||||
|
|
||||||
console.log('Gracefully exiting...');
|
console.log(`Cleaning up... (${signal})`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all([usersDatabase.$disconnect(), client.destroy()]);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Cleanup error:", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Gracefully exiting...");
|
||||||
|
|
||||||
EXIT_EVENTS.forEach((event) => process.off(event, cleanup));
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerProcesses() {
|
export function registerProcesses() {
|
||||||
process.on('uncaughtException', console.error);
|
process.on("uncaughtException", (err) => {
|
||||||
client.on('error', console.error);
|
console.error("uncaughtException:", err);
|
||||||
|
});
|
||||||
|
|
||||||
EXIT_EVENTS.forEach((event) => process.on(event, cleanup));
|
process.on("unhandledRejection", (err) => {
|
||||||
|
console.error("unhandledRejection:", err);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("error", console.error);
|
||||||
|
|
||||||
|
EXIT_EVENTS.forEach((event) => process.on(event, () => cleanup(event)));
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,10 @@ 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 type { 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 {
|
||||||
import { blitzStarsTankAverages } from "./tankAverages";
|
averageDefinitions,
|
||||||
|
tankDefinitions,
|
||||||
|
} from "../blitzkit/nonBlockingPromises";
|
||||||
|
|
||||||
export interface StatFilters {
|
export interface StatFilters {
|
||||||
nation?: string;
|
nation?: string;
|
||||||
@@ -16,13 +18,13 @@ 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 };
|
||||||
|
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
const awaitedTankAverages = await blitzStarsTankAverages;
|
const awaitedTankAverages = await averageDefinitions;
|
||||||
const filteredOrder = order.filter((id) => {
|
const filteredOrder = order.filter((id) => {
|
||||||
const entry = awaitedTankDefinitions.tanks[id];
|
const entry = awaitedTankDefinitions.tanks[id];
|
||||||
|
|
||||||
@@ -44,26 +46,28 @@ export async function filterStats(
|
|||||||
const stats = sumAllStats(filteredOrder.map((id) => diff[id]));
|
const stats = sumAllStats(filteredOrder.map((id) => diff[id]));
|
||||||
const battlesOfTanksWithAverages = filteredOrder.reduce<number>(
|
const battlesOfTanksWithAverages = filteredOrder.reduce<number>(
|
||||||
(accumulator, id) =>
|
(accumulator, id) =>
|
||||||
awaitedTankAverages[id] ? accumulator + diff[id].battles : accumulator,
|
awaitedTankAverages.averages[id]
|
||||||
0
|
? accumulator + diff[id].battles
|
||||||
|
: accumulator,
|
||||||
|
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:
|
||||||
filteredOrder.reduce<number>(
|
filteredOrder.reduce<number>(
|
||||||
(accumulator, id) =>
|
(accumulator, id) =>
|
||||||
awaitedTankAverages[id]
|
awaitedTankAverages.averages[id]
|
||||||
? accumulator +
|
? accumulator +
|
||||||
calculateWN8(awaitedTankAverages[id].all, diff[id]) *
|
calculateWN8(awaitedTankAverages.averages[id].mu, diff[id]) *
|
||||||
diff[id].battles
|
diff[id].battles
|
||||||
: accumulator,
|
: accumulator,
|
||||||
0
|
0,
|
||||||
) / battlesOfTanksWithAverages,
|
) / battlesOfTanksWithAverages,
|
||||||
tier:
|
tier:
|
||||||
filteredOrder.reduce<number>(
|
filteredOrder.reduce<number>(
|
||||||
@@ -72,7 +76,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,101 +0,0 @@
|
|||||||
import { BlitzStats } from '@blitzkit/core';
|
|
||||||
import { context } from '@blitzkit/core/src/blitzkit/context';
|
|
||||||
|
|
||||||
interface SpecialStats {
|
|
||||||
winrate: number;
|
|
||||||
damageRatio: number;
|
|
||||||
kdr: number;
|
|
||||||
damagePerBattle: number;
|
|
||||||
killsPerBattle: number;
|
|
||||||
hitsPerBattle: number;
|
|
||||||
spotsPerBattle: number;
|
|
||||||
wpm: number;
|
|
||||||
dpm: number;
|
|
||||||
kpm: number;
|
|
||||||
hitRate: number;
|
|
||||||
survivalRate: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Percentiles = [
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
number,
|
|
||||||
];
|
|
||||||
|
|
||||||
export interface SpecialPercentiles {
|
|
||||||
winRate: Percentiles;
|
|
||||||
damageRatio: Percentiles;
|
|
||||||
kdr: Percentiles;
|
|
||||||
damagePerBattle: Percentiles;
|
|
||||||
killsPerBattle: Percentiles;
|
|
||||||
hitsPerBattle: Percentiles;
|
|
||||||
spotsPerBattle: Percentiles;
|
|
||||||
wpm: Percentiles;
|
|
||||||
dpm: Percentiles;
|
|
||||||
kpm: Percentiles;
|
|
||||||
hitRate: Percentiles;
|
|
||||||
survivalRate: Percentiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MeanSd {
|
|
||||||
winrateMean: number;
|
|
||||||
winrateSd: number;
|
|
||||||
hitRateMean: number;
|
|
||||||
hitRateSd: number;
|
|
||||||
survivalRateMean: number;
|
|
||||||
survivalRateSd: number;
|
|
||||||
damageRatioMean: number;
|
|
||||||
damageRatioSd: number;
|
|
||||||
kdrMean: number;
|
|
||||||
kdrSd: number;
|
|
||||||
dpbMean: number;
|
|
||||||
dpbSd: number;
|
|
||||||
kpbMean: number;
|
|
||||||
kpbSd: number;
|
|
||||||
hpbMean: number;
|
|
||||||
hpbSd: number;
|
|
||||||
spbMean: number;
|
|
||||||
spbSd: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IndividualTankAverage {
|
|
||||||
_id: number;
|
|
||||||
battle_life_time: number;
|
|
||||||
total_battle_life_time: number;
|
|
||||||
number_of_players: number;
|
|
||||||
tank_id: number;
|
|
||||||
all: BlitzStats;
|
|
||||||
special: SpecialStats;
|
|
||||||
percentiles: SpecialPercentiles;
|
|
||||||
percentiles_player_count: number;
|
|
||||||
meanSd: MeanSd;
|
|
||||||
shotEff: number;
|
|
||||||
last_update: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type BlitzStarsTankAverages = Record<number, IndividualTankAverage>;
|
|
||||||
|
|
||||||
export const blitzStarsTankAverages = fetch(
|
|
||||||
'https://www.blitzstars.com/api/tankaverages.json',
|
|
||||||
)
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((json) => {
|
|
||||||
if (context === 'server') {
|
|
||||||
const partialTankAverages: BlitzStarsTankAverages = {};
|
|
||||||
|
|
||||||
(json as IndividualTankAverage[]).forEach((individualTankAverage) => {
|
|
||||||
partialTankAverages[individualTankAverage.tank_id] =
|
|
||||||
individualTankAverage;
|
|
||||||
});
|
|
||||||
|
|
||||||
return partialTankAverages;
|
|
||||||
} else {
|
|
||||||
return json as BlitzStarsTankAverages;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Client, GatewayIntentBits } from 'discord.js';
|
import { Client, GatewayIntentBits } from "discord.js";
|
||||||
import { interactionCreate } from '../../events/interactionCreate';
|
import { interactionCreate } from "../../events/interactionCreate";
|
||||||
import { ready } from '../../events/ready';
|
import { ready } from "../../events/ready";
|
||||||
|
|
||||||
export const client = new Client({
|
export const client = new Client({
|
||||||
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers],
|
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers],
|
||||||
})
|
})
|
||||||
.on('ready', ready)
|
.on("clientReady", ready)
|
||||||
.on('interactionCreate', interactionCreate);
|
.on("interactionCreate", interactionCreate);
|
||||||
@@ -22,11 +22,11 @@ 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()
|
||||||
@@ -35,14 +35,14 @@ 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) {
|
||||||
@@ -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,10 +1,10 @@
|
|||||||
import { AutocompleteInteraction, CacheType } from 'discord.js';
|
import { AutocompleteInteraction, CacheType } from "discord.js";
|
||||||
import { commands } from '..';
|
import { commands } from "..";
|
||||||
|
|
||||||
export async function handleAutocomplete(
|
export async function handleAutocomplete(
|
||||||
interaction: AutocompleteInteraction<CacheType>,
|
interaction: AutocompleteInteraction<CacheType>,
|
||||||
) {
|
) {
|
||||||
const command = (await commands)[interaction.commandName];
|
const command = commands[interaction.commandName];
|
||||||
|
|
||||||
if (!command) {
|
if (!command) {
|
||||||
console.error(`No command matching ${interaction.commandName} was found.`);
|
console.error(`No command matching ${interaction.commandName} was found.`);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { ButtonInteraction, CacheType } from 'discord.js';
|
import { ButtonInteraction, CacheType } from "discord.js";
|
||||||
import { commands } from '..';
|
import { commands } from "..";
|
||||||
import { normalizeInteractionReturnable } from '../../../core/discord/normalizeInteractionReturnable';
|
import { normalizeInteractionReturnable } from "../../../core/discord/normalizeInteractionReturnable";
|
||||||
|
|
||||||
export async function handleButton(interaction: ButtonInteraction<CacheType>) {
|
export async function handleButton(interaction: ButtonInteraction<CacheType>) {
|
||||||
await interaction.deferUpdate();
|
await interaction.deferUpdate();
|
||||||
|
|
||||||
const url = new URL(`https://example.com/${interaction.customId}`);
|
const url = new URL(`https://example.com/${interaction.customId}`);
|
||||||
const commandName = url.pathname.split('/')[1];
|
const commandName = url.pathname.split("/")[1];
|
||||||
const button = (await commands)[commandName]?.button;
|
const button = commands[commandName]?.button;
|
||||||
|
|
||||||
if (!button) {
|
if (!button) {
|
||||||
throw new Error(`Button handler not found for "${commandName}"`);
|
throw new Error(`Button handler not found for "${commandName}"`);
|
||||||
@@ -16,7 +16,7 @@ export async function handleButton(interaction: ButtonInteraction<CacheType>) {
|
|||||||
if (interaction.message.interaction?.user.id !== interaction.user.id) {
|
if (interaction.message.interaction?.user.id !== interaction.user.id) {
|
||||||
interaction.followUp({
|
interaction.followUp({
|
||||||
ephemeral: true,
|
ephemeral: true,
|
||||||
content: 'You are not the author of this command.',
|
content: "You are not the author of this command.",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,11 @@ import { translator } from "../../../core/localization/translator";
|
|||||||
import type { 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();
|
||||||
|
|
||||||
const awaitedCommands = await commands;
|
const registry = commands[interaction.commandName];
|
||||||
const registry = awaitedCommands[interaction.commandName];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const returnable = await registry.handler(interaction);
|
const returnable = await registry.handler(interaction);
|
||||||
@@ -36,7 +35,7 @@ export async function handleChatInputCommand(
|
|||||||
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;
|
||||||
@@ -59,7 +58,7 @@ export async function handleChatInputCommand(
|
|||||||
} 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 +71,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)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +102,7 @@ export async function handleChatInputCommand(
|
|||||||
} 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 +115,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)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +132,7 @@ export async function handleChatInputCommand(
|
|||||||
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) {
|
||||||
|
|||||||
@@ -72,13 +72,13 @@ interface CommandRegistryImplicit extends CommandRegistryBase {
|
|||||||
interface CommandRegistryExplicit extends CommandRegistryBase {
|
interface CommandRegistryExplicit extends CommandRegistryBase {
|
||||||
handlesInteraction?: false;
|
handlesInteraction?: false;
|
||||||
handler: (
|
handler: (
|
||||||
interaction: ChatInputCommandInteraction<CacheType>
|
interaction: ChatInputCommandInteraction<CacheType>,
|
||||||
) => InteractionReturnable;
|
) => InteractionReturnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
|
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
|
||||||
|
|
||||||
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
export const commandsArray: Promise<CommandRegistry>[] = [
|
||||||
// auctionCommand,
|
// auctionCommand,
|
||||||
permissionsCommand,
|
permissionsCommand,
|
||||||
debugCommand,
|
debugCommand,
|
||||||
@@ -101,34 +101,28 @@ export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
|||||||
replayCommand,
|
replayCommand,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const commands = Promise.allSettled(COMMANDS_RAW).then((rawCommands) => {
|
export const commands: Record<string, CommandRegistry> = {};
|
||||||
return rawCommands.reduce<Record<string, CommandRegistry>>(
|
const commandsFulfilled: CommandRegistry[] = [];
|
||||||
(commands, registry, index) => {
|
|
||||||
if (registry.status === "rejected") {
|
let index = 0;
|
||||||
console.warn(
|
for (const registry of await Promise.allSettled(commandsArray)) {
|
||||||
`Command ${index} failed to load; skipping...`,
|
if (registry.status === "rejected") {
|
||||||
registry.reason
|
console.warn(`Command ${index} rejected`, registry.reason);
|
||||||
);
|
continue;
|
||||||
return commands;
|
}
|
||||||
}
|
|
||||||
return { ...commands, [registry.value.command.name]: registry.value };
|
commandsFulfilled.push(registry.value);
|
||||||
},
|
commands[registry.value.command.name] = registry.value;
|
||||||
{}
|
index++;
|
||||||
);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
const rest = new REST().setToken(assertSecret(import.meta.env.DISCORD_TOKEN));
|
const rest = new REST().setToken(assertSecret(import.meta.env.DISCORD_TOKEN));
|
||||||
|
const body = commandsFulfilled.map((registry) => registry.command.toJSON());
|
||||||
|
const applicationCommandsRoute = Routes.applicationCommands(
|
||||||
|
assertSecret(import.meta.env.DISCORD_CLIENT_ID),
|
||||||
|
);
|
||||||
|
|
||||||
commands.then((awaitedCommands) => {
|
await rest.put(applicationCommandsRoute, { body });
|
||||||
const body = Object.values(awaitedCommands).map((registry) =>
|
|
||||||
registry.command.toJSON()
|
|
||||||
);
|
|
||||||
|
|
||||||
rest.put(
|
|
||||||
Routes.applicationCommands(assertSecret(import.meta.env.DISCORD_CLIENT_ID)),
|
|
||||||
{ body }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export async function interactionCreate(interaction: Interaction<CacheType>) {
|
export async function interactionCreate(interaction: Interaction<CacheType>) {
|
||||||
if (interaction.isAutocomplete()) {
|
if (interaction.isAutocomplete()) {
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import { assertSecret } from '@blitzkit/core';
|
import { assertSecret } from "@blitzkit/core";
|
||||||
import { ActivityType, ShardingManager } from 'discord.js';
|
import { ActivityType, ShardingManager } from "discord.js";
|
||||||
import {
|
import {
|
||||||
discoveredIdsDefinitions,
|
discoveredIdsDefinitions,
|
||||||
tankDefinitions,
|
tankDefinitions,
|
||||||
} from './core/blitzkit/nonBlockingPromises';
|
} from "./core/blitzkit/nonBlockingPromises";
|
||||||
|
|
||||||
|
let manager: ShardingManager;
|
||||||
let iteration = 0;
|
let iteration = 0;
|
||||||
const interval = setInterval(async () => {
|
const interval = setInterval(async () => {
|
||||||
iteration++;
|
console.log(`Attempting launch on iteration ${++iteration}`);
|
||||||
|
|
||||||
console.log(`Attempting launch on iteration ${iteration}`);
|
manager?.respawnAll();
|
||||||
|
manager = new ShardingManager("dist/bot/workers/bot.js", {
|
||||||
const manager = new ShardingManager('dist/bot/workers/bot.js', {
|
|
||||||
token: assertSecret(import.meta.env.DISCORD_TOKEN),
|
token: assertSecret(import.meta.env.DISCORD_TOKEN),
|
||||||
});
|
});
|
||||||
|
|
||||||
const shards = await manager
|
const shards = await manager
|
||||||
.on('shardCreate', (shard) => {
|
.on("shardCreate", (shard) => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
console.log(`🟡 Launching shard ${shard.id}`);
|
console.log(`🟡 Launching shard ${shard.id}`);
|
||||||
shard.on('ready', () => console.log(`🟢 Launched shard ${shard.id}`));
|
shard.on("ready", () => console.log(`🟢 Launched shard ${shard.id}`));
|
||||||
})
|
})
|
||||||
.spawn();
|
.spawn({ timeout: 60000 });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let servers = 0;
|
let servers = 0;
|
||||||
@@ -29,7 +29,7 @@ const interval = setInterval(async () => {
|
|||||||
let users = 0;
|
let users = 0;
|
||||||
|
|
||||||
for (const [, shard] of shards) {
|
for (const [, shard] of shards) {
|
||||||
const guilds = (await shard.fetchClientValue('guilds.cache')) as any;
|
const guilds = (await shard.fetchClientValue("guilds.cache")) as any;
|
||||||
|
|
||||||
servers += guilds.length;
|
servers += guilds.length;
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ const interval = setInterval(async () => {
|
|||||||
for (const guild of client.guilds.cache.values()) {
|
for (const guild of client.guilds.cache.values()) {
|
||||||
try {
|
try {
|
||||||
const botMember = await guild.members.fetch(client.user.id);
|
const botMember = await guild.members.fetch(client.user.id);
|
||||||
await botMember.setNickname('BlitzKit');
|
await botMember.setNickname("BlitzKit");
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -74,8 +74,8 @@ const interval = setInterval(async () => {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'An error occurred when setting up presence, ignoring to keep the process alive',
|
"An error occurred when setting up presence, ignoring to keep the process alive",
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 15000);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { assertSecret } from '@blitzkit/core';
|
import { assertSecret } from "@blitzkit/core";
|
||||||
import { registerProcesses } from '../core/blitzkit/processes';
|
import { registerProcesses } from "../core/blitzkit/processes";
|
||||||
import { client } from '../core/discord/client';
|
import { client } from "../core/discord/client";
|
||||||
|
|
||||||
console.log(`🟡 Launching bot ${client.shard?.ids[0]}`);
|
console.log(`🟡 Launching bot ${client.shard?.ids[0]}`);
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,50 @@
|
|||||||
export * from './assertSecret';
|
export * from "./assertSecret";
|
||||||
export * from './asset';
|
export * from "./asset";
|
||||||
export * from './availableProvisions';
|
export * from "./availableProvisions";
|
||||||
export * from './averageDefinitions';
|
export * from "./averageDefinitions";
|
||||||
// export * from './camouflageDefinitions';
|
// export * from './camouflageDefinitions';
|
||||||
// export * from './checkConsumableProvisionInclusivity';
|
// export * from './checkConsumableProvisionInclusivity';
|
||||||
export * from './coefficient';
|
export * from "./coefficient";
|
||||||
export * from './consumableDefinitions';
|
export * from "./consumableDefinitions";
|
||||||
// export * from './context';
|
// export * from './context';
|
||||||
export * from './createDefaultSkills';
|
export * from "./createDefaultSkills";
|
||||||
export * from './degressiveStat';
|
export * from "./degressiveStat";
|
||||||
export * from './discoveredIdDefinitions';
|
export * from "./discoveredIdDefinitions";
|
||||||
export * from './emblemURL';
|
export * from "./emblemURL";
|
||||||
export * from './equipmentDefinitions';
|
export * from "./equipmentDefinitions";
|
||||||
export * from './eventManager';
|
export * from "./eventManager";
|
||||||
export * from './gameDefinitions';
|
export * from "./gameDefinitions";
|
||||||
export * from './getArchivedLatestSeasonNumber';
|
export * from "./getArchivedLatestSeasonNumber";
|
||||||
// export * from './getArchivedRatingInfo';
|
// export * from './getArchivedRatingInfo';
|
||||||
export * from './getArchivedRatingLeaderboard';
|
export * from "./getArchivedRatingLeaderboard";
|
||||||
// export * from './getArchivedRatingMidnightLeaderboard';
|
// export * from './getArchivedRatingMidnightLeaderboard';
|
||||||
export * from './getTimeDaysAgo';
|
export * from "./getTimeDaysAgo";
|
||||||
export * from './isExplosive';
|
export * from "./isExplosive";
|
||||||
export * from './mapDefinitions';
|
export * from "./mapDefinitions";
|
||||||
export * from './modelDefinitions';
|
export * from "./modelDefinitions";
|
||||||
export * from './normalizeBoundingBox';
|
export * from "./normalizeBoundingBox";
|
||||||
// export * from './parseBkni';
|
// export * from './parseBkni';
|
||||||
// export * from './patientFetch';
|
// export * from './patientFetch';
|
||||||
export * from './patientFetchJSON';
|
export * from "./patientFetchJSON";
|
||||||
export * from './progressiveStat';
|
export * from "./progressiveStat";
|
||||||
export * from './provisionDefinitions';
|
export * from "./provisionDefinitions";
|
||||||
export * from './resolveDpm';
|
export * from "./resolveDpm";
|
||||||
export * from './resolvePenetrationCoefficient';
|
export * from "./resolvePenetrationCoefficient";
|
||||||
export * from './reviews';
|
export * from "./reviews";
|
||||||
export * from './skillDefinitions';
|
export * from "./skillDefinitions";
|
||||||
export * from './sum';
|
export * from "./sum";
|
||||||
export * from './tankDefinitions';
|
export * from "./tankDefinitions";
|
||||||
export * from './tankIcon';
|
export * from "./tankIcon";
|
||||||
export * from './tankNames';
|
export * from "./tankNames";
|
||||||
export * from './unionBoundingBox';
|
export * from "./unionBoundingBox";
|
||||||
export * from './uniqueGuns';
|
export * from "./uniqueGuns";
|
||||||
export * from './unwrapBlitzkitResponse';
|
export * from "./unwrapBlitzkitResponse";
|
||||||
export * from './votes';
|
export * from "./votes";
|
||||||
// export * from './withCORSProxy';
|
// export * from './withCORSProxy';
|
||||||
export * from './createDefaultProvisions';
|
export * from "./createDefaultProvisions";
|
||||||
export * from './gallery';
|
export * from "./gallery";
|
||||||
export * from './metaSortTank';
|
export * from "./metaSortTank";
|
||||||
export * from './popularTanks';
|
export * from "./popularTanks";
|
||||||
export * from './romanize';
|
export * from "./romanize";
|
||||||
export * from './youtubers';
|
export * from "./sluggify.ts";
|
||||||
|
export * from "./youtubers";
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { deburr } from "lodash-es";
|
||||||
|
|
||||||
|
const nonAlphanumericRegex = /[^a-z0-9]/g;
|
||||||
|
const multipleDashesRegex = /--+/g;
|
||||||
|
const trailingDashRegex = /-$/g;
|
||||||
|
const leadingDashRegex = /^-/g;
|
||||||
|
|
||||||
|
export function sluggify(value: string) {
|
||||||
|
let slug = deburr(value).toLowerCase();
|
||||||
|
slug = slug.replaceAll(nonAlphanumericRegex, "-");
|
||||||
|
slug = slug.replaceAll(multipleDashesRegex, "-");
|
||||||
|
slug = slug.replaceAll(trailingDashRegex, "");
|
||||||
|
slug = slug.replaceAll(leadingDashRegex, "");
|
||||||
|
|
||||||
|
return slug;
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ export * from "./imgur";
|
|||||||
export * from "./math";
|
export * from "./math";
|
||||||
export * from "./patreon";
|
export * from "./patreon";
|
||||||
export * from "./protobuf";
|
export * from "./protobuf";
|
||||||
export * from "./protos";
|
|
||||||
export * from "./statistics";
|
export * from "./statistics";
|
||||||
export * from "./streams";
|
export * from "./streams";
|
||||||
export * from "./types";
|
export * from "./types";
|
||||||
@@ -3,6 +3,7 @@ export * from "./fisherYates";
|
|||||||
export * from "./formatCompact";
|
export * from "./formatCompact";
|
||||||
export * from "./isNumber";
|
export * from "./isNumber";
|
||||||
export * from "./NaNFallback";
|
export * from "./NaNFallback";
|
||||||
|
export * from "./normalizeAngleDeg";
|
||||||
export * from "./normalizeAngleRad";
|
export * from "./normalizeAngleRad";
|
||||||
export * from "./normalToEuler";
|
export * from "./normalToEuler";
|
||||||
export * from "./numberToRomanNumeral";
|
export * from "./numberToRomanNumeral";
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export function normalizeAngleDeg(angle: number) {
|
||||||
|
const newAngle = angle % 360;
|
||||||
|
if (newAngle > 360) return newAngle - 360;
|
||||||
|
if (newAngle < -360) return newAngle + 360;
|
||||||
|
return newAngle;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export function bufferToBigInt(buffer: ArrayBuffer) {
|
||||||
|
return new DataView(buffer).getBigUint64(0, true);
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './buffer';
|
export * from './buffer';
|
||||||
|
export * from './bufferToBigInt';
|
||||||
export * from './dds';
|
export * from './dds';
|
||||||
export * from './dids';
|
export * from './dids';
|
||||||
export * from './pvr';
|
export * from './pvr';
|
||||||
@@ -7,3 +8,4 @@ export * from './sc2';
|
|||||||
export * from './scg';
|
export * from './scg';
|
||||||
export * from './scpg';
|
export * from './scpg';
|
||||||
export * from './windows';
|
export * from './windows';
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[*.cs]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
## A streamlined .gitignore for modern .NET projects
|
||||||
|
## including temporary files, build results, and
|
||||||
|
## files generated by popular .NET tools. If you are
|
||||||
|
## developing with Visual Studio, the VS .gitignore
|
||||||
|
## https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
## has more thorough IDE-specific entries.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/main/Dotnet.gitignore
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Others
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
CodeCoverage/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using BlitzKit.Game.Models;
|
||||||
|
using CUE4Parse_Conversion.Textures;
|
||||||
|
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||||
|
using CUE4Parse.UE4.Objects.Engine;
|
||||||
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
|
using Microsoft.JavaScript.NodeApi;
|
||||||
|
|
||||||
|
namespace BlitzKit.Game.JSExport;
|
||||||
|
|
||||||
|
[JSExport]
|
||||||
|
public class GameInterface
|
||||||
|
{
|
||||||
|
private readonly BlitzFileProvider provider;
|
||||||
|
|
||||||
|
public string[] files;
|
||||||
|
public string[] tanksDirectoryNations;
|
||||||
|
|
||||||
|
public GameInterface(string directory)
|
||||||
|
{
|
||||||
|
provider = new(directory);
|
||||||
|
|
||||||
|
files = [.. provider.Files.Keys];
|
||||||
|
|
||||||
|
var tanksBase = "Blitz/Content/Tanks/";
|
||||||
|
tanksDirectoryNations =
|
||||||
|
[
|
||||||
|
.. files
|
||||||
|
.Where(path => path.StartsWith(tanksBase))
|
||||||
|
.Select(path => path[tanksBase.Length..])
|
||||||
|
.Select(path => path.Split('/')[0])
|
||||||
|
.Where(nation => !nation.EndsWith(".uasset") && nation != "TankStub")
|
||||||
|
.Distinct(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] Files => files;
|
||||||
|
public string[] TanksDirectoryNations => tanksDirectoryNations;
|
||||||
|
|
||||||
|
public byte[] TankBigIcon(string tankId, string pdaName)
|
||||||
|
{
|
||||||
|
foreach (var nation in tanksDirectoryNations)
|
||||||
|
{
|
||||||
|
var path = $"Blitz/Content/Tanks/{nation}/{tankId}/{pdaName}.{pdaName}";
|
||||||
|
|
||||||
|
if (provider.TryLoadPackageObject<UPrimaryDataAsset>(path, out var pda))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return pda.Get<FSoftObjectPath>("BigIcon")
|
||||||
|
.Load<UTexture2D>()
|
||||||
|
.Decode(ETexturePlatform.DesktopMobile)!
|
||||||
|
.ToSkBitmap()
|
||||||
|
.Encode(SkiaSharp.SKEncodedImageFormat.Webp, 80)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileNotFoundException($"Tank {tankId}/{pdaName} not found in any nation");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using CUE4Parse.Compression;
|
||||||
|
using CUE4Parse.FileProvider;
|
||||||
|
using CUE4Parse.MappingsProvider;
|
||||||
|
using CUE4Parse.UE4.Versions;
|
||||||
|
|
||||||
|
namespace BlitzKit.Game.Models;
|
||||||
|
|
||||||
|
public class BlitzFileProvider : DefaultFileProvider
|
||||||
|
{
|
||||||
|
public BlitzFileProvider(string directory)
|
||||||
|
: base(
|
||||||
|
directory: directory,
|
||||||
|
searchOption: SearchOption.AllDirectories,
|
||||||
|
versions: new(EGame.GAME_UE5_5),
|
||||||
|
pathComparer: StringComparer.OrdinalIgnoreCase
|
||||||
|
)
|
||||||
|
{
|
||||||
|
MappingsContainer = new FileUsmapTypeMappingsProvider("../../packages/closed/blitz.usmap");
|
||||||
|
|
||||||
|
Initialize();
|
||||||
|
Mount();
|
||||||
|
|
||||||
|
string libraryExtension;
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
libraryExtension = "dll";
|
||||||
|
}
|
||||||
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
{
|
||||||
|
libraryExtension = "so";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Unsupported OS");
|
||||||
|
}
|
||||||
|
|
||||||
|
OodleHelper.DownloadOodleDll($"../../temp/oodle.{libraryExtension}");
|
||||||
|
OodleHelper.Initialize($"../../temp/oodle.{libraryExtension}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>BlitzKit.Game</RootNamespace>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<NodeApiAssemblyJSModuleType>esm</NodeApiAssemblyJSModuleType>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../cue4parse/CUE4Parse/CUE4Parse.csproj" />
|
||||||
|
<ProjectReference Include="../cue4parse/CUE4Parse-Conversion/CUE4Parse-Conversion.csproj" />
|
||||||
|
<PackageReference Include="Microsoft.JavaScript.NodeApi" Version="0.9.19" />
|
||||||
|
<PackageReference Include="Microsoft.JavaScript.NodeApi.Generator" Version="0.9.19" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "@blitzkit/game",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"main": "src/index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "dotnet build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"node-api-dotnet": "^0.9.19"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "../bin/Debug/net9.0/win-x64/game";
|
||||||
@@ -1,4 +1,2 @@
|
|||||||
export * from "./literals";
|
export * from "./literals";
|
||||||
export * from "./strings";
|
export * from "./strings";
|
||||||
export * from "./unwrapper";
|
|
||||||
export * from "./wrapper";
|
|
||||||
@@ -1,16 +1,45 @@
|
|||||||
export function literals(
|
export function literals(
|
||||||
string: string,
|
string: string,
|
||||||
literals?: Record<string, string | number | undefined>
|
literals?: Record<string, string | number | undefined>,
|
||||||
) {
|
) {
|
||||||
for (const key in literals) {
|
for (const key in literals) {
|
||||||
const mutated = string.replaceAll(`{${key}}`, `${literals[key]}`);
|
string = string.replaceAll(`{${key}}`, `${literals[key]}`);
|
||||||
|
|
||||||
if (import.meta.env.DEV && mutated === string) {
|
|
||||||
console.warn(`Could not find literal {${key}} in string "${string}"`);
|
|
||||||
}
|
|
||||||
|
|
||||||
string = mutated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function literalsArray<Type, Literal = Type | string>(
|
||||||
|
string: string,
|
||||||
|
literals?: Record<string, Literal>,
|
||||||
|
) {
|
||||||
|
if (!literals) return [string];
|
||||||
|
|
||||||
|
let array: (string | Literal)[] = [string];
|
||||||
|
|
||||||
|
for (const key in literals) {
|
||||||
|
const value = literals[key];
|
||||||
|
const next: (string | Literal)[] = [];
|
||||||
|
|
||||||
|
for (const chunk of array) {
|
||||||
|
if (typeof chunk !== "string") {
|
||||||
|
next.push(chunk);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = chunk.split(`{${key}}`);
|
||||||
|
|
||||||
|
for (let index = 0; index < parts.length; index++) {
|
||||||
|
if (parts[index]) next.push(parts[index]);
|
||||||
|
|
||||||
|
if (index < parts.length - 1) {
|
||||||
|
next.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
array = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
@@ -1,68 +1,3 @@
|
|||||||
import { merge } from "ts-deepmerge";
|
import type en from "../strings/en.json";
|
||||||
import locales from "../locales.json";
|
|
||||||
import en from "../strings/en.json";
|
|
||||||
import es from "../strings/es.json";
|
|
||||||
import fr from "../strings/fr.json";
|
|
||||||
import ja from "../strings/ja.json";
|
|
||||||
import pl from "../strings/pl.json";
|
|
||||||
import pt from "../strings/pt.json";
|
|
||||||
import ru from "../strings/ru.json";
|
|
||||||
import uk from "../strings/uk.json";
|
|
||||||
import zh from "../strings/zh.json";
|
|
||||||
|
|
||||||
export type BlitzKitStrings = typeof en;
|
export type Strings = typeof en;
|
||||||
|
|
||||||
const stringsRaw: Record<string, TranslationTree> = {
|
|
||||||
en,
|
|
||||||
es,
|
|
||||||
fr,
|
|
||||||
ja,
|
|
||||||
pl,
|
|
||||||
pt,
|
|
||||||
ru,
|
|
||||||
uk,
|
|
||||||
zh,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const STRINGS: Record<string, BlitzKitStrings> = {};
|
|
||||||
|
|
||||||
for (const locale in stringsRaw) {
|
|
||||||
if (locale === locales.default) {
|
|
||||||
STRINGS[locales.default] = stringsRaw[locales.default] as BlitzKitStrings;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const localeStrings = stringsRaw[locale];
|
|
||||||
STRINGS[locale] = merge(
|
|
||||||
stringsRaw[locales.default],
|
|
||||||
localeStrings
|
|
||||||
) as BlitzKitStrings;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SUPPORTED_LOCALE_BLITZ_MAP: Record<string, string> = {
|
|
||||||
en: "en",
|
|
||||||
es: "es",
|
|
||||||
fr: "fr",
|
|
||||||
ja: "ja",
|
|
||||||
pt: "pt",
|
|
||||||
ru: "ru",
|
|
||||||
uk: "uk",
|
|
||||||
zh: "zh-Hans",
|
|
||||||
pl: "pl",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SUPPORTED_LOCALE_FLAGS: Record<string, string> = {
|
|
||||||
en: "🇺🇸",
|
|
||||||
es: "🇪🇸",
|
|
||||||
fr: "🇫🇷",
|
|
||||||
ja: "🇯🇵",
|
|
||||||
pt: "🇵🇹",
|
|
||||||
ru: "🇷🇺",
|
|
||||||
uk: "🇺🇦",
|
|
||||||
zh: "🇨🇳",
|
|
||||||
pl: "🇵🇱",
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TranslationTree = { [key: string]: TranslationNode };
|
|
||||||
|
|
||||||
export type TranslationNode = string | TranslationTree;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
import { I18nString } from "../../core/src";
|
|
||||||
import locales from "../locales.json";
|
|
||||||
|
|
||||||
export function unwrapper(locale = locales.default) {
|
|
||||||
return function (i18nString: I18nString) {
|
|
||||||
if (locale in i18nString.locales) {
|
|
||||||
return i18nString.locales[locale];
|
|
||||||
}
|
|
||||||
|
|
||||||
return i18nString.locales[locales.default];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import locales from "../locales.json";
|
|
||||||
import { type BlitzKitStrings, STRINGS } from "./strings";
|
|
||||||
|
|
||||||
export function wrapper(slicer: (strings: BlitzKitStrings) => string) {
|
|
||||||
const defaultString = slicer(STRINGS[locales.default] as BlitzKitStrings);
|
|
||||||
|
|
||||||
const object = { [locales.default]: defaultString };
|
|
||||||
|
|
||||||
for (const { locale } of locales.supported) {
|
|
||||||
const string = slicer(STRINGS[locale] as BlitzKitStrings);
|
|
||||||
if (string !== defaultString) object[locale] = string;
|
|
||||||
}
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "repetición",
|
"name": "repetición",
|
||||||
"description": "Mostrar resultados de la repetición"
|
"description": "Mostrar resultados de la repetición",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"description": "Replay file"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "desarollar",
|
"name": "desarollar",
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "Características",
|
"title": "Características",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "Comparar con",
|
"label": "Comparar con",
|
||||||
"class": "Tier {tier} {class}",
|
"class": "{tier} {class}",
|
||||||
"tier": "All of tier {tier}",
|
"tier": "All tier {tier}",
|
||||||
"all": "Todos los tanques"
|
"all": "Todos los tanques"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
|
|||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "rejouer",
|
"name": "rejouer",
|
||||||
"description": "Afficher les résultats de la relecture"
|
"description": "Afficher les résultats de la relecture",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"description": "Replay file"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "recherche",
|
"name": "recherche",
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "Characteristics",
|
"title": "Characteristics",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "Compare against",
|
"label": "Compare against",
|
||||||
"class": "Tier {tier} {class}",
|
"class": "{tier} {class}",
|
||||||
"tier": "All of tier {tier}",
|
"tier": "All tier {tier}",
|
||||||
"all": "All tanks"
|
"all": "All tanks"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
|
|||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "replay",
|
"name": "replay",
|
||||||
"description": "Display replay results"
|
"description": "Display replay results",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"description": "Replay file"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "研究",
|
"name": "研究",
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "性能値",
|
"title": "性能値",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "比較対象",
|
"label": "比較対象",
|
||||||
"class": "Tier {tier} {class}",
|
"class": "{tier} {class}",
|
||||||
"tier": "All of tier {tier}",
|
"tier": "All tier {tier}",
|
||||||
"all": "全車輌"
|
"all": "全車輌"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"test": {
|
"test": {
|
||||||
"default": "",
|
"default": "",
|
||||||
"long": "This is a long test string. You MUST NEVER see this in the UI. My favorite fruit is {fruit} because it has the color of {color}. I like it so much that I will say its name 3 times! {fruit}! {fruit}! {fruit}! Once again, it's {color}, not {not_color}.",
|
"long": ".",
|
||||||
"fox": "Szybki brązowy lis przeskoczył nad leniwym psem."
|
"fox": "Szybki brązowy lis przeskoczył nad leniwym psem."
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "powtórz",
|
"name": "powtórz",
|
||||||
"description": "Wyświetl wyniki powtórki"
|
"description": "Wyświetl wyniki powtórki",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"description": "Replay file"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "badanie",
|
"name": "badanie",
|
||||||
@@ -493,7 +500,7 @@
|
|||||||
"description": "Search clans",
|
"description": "Search clans",
|
||||||
"options": {
|
"options": {
|
||||||
"limit": {
|
"limit": {
|
||||||
"name": "limit",
|
"name": "",
|
||||||
"description": "The max number of clan results (default: {limit})"
|
"description": "The max number of clan results (default: {limit})"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -507,7 +514,7 @@
|
|||||||
"description": "Search players",
|
"description": "Search players",
|
||||||
"options": {
|
"options": {
|
||||||
"limit": {
|
"limit": {
|
||||||
"name": "limit",
|
"name": "",
|
||||||
"description": "The max number of player results (default: {limit})"
|
"description": "The max number of player results (default: {limit})"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -531,7 +538,7 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"limit": {
|
"limit": {
|
||||||
"name": "limit",
|
"name": "",
|
||||||
"description": "How many neighbors to display (default: {count})"
|
"description": "How many neighbors to display (default: {count})"
|
||||||
},
|
},
|
||||||
"season": {
|
"season": {
|
||||||
@@ -675,7 +682,7 @@
|
|||||||
"active": "{name} (Active)",
|
"active": "{name} (Active)",
|
||||||
"no_tanks_found": {
|
"no_tanks_found": {
|
||||||
"body": "No tanks found.",
|
"body": "No tanks found.",
|
||||||
"search_again": "Try searching again.",
|
"search_again": "",
|
||||||
"clear_filters": "Try clearing filters."
|
"clear_filters": "Try clearing filters."
|
||||||
},
|
},
|
||||||
"sort": {
|
"sort": {
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "Characteristics",
|
"title": "Characteristics",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "Compare against",
|
"label": "Compare against",
|
||||||
"class": "Tier {tier} {class}",
|
"class": "{tier} {class}",
|
||||||
"tier": "All of tier {tier}",
|
"tier": "All tier {tier}",
|
||||||
"all": "All tanks"
|
"all": "All tanks"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
|
|||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "replay",
|
"name": "replay",
|
||||||
"description": "Exibir resultados de replays"
|
"description": "Exibir resultados de replays",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"description": "Replay file"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "pesquisa",
|
"name": "pesquisa",
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "Características",
|
"title": "Características",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "Comparar com",
|
"label": "Comparar com",
|
||||||
"class": "Tier {tier} {class}",
|
"class": "{tier} {class}",
|
||||||
"tier": "All of tier {tier}",
|
"tier": "All tier {tier}",
|
||||||
"all": "Todos os tanques"
|
"all": "Todos os tanques"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"shells": {
|
"shells": {
|
||||||
"ap": "ББ",
|
"ap": "ББ",
|
||||||
"ap_cr": "БП",
|
"ap_cr": "БП",
|
||||||
"hc": "ОФ",
|
"hc": "КС",
|
||||||
"he": "ОФ"
|
"he": "ОФ"
|
||||||
},
|
},
|
||||||
"player_count_period": {
|
"player_count_period": {
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"branches": {
|
"branches": {
|
||||||
"local": "dev",
|
"local": "dev",
|
||||||
"dev": "бета",
|
"dev": "бета",
|
||||||
"opentest": "открытый тест",
|
"opentest": "общий тест",
|
||||||
"preview": "превью"
|
"preview": "превью"
|
||||||
},
|
},
|
||||||
"locales": {
|
"locales": {
|
||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": ".",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "повтор",
|
"name": "повтор",
|
||||||
"description": "Показать результаты повтора"
|
"description": "Показать результаты повтора",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "Файл",
|
||||||
|
"description": "Запись повтора"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "исследование",
|
"name": "исследование",
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "Характеристики",
|
"title": "Характеристики",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "Сравнивать с",
|
"label": "Сравнивать с",
|
||||||
"class": "{class} {tier} уровня",
|
"class": "Уровень Тип",
|
||||||
"tier": "Все {tier} уровня",
|
"tier": "Все уровни",
|
||||||
"all": "Все танки"
|
"all": "Все танки"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"test": {
|
"test": {
|
||||||
"default": "тест",
|
"default": "тест",
|
||||||
"long": "{fruit}",
|
"long": "{color}{fruit}",
|
||||||
"fox": "Швидка бура лисиця перестрибує через лінивого собаку."
|
"fox": "Швидка бура лисиця перестрибує через лінивого собаку."
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
"shells": {
|
"shells": {
|
||||||
"ap": "ББ",
|
"ap": "ББ",
|
||||||
"ap_cr": "APCR",
|
"ap_cr": "",
|
||||||
"hc": "HEAT",
|
"hc": "HEAT",
|
||||||
"he": "ОФ"
|
"he": "ОФ"
|
||||||
},
|
},
|
||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": ".",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "реплей",
|
"name": "реплей",
|
||||||
"description": "Показати результати реплею"
|
"description": "Показати результати реплею",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "",
|
||||||
|
"description": "Replay filehttps://crowdin.com/editor/blitzkrieg/80/en-uk?view=side-by-side#9706"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "дослідження",
|
"name": "дослідження",
|
||||||
@@ -660,7 +667,7 @@
|
|||||||
},
|
},
|
||||||
"tank_search": {
|
"tank_search": {
|
||||||
"select_dialog_title": "Знайти танк",
|
"select_dialog_title": "Знайти танк",
|
||||||
"swap_dialog_title": "Swap tank",
|
"swap_dialog_title": "Резервуар підміни",
|
||||||
"clear_filters": "Очистити",
|
"clear_filters": "Очистити",
|
||||||
"login": "Увійдіть, щоб скористатися",
|
"login": "Увійдіть, щоб скористатися",
|
||||||
"search_bar_hint": "Шукайте техніку...",
|
"search_bar_hint": "Шукайте техніку...",
|
||||||
@@ -671,8 +678,8 @@
|
|||||||
"sorting_by": "Відсортувати за {name}",
|
"sorting_by": "Відсортувати за {name}",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"tier": "Рівень {tier}",
|
"tier": "Рівень {tier}",
|
||||||
"passive": "{name} (Passive)",
|
"passive": "",
|
||||||
"active": "{name} (Active)",
|
"active": "{name}{name}",
|
||||||
"no_tanks_found": {
|
"no_tanks_found": {
|
||||||
"body": "Нічого не знайдено.",
|
"body": "Нічого не знайдено.",
|
||||||
"search_again": "Спробуйте шукати заново.",
|
"search_again": "Спробуйте шукати заново.",
|
||||||
@@ -735,11 +742,11 @@
|
|||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"pwa": {
|
"pwa": {
|
||||||
"title": "Install the BlitzKit App",
|
"title": "",
|
||||||
"new": "",
|
"new": "",
|
||||||
"checking": "Checking compatibility...",
|
"checking": "",
|
||||||
"instructions": "Instructions for Apple devices.",
|
"instructions": ".",
|
||||||
"install": "Install",
|
"install": "",
|
||||||
"dismiss": "Dismiss"
|
"dismiss": "Dismiss"
|
||||||
},
|
},
|
||||||
"discord": {
|
"discord": {
|
||||||
@@ -823,7 +830,7 @@
|
|||||||
"help": {
|
"help": {
|
||||||
"title": "Partially reveal tank?",
|
"title": "Partially reveal tank?",
|
||||||
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
"description": "Reveals the tank without showing the name. This round will be considered incorrect and break your streak!",
|
||||||
"cancel": "Cancel",
|
"cancel": "",
|
||||||
"reveal": "Reveal"
|
"reveal": "Reveal"
|
||||||
},
|
},
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "Characteristics",
|
"title": "Characteristics",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "Compare against",
|
"label": "Compare against",
|
||||||
"class": "Tier {tier} {class}",
|
"class": "{tier} {class}",
|
||||||
"tier": "All of tier {tier}",
|
"tier": "All tier {tier}",
|
||||||
"all": "Усі танки"
|
"all": "Усі танки"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
@@ -1274,7 +1281,7 @@
|
|||||||
"button": "Generate URL",
|
"button": "Generate URL",
|
||||||
"title": "Generate URL",
|
"title": "Generate URL",
|
||||||
"subtitle": "Search an account to track",
|
"subtitle": "Search an account to track",
|
||||||
"cancel": "Cancel",
|
"cancel": "",
|
||||||
"success": {
|
"success": {
|
||||||
"title": "Copy URL",
|
"title": "Copy URL",
|
||||||
"info": "Generated the URL for {name}. The embed will start tracking as soon as the URL is pasted. Reset at any time by right-clicking on PC or long-pressing on mobile and then selecting \"Reset\".",
|
"info": "Generated the URL for {name}. The embed will start tracking as soon as the URL is pasted. Reset at any time by right-clicking on PC or long-pressing on mobile and then selecting \"Reset\".",
|
||||||
|
|||||||
@@ -320,9 +320,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
|
"dead": "# Stat Commands Are Dead\n\nThe BlitzKit Discord bot used to use BlitzStars to fetch periodic statistics. BlitzStars has enabled aggressive Cloudflare protections; hence, disabling BlitzKit from using BlitzStar's API. This has impacted the following commands:\n\n- `/stats`\n- `/today`\n- `/breakdown`\n- `/evolution`\n- `/full-stats`\n\nPlease use [Aftermath](<https://amth.one/invite>) as an alternative which is completely independent of BlitzStars. BlitzKit-hosted stat commands will return in the near future.",
|
||||||
"replay": {
|
"replay": {
|
||||||
"name": "回放",
|
"name": "回放",
|
||||||
"description": "显示重播结果"
|
"description": "显示重播结果",
|
||||||
|
"options": {
|
||||||
|
"file": {
|
||||||
|
"name": "file",
|
||||||
|
"description": "Replay file"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"name": "研发",
|
"name": "研发",
|
||||||
@@ -1005,8 +1012,8 @@
|
|||||||
"title": "属性",
|
"title": "属性",
|
||||||
"compare": {
|
"compare": {
|
||||||
"label": "比较",
|
"label": "比较",
|
||||||
"class": "{tier}阶 {class}",
|
"class": "{tier} {class}",
|
||||||
"tier": "所有 {tier} 阶",
|
"tier": "All tier {tier}",
|
||||||
"all": "所有坦克"
|
"all": "所有坦克"
|
||||||
},
|
},
|
||||||
"values": {
|
"values": {
|
||||||
|
|||||||
@@ -12,12 +12,14 @@ export async function tankModels() {
|
|||||||
|
|
||||||
using uploader = new AssetUploader("tank models");
|
using uploader = new AssetUploader("tank models");
|
||||||
const nodeIO = new NodeIO().registerExtensions(ALL_EXTENSIONS);
|
const nodeIO = new NodeIO().registerExtensions(ALL_EXTENSIONS);
|
||||||
const nations = vfs.dir(`Data/XML/item_defs/vehicles`).filter((nation) => nation !== "common")
|
const nations = vfs
|
||||||
|
.dir(`Data/XML/item_defs/vehicles`)
|
||||||
|
.filter((nation) => nation !== "common");
|
||||||
|
|
||||||
for (const nationIndex in nations) {
|
for (const nationIndex in nations) {
|
||||||
const nation = nations[nationIndex];
|
const nation = nations[nationIndex];
|
||||||
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
|
const tanks = await vfs.xml<{ root: VehicleDefinitionList }>(
|
||||||
`Data/XML/item_defs/vehicles/${nation}/list.xml`
|
`Data/XML/item_defs/vehicles/${nation}/list.xml`,
|
||||||
);
|
);
|
||||||
const entries = Object.entries(tanks.root);
|
const entries = Object.entries(tanks.root);
|
||||||
|
|
||||||
@@ -26,11 +28,11 @@ export async function tankModels() {
|
|||||||
|
|
||||||
const id = toUniqueId(nation, tank.id);
|
const id = toUniqueId(nation, tank.id);
|
||||||
const parameters = await vfs.yaml<TankParameters>(
|
const parameters = await vfs.yaml<TankParameters>(
|
||||||
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`
|
`Data/3d/Tanks/Parameters/${nation}/${tankKey}.yaml`,
|
||||||
);
|
);
|
||||||
const model = await extractModel(
|
const model = await extractModel(
|
||||||
vfs,
|
vfs,
|
||||||
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, "")
|
parameters.resourcesPath.blitzModelPath.replace(/\.sc2$/, ""),
|
||||||
);
|
);
|
||||||
const content = Buffer.from(await nodeIO.writeBinary(model));
|
const content = Buffer.from(await nodeIO.writeBinary(model));
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import { build } from "esbuild";
|
import { build } from "esbuild";
|
||||||
import { cp, readdir, rm } from "fs/promises";
|
import { cp, readdir, rm } from "fs/promises";
|
||||||
import { argv } from "process";
|
|
||||||
|
|
||||||
const dev = argv.includes("--dev");
|
|
||||||
|
|
||||||
const projectDir = "../..";
|
const projectDir = "../..";
|
||||||
const srcRoot = `${projectDir}/packages/bot`;
|
const srcRoot = `${projectDir}/packages/bot`;
|
||||||
const distRoot = `${projectDir}/dist/bot`;
|
const distRoot = `${projectDir}/dist/bot`;
|
||||||
const modulesRoot = dev
|
const modulesRoot = "../../node_modules";
|
||||||
? "../../packages/bot/node_modules"
|
|
||||||
: "../../node_modules";
|
|
||||||
const workers = await readdir(`${srcRoot}/src/workers`);
|
const workers = await readdir(`${srcRoot}/src/workers`);
|
||||||
|
|
||||||
await rm(distRoot, { recursive: true, force: true });
|
await rm(distRoot, { recursive: true, force: true });
|
||||||
@@ -30,9 +25,9 @@ build({
|
|||||||
},
|
},
|
||||||
external: ["sharp"],
|
external: ["sharp"],
|
||||||
minifyIdentifiers: false, // causes goofy ahh issues
|
minifyIdentifiers: false, // causes goofy ahh issues
|
||||||
minifySyntax: !dev,
|
minifySyntax: true,
|
||||||
minifyWhitespace: !dev,
|
minifyWhitespace: true,
|
||||||
sourcemap: !dev,
|
sourcemap: true,
|
||||||
jsxImportSource: "react",
|
jsxImportSource: "react",
|
||||||
jsx: "automatic",
|
jsx: "automatic",
|
||||||
});
|
});
|
||||||
@@ -44,18 +39,16 @@ for (const module of await readdir(`${modulesRoot}/@resvg`)) {
|
|||||||
.map((file) =>
|
.map((file) =>
|
||||||
cp(
|
cp(
|
||||||
`${modulesRoot}/@resvg/${module}/${file}`,
|
`${modulesRoot}/@resvg/${module}/${file}`,
|
||||||
`${distRoot}/workers/${file}`
|
`${distRoot}/workers/${file}`,
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev) {
|
await cp(`${projectDir}/prisma`, `${distRoot}/prisma`, { recursive: true });
|
||||||
await cp(`${projectDir}/prisma`, `${distRoot}/prisma`, { recursive: true });
|
|
||||||
|
|
||||||
for (const file of await readdir(`${modulesRoot}/prisma`).then((files) =>
|
for (const file of await readdir(`${modulesRoot}/prisma`).then((files) =>
|
||||||
files.filter((file) => file.endsWith(".node"))
|
files.filter((file) => file.endsWith(".node")),
|
||||||
)) {
|
)) {
|
||||||
cp(`${modulesRoot}/prisma/${file}`, `${distRoot}/prisma/${file}`);
|
cp(`${modulesRoot}/prisma/${file}`, `${distRoot}/prisma/${file}`);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,20 +6,20 @@ import {
|
|||||||
} from "@blitzkit/core";
|
} from "@blitzkit/core";
|
||||||
import { Accessor, Document, Node, Scene } from "@gltf-transform/core";
|
import { Accessor, Document, Node, Scene } from "@gltf-transform/core";
|
||||||
import { times } from "lodash-es";
|
import { times } from "lodash-es";
|
||||||
import { SteamVFS } from "../vfs/vfs";
|
import { AbstractVFS } from "../vfs/abstract";
|
||||||
import {
|
import {
|
||||||
vertexAttributeGLTFName,
|
vertexAttributeGLTFName,
|
||||||
vertexAttributeGltfVectorSizes,
|
vertexAttributeGltfVectorSizes,
|
||||||
} from "./extractModel/constants";
|
} from "./extractModel/constants";
|
||||||
|
|
||||||
export async function extractArmor(vfs: SteamVFS, fileName: string) {
|
export async function extractArmor(vfs: AbstractVFS, fileName: string) {
|
||||||
const sc2Path = `Data/3d/Tanks/CollisionMeshes/${fileName}.sc2`;
|
const sc2Path = `Data/3d/Tanks/CollisionMeshes/${fileName}.sc2`;
|
||||||
const scgPath = `Data/3d/Tanks/CollisionMeshes/${fileName}.scg`;
|
const scgPath = `Data/3d/Tanks/CollisionMeshes/${fileName}.scg`;
|
||||||
const sc2 = new Sc2ReadStream(
|
const sc2 = new Sc2ReadStream(
|
||||||
(await vfs.file(sc2Path)).buffer as ArrayBuffer
|
(await vfs.file(sc2Path)).buffer as ArrayBuffer,
|
||||||
).sc2();
|
).sc2();
|
||||||
const scg = new ScgReadStream(
|
const scg = new ScgReadStream(
|
||||||
(await vfs.file(scgPath)).buffer as ArrayBuffer
|
(await vfs.file(scgPath)).buffer as ArrayBuffer,
|
||||||
).scg();
|
).scg();
|
||||||
const document = new Document();
|
const document = new Document();
|
||||||
const scene = document.createScene();
|
const scene = document.createScene();
|
||||||
@@ -29,7 +29,7 @@ export async function extractArmor(vfs: SteamVFS, fileName: string) {
|
|||||||
hierarchies.forEach((hierarchy) => {
|
hierarchies.forEach((hierarchy) => {
|
||||||
const components = times(
|
const components = times(
|
||||||
hierarchy.components.count,
|
hierarchy.components.count,
|
||||||
(index) => hierarchy.components[index.toString().padStart(4, "0")]
|
(index) => hierarchy.components[index.toString().padStart(4, "0")],
|
||||||
);
|
);
|
||||||
|
|
||||||
components.forEach((component) => {
|
components.forEach((component) => {
|
||||||
@@ -43,7 +43,7 @@ export async function extractArmor(vfs: SteamVFS, fileName: string) {
|
|||||||
|
|
||||||
if (!polygonGroup) {
|
if (!polygonGroup) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Missing polygon group ${batch["rb.datasource"]} (${hierarchy.name}); skipping...`
|
`Missing polygon group ${batch["rb.datasource"]} (${hierarchy.name}); skipping...`,
|
||||||
);
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -73,7 +73,7 @@ export async function extractArmor(vfs: SteamVFS, fileName: string) {
|
|||||||
VertexAttribute.TANGENT,
|
VertexAttribute.TANGENT,
|
||||||
attributes
|
attributes
|
||||||
.get(VertexAttribute.TANGENT)!
|
.get(VertexAttribute.TANGENT)!
|
||||||
.map((tangent) => [...tangent, 1])
|
.map((tangent) => [...tangent, 1]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ export async function extractArmor(vfs: SteamVFS, fileName: string) {
|
|||||||
|
|
||||||
hardJointIndices.forEach((hardJointIndex) => {
|
hardJointIndices.forEach((hardJointIndex) => {
|
||||||
const node = document.createNode(
|
const node = document.createNode(
|
||||||
`${hierarchy.name}_armor_${hardJointIndex}`
|
`${hierarchy.name}_armor_${hardJointIndex}`,
|
||||||
);
|
);
|
||||||
const mesh = document.createMesh(batch["##name"]);
|
const mesh = document.createMesh(batch["##name"]);
|
||||||
const indicesAccessor = document
|
const indicesAccessor = document
|
||||||
@@ -104,9 +104,9 @@ export async function extractArmor(vfs: SteamVFS, fileName: string) {
|
|||||||
new Uint16Array(
|
new Uint16Array(
|
||||||
polygonGroup.indices.filter(
|
polygonGroup.indices.filter(
|
||||||
(index) =>
|
(index) =>
|
||||||
vertexHardJointIndices.get(index) === hardJointIndex
|
vertexHardJointIndices.get(index) === hardJointIndex,
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.setBuffer(buffer);
|
.setBuffer(buffer);
|
||||||
const primitive = document
|
const primitive = document
|
||||||
@@ -127,7 +127,7 @@ export async function extractArmor(vfs: SteamVFS, fileName: string) {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
throw new TypeError(
|
throw new TypeError(
|
||||||
`Unhandled component type: ${component["comp.typename"]}`
|
`Unhandled component type: ${component["comp.typename"]}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
bufferToBigInt,
|
||||||
Hierarchy,
|
Hierarchy,
|
||||||
Sc2ReadStream,
|
Sc2ReadStream,
|
||||||
ScgReadStream,
|
ScgReadStream,
|
||||||
@@ -9,7 +10,7 @@ import { Document, Material, Node, Scene } from "@gltf-transform/core";
|
|||||||
import { dedup, prune } from "@gltf-transform/functions";
|
import { dedup, prune } from "@gltf-transform/functions";
|
||||||
import { times } from "lodash-es";
|
import { times } from "lodash-es";
|
||||||
import { dirname } from "path";
|
import { dirname } from "path";
|
||||||
import { SteamVFS } from "../../vfs/vfs";
|
import { AbstractVFS } from "../../vfs/abstract";
|
||||||
import { readBaseColor } from "../readBaseColor";
|
import { readBaseColor } from "../readBaseColor";
|
||||||
import { readNormal } from "../readNormal";
|
import { readNormal } from "../readNormal";
|
||||||
import { readRoughnessMetallic } from "../readRoughnessMetallic";
|
import { readRoughnessMetallic } from "../readRoughnessMetallic";
|
||||||
@@ -25,14 +26,14 @@ const omitMeshNames = {
|
|||||||
end: ["_POINT"],
|
end: ["_POINT"],
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function extractModel(vfs: SteamVFS, path: string) {
|
export async function extractModel(vfs: AbstractVFS, path: string) {
|
||||||
const sc2Path = `Data/3d/${path}.sc2`;
|
const sc2Path = `Data/3d/${path}.sc2`;
|
||||||
const scgPath = `Data/3d/${path}.scg`;
|
const scgPath = `Data/3d/${path}.scg`;
|
||||||
const sc2 = new Sc2ReadStream(
|
const sc2 = new Sc2ReadStream(
|
||||||
(await vfs.file(sc2Path)).buffer as ArrayBuffer
|
(await vfs.file(sc2Path)).buffer as ArrayBuffer,
|
||||||
).sc2();
|
).sc2();
|
||||||
const scg = new ScgReadStream(
|
const scg = new ScgReadStream(
|
||||||
(await vfs.file(scgPath)).buffer as ArrayBuffer
|
(await vfs.file(scgPath)).buffer as ArrayBuffer,
|
||||||
).scg();
|
).scg();
|
||||||
const document = new Document();
|
const document = new Document();
|
||||||
const scene = document.createScene();
|
const scene = document.createScene();
|
||||||
@@ -40,7 +41,7 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
const materials = new Map<bigint, Material | bigint | undefined>();
|
const materials = new Map<bigint, Material | bigint | undefined>();
|
||||||
|
|
||||||
for (const node of sc2["#dataNodes"]) {
|
for (const node of sc2["#dataNodes"]) {
|
||||||
const id = new DataView(node["#id"]).getBigUint64(0, true);
|
const id = bufferToBigInt(node["#id"]);
|
||||||
|
|
||||||
if (node.parentMaterialKey !== undefined) {
|
if (node.parentMaterialKey !== undefined) {
|
||||||
/**
|
/**
|
||||||
@@ -61,20 +62,17 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (textures) {
|
if (textures) {
|
||||||
|
const { image: baseColor, hasAlpha } = await readBaseColor(
|
||||||
|
`Data/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`,
|
||||||
|
textures.miscMap
|
||||||
|
? `Data/3d/${dirname(path)}/${textures.miscMap}`
|
||||||
|
: undefined,
|
||||||
|
);
|
||||||
material.setBaseColorTexture(
|
material.setBaseColorTexture(
|
||||||
document
|
document
|
||||||
.createTexture(node.materialName)
|
.createTexture(node.materialName)
|
||||||
.setMimeType("image/webp")
|
.setMimeType("image/webp")
|
||||||
.setImage(
|
.setImage(baseColor),
|
||||||
await readBaseColor(
|
|
||||||
`Data/3d/${dirname(path)}/${
|
|
||||||
textures.baseColorMap ?? textures.albedo
|
|
||||||
}`,
|
|
||||||
textures.miscMap
|
|
||||||
? `Data/3d/${dirname(path)}/${textures.miscMap}`
|
|
||||||
: undefined
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (node.configCount) {
|
if (node.configCount) {
|
||||||
@@ -92,7 +90,11 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
material.setAlphaMode("BLEND").setDoubleSided(true);
|
const view = new DataView(archive.properties.alphatestThreshold);
|
||||||
|
const _ = view.getUint8(0); // only god knows what these flags are
|
||||||
|
const alphaCutoff = view.getFloat32(1, true);
|
||||||
|
|
||||||
|
material.setAlphaMode("MASK").setAlphaCutoff(alphaCutoff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,9 +105,9 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
.setMimeType("image/webp")
|
.setMimeType("image/webp")
|
||||||
.setImage(
|
.setImage(
|
||||||
await readRoughnessMetallic(
|
await readRoughnessMetallic(
|
||||||
`Data/3d/${dirname(path)}/${textures.baseRMMap}`
|
`Data/3d/${dirname(path)}/${textures.baseRMMap}`,
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,13 +123,13 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
`Data/3d/${dirname(path)}/${
|
`Data/3d/${dirname(path)}/${
|
||||||
textures.baseNormalMap ?? textures.normalmap
|
textures.baseNormalMap ?? textures.normalmap
|
||||||
}`,
|
}`,
|
||||||
isBase
|
isBase,
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
materials.set(new DataView(node["#id"]).getBigUint64(0, true), material);
|
materials.set(id, material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +159,7 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
const node = document.createNode(hierarchy.name);
|
const node = document.createNode(hierarchy.name);
|
||||||
const components = times(
|
const components = times(
|
||||||
hierarchy.components.count,
|
hierarchy.components.count,
|
||||||
(index) => hierarchy.components[index.toString().padStart(4, "0")]
|
(index) => hierarchy.components[index.toString().padStart(4, "0")],
|
||||||
);
|
);
|
||||||
|
|
||||||
components.forEach((component) => {
|
components.forEach((component) => {
|
||||||
@@ -194,7 +196,7 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
}
|
}
|
||||||
if (polygonGroup === undefined) {
|
if (polygonGroup === undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Missing polygon group ${batch["rb.datasource"]}`
|
`Missing polygon group ${batch["rb.datasource"]}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +257,7 @@ export async function extractModel(vfs: SteamVFS, path: string) {
|
|||||||
default: {
|
default: {
|
||||||
if (ERROR_ON_UNKNOWN_COMPONENT) {
|
if (ERROR_ON_UNKNOWN_COMPONENT) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled component type: ${component["comp.typename"]}`
|
`Unhandled component type: ${component["comp.typename"]}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import sharp from "sharp";
|
|||||||
import { readTexture } from "./readTexture";
|
import { readTexture } from "./readTexture";
|
||||||
|
|
||||||
export async function readBaseColor(path: string, occlusionPath?: string) {
|
export async function readBaseColor(path: string, occlusionPath?: string) {
|
||||||
|
let hasAlpha = false;
|
||||||
const baseRaw = await readTexture(path);
|
const baseRaw = await readTexture(path);
|
||||||
const occlusionRaw = occlusionPath
|
const occlusionRaw = occlusionPath
|
||||||
? await readTexture(occlusionPath)
|
? await readTexture(occlusionPath)
|
||||||
@@ -30,10 +31,13 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
|
|||||||
c = occlusion![occlusionI] / 255;
|
c = occlusion![occlusionI] / 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const alpha = base[i * 4 + 3];
|
||||||
|
hasAlpha ||= alpha < 255;
|
||||||
|
|
||||||
combined[i * 4 + 0] = Math.round(base[i * 4 + 0] * c);
|
combined[i * 4 + 0] = Math.round(base[i * 4 + 0] * c);
|
||||||
combined[i * 4 + 1] = Math.round(base[i * 4 + 1] * c);
|
combined[i * 4 + 1] = Math.round(base[i * 4 + 1] * c);
|
||||||
combined[i * 4 + 2] = Math.round(base[i * 4 + 2] * c);
|
combined[i * 4 + 2] = Math.round(base[i * 4 + 2] * c);
|
||||||
combined[i * 4 + 3] = base[i * 4 + 3];
|
combined[i * 4 + 3] = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
const image = await sharp(combined, {
|
const image = await sharp(combined, {
|
||||||
@@ -42,5 +46,5 @@ export async function readBaseColor(path: string, occlusionPath?: string) {
|
|||||||
.webp()
|
.webp()
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|
||||||
return image;
|
return { hasAlpha, image };
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,16 @@
|
|||||||
import { exec as execSync } from "child_process";
|
import { execFile } from "child_process";
|
||||||
import { existsSync } from "fs";
|
import { existsSync } from "fs";
|
||||||
import { readdir, rm } from "fs/promises";
|
import { mkdir, readdir, rm, writeFile } from "fs/promises";
|
||||||
import { promisify } from "util";
|
|
||||||
|
|
||||||
const MAX_COMMAND_LENGTH = 2 ** 11;
|
|
||||||
const TS_PROTO_EXECUTABLE_LOCATIONS = [
|
const TS_PROTO_EXECUTABLE_LOCATIONS = [
|
||||||
"./node_modules/.bin/protoc-gen-ts_proto",
|
"./node_modules/.bin/protoc-gen-ts_proto",
|
||||||
"../../node_modules/.bin/protoc-gen-ts_proto",
|
"../../node_modules/.bin/protoc-gen-ts_proto",
|
||||||
];
|
];
|
||||||
|
const ROOTS = [
|
||||||
const roots = [
|
|
||||||
// "../../packages/core/src/protos",
|
|
||||||
"../../packages/closed/protos",
|
"../../packages/closed/protos",
|
||||||
|
"../../packages/website-ue/src/protos",
|
||||||
];
|
];
|
||||||
|
|
||||||
const exec = promisify(execSync);
|
|
||||||
|
|
||||||
let tsProtoExecutableLocation: string | undefined = undefined;
|
let tsProtoExecutableLocation: string | undefined = undefined;
|
||||||
|
|
||||||
for (const location of TS_PROTO_EXECUTABLE_LOCATIONS) {
|
for (const location of TS_PROTO_EXECUTABLE_LOCATIONS) {
|
||||||
@@ -36,42 +31,38 @@ if (!tsProtoExecutableLocation) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const root of roots) {
|
await mkdir("temp", { recursive: true });
|
||||||
|
|
||||||
|
for (const root of ROOTS) {
|
||||||
|
let args = "";
|
||||||
|
|
||||||
|
for (const include of ROOTS) {
|
||||||
|
args += `-I=${include}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
args += `--plugin=${tsProtoExecutableLocation}\n`;
|
||||||
|
args += "--ts_proto_opt=esModuleInterop=true\n";
|
||||||
|
args += "--ts_proto_opt=oneof=unions-value\n";
|
||||||
|
args += "--ts_proto_opt=unrecognizedEnum=false\n";
|
||||||
|
args += "--ts_proto_opt=snakeToCamel=false\n";
|
||||||
|
args += `--ts_proto_out=${root}\n`;
|
||||||
|
|
||||||
const filesRaw = await readdir(`${root}`);
|
const filesRaw = await readdir(`${root}`);
|
||||||
const files: string[] = [];
|
const files: string[] = [];
|
||||||
|
|
||||||
for (const file of filesRaw) {
|
for (const file of filesRaw) {
|
||||||
if (file.endsWith(".proto")) files.push(file);
|
if (file.endsWith(".proto")) {
|
||||||
|
files.push(file);
|
||||||
|
args += `${root}/${file}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
if (file.endsWith(".ts")) await rm(`${root}/${file}`);
|
if (file.endsWith(".ts")) await rm(`${root}/${file}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (files.length > 0) {
|
await writeFile("temp/protoc.txt", args);
|
||||||
let command = [
|
execFile("protoc", ["@temp/protoc.txt"], (error, stdout, stderr) => {
|
||||||
"protoc",
|
if (error) throw new Error(error.message);
|
||||||
`--plugin=${tsProtoExecutableLocation}`,
|
if (stderr) console.error(stderr);
|
||||||
"--ts_proto_opt=esModuleInterop=true",
|
if (stdout) console.log(stdout);
|
||||||
"--ts_proto_opt=oneof=unions-value",
|
});
|
||||||
// "--ts_proto_opt=removeEnumPrefix=true",
|
|
||||||
"--ts_proto_opt=unrecognizedEnum=false",
|
|
||||||
"--ts_proto_opt=snakeToCamel=false",
|
|
||||||
`--ts_proto_out=${root}`,
|
|
||||||
`-I=${root}`,
|
|
||||||
].join(" ");
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (files.length === 0) break;
|
|
||||||
|
|
||||||
const file = files.at(-1);
|
|
||||||
const newLine = ` ${root}/${file}`;
|
|
||||||
|
|
||||||
if (command.length + newLine.length < MAX_COMMAND_LENGTH) {
|
|
||||||
command += newLine;
|
|
||||||
files.pop();
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await exec(command);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import node from "@astrojs/node";
|
||||||
|
import react from "@astrojs/react";
|
||||||
|
import locales from "@blitzkit/i18n/locales.json";
|
||||||
|
import strings from "@blitzkit/i18n/strings/en.json";
|
||||||
|
import { mauve, mauveDark } from "@radix-ui/colors";
|
||||||
|
import favicons from "astro-favicons";
|
||||||
|
import { defineConfig } from "astro/config";
|
||||||
|
import packageJSON from "../../package.json";
|
||||||
|
|
||||||
|
const POSSIBLE_TARGETS = ["app", "web"];
|
||||||
|
|
||||||
|
const target = process.env.PUBLIC_TARGET;
|
||||||
|
|
||||||
|
if (!target || !POSSIBLE_TARGETS.includes(target)) {
|
||||||
|
throw new Error("Invalid target");
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
devToolbar: { enabled: false },
|
||||||
|
|
||||||
|
vite: {
|
||||||
|
server: { allowedHosts: [] },
|
||||||
|
|
||||||
|
esbuild: {
|
||||||
|
minifyIdentifiers: true,
|
||||||
|
minifySyntax: false,
|
||||||
|
minifyWhitespace: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: target === "web" ? "static" : "server",
|
||||||
|
site: "https://blitzkit.app",
|
||||||
|
outDir: "../../dist/website",
|
||||||
|
prefetch: { defaultStrategy: "hover", prefetchAll: true },
|
||||||
|
|
||||||
|
build: { concurrency: 4 },
|
||||||
|
adapter: target === "app" ? node({ mode: "standalone" }) : undefined,
|
||||||
|
|
||||||
|
integrations: [
|
||||||
|
favicons({
|
||||||
|
name: strings.common.name,
|
||||||
|
short_name: strings.common.name,
|
||||||
|
|
||||||
|
background: mauveDark.mauve1,
|
||||||
|
themes: [mauve.mauve1, mauveDark.mauve1],
|
||||||
|
appleStatusBarStyle: "black-translucent",
|
||||||
|
|
||||||
|
version: packageJSON.version,
|
||||||
|
|
||||||
|
// shortcuts: Object.values(tools)
|
||||||
|
// .filter((tool) => !tool.disabled && !tool.href)
|
||||||
|
// .map((tool) => {
|
||||||
|
// const stringId = (tool.strings ??
|
||||||
|
// tool.id) as keyof typeof strings.website.tools;
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// name: strings.website.tools[stringId].name,
|
||||||
|
// name_localized: wrapper(
|
||||||
|
// (strings) => strings.website.tools[stringId].name
|
||||||
|
// ),
|
||||||
|
// description: strings.website.tools[stringId].description,
|
||||||
|
// description_localized: wrapper(
|
||||||
|
// (strings) => strings.website.tools[stringId].description
|
||||||
|
// ),
|
||||||
|
// short_name: strings.website.tools[stringId].name,
|
||||||
|
// short_name_localized: wrapper(
|
||||||
|
// (strings) => strings.website.tools[stringId].name
|
||||||
|
// ),
|
||||||
|
// url: `/${tool.id}`,
|
||||||
|
// icon: `public/assets/tools/${tool.id}.webp`,
|
||||||
|
// };
|
||||||
|
// }),
|
||||||
|
|
||||||
|
manifest: {
|
||||||
|
// description: strings.website.home.seo_description,
|
||||||
|
// description_localized: wrapper(
|
||||||
|
// (strings) => strings.website.home.seo_description
|
||||||
|
// ),
|
||||||
|
|
||||||
|
dir: "ltr",
|
||||||
|
categories: ["utilities", "games", "developer", "developer tools"],
|
||||||
|
|
||||||
|
id: "com.tresabhi.blitzkit",
|
||||||
|
start_url: "/",
|
||||||
|
launch_handler: { client_mode: "navigate-new" },
|
||||||
|
display: "fullscreen",
|
||||||
|
display_override: ["fullscreen", "standalone", "minimal-ui"],
|
||||||
|
|
||||||
|
lang: locales.default,
|
||||||
|
orientation: "any",
|
||||||
|
},
|
||||||
|
|
||||||
|
icons: {
|
||||||
|
windows: true,
|
||||||
|
android: true,
|
||||||
|
appleIcon: true,
|
||||||
|
appleStartup: true,
|
||||||
|
favicons: true,
|
||||||
|
yandex: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
|
react(),
|
||||||
|
],
|
||||||
|
});
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"name": "@blitzkit/website-ue",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "PUBLIC_TARGET=web astro dev",
|
||||||
|
"build": "PUBLIC_TARGET=web astro build",
|
||||||
|
"preview": "PUBLIC_TARGET=web astro preview",
|
||||||
|
"lint": "PUBLIC_TARGET=web astro check",
|
||||||
|
"astro": "astro"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/check": "^0.9.4",
|
||||||
|
"@astrojs/node": "^9.4.4",
|
||||||
|
"@astrojs/react": "^4.4.0",
|
||||||
|
"@astrolib/seo": "^1.0.0-beta.8",
|
||||||
|
"@blitzkit/closed": "workspace:*",
|
||||||
|
"@blitzkit/core": "workspace:*",
|
||||||
|
"@blitzkit/game": "workspace:*",
|
||||||
|
"@blitzkit/i18n": "workspace:*",
|
||||||
|
"@bufbuild/protobuf": "^2.10.2",
|
||||||
|
"@fontsource-variable/roboto-flex": "^5.2.8",
|
||||||
|
"@fontsource-variable/roboto-mono": "^5.2.8",
|
||||||
|
"@radix-ui/colors": "^3.0.0",
|
||||||
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
|
"@react-three/drei": "^10.7.6",
|
||||||
|
"@react-three/fiber": "^9.4.0",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/react": "^19.2.2",
|
||||||
|
"@types/react-dom": "^19.2.2",
|
||||||
|
"@types/three": "^0.180.0",
|
||||||
|
"@vite-pwa/astro": "^1.1.0",
|
||||||
|
"@wooorm/starry-night": "^3.9.0",
|
||||||
|
"astro": "^5.14.4",
|
||||||
|
"astro-favicons": "^3.1.5",
|
||||||
|
"autoprefixer": "^10.4.23",
|
||||||
|
"cssnano": "^7.1.2",
|
||||||
|
"fuzzysort": "^3.1.0",
|
||||||
|
"googleapis": "^171.1.0",
|
||||||
|
"hast-util-to-jsx-runtime": "^2.3.6",
|
||||||
|
"immer": "^10.1.3",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"postcss": "^8.5.6",
|
||||||
|
"postcss-load-config": "^6.0.1",
|
||||||
|
"postcss-nested": "^7.0.2",
|
||||||
|
"postcss-preset-env": "^11.1.1",
|
||||||
|
"quicklime": "^1.2.0",
|
||||||
|
"react": "^19.2.0",
|
||||||
|
"react-dom": "^19.2.0",
|
||||||
|
"react-markdown": "^10.1.0",
|
||||||
|
"react-promise-suspense": "^0.3.4",
|
||||||
|
"sharp": "^0.34.5",
|
||||||
|
"three": "^0.180.0",
|
||||||
|
"three-stdlib": "^2.36.0",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"varuna": "workspace:*",
|
||||||
|
"vite": "^7.1.9",
|
||||||
|
"yaml": "^2.8.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import cssnano from "cssnano";
|
||||||
|
import type { Config } from "postcss-load-config";
|
||||||
|
import postcssPresetEnv from "postcss-preset-env";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
plugins: [
|
||||||
|
require("autoprefixer"),
|
||||||
|
require("postcss-nested"),
|
||||||
|
|
||||||
|
cssnano({
|
||||||
|
preset: "default",
|
||||||
|
}),
|
||||||
|
|
||||||
|
postcssPresetEnv({
|
||||||
|
features: {},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
} satisfies Config;
|
||||||
|
After Width: | Height: | Size: 481 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="21" height="54" viewBox="0 0 21 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21 38L10 49H0L11 38L0 27H10L21 38ZM21 1V21L20 22H10L21 11L10 0H20L21 1ZM10 11L0 21V1L10 11Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 221 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="30" height="52" viewBox="0 0 30 52" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M13.8564 44V52H0V36L13.8564 44ZM30 52H16.1436V44L30 36V52ZM28.8564 18V34L15 42L1.14355 34V18L15 10L28.8564 18ZM13.8564 8L0 16V0H13.8564V8ZM30 16L16.1436 8V0H30V16Z" fill="#EEEEF0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 294 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="70" height="35" viewBox="0 0 70 35" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M70 32L64 35H0L70 0V32ZM0 32V0H64L0 32Z" fill="#EEEEF0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 453 KiB |
|
After Width: | Height: | Size: 676 KiB |
|
After Width: | Height: | Size: 405 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 443 KiB |
|
After Width: | Height: | Size: 330 KiB |
|
After Width: | Height: | Size: 715 KiB |
|
After Width: | Height: | Size: 144 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 274 KiB |
|
After Width: | Height: | Size: 346 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 406 KiB |
|
After Width: | Height: | Size: 360 KiB |